diff --git a/DEPS b/DEPS
index 90acccb7d..c97f40b 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'ea49cd0a053b89c31013b98a4763b9c9c75fe07a',
+  'v8_revision': '165c183f7c47e7ff100baa5dd4d96948e239460b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -64,7 +64,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': 'cddc8eddbd33e8e96540341eb9781403ae423b93',
+  'pdfium_revision': '5e57faaa7fbcfe25a9b708b3972509b322f803db',
   # 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.
@@ -96,7 +96,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': 'a64c010c74cc810921c037fcf7ccee1d5c5b0c00',
+  'catapult_revision': '06fd359d488b119665f6281e31b98514b0cf77a3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.cc b/android_webview/browser/net/aw_cookie_store_wrapper.cc
index 70f7b4c..17423fd 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.cc
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.cc
@@ -16,8 +16,8 @@
 namespace {
 
 // Posts |task| to the thread that the global CookieStore lives on.
-void PostTaskToCookieStoreTaskRunner(const base::Closure& task) {
-  GetCookieStoreTaskRunner()->PostTask(FROM_HERE, task);
+void PostTaskToCookieStoreTaskRunner(base::OnceClosure task) {
+  GetCookieStoreTaskRunner()->PostTask(FROM_HERE, std::move(task));
 }
 
 // Wraps a subscription to cookie change notifications for the global
@@ -128,6 +128,15 @@
       last_access_time, secure, http_only, same_site, priority, callback);
 }
 
+void SetCanonicalCookieAsyncOnCookieThread(
+    std::unique_ptr<net::CanonicalCookie> cookie,
+    bool secure_source,
+    bool modify_http_only,
+    const net::CookieStore::SetCookiesCallback& callback) {
+  GetCookieStore()->SetCanonicalCookieAsync(std::move(cookie), secure_source,
+                                            modify_http_only, callback);
+}
+
 void GetCookiesWithOptionsAsyncOnCookieThread(
     const GURL& url,
     const net::CookieOptions& options,
@@ -230,6 +239,17 @@
                  CreateWrappedCallback<bool>(callback)));
 }
 
+void AwCookieStoreWrapper::SetCanonicalCookieAsync(
+    std::unique_ptr<net::CanonicalCookie> cookie,
+    bool secure_source,
+    bool modify_http_only,
+    const SetCookiesCallback& callback) {
+  DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+  PostTaskToCookieStoreTaskRunner(base::BindOnce(
+      &SetCanonicalCookieAsyncOnCookieThread, std::move(cookie), secure_source,
+      modify_http_only, CreateWrappedCallback<bool>(callback)));
+}
+
 void AwCookieStoreWrapper::GetCookiesWithOptionsAsync(
     const GURL& url,
     const net::CookieOptions& options,
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.h b/android_webview/browser/net/aw_cookie_store_wrapper.h
index cf8bfbd..860f81a4a 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.h
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.h
@@ -58,6 +58,10 @@
                                  net::CookieSameSite same_site,
                                  net::CookiePriority priority,
                                  const SetCookiesCallback& callback) override;
+  void SetCanonicalCookieAsync(std::unique_ptr<net::CanonicalCookie> cookie,
+                               bool secure_source,
+                               bool modify_http_only,
+                               const SetCookiesCallback& callback) override;
   void GetCookiesWithOptionsAsync(const GURL& url,
                                   const net::CookieOptions& options,
                                   const GetCookiesCallback& callback) override;
diff --git a/base/logging.h b/base/logging.h
index ccfb62a2..0660e7c 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -306,6 +306,9 @@
 // to Clang which control what code paths are statically analyzed,
 // and is meant to be used in conjunction with assert & assert-like functions.
 // The expression is passed straight through if analysis isn't enabled.
+//
+// ANALYZER_SKIP_THIS_PATH() suppresses static analysis for the current
+// codepath and any other branching codepaths that might follow.
 #if defined(__clang_analyzer__)
 
 inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) {
@@ -318,11 +321,14 @@
   return arg || AnalyzerNoReturn();
 }
 
-#define ANALYZER_ASSUME_TRUE(arg) ::logging::AnalyzerAssumeTrue(!!(arg))
+#define ANALYZER_ASSUME_TRUE(arg) logging::AnalyzerAssumeTrue(!!(arg))
+#define ANALYZER_SKIP_THIS_PATH() \
+  static_cast<void>(::logging::AnalyzerNoReturn())
 
 #else  // !defined(__clang_analyzer__)
 
 #define ANALYZER_ASSUME_TRUE(arg) (arg)
+#define ANALYZER_SKIP_THIS_PATH()
 
 #endif  // defined(__clang_analyzer__)
 
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
index 3695f87b..56bd4025 100644
--- a/base/memory/ref_counted.h
+++ b/base/memory/ref_counted.h
@@ -271,6 +271,11 @@
 
   void Release() const {
     if (subtle::RefCountedBase::Release()) {
+      // Prune the code paths which the static analyzer may take to simulate
+      // object destruction. Use-after-free errors aren't possible given the
+      // lifetime guarantees of the refcounting system.
+      ANALYZER_SKIP_THIS_PATH();
+
       delete static_cast<const T*>(this);
     }
   }
@@ -328,6 +333,7 @@
 
   void Release() const {
     if (subtle::RefCountedThreadSafeBase::Release()) {
+      ANALYZER_SKIP_THIS_PATH();
       Traits::Destruct(static_cast<const T*>(this));
     }
   }
@@ -527,13 +533,19 @@
   }
 
   scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
-    scoped_refptr<T>(std::move(r)).swap(*this);
+    scoped_refptr<T> tmp(std::move(r));
+    tmp.swap(*this);
     return *this;
   }
 
   template <typename U>
   scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
-    scoped_refptr<T>(std::move(r)).swap(*this);
+    // We swap with a temporary variable to guarantee that |ptr_| is released
+    // immediately. A naive implementation which swaps |this| and |r| would
+    // unintentionally extend the lifetime of |ptr_| to at least the lifetime of
+    // |r|.
+    scoped_refptr<T> tmp(std::move(r));
+    tmp.swap(*this);
     return *this;
   }
 
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc
index 62e3f54..f91fd420 100644
--- a/base/memory/ref_counted_unittest.cc
+++ b/base/memory/ref_counted_unittest.cc
@@ -415,6 +415,27 @@
   EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
 }
 
+TEST(RefCountedUnitTest, MoveAssignmentSelfMove) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase* raw = new ScopedRefPtrCountBase;
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+    scoped_refptr<ScopedRefPtrCountBase>& p1_ref = p1;
+
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    p1 = std::move(p1_ref);
+
+    // |p1| is "valid but unspecified", so don't bother inspecting its
+    // contents, just ensure that we don't crash.
+  }
+
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
 TEST(RefCountedUnitTest, MoveAssignmentDerived) {
   ScopedRefPtrCountBase::reset_count();
   ScopedRefPtrCountDerived::reset_count();
diff --git a/base/process/launch_fuchsia.cc b/base/process/launch_fuchsia.cc
index 21ab302..54591f9f 100644
--- a/base/process/launch_fuchsia.cc
+++ b/base/process/launch_fuchsia.cc
@@ -93,17 +93,25 @@
   launchpad_load_from_file(lp, argv_cstr[0]);
   launchpad_set_args(lp, argv.size(), argv_cstr.data());
 
-  uint32_t to_clone =
-      LP_CLONE_MXIO_ROOT | LP_CLONE_MXIO_CWD | LP_CLONE_DEFAULT_JOB;
+  uint32_t to_clone = LP_CLONE_MXIO_ROOT | LP_CLONE_DEFAULT_JOB;
 
   std::unique_ptr<char* []> new_environ;
   char* const empty_environ = nullptr;
   char* const* old_environ = environ;
   if (options.clear_environ)
     old_environ = &empty_environ;
-  if (!options.environ.empty())
-    new_environ = AlterEnvironment(old_environ, options.environ);
-  if (!options.environ.empty() || options.clear_environ)
+
+  EnvironmentMap environ_modifications = options.environ;
+  if (!options.current_directory.empty()) {
+    environ_modifications["PWD"] = options.current_directory.value();
+  } else {
+    to_clone |= LP_CLONE_MXIO_CWD;
+  }
+
+  if (!environ_modifications.empty())
+    new_environ = AlterEnvironment(old_environ, environ_modifications);
+
+  if (!environ_modifications.empty() || options.clear_environ)
     launchpad_set_environ(lp, new_environ.get());
   else
     to_clone |= LP_CLONE_ENVIRON;
diff --git a/build/android/gyp/lint.py b/build/android/gyp/lint.py
index ea9055cf..22d0506 100755
--- a/build/android/gyp/lint.py
+++ b/build/android/gyp/lint.py
@@ -23,7 +23,7 @@
 
 def _OnStaleMd5(lint_path, config_path, processed_config_path,
                 manifest_path, result_path, product_dir, sources, jar_path,
-                cache_dir, android_sdk_version, resource_sources,
+                cache_dir, android_sdk_version, srcjars, resource_sources,
                 disable=None, classpath=None, can_fail_build=False,
                 silent=False):
   def _RebasePath(path):
@@ -150,6 +150,14 @@
         cmd.extend(['--sources', _RebasePath(src_dir)])
       os.symlink(os.path.abspath(src), PathInDir(src_dir, src))
 
+    if srcjars:
+      srcjar_paths = build_utils.ParseGnList(srcjars)
+      if srcjar_paths:
+        srcjar_dir = _NewTempSubdir('SRC_ROOT')
+        cmd.extend(['--sources', _RebasePath(srcjar_dir)])
+        for srcjar in srcjar_paths:
+          build_utils.ExtractAll(srcjar, path=srcjar_dir)
+
     if disable:
       cmd.extend(['--disable', ','.join(disable)])
 
@@ -287,6 +295,8 @@
                       help='Directories containing java files.')
   parser.add_argument('--stamp',
                       help='Path to touch on success.')
+  parser.add_argument('--srcjars',
+                      help='GN list of included srcjars.')
 
   args = parser.parse_args(build_utils.ExpandFileArgs(sys.argv[1:]))
 
@@ -358,6 +368,7 @@
                           args.jar_path,
                           args.cache_dir,
                           args.android_sdk_version,
+                          args.srcjars,
                           resource_sources,
                           disable=disable,
                           classpath=classpath,
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 2da62f84..c085176 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -417,6 +417,8 @@
     if options.bundled_srcjars:
       gradle['bundled_srcjars'] = (
           build_utils.ParseGnList(options.bundled_srcjars))
+    else:
+      gradle['bundled_srcjars'] = []
 
     gradle['dependent_android_projects'] = []
     gradle['dependent_java_projects'] = []
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index b7a7dda..6eebc4a 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -268,6 +268,8 @@
     <ignore regexp="chrome/android/chrome_strings_grd.resources.zip/values-sv/android_chrome_strings.xml"/>
     <ignore regexp="chrome/android/chrome_strings_grd.resources.zip/values-tl/android_chrome_strings.xml"/>
   </issue>
+  <!-- We have many C++ enums that we don't care about in java -->
+  <issue id="SwitchIntDef" severity="ignore"/>
   <issue id="TextFields" severity="Error">
     <ignore regexp="chromecast/internal"/>
   </issue>
@@ -290,6 +292,8 @@
     <ignore regexp="chrome/android/chrome_strings_grd.resources.zip/values-zh-rCN/android_chrome_strings.xml"/>
     <ignore regexp="chrome/android/chrome_strings_grd.resources.zip/values-zh-rTW/android_chrome_strings.xml"/>
   </issue>
+  <!-- Our generated enums are allowed to have the same values. -->
+  <issue id="UniqueConstants" severity="ignore"/>
   <!-- TODO(crbug.com/635567): Fix this properly. -->
   <issue id="UnusedResources" severity="ignore"/>
   <issue id="UnusedResources">
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 6407731..1d3b2f5 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -835,6 +835,7 @@
           "--classpath=@FileArg($_rebased_build_config:javac:interface_classpath)",
           "--resource-sources=@FileArg($_rebased_build_config:deps_info:owned_resources_dirs)",
           "--resource-sources=@FileArg($_rebased_build_config:deps_info:owned_resources_zips)",
+          "--srcjars=@FileArg($_rebased_build_config:gradle:bundled_srcjars)",
           "--can-fail-build",
         ]
       }
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc
index 8714fb5..a79d886c 100644
--- a/cc/paint/display_item_list.cc
+++ b/cc/paint/display_item_list.cc
@@ -73,8 +73,7 @@
   paint_op_buffer_.ShrinkToFit();
   rtree_.Build(visual_rects_);
 
-  if (!retain_visual_rects_)
-    visual_rects_.clear();
+  visual_rects_.clear();
   visual_rects_.shrink_to_fit();
   begin_paired_indices_.shrink_to_fit();
 }
@@ -110,15 +109,7 @@
     state->BeginArray("items");
 
     for (size_t i = 0; i < paint_op_buffer_.size(); ++i) {
-      gfx::Rect visual_rect = visual_rects_[i];
-
       state->BeginDictionary();
-      state->BeginArray("visualRect");
-      state->AppendInteger(visual_rect.x());
-      state->AppendInteger(visual_rect.y());
-      state->AppendInteger(visual_rect.width());
-      state->AppendInteger(visual_rect.height());
-      state->EndArray();
 
       SkPictureRecorder recorder;
       SkCanvas* canvas =
@@ -130,6 +121,7 @@
       std::string b64_picture;
       PictureDebugUtil::SerializeAsBase64(picture.get(), &b64_picture);
       state->SetString("skp64", b64_picture);
+
       state->EndDictionary();
     }
 
diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h
index a115c90..e204d8f 100644
--- a/cc/paint/display_item_list.h
+++ b/cc/paint/display_item_list.h
@@ -123,10 +123,6 @@
                                   std::vector<DrawImage>* images);
   gfx::Rect GetRectForImage(PaintImage::Id image_id) const;
 
-  void SetRetainVisualRectsForTesting(bool retain) {
-    retain_visual_rects_ = retain;
-  }
-
   gfx::Rect VisualRectForTesting(int index) { return visual_rects_[index]; }
 
   void GatherDiscardableImages(DiscardableImageStore* image_store) const;
@@ -181,9 +177,6 @@
   bool in_painting_ = false;
 
   size_t op_count_ = 0u;
-  // For testing purposes only. Whether to keep visual rects across calls to
-  // Finalize().
-  bool retain_visual_rects_ = false;
 
   friend class base::RefCountedThreadSafe<DisplayItemList>;
   FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, BytesUsed);
diff --git a/cc/paint/display_item_list_unittest.cc b/cc/paint/display_item_list_unittest.cc
index 6250247..d5ff486 100644
--- a/cc/paint/display_item_list_unittest.cc
+++ b/cc/paint/display_item_list_unittest.cc
@@ -380,7 +380,6 @@
 
 TEST(DisplayItemListTest, AsValueWithNoOps) {
   auto list = make_scoped_refptr(new DisplayItemList);
-  list->SetRetainVisualRectsForTesting(true);
   list->Finalize();
 
   // Pass |true| to ask for PaintOps even though there are none.
@@ -442,7 +441,6 @@
 TEST(DisplayItemListTest, AsValueWithOps) {
   gfx::Rect layer_rect = gfx::Rect(1, 2, 8, 9);
   auto list = make_scoped_refptr(new DisplayItemList);
-  list->SetRetainVisualRectsForTesting(true);
   gfx::Transform transform;
   transform.Translate(6.f, 7.f);
 
@@ -505,20 +503,12 @@
 
       for (int i = 0; i < 6; ++i) {
         const base::DictionaryValue* item_dict;
-        const base::ListValue* visual_rect_list;
 
         ASSERT_TRUE(list->GetDictionary(i, &item_dict));
 
         // The SkPicture for each item exists.
         EXPECT_TRUE(
             item_dict->GetString("skp64", static_cast<std::string*>(nullptr)));
-        // The range has a visual rect, it is the same for each item here.
-        EXPECT_TRUE(item_dict->GetList("visualRect", &visual_rect_list));
-        ASSERT_EQ(4u, visual_rect_list->GetSize());
-        EXPECT_TRUE(visual_rect_list->GetDouble(0, &d) && d == 2) << d;
-        EXPECT_TRUE(visual_rect_list->GetDouble(1, &d) && d == 3) << d;
-        EXPECT_TRUE(visual_rect_list->GetDouble(2, &d) && d == 8) << d;
-        EXPECT_TRUE(visual_rect_list->GetDouble(3, &d) && d == 9) << d;
       }
     }
   }
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc
index 5b5e74d..a384a53 100644
--- a/cc/test/fake_content_layer_client.cc
+++ b/cc/test/fake_content_layer_client.cc
@@ -45,7 +45,6 @@
 FakeContentLayerClient::PaintContentsToDisplayList(
     PaintingControlSetting painting_control) {
   auto display_list = make_scoped_refptr(new DisplayItemList);
-  display_list->SetRetainVisualRectsForTesting(true);
 
   for (RectPaintVector::const_iterator it = draw_rects_.begin();
        it != draw_rects_.end(); ++it) {
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index f1f0836..7c258ae6 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -160,6 +160,14 @@
   ]
 }
 
+android_aidl("photo_picker_aidl") {
+  import_include = [ "java/src/org/chromium/chrome/browser/photo_picker" ]
+  sources = [
+    "java/src/org/chromium/chrome/browser/photo_picker/IDecoderService.aidl",
+    "java/src/org/chromium/chrome/browser/photo_picker/IDecoderServiceCallback.aidl",
+  ]
+}
+
 android_library("chrome_java") {
   deps = [
     ":chrome_java_resources",
@@ -247,6 +255,7 @@
     ":chrome_android_java_enums_srcjar",
     ":chrome_android_java_google_api_keys_srcjar",
     ":chrome_version_srcjar",
+    ":photo_picker_aidl",
     ":resource_id_javagen",
     "//chrome:content_setting_javagen",
     "//chrome:content_settings_type_javagen",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WebApkChildProcessServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/WebApkChildProcessServiceImpl.java
index 746e28f8b..5660351 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/WebApkChildProcessServiceImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WebApkChildProcessServiceImpl.java
@@ -10,6 +10,7 @@
 
 import org.chromium.base.annotations.UsedByReflection;
 import org.chromium.content.app.ChildProcessServiceImpl;
+import org.chromium.content.app.ContentChildProcessServiceDelegate;
 
 /**
  * This class exposes ChildProcessServiceImpl so that WebApkSandboxedProcessService can access it
@@ -20,7 +21,8 @@
     private final ChildProcessServiceImpl mChildProcessServiceImpl;
 
     public WebApkChildProcessServiceImpl() {
-        mChildProcessServiceImpl = new ChildProcessServiceImpl();
+        mChildProcessServiceImpl =
+                new ChildProcessServiceImpl(new ContentChildProcessServiceDelegate());
     }
 
     @UsedByReflection("WebApkSandboxedProcessService")
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
index f37ecd6d..2e0681b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
@@ -70,7 +70,7 @@
      * @param phoneNumber The phone number to possibly add.
      */
     public void addPhoneNumberIfValid(@Nullable CharSequence phoneNumber) {
-        if (TextUtils.isEmpty(phoneNumber)) mPhoneNumbers.add(phoneNumber.toString());
+        if (!TextUtils.isEmpty(phoneNumber)) mPhoneNumbers.add(phoneNumber.toString());
     }
 
     /**
@@ -143,6 +143,12 @@
         // that's being edited. This will not fire the dropdown callback.
         mCountryField.setValue(AutofillAddress.getCountryCode(mProfile));
 
+        // Phone number validator and formatter are cached, so their contry code needs to be updated
+        // for the new profile that's being edited.
+        assert mCountryField.getValue() != null;
+        mPhoneValidator.setCountryCode(mCountryField.getValue().toString());
+        mPhoneFormatter.setCountryCode(mCountryField.getValue().toString());
+
         // There's a finite number of fields for address editing. Changing the country will re-order
         // and relabel the fields. The meaning of each field remains the same.
         if (mAddressFields.isEmpty()) {
@@ -170,9 +176,6 @@
 
         // Phone number is present and required for all countries.
         if (mPhoneField == null) {
-            assert mCountryField.getValue() != null;
-            mPhoneValidator.setCountryCode(mCountryField.getValue().toString());
-            mPhoneFormatter.setCountryCode(mCountryField.getValue().toString());
             mPhoneField = EditorFieldModel.createTextInput(EditorFieldModel.INPUT_TYPE_HINT_PHONE,
                     mContext.getString(R.string.autofill_profile_editor_phone_number),
                     mPhoneNumbers, mPhoneFormatter, mPhoneValidator, null,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
index 9f307683..77c06c19 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
@@ -8,10 +8,7 @@
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -25,19 +22,10 @@
  * A service to accept requests to take image file contents and decode them.
  */
 public class DecoderService extends Service {
-    // Message ids for communicating with the client.
-
-    // A message sent by the client to decode an image.
-    static final int MSG_DECODE_IMAGE = 1;
-    // A message sent by the server to notify the client of the results of the decoding.
-    static final int MSG_IMAGE_DECODED_REPLY = 2;
-
     // The keys for the bundle when passing data to and from this service.
     static final String KEY_FILE_DESCRIPTOR = "file_descriptor";
     static final String KEY_FILE_PATH = "file_path";
     static final String KEY_IMAGE_BITMAP = "image_bitmap";
-    static final String KEY_IMAGE_BYTE_COUNT = "image_byte_count";
-    static final String KEY_IMAGE_DESCRIPTOR = "image_descriptor";
     static final String KEY_SIZE = "size";
     static final String KEY_SUCCESS = "success";
     static final String KEY_DECODE_TIME = "decode_time";
@@ -45,98 +33,78 @@
     // A tag for logging error messages.
     private static final String TAG = "ImageDecoder";
 
-    /**
-     * Handler for incoming messages from clients.
-     */
-    static class IncomingHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_DECODE_IMAGE:
-                    Bundle bundle = null;
-                    Messenger client = null;
-                    String filePath = "";
-                    int size = 0;
-                    try {
-                        Bundle payload = msg.getData();
-                        client = msg.replyTo;
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
 
-                        filePath = payload.getString(KEY_FILE_PATH);
-                        ParcelFileDescriptor pfd = payload.getParcelable(KEY_FILE_DESCRIPTOR);
-                        size = payload.getInt(KEY_SIZE);
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
 
-                        // Setup a minimum viable response to parent process. Will be fleshed out
-                        // further below.
-                        bundle = new Bundle();
-                        bundle.putString(KEY_FILE_PATH, filePath);
-                        bundle.putBoolean(KEY_SUCCESS, false);
+    private final IDecoderService.Stub mBinder = new IDecoderService.Stub() {
+        public void decodeImage(Bundle payload, IDecoderServiceCallback callback) {
+            Bundle bundle = null;
+            String filePath = "";
+            int size = 0;
+            try {
+                filePath = payload.getString(KEY_FILE_PATH);
+                ParcelFileDescriptor pfd = payload.getParcelable(KEY_FILE_DESCRIPTOR);
+                size = payload.getInt(KEY_SIZE);
 
-                        FileDescriptor fd = pfd.getFileDescriptor();
+                // Setup a minimum viable response to parent process. Will be fleshed out
+                // further below.
+                bundle = new Bundle();
+                bundle.putString(KEY_FILE_PATH, filePath);
+                bundle.putBoolean(KEY_SUCCESS, false);
 
-                        long begin = SystemClock.elapsedRealtime();
-                        Bitmap bitmap = BitmapUtils.decodeBitmapFromFileDescriptor(fd, size);
-                        long decodeTime = SystemClock.elapsedRealtime() - begin;
+                FileDescriptor fd = pfd.getFileDescriptor();
 
-                        try {
-                            pfd.close();
-                        } catch (IOException e) {
-                            Log.e(TAG, "Closing failed " + filePath + " (size: " + size + ") " + e);
-                        }
+                long begin = SystemClock.elapsedRealtime();
+                Bitmap bitmap = BitmapUtils.decodeBitmapFromFileDescriptor(fd, size);
+                long decodeTime = SystemClock.elapsedRealtime() - begin;
 
-                        if (bitmap == null) {
-                            Log.e(TAG, "Decode failed " + filePath + " (size: " + size + ")");
-                            sendReply(client, bundle); // Sends SUCCESS == false;
-                            return;
-                        }
+                try {
+                    pfd.close();
+                } catch (IOException e) {
+                    Log.e(TAG, "Closing failed " + filePath + " (size: " + size + ") " + e);
+                }
 
-                        // The most widely supported, easiest, and reasonably efficient method is to
-                        // decode to an immutable bitmap and just return the bitmap over binder. It
-                        // will internally memcpy itself to ashmem and then just send over the file
-                        // descriptor. In the receiving process it will just leave the bitmap on
-                        // ashmem since it's immutable and carry on.
-                        bundle.putParcelable(KEY_IMAGE_BITMAP, bitmap);
-                        bundle.putBoolean(KEY_SUCCESS, true);
-                        bundle.putLong(KEY_DECODE_TIME, decodeTime);
-                        sendReply(client, bundle);
-                        bitmap.recycle();
-                    } catch (Exception e) {
-                        // This service has no UI and maintains no state so if it crashes on
-                        // decoding a photo, it is better UX to eat the exception instead of showing
-                        // a crash dialog and discarding other requests that have already been sent.
-                        Log.e(TAG,
-                                "Unexpected error during decoding " + filePath + " (size: " + size
-                                        + ") " + e);
+                if (bitmap == null) {
+                    Log.e(TAG, "Decode failed " + filePath + " (size: " + size + ")");
+                    sendReply(callback, bundle); // Sends SUCCESS == false;
+                    return;
+                }
 
-                        if (bundle != null && client != null) sendReply(client, bundle);
-                    }
-                    break;
-                default:
-                    super.handleMessage(msg);
+                // The most widely supported, easiest, and reasonably efficient method is to
+                // decode to an immutable bitmap and just return the bitmap over binder. It
+                // will internally memcpy itself to ashmem and then just send over the file
+                // descriptor. In the receiving process it will just leave the bitmap on
+                // ashmem since it's immutable and carry on.
+                bundle.putParcelable(KEY_IMAGE_BITMAP, bitmap);
+                bundle.putBoolean(KEY_SUCCESS, true);
+                bundle.putLong(KEY_DECODE_TIME, decodeTime);
+                sendReply(callback, bundle);
+                bitmap.recycle();
+            } catch (Exception e) {
+                // This service has no UI and maintains no state so if it crashes on
+                // decoding a photo, it is better UX to eat the exception instead of showing
+                // a crash dialog and discarding other requests that have already been sent.
+                Log.e(TAG,
+                        "Unexpected error during decoding " + filePath + " (size: " + size + ") "
+                                + e);
+
+                if (bundle != null) sendReply(callback, bundle);
             }
         }
 
-        private void sendReply(Messenger client, Bundle bundle) {
-            Message reply = Message.obtain(null, MSG_IMAGE_DECODED_REPLY);
-            reply.setData(bundle);
+        private void sendReply(IDecoderServiceCallback callback, Bundle bundle) {
             try {
-                client.send(reply);
+                callback.onDecodeImageDone(bundle);
             } catch (RemoteException remoteException) {
                 Log.e(TAG, "Remote error while replying: " + remoteException);
             }
         }
-    }
-
-    /**
-     * The target we publish for clients to send messages to IncomingHandler.
-     */
-    final Messenger mMessenger = new Messenger(new IncomingHandler());
-
-    /**
-     * When binding to the service, we return an interface to our messenger
-     * for sending messages to the service.
-     */
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mMessenger.getBinder();
-    }
+    };
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
index e5cf11c..b3b728c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
@@ -10,16 +10,15 @@
 import android.content.ServiceConnection;
 import android.graphics.Bitmap;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.SystemClock;
+import android.support.annotation.Nullable;
 
 import org.chromium.base.Log;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.util.ConversionUtils;
 
@@ -27,17 +26,31 @@
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.lang.ref.WeakReference;
 import java.util.LinkedHashMap;
 import java.util.concurrent.TimeUnit;
 
 /**
  * A class to communicate with the {@link DecoderService}.
  */
-public class DecoderServiceHost {
+public class DecoderServiceHost extends IDecoderServiceCallback.Stub {
     // A tag for logging error messages.
     private static final String TAG = "ImageDecoderHost";
 
+    IDecoderService mIRemoteService;
+    private ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            mIRemoteService = IDecoderService.Stub.asInterface(service);
+            mBound = true;
+            mCallback.serviceReady();
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            Log.e(TAG, "Service has unexpectedly disconnected");
+            mIRemoteService = null;
+            mBound = false;
+        }
+    };
+
     /**
      * Interface for notifying clients of the service being ready.
      */
@@ -61,30 +74,6 @@
     }
 
     /**
-     * Class for interacting with the main interface of the service.
-     */
-    private class DecoderServiceConnection implements ServiceConnection {
-        // The callback to use to notify the service being ready.
-        private ServiceReadyCallback mCallback;
-
-        public DecoderServiceConnection(ServiceReadyCallback callback) {
-            mCallback = callback;
-        }
-
-        // Called when a connection to the service has been established.
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            mService = new Messenger(service);
-            mBound = true;
-            mCallback.serviceReady();
-        }
-
-        // Called when a connection to the service has been lost.
-        public void onServiceDisconnected(ComponentName name) {
-            mBound = false;
-        }
-    }
-
-    /**
      * Class for keeping track of the data involved with each request.
      */
     private static class DecoderServiceParams {
@@ -116,24 +105,18 @@
     // The callback used to notify the client when the service is ready.
     private ServiceReadyCallback mCallback;
 
-    // Messenger for communicating with the remote service.
-    Messenger mService = null;
-
-    // Our service connection to the {@link DecoderService}.
-    private DecoderServiceConnection mConnection;
-
     // Flag indicating whether we are bound to the service.
-    boolean mBound;
+    private boolean mBound;
 
-    // The inbound messenger used by the remote service to communicate with us.
-    final Messenger mMessenger = new Messenger(new IncomingHandler(this));
+    private final Context mContext;
 
     /**
      * The DecoderServiceHost constructor.
      * @param callback The callback to use when communicating back to the client.
      */
-    public DecoderServiceHost(ServiceReadyCallback callback) {
+    public DecoderServiceHost(ServiceReadyCallback callback, Context context) {
         mCallback = callback;
+        mContext = context;
     }
 
     /**
@@ -141,9 +124,9 @@
      * @param context The context to use.
      */
     public void bind(Context context) {
-        mConnection = new DecoderServiceConnection(mCallback);
-        Intent intent = new Intent(context, DecoderService.class);
-        context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+        Intent intent = new Intent(mContext, DecoderService.class);
+        intent.setAction(IDecoderService.class.getName());
+        mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
     }
 
     /**
@@ -181,15 +164,35 @@
         }
     }
 
+    @Override
+    public void onDecodeImageDone(final Bundle payload) {
+        // As per the Android documentation, AIDL callbacks can (and will) happen on any thread, so
+        // make sure the code runs on the UI thread, since further down the callchain the code will
+        // end up creating UI objects.
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Read the reply back from the service.
+                String filePath = payload.getString(DecoderService.KEY_FILE_PATH);
+                Boolean success = payload.getBoolean(DecoderService.KEY_SUCCESS);
+                Bitmap bitmap = success
+                        ? (Bitmap) payload.getParcelable(DecoderService.KEY_IMAGE_BITMAP)
+                        : null;
+                long decodeTime = payload.getLong(DecoderService.KEY_DECODE_TIME);
+                closeRequest(filePath, bitmap, decodeTime);
+            }
+        });
+    }
+
     /**
      * Ties up all the loose ends from the decoding request (communicates the results of the
      * decoding process back to the client, and takes care of house-keeping chores regarding
      * the request queue).
      * @param filePath The path to the image that was just decoded.
-     * @param bitmap The resulting decoded bitmap.
+     * @param bitmap The resulting decoded bitmap, or null if decoding fails.
      * @param decodeTime The length of time it took to decode the bitmap.
      */
-    public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) {
+    public void closeRequest(String filePath, @Nullable Bitmap bitmap, long decodeTime) {
         DecoderServiceParams params = getRequests().get(filePath);
         if (params != null) {
             long endRpcCall = SystemClock.elapsedRealtime();
@@ -198,7 +201,7 @@
 
             params.mCallback.imageDecodedCallback(filePath, bitmap);
 
-            if (decodeTime != -1) {
+            if (decodeTime != -1 && bitmap != null) {
                 RecordHistogram.recordTimesHistogram(
                         "Android.PhotoPicker.ImageDecodeTime", decodeTime, TimeUnit.MILLISECONDS);
 
@@ -248,13 +251,10 @@
         if (pfd == null) return;
 
         // Prepare and send the data over.
-        Message payload = Message.obtain(null, DecoderService.MSG_DECODE_IMAGE);
-        payload.replyTo = mMessenger;
         bundle.putString(DecoderService.KEY_FILE_PATH, filePath);
         bundle.putInt(DecoderService.KEY_SIZE, size);
-        payload.setData(bundle);
         try {
-            mService.send(payload);
+            mIRemoteService.decodeImage(bundle, this);
             pfd.close();
         } catch (RemoteException e) {
             Log.e(TAG, "Communications failed (Remote): " + e);
@@ -272,46 +272,4 @@
     public void cancelDecodeImage(String filePath) {
         mRequests.remove(filePath);
     }
-
-    /**
-     * A class for handling communications from the service to us.
-     */
-    static class IncomingHandler extends Handler {
-        // The DecoderServiceHost object to communicate with.
-        private final WeakReference<DecoderServiceHost> mHost;
-
-        /**
-         * Constructor for IncomingHandler.
-         * @param host The DecoderServiceHost object to communicate with.
-         */
-        IncomingHandler(DecoderServiceHost host) {
-            mHost = new WeakReference<DecoderServiceHost>(host);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            DecoderServiceHost host = mHost.get();
-            if (host == null) {
-                super.handleMessage(msg);
-                return;
-            }
-
-            switch (msg.what) {
-                case DecoderService.MSG_IMAGE_DECODED_REPLY:
-                    Bundle payload = msg.getData();
-
-                    // Read the reply back from the service.
-                    String filePath = payload.getString(DecoderService.KEY_FILE_PATH);
-                    Boolean success = payload.getBoolean(DecoderService.KEY_SUCCESS);
-                    Bitmap bitmap = success
-                            ? (Bitmap) payload.getParcelable(DecoderService.KEY_IMAGE_BITMAP)
-                            : null;
-                    long decodeTime = payload.getLong(DecoderService.KEY_DECODE_TIME);
-                    host.closeRequest(filePath, bitmap, decodeTime);
-                    break;
-                default:
-                    super.handleMessage(msg);
-            }
-        }
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/IDecoderService.aidl b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/IDecoderService.aidl
new file mode 100644
index 0000000..778c3aa
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/IDecoderService.aidl
@@ -0,0 +1,21 @@
+// 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.
+
+package org.chromium.chrome.browser.photo_picker;
+
+import android.os.Bundle;
+
+import IDecoderServiceCallback;
+
+/**
+ * This interface is called by the Photo Picker to start image decoding jobs in
+ * a separate process.
+ */
+interface IDecoderService {
+  /**
+   * Decode an image.
+   * @param payload The data containing the details for the decoding request.
+   */
+  oneway void decodeImage(in Bundle payload, IDecoderServiceCallback listener);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/IDecoderServiceCallback.aidl b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/IDecoderServiceCallback.aidl
new file mode 100644
index 0000000..31fefa5
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/IDecoderServiceCallback.aidl
@@ -0,0 +1,18 @@
+// 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.
+
+package org.chromium.chrome.browser.photo_picker;
+
+/**
+ * This interface is used to communicate the results of an image decoding
+ * request.
+ */
+interface IDecoderServiceCallback {
+ /**
+  * Called when decoding is done.
+  * @param payload The results of the image decoding request, including the
+  *                decoded bitmap.
+  */
+  oneway void onDecodeImageDone(in Bundle payload);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/OWNERS
index 2cf393627..71a7706 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/OWNERS
@@ -1,2 +1,5 @@
 finnur@chromium.org
 twellington@chromium.org
+
+per-file *.aidl=set noparent
+per-file *.aidl=file://ipc/SECURITY_OWNERS
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java
index fa8e3aae..a53c5e3d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java
@@ -131,8 +131,8 @@
         super(context);
         mActivity = (ChromeActivity) context;
 
-        mDecoderServiceHost = new DecoderServiceHost(this);
-        mDecoderServiceHost.bind(mActivity);
+        mDecoderServiceHost = new DecoderServiceHost(this, context);
+        mDecoderServiceHost.bind(context);
 
         mSelectionDelegate = new SelectionDelegate<PickerBitmap>();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index c058303..322123d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -1050,11 +1050,9 @@
     private void setSheetOffsetFromBottom(float offset) {
         if (MathUtils.areFloatsEqual(offset, getSheetOffsetFromBottom())) return;
 
-        if (MathUtils.areFloatsEqual(getSheetOffsetFromBottom(), getMinOffset())
-                && offset > getMinOffset()) {
+        if (offset > getMinOffset()) {
             onSheetOpened();
-        } else if (MathUtils.areFloatsEqual(offset, getMinOffset())
-                && getSheetOffsetFromBottom() > getMinOffset()) {
+        } else if (getSheetOffsetFromBottom() > getMinOffset()) {
             onSheetClosed();
         }
 
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 1b6ad13b..c382e53 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -966,9 +966,9 @@
 int ChromeMainDelegate::RunProcess(
     const std::string& process_type,
     const content::MainFunctionParams& main_function_params) {
-// ANDROID doesn't support "cloud-print-service", so no
-// CloudPrintServiceProcessMain, and arraysize doesn't support empty array. So
-// we comment out the block for Android.
+// ANDROID doesn't support "service", so no CloudPrintServiceProcessMain, and
+// arraysize doesn't support empty array. So we comment out the block for
+// Android.
 #if !defined(OS_ANDROID)
   static const MainFunction kMainFunctions[] = {
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW) && !defined(CHROME_MULTIPLE_DLL_CHILD)
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index a9651a34..8f55b28 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -21,6 +21,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
 #include "chrome/browser/apps/app_window_registry_util.h"
@@ -90,7 +92,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/sessions/core/tab_restore_service.h"
 #include "components/signin/core/browser/signin_manager.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
@@ -106,7 +107,6 @@
 using apps::ExtensionAppShimHandler;
 using base::UserMetricsAction;
 using content::BrowserContext;
-using content::BrowserThread;
 using content::DownloadManager;
 
 namespace {
@@ -170,7 +170,7 @@
   // real, user-visible app bundle directory. (The alternatives give either the
   // framework's path or the initial app's path, which may be an app mode shim
   // or a unit test.)
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   base::FilePath app_bundle_path =
       chrome::GetVersionedDirectory().DirName().DirName().DirName();
@@ -728,11 +728,11 @@
   [NSApp setHelpMenu:helpMenu_];
 
   // Record the path to the (browser) app bundle; this is used by the app mode
-  // shim.  It has to be done in FILE thread because getting the path requires
-  // I/O.
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&RecordLastRunAppBundlePath));
+  // shim.
+  base::PostTaskWithTraits(FROM_HERE,
+                           {base::MayBlock(), base::TaskPriority::BACKGROUND,
+                            base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+                           base::Bind(&RecordLastRunAppBundlePath));
 
   // Makes "Services" menu items available.
   [self registerServicesMenuTypesTo:[notify object]];
diff --git a/chrome/browser/chromeos/customization/customization_document.cc b/chrome/browser/chromeos/customization/customization_document.cc
index 3a14bfc..ada7398 100644
--- a/chrome/browser/chromeos/customization/customization_document.cc
+++ b/chrome/browser/chromeos/customization/customization_document.cc
@@ -24,6 +24,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/customization/customization_wallpaper_downloader.h"
@@ -49,8 +50,6 @@
 #include "net/http/http_status_code.h"
 #include "net/url_request/url_fetcher.h"
 
-using content::BrowserThread;
-
 namespace chromeos {
 namespace {
 
@@ -151,6 +150,19 @@
   *exists = base::PathExists(path);
 }
 
+std::string ReadFileInBackground(const base::FilePath& file) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  std::string manifest;
+  if (!base::ReadFileToString(file, &manifest)) {
+    manifest.clear();
+    LOG(ERROR) << "Failed to load services customization manifest from: "
+               << file.value();
+  }
+
+  return manifest;
+}
+
 }  // anonymous namespace
 
 // Template URL where to fetch OEM services customization manifest from.
@@ -533,36 +545,18 @@
   if (url_.is_valid()) {
     fetch_started_ = true;
     if (url_.SchemeIsFile()) {
-      BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-          base::Bind(&ServicesCustomizationDocument::ReadFileInBackground,
-                     weak_ptr_factory_.GetWeakPtr(),
-                     base::FilePath(url_.path())));
+      base::PostTaskWithTraitsAndReplyWithResult(
+          FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
+          base::BindOnce(&ReadFileInBackground, base::FilePath(url_.path())),
+          base::BindOnce(&ServicesCustomizationDocument::OnManifestRead,
+                         weak_ptr_factory_.GetWeakPtr()));
     } else {
       StartFileFetch();
     }
   }
 }
 
-// static
-void ServicesCustomizationDocument::ReadFileInBackground(
-    base::WeakPtr<ServicesCustomizationDocument> self,
-    const base::FilePath& file) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
-  std::string manifest;
-  if (!base::ReadFileToString(file, &manifest)) {
-    manifest.clear();
-    LOG(ERROR) << "Failed to load services customization manifest from: "
-               << file.value();
-  }
-
-  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-      base::Bind(&ServicesCustomizationDocument::OnManifesteRead,
-                 self,
-                 manifest));
-}
-
-void ServicesCustomizationDocument::OnManifesteRead(
+void ServicesCustomizationDocument::OnManifestRead(
     const std::string& manifest) {
   if (!manifest.empty())
     LoadManifestFromString(manifest);
diff --git a/chrome/browser/chromeos/customization/customization_document.h b/chrome/browser/chromeos/customization/customization_document.h
index a971206..3ffbb0e1 100644
--- a/chrome/browser/chromeos/customization/customization_document.h
+++ b/chrome/browser/chromeos/customization/customization_document.h
@@ -236,13 +236,8 @@
   // Initiate file fetching. Don't wait for online status.
   void DoStartFileFetch();
 
-  // Executes on FILE thread and reads file to string.
-  static void ReadFileInBackground(
-      base::WeakPtr<ServicesCustomizationDocument> self,
-      const base::FilePath& file);
-
   // Called on UI thread with results of ReadFileInBackground.
-  void OnManifesteRead(const std::string& manifest);
+  void OnManifestRead(const std::string& manifest);
 
   // Method called when manifest was successfully loaded.
   void OnManifestLoaded();
diff --git a/chrome/browser/chromeos/device/input_service_proxy.cc b/chrome/browser/chromeos/device/input_service_proxy.cc
index 601bc61..20fbd6d 100644
--- a/chrome/browser/chromeos/device/input_service_proxy.cc
+++ b/chrome/browser/chromeos/device/input_service_proxy.cc
@@ -6,39 +6,60 @@
 
 #include "base/bind_helpers.h"
 #include "base/macros.h"
+#include "base/sequence_checker.h"
 #include "base/task_runner_util.h"
+#include "base/task_scheduler/lazy_task_runner.h"
+#include "base/task_scheduler/post_task.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
 using device::InputServiceLinux;
 
-typedef device::InputServiceLinux::InputDeviceInfo InputDeviceInfo;
-
 namespace chromeos {
 
-// static
-BrowserThread::ID InputServiceProxy::thread_identifier_ = BrowserThread::FILE;
+namespace {
+
+using InputDeviceInfo = device::InputServiceLinux::InputDeviceInfo;
+
+bool use_ui_thread_for_test = false;
+
+// SequencedTaskRunner could be used after InputServiceLinux and friends
+// are updated to check on sequence instead of thread.
+base::LazySingleThreadTaskRunner default_input_service_task_runner =
+    LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
+        base::TaskTraits({base::TaskPriority::BACKGROUND, base::MayBlock()}),
+        base::SingleThreadTaskRunnerThreadMode::SHARED);
+
+}  // namespace
 
 class InputServiceProxy::ServiceObserver : public InputServiceLinux::Observer {
  public:
-  ServiceObserver() { DCHECK_CURRENTLY_ON(BrowserThread::UI); }
-  ~ServiceObserver() override { DCHECK(CalledOnValidThread()); }
+  ServiceObserver() {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+    // Detach since this object is constructed on UI thread and forever after
+    // used from another sequence.
+    DETACH_FROM_SEQUENCE(sequence_checker_);
+  }
+  ~ServiceObserver() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  }
 
   void Initialize(const base::WeakPtr<InputServiceProxy>& proxy) {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     InputServiceLinux::GetInstance()->AddObserver(this);
     proxy_ = proxy;
   }
 
   void Shutdown() {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     if (InputServiceLinux::HasInstance())
       InputServiceLinux::GetInstance()->RemoveObserver(this);
     delete this;
   }
 
   std::vector<InputDeviceInfo> GetDevices() {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     std::vector<InputDeviceInfo> devices;
     if (InputServiceLinux::HasInstance())
       InputServiceLinux::GetInstance()->GetDevices(&devices);
@@ -47,81 +68,72 @@
 
   void GetDeviceInfo(const std::string& id,
                      const InputServiceProxy::GetDeviceInfoCallback& callback) {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     bool success = false;
     InputDeviceInfo info;
     info.id = id;
     if (InputServiceLinux::HasInstance())
       success = InputServiceLinux::GetInstance()->GetDeviceInfo(id, &info);
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE, base::Bind(callback, success, info));
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::BindOnce(callback, success, info));
   }
 
   // InputServiceLinux::Observer implementation:
   void OnInputDeviceAdded(
       const InputServiceLinux::InputDeviceInfo& info) override {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     BrowserThread::PostTask(
-        BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(&InputServiceProxy::OnDeviceAdded, proxy_, info));
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(&InputServiceProxy::OnDeviceAdded, proxy_, info));
   }
 
   void OnInputDeviceRemoved(const std::string& id) override {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     BrowserThread::PostTask(
-        BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(&InputServiceProxy::OnDeviceRemoved, proxy_, id));
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(&InputServiceProxy::OnDeviceRemoved, proxy_, id));
   }
 
  private:
-  bool CalledOnValidThread() const {
-    return BrowserThread::CurrentlyOn(InputServiceProxy::thread_identifier_);
-  }
-
   base::WeakPtr<InputServiceProxy> proxy_;
+  SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(ServiceObserver);
 };
 
 InputServiceProxy::InputServiceProxy()
     : service_observer_(new ServiceObserver()),
-      task_runner_(BrowserThread::GetTaskRunnerForThread(thread_identifier_)),
       weak_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&InputServiceProxy::ServiceObserver::Initialize,
-                 base::Unretained(service_observer_.get()),
-                 weak_factory_.GetWeakPtr()));
+  GetInputServiceTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(&InputServiceProxy::ServiceObserver::Initialize,
+                                base::Unretained(service_observer_.get()),
+                                weak_factory_.GetWeakPtr()));
 }
 
 InputServiceProxy::~InputServiceProxy() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&InputServiceProxy::ServiceObserver::Shutdown,
-                 base::Unretained(service_observer_.release())));
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  GetInputServiceTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(&InputServiceProxy::ServiceObserver::Shutdown,
+                                base::Unretained(service_observer_.release())));
 }
 
 void InputServiceProxy::AddObserver(Observer* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (observer)
     observers_.AddObserver(observer);
 }
 
 void InputServiceProxy::RemoveObserver(Observer* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (observer)
     observers_.RemoveObserver(observer);
 }
 
 void InputServiceProxy::GetDevices(const GetDevicesCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   base::PostTaskAndReplyWithResult(
-      task_runner_.get(),
-      FROM_HERE,
+      GetInputServiceTaskRunner().get(), FROM_HERE,
       base::Bind(&InputServiceProxy::ServiceObserver::GetDevices,
                  base::Unretained(service_observer_.get())),
       callback);
@@ -129,29 +141,36 @@
 
 void InputServiceProxy::GetDeviceInfo(const std::string& id,
                                       const GetDeviceInfoCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  task_runner_->PostTask(
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  GetInputServiceTaskRunner()->PostTask(
       FROM_HERE,
-      base::Bind(&InputServiceProxy::ServiceObserver::GetDeviceInfo,
-                 base::Unretained(service_observer_.release()),
-                 id,
-                 callback));
+      base::BindOnce(&InputServiceProxy::ServiceObserver::GetDeviceInfo,
+                     base::Unretained(service_observer_.get()), id, callback));
 }
 
 // static
-void InputServiceProxy::SetThreadIdForTesting(BrowserThread::ID thread_id) {
-  InputServiceProxy::thread_identifier_ = thread_id;
+scoped_refptr<base::SequencedTaskRunner>
+InputServiceProxy::GetInputServiceTaskRunner() {
+  if (use_ui_thread_for_test)
+    return BrowserThread::GetTaskRunnerForThread(BrowserThread::UI);
+
+  return default_input_service_task_runner.Get();
+}
+
+// static
+void InputServiceProxy::SetUseUIThreadForTesting(bool use_ui_thread) {
+  use_ui_thread_for_test = use_ui_thread;
 }
 
 void InputServiceProxy::OnDeviceAdded(
     const InputServiceLinux::InputDeviceInfo& info) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   for (auto& observer : observers_)
     observer.OnInputDeviceAdded(info);
 }
 
 void InputServiceProxy::OnDeviceRemoved(const std::string& id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   for (auto& observer : observers_)
     observer.OnInputDeviceRemoved(id);
 }
diff --git a/chrome/browser/chromeos/device/input_service_proxy.h b/chrome/browser/chromeos/device/input_service_proxy.h
index 3c00da6e3..ab76958 100644
--- a/chrome/browser/chromeos/device/input_service_proxy.h
+++ b/chrome/browser/chromeos/device/input_service_proxy.h
@@ -10,11 +10,11 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/task_runner.h"
+#include "base/sequenced_task_runner.h"
 #include "base/threading/thread_checker.h"
-#include "content/public/browser/browser_thread.h"
 #include "device/hid/input_service_linux.h"
 
 namespace chromeos {
@@ -47,12 +47,15 @@
   void GetDeviceInfo(const std::string& id,
                      const GetDeviceInfoCallback& callback);
 
+  // Returns the SequencedTaskRunner for device::InputServiceLinux. Make it
+  // static so that all InputServiceProxy instances and code that needs access
+  // to device::InputServiceLinux uses the same sequence.
+  static scoped_refptr<base::SequencedTaskRunner> GetInputServiceTaskRunner();
+
   // Should be called once before any InputServiceProxy instance is created.
-  static void SetThreadIdForTesting(content::BrowserThread::ID thread_id);
+  static void SetUseUIThreadForTesting(bool use_ui_thread);
 
  private:
-  static content::BrowserThread::ID thread_identifier_;
-
   class ServiceObserver;
 
   void OnDeviceAdded(const device::InputServiceLinux::InputDeviceInfo& info);
@@ -61,9 +64,7 @@
   base::ObserverList<Observer> observers_;
   std::unique_ptr<ServiceObserver> service_observer_;
 
-  base::ThreadChecker thread_checker_;
-
-  scoped_refptr<base::TaskRunner> task_runner_;
+  THREAD_CHECKER(thread_checker_);
 
   base::WeakPtrFactory<InputServiceProxy> weak_factory_;
 
diff --git a/chrome/browser/chromeos/device/input_service_test_helper.cc b/chrome/browser/chromeos/device/input_service_test_helper.cc
index 7cc5e87b..42ac2e8 100644
--- a/chrome/browser/chromeos/device/input_service_test_helper.cc
+++ b/chrome/browser/chromeos/device/input_service_test_helper.cc
@@ -8,11 +8,9 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "chrome/browser/chromeos/device/input_service_proxy.h"
-#include "content/public/browser/browser_thread.h"
 #include "device/hid/fake_input_service_linux.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using content::BrowserThread;
 using device::InputServiceLinux;
 using device::FakeInputServiceLinux;
 
@@ -20,17 +18,17 @@
 
 namespace {
 
-void InitInputServiceOnFileThread() {
+void InitInputServiceOnInputServiceSequence() {
   InputServiceLinux::SetForTesting(base::MakeUnique<FakeInputServiceLinux>());
 }
 
-void AddDeviceOnFileThread(const InputDeviceInfo& device) {
+void AddDeviceOnInputServiceSequence(const InputDeviceInfo& device) {
   FakeInputServiceLinux* service =
       static_cast<FakeInputServiceLinux*>(InputServiceLinux::GetInstance());
   service->AddDeviceForTesting(device);
 }
 
-void RemoveDeviceOnFileThread(const std::string& id) {
+void RemoveDeviceOnInputServiceSequence(const std::string& id) {
   FakeInputServiceLinux* service =
       static_cast<FakeInputServiceLinux*>(InputServiceLinux::GetInstance());
   service->RemoveDeviceForTesting(id);
@@ -118,8 +116,8 @@
 const char InputServiceTestHelper::kMouseId[] = "mouse";
 
 InputServiceTestHelper::InputServiceTestHelper() : observer_(new TestObserver) {
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::Bind(&InitInputServiceOnFileThread));
+  InputServiceProxy::GetInputServiceTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(&InitInputServiceOnInputServiceSequence));
 }
 
 InputServiceTestHelper::~InputServiceTestHelper() {}
@@ -142,15 +140,15 @@
   device.type = type;
   device.is_mouse = is_mouse;
   device.is_keyboard = !is_mouse;
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::Bind(&AddDeviceOnFileThread, device));
+  InputServiceProxy::GetInputServiceTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(&AddDeviceOnInputServiceSequence, device));
   observer_->WaitForDeviceAddition(device);
 }
 
 void InputServiceTestHelper::RemoveDeviceFromService(bool is_mouse) {
   std::string id = is_mouse ? kMouseId : kKeyboardId;
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-                          base::Bind(&RemoveDeviceOnFileThread, id));
+  InputServiceProxy::GetInputServiceTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(&RemoveDeviceOnInputServiceSequence, id));
   observer_->WaitForDeviceRemoval(id);
 }
 
diff --git a/chrome/browser/chromeos/login/bluetooth_host_pairing_browsertest.cc b/chrome/browser/chromeos/login/bluetooth_host_pairing_browsertest.cc
index f86c942..c662be2 100644
--- a/chrome/browser/chromeos/login/bluetooth_host_pairing_browsertest.cc
+++ b/chrome/browser/chromeos/login/bluetooth_host_pairing_browsertest.cc
@@ -67,7 +67,7 @@
   using InputDeviceInfo = device::InputServiceLinux::InputDeviceInfo;
 
   BluetoothHostPairingNoInputTest() {
-    InputServiceProxy::SetThreadIdForTesting(content::BrowserThread::UI);
+    InputServiceProxy::SetUseUIThreadForTesting(true);
     device::InputServiceLinux::SetForTesting(
         base::MakeUnique<device::FakeInputServiceLinux>());
 
diff --git a/chrome/browser/chromeos/login/hid_detection_browsertest.cc b/chrome/browser/chromeos/login/hid_detection_browsertest.cc
index 75ad707..facfcfd 100644
--- a/chrome/browser/chromeos/login/hid_detection_browsertest.cc
+++ b/chrome/browser/chromeos/login/hid_detection_browsertest.cc
@@ -51,7 +51,7 @@
   typedef device::InputServiceLinux::InputDeviceInfo InputDeviceInfo;
 
   HidDetectionTest() : weak_ptr_factory_(this) {
-    InputServiceProxy::SetThreadIdForTesting(content::BrowserThread::UI);
+    InputServiceProxy::SetUseUIThreadForTesting(true);
     HidDetectionTest::InitInputService();
   }
 
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index da28bd5..84e70e6 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h"
 #include "chrome/browser/chromeos/customization/customization_document.h"
+#include "chrome/browser/chromeos/device/input_service_proxy.h"
 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h"
 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
@@ -422,7 +423,7 @@
     if (!remora_controller_) {
       remora_controller_.reset(
           new pairing_chromeos::BluetoothHostPairingController(
-              BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE)));
+              InputServiceProxy::GetInputServiceTaskRunner()));
       remora_controller_->StartPairing();
     }
     return new HostPairingScreen(this, this,
@@ -1620,7 +1621,7 @@
   if (!shark_connection_listener_) {
     shark_connection_listener_.reset(
         new pairing_chromeos::SharkConnectionListener(
-            BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE),
+            InputServiceProxy::GetInputServiceTaskRunner(),
             base::Bind(&WizardController::OnSharkConnected,
                        weak_factory_.GetWeakPtr())));
   }
diff --git a/chrome/browser/chromeos/policy/active_directory_policy_manager.cc b/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
index 5b3ca71..23c19e9 100644
--- a/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
+++ b/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
@@ -9,7 +9,6 @@
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/dbus/auth_policy_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/policy/core/common/policy_bundle.h"
@@ -22,9 +21,6 @@
 // https://technet.microsoft.com/en-us/library/cc940895.aspx
 constexpr base::TimeDelta kRefreshInterval = base::TimeDelta::FromMinutes(90);
 
-// Retry delay in case of |refresh_in_progress_|.
-constexpr base::TimeDelta kBusyRetryInterval = base::TimeDelta::FromSeconds(1);
-
 }  // namespace
 
 namespace policy {
@@ -59,7 +55,12 @@
   // Does nothing if |store_| hasn't yet initialized.
   PublishPolicy();
 
-  ScheduleAutomaticRefresh();
+  scheduler_ = base::MakeUnique<PolicyScheduler>(
+      base::BindRepeating(&ActiveDirectoryPolicyManager::DoRefresh,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&ActiveDirectoryPolicyManager::OnPolicyRefreshed,
+                          weak_ptr_factory_.GetWeakPtr()),
+      kRefreshInterval);
 }
 
 void ActiveDirectoryPolicyManager::Shutdown() {
@@ -76,7 +77,7 @@
 }
 
 void ActiveDirectoryPolicyManager::RefreshPolicies() {
-  ScheduleRefresh(base::TimeDelta());
+  scheduler_->ScheduleTaskNow();
 }
 
 void ActiveDirectoryPolicyManager::OnStoreLoaded(
@@ -97,9 +98,7 @@
 ActiveDirectoryPolicyManager::ActiveDirectoryPolicyManager(
     const AccountId& account_id,
     std::unique_ptr<CloudPolicyStore> store)
-    : account_id_(account_id),
-      store_(std::move(store)),
-      weak_ptr_factory_(this) {}
+    : account_id_(account_id), store_(std::move(store)) {}
 
 void ActiveDirectoryPolicyManager::PublishPolicy() {
   if (!store_->is_initialized()) {
@@ -118,61 +117,8 @@
   UpdatePolicy(std::move(bundle));
 }
 
-void ActiveDirectoryPolicyManager::OnPolicyRefreshed(bool success) {
-  if (!success) {
-    LOG(ERROR) << "Active Directory policy refresh failed.";
-  }
-  // Load independently of success or failure to keep up to date with whatever
-  // has happened on the authpolicyd / session manager side.
-  store_->Load();
-
-  refresh_in_progress_ = false;
-  last_refresh_ = base::TimeTicks::Now();
-  ScheduleAutomaticRefresh();
-}
-
-void ActiveDirectoryPolicyManager::ScheduleRefresh(base::TimeDelta delay) {
-  if (refresh_task_) {
-    refresh_task_->Cancel();
-  }
-  refresh_task_ = base::MakeUnique<base::CancelableClosure>(
-      base::Bind(&ActiveDirectoryPolicyManager::RunScheduledRefresh,
-                 weak_ptr_factory_.GetWeakPtr()));
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, refresh_task_->callback(), delay);
-}
-
-void ActiveDirectoryPolicyManager::ScheduleAutomaticRefresh() {
-  base::TimeTicks baseline;
-  base::TimeDelta interval;
-  if (retry_refresh_) {
-    baseline = last_refresh_;
-    interval = kBusyRetryInterval;
-  } else if (last_refresh_ == base::TimeTicks()) {
-    baseline = startup_;
-    interval = base::TimeDelta();
-  } else {
-    baseline = last_refresh_;
-    interval = kRefreshInterval;
-  }
-  base::TimeDelta delay;
-  const base::TimeTicks now(base::TimeTicks::Now());
-  if (now < baseline + interval) {
-    delay = baseline + interval - now;
-  }
-  ScheduleRefresh(delay);
-}
-
-void ActiveDirectoryPolicyManager::RunScheduledRefresh() {
-  // Abort if a refresh is currently in progress (to avoid D-Bus jobs piling up
-  // behind each other).
-  if (refresh_in_progress_) {
-    retry_refresh_ = true;
-    return;
-  }
-
-  retry_refresh_ = false;
-  refresh_in_progress_ = true;
+void ActiveDirectoryPolicyManager::DoRefresh(
+    base::OnceCallback<void(bool success)> callback) {
   chromeos::DBusThreadManager* thread_manager =
       chromeos::DBusThreadManager::Get();
   DCHECK(thread_manager);
@@ -180,15 +126,19 @@
       thread_manager->GetAuthPolicyClient();
   DCHECK(auth_policy_client);
   if (account_id_ == EmptyAccountId()) {
-    auth_policy_client->RefreshDevicePolicy(
-        base::Bind(&ActiveDirectoryPolicyManager::OnPolicyRefreshed,
-                   weak_ptr_factory_.GetWeakPtr()));
+    auth_policy_client->RefreshDevicePolicy(std::move(callback));
   } else {
-    auth_policy_client->RefreshUserPolicy(
-        account_id_,
-        base::Bind(&ActiveDirectoryPolicyManager::OnPolicyRefreshed,
-                   weak_ptr_factory_.GetWeakPtr()));
+    auth_policy_client->RefreshUserPolicy(account_id_, std::move(callback));
   }
 }
 
+void ActiveDirectoryPolicyManager::OnPolicyRefreshed(bool success) {
+  if (!success) {
+    LOG(ERROR) << "Active Directory policy refresh failed.";
+  }
+  // Load independently of success or failure to keep up to date with whatever
+  // has happened on the authpolicyd / session manager side.
+  store_->Load();
+}
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/active_directory_policy_manager.h b/chrome/browser/chromeos/policy/active_directory_policy_manager.h
index 9bf7935..598c545 100644
--- a/chrome/browser/chromeos/policy/active_directory_policy_manager.h
+++ b/chrome/browser/chromeos/policy/active_directory_policy_manager.h
@@ -7,12 +7,11 @@
 
 #include <memory>
 
-#include "base/cancelable_callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 #include "components/policy/core/common/configuration_policy_provider.h"
+#include "components/policy/core/common/policy_scheduler.h"
 #include "components/signin/core/account_id/account_id.h"
 
 namespace policy {
@@ -57,35 +56,20 @@
   // Publish the policy that's currently cached in the store.
   void PublishPolicy();
 
-  // Callback from authpolicyd.
+  // Calls into authpolicyd to fetch policy. Reports success or failure via
+  // |callback|.
+  void DoRefresh(PolicyScheduler::TaskCallback callback);
+
+  // Called by scheduler with result of policy fetch.
   void OnPolicyRefreshed(bool success);
 
-  // Schedule next policy refresh to run after |delay|.  (Deletes any previously
-  // scheduled refresh tasks.)
-  void ScheduleRefresh(base::TimeDelta delay);
-
-  // Schedule next automatic policy refresh based on initial fetch delay or
-  // refresh interval.  (Deletes any previously scheduled refresh tasks.)
-  void ScheduleAutomaticRefresh();
-
-  // Actually execute the scheduled policy refresh.
-  void RunScheduledRefresh();
-
   const AccountId account_id_;
   std::unique_ptr<CloudPolicyStore> store_;
 
-  // Whether a policy refresh is in progress (and thus any further requests need
-  // to be blocked).
-  bool refresh_in_progress_ = false;
-  // Whether a refresh had been blocked and thus the next refresh needs to be
-  // scheduled at the shorter "retry" interval.
-  bool retry_refresh_ = false;
-  base::TimeTicks last_refresh_;
-  const base::TimeTicks startup_ = base::TimeTicks::Now();
-  std::unique_ptr<base::CancelableClosure> refresh_task_;
+  std::unique_ptr<PolicyScheduler> scheduler_;
 
   // Must be last member.
-  base::WeakPtrFactory<ActiveDirectoryPolicyManager> weak_ptr_factory_;
+  base::WeakPtrFactory<ActiveDirectoryPolicyManager> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ActiveDirectoryPolicyManager);
 };
diff --git a/chrome/browser/chromeos/power/cpu_data_collector.cc b/chrome/browser/chromeos/power/cpu_data_collector.cc
index f6109e00..189b192 100644
--- a/chrome/browser/chromeos/power/cpu_data_collector.cc
+++ b/chrome/browser/chromeos/power/cpu_data_collector.cc
@@ -392,7 +392,10 @@
     const std::string state_name = base::IntToString(freq_in_khz / 1000);
     size_t index = EnsureInVector(state_name, cpu_freq_state_names);
     for (int cpu = 0; cpu < cpu_count; ++cpu) {
-      if (!(*freq_samples)[cpu].cpu_online) {
+      // array.size() is previously checked to be equal to cpu_count+1. cpu
+      // ranges from [0,cpu_count), so cpu+1 never exceeds cpu_count and is
+      // safe.
+      if (!(*freq_samples)[cpu].cpu_online || array[cpu + 1] == "N/A") {
         continue;
       }
       if (index >= (*freq_samples)[cpu].time_in_state.size())
diff --git a/chrome/browser/chromeos/power/cpu_data_collector_unittest.cc b/chrome/browser/chromeos/power/cpu_data_collector_unittest.cc
index de359ad1..bb8a3689 100644
--- a/chrome/browser/chromeos/power/cpu_data_collector_unittest.cc
+++ b/chrome/browser/chromeos/power/cpu_data_collector_unittest.cc
@@ -44,6 +44,14 @@
     "60000\t\t90000\t\t91000\t\t\n"
     "100000\t\t50000\t\t51000\t\t\n";
 
+// The string content of the fake cpu frequency file for all cpus except one
+// that reports "N/A" as the cpu/freq combinations that are invalid.
+constexpr char kAllTimeInStateContentNA[] =
+    "freq\t\tcpu0\t\tcpu1\t\tcpu2\t\t\n"
+    "20000\t\t30000000\t\t31000000\t\tN/A\t\t\n"
+    "60000\t\t90000\t\t91000\t\tN/A\t\t\n"
+    "100000\t\t50000\t\t51000\t\tN/A\t\t\n";
+
 }  // namespace
 
 class CpuDataCollectorTest : public testing::Test {
@@ -67,19 +75,6 @@
         temp_dir_.GetPath().AppendASCII(kTimeInStateSuffixPathCpu1);
     all_time_in_state_path_ =
         temp_dir_.GetPath().AppendASCII(kAllTimeInStateSuffixPath);
-
-    ASSERT_TRUE(base::CreateTemporaryFile(&time_in_state_path_cpu0_));
-    ASSERT_TRUE(base::CreateTemporaryFile(&time_in_state_path_cpu1_));
-    ASSERT_TRUE(base::CreateTemporaryFile(&all_time_in_state_path_));
-    ASSERT_TRUE(base::WriteFile(
-                    time_in_state_path_cpu0_, kTimeInStateContentCpu0,
-                    static_cast<int>(strlen(kTimeInStateContentCpu0))) != -1);
-    ASSERT_TRUE(base::WriteFile(
-                    time_in_state_path_cpu1_, kTimeInStateContentCpu1,
-                    static_cast<int>(strlen(kTimeInStateContentCpu1))) != -1);
-    ASSERT_TRUE(base::WriteFile(
-                    all_time_in_state_path_, kAllTimeInStateContent,
-                    static_cast<int>(strlen(kAllTimeInStateContent))) != -1);
   }
 
  protected:
@@ -103,6 +98,15 @@
 };
 
 TEST_F(CpuDataCollectorTest, ReadCpuFreqTimeInState) {
+  ASSERT_TRUE(base::CreateTemporaryFile(&time_in_state_path_cpu0_));
+  ASSERT_TRUE(base::CreateTemporaryFile(&time_in_state_path_cpu1_));
+  ASSERT_TRUE(
+      base::WriteFile(time_in_state_path_cpu0_, kTimeInStateContentCpu0,
+                      static_cast<int>(strlen(kTimeInStateContentCpu0))) != -1);
+  ASSERT_TRUE(
+      base::WriteFile(time_in_state_path_cpu1_, kTimeInStateContentCpu1,
+                      static_cast<int>(strlen(kTimeInStateContentCpu1))) != -1);
+
   std::vector<std::string> cpu_freq_state_names;
   CpuDataCollector::StateOccupancySample freq_sample_cpu0;
   CpuDataCollector::StateOccupancySample freq_sample_cpu1;
@@ -120,6 +124,11 @@
 }
 
 TEST_F(CpuDataCollectorTest, ReadCpuFreqAllTimeInState) {
+  ASSERT_TRUE(base::CreateTemporaryFile(&all_time_in_state_path_));
+  ASSERT_TRUE(
+      base::WriteFile(all_time_in_state_path_, kAllTimeInStateContent,
+                      static_cast<int>(strlen(kAllTimeInStateContent))) != -1);
+
   std::vector<std::string> cpu_freq_state_names;
   std::vector<CpuDataCollector::StateOccupancySample> freq_samples;
   CpuDataCollector::StateOccupancySample freq_sample_cpu0;
@@ -137,4 +146,31 @@
   EXPECT_EQ(kExpectedTimeInStateCpu1, freq_samples[1].time_in_state);
 }
 
+TEST_F(CpuDataCollectorTest, ReadCpuFreqAllTimeInStateNA) {
+  ASSERT_TRUE(base::CreateTemporaryFile(&all_time_in_state_path_));
+  ASSERT_TRUE(base::WriteFile(
+                  all_time_in_state_path_, kAllTimeInStateContentNA,
+                  static_cast<int>(strlen(kAllTimeInStateContentNA))) != -1);
+
+  std::vector<std::string> cpu_freq_state_names;
+  std::vector<CpuDataCollector::StateOccupancySample> freq_samples;
+  CpuDataCollector::StateOccupancySample freq_sample_cpu0;
+  CpuDataCollector::StateOccupancySample freq_sample_cpu1;
+  CpuDataCollector::StateOccupancySample freq_sample_cpu2;
+  // |ReadCpuFreqAllTimeInState| only completes sample for cpu that is online.
+  freq_sample_cpu0.cpu_online = true;
+  freq_sample_cpu1.cpu_online = true;
+  freq_sample_cpu2.cpu_online = true;
+  freq_samples.push_back(freq_sample_cpu0);
+  freq_samples.push_back(freq_sample_cpu1);
+  freq_samples.push_back(freq_sample_cpu2);
+
+  CpuDataCollector::ReadCpuFreqAllTimeInState(
+      3, all_time_in_state_path_, &cpu_freq_state_names, &freq_samples);
+  EXPECT_EQ(kExpectedCpuFreqStateNames, cpu_freq_state_names);
+  EXPECT_EQ(kExpectedTimeInStateCpu0, freq_samples[0].time_in_state);
+  EXPECT_EQ(kExpectedTimeInStateCpu1, freq_samples[1].time_in_state);
+  EXPECT_TRUE(freq_samples[2].time_in_state.empty());
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/extensions/api/cookies/cookies_unittest.cc b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
index a236be2..6aeccbf 100644
--- a/chrome/browser/extensions/api/cookies/cookies_unittest.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
@@ -188,7 +188,7 @@
   std::unique_ptr<net::CanonicalCookie> canonical_cookie(
       net::CanonicalCookie::Create(GURL("http://test.com"),
                                    "=011Q255bNX_1!yd\203e+;path=/path\203",
-                                   base::Time(), net::CookieOptions()));
+                                   base::Time::Now(), net::CookieOptions()));
   ASSERT_NE(nullptr, canonical_cookie.get());
   Cookie cookie =
       cookies_helpers::CreateCookie(*canonical_cookie, "some cookie store");
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
index ae5450bd..96f2635 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
@@ -415,7 +415,20 @@
           cursors.Range.fromNode(evt.target));
     }
 
-    this.createTextEditHandlerIfNeeded_(evt.target);
+    // Re-target the node to the root of the editable.
+    var target = evt.target;
+    while (target.parent && target.parent.state.editable)
+      target = target.parent;
+    var voxTarget = ChromeVoxState.instance.currentRange.start.node;
+    while (voxTarget && voxTarget.parent && voxTarget.parent.state.editable)
+      voxTarget = voxTarget.parent;
+
+    // It is possible that ChromeVox has range over some other node
+    // when a text field is focused.
+    if (!target.state.focused || target != voxTarget)
+      return;
+
+    this.createTextEditHandlerIfNeeded_(target);
 
     // Sync the ChromeVox range to the editable, if a selection exists.
     var anchorObject = evt.target.root.anchorObject;
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
index fdb9fa0..7841f9b4 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
@@ -34,6 +34,7 @@
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/payments/content/payment_request_spec.h"
 #include "components/payments/content/payment_request_state.h"
+#include "components/payments/core/payment_request_data_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/insets.h"
@@ -136,29 +137,6 @@
   DISALLOW_COPY_AND_ASSIGN(ExpirationDateValidationDelegate);
 };
 
-// Formats card number. For example, "4111111111111111" is formatted into
-// "4111 1111 1111 1111".
-base::string16 FormatCardNumber(const base::string16& text) {
-  // Do not format masked card numbers, which start with a letter.
-  base::string16 number = autofill::CreditCard::StripSeparators(text);
-  if (number.empty() || !base::IsAsciiDigit(number[0]))
-    return text;
-
-  std::vector<size_t> positions = {4U, 9U, 14U};
-  if (autofill::CreditCard::GetCardNetwork(number) ==
-      autofill::kAmericanExpressCard) {
-    positions = {4U, 11U};
-  }
-
-  static const base::char16 kSeparator = base::ASCIIToUTF16(" ")[0];
-  for (size_t i : positions) {
-    if (number.size() > i)
-      number.insert(i, 1U, kSeparator);
-  }
-
-  return number;
-}
-
 }  // namespace
 
 CreditCardEditorViewController::CreditCardEditorViewController(
@@ -368,7 +346,9 @@
   base::string16 info = credit_card_to_edit_->GetInfo(
       autofill::AutofillType(type), state()->GetApplicationLocale());
 
-  return type == autofill::CREDIT_CARD_NUMBER ? FormatCardNumber(info) : info;
+  return type == autofill::CREDIT_CARD_NUMBER
+             ? data_util::FormatCardNumberForDisplay(info)
+             : info;
 }
 
 bool CreditCardEditorViewController::ValidateModelAndSave() {
@@ -627,7 +607,7 @@
 base::string16
 CreditCardEditorViewController::CreditCardValidationDelegate::Format(
     const base::string16& text) {
-  return FormatCardNumber(text);
+  return data_util::FormatCardNumberForDisplay(text);
 }
 
 bool CreditCardEditorViewController::CreditCardValidationDelegate::
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 7c39318..53cdd61 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -117,8 +117,12 @@
 // print job. Defaults to null if unspecified.
 const char kCloudPrintPrintTicket[]         = "cloud-print-print-ticket";
 
-// Causes the process to run as a cloud print service process.
-const char kCloudPrintServiceProcess[]      = "cloud-print-service";
+// The process type value which causes a process to run as a cloud print service
+// process.
+//
+// DO NOT CHANGE THIS VALUE. Cloud printing relies on an external binary
+// launching Chrome with this process type.
+const char kCloudPrintServiceProcess[]      = "service";
 
 // Setup cloud print proxy for provided printers. This does not start
 // service or register proxy for autostart.
@@ -315,8 +319,8 @@
 const char kEnableClearBrowsingDataCounters[] =
     "enable-clear-browsing-data-counters";
 
-// This applies only when the process type is "cloud-print-service". Enables the
-// Cloud Print Proxy component within the service process.
+// This applies only when the process type is "service". Enables the Cloud Print
+// Proxy component within the service process.
 const char kEnableCloudPrintProxy[]         = "enable-cloud-print-proxy";
 
 // Enable device discovery notifications.
diff --git a/chrome/common/extensions/manifest_handlers/app_launch_info.cc b/chrome/common/extensions/manifest_handlers/app_launch_info.cc
index 6506824..74711b0 100644
--- a/chrome/common/extensions/manifest_handlers/app_launch_info.cc
+++ b/chrome/common/extensions/manifest_handlers/app_launch_info.cc
@@ -213,8 +213,8 @@
       OverrideLaunchURL(extension, gallery_url);
     }
   } else if (extension->id() == extension_misc::kCloudPrintAppId) {
-    // In order for the --cloud-print-service switch to work, we must update
-    // the launch URL and web extent.
+    // In order for the --type=service switch to work, we must update the launch
+    // URL and web extent.
     GURL url =
         cloud_devices::GetCloudPrintRelativeURL("enable_chrome_connector");
     if (!url.is_empty()) {
diff --git a/chrome/install_static/install_util.cc b/chrome/install_static/install_util.cc
index b573e2d1..af1d580 100644
--- a/chrome/install_static/install_util.cc
+++ b/chrome/install_static/install_util.cc
@@ -77,7 +77,7 @@
 constexpr wchar_t kRegValueUsageStats[] = L"usagestats";
 constexpr wchar_t kMetricsReportingEnabled[] = L"MetricsReportingEnabled";
 
-constexpr wchar_t kCloudPrintServiceProcess[] = L"cloud-print-service";
+constexpr wchar_t kCloudPrintServiceProcess[] = L"service";
 constexpr wchar_t kCrashpadHandlerProcess[] = L"crashpad-handler";
 #if !defined(DISABLE_NACL)
 constexpr wchar_t kNaClBrokerProcess[] = L"nacl-broker";
diff --git a/chrome/renderer/safe_browsing/phishing_classifier.cc b/chrome/renderer/safe_browsing/phishing_classifier.cc
index 87915f4..d42f506 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier.cc
+++ b/chrome/renderer/safe_browsing/phishing_classifier.cc
@@ -42,8 +42,9 @@
 // Used for UMA, do not reorder.
 enum SkipClassificationReason {
   CLASSIFICATION_PROCEED = 0,
-  SKIP_HTTPS = 1,
+  DEPRECATED_SKIP_HTTPS = 1,
   SKIP_NONE_GET = 2,
+  SKIP_SCHEME_NOT_SUPPORTED = 3,
   SKIP_REASON_MAX
 };
 
@@ -126,10 +127,10 @@
   blink::WebLocalFrame* frame = render_frame_->GetWebFrame();
 
   // Check whether the URL is one that we should classify.
-  // Currently, we only classify http: URLs that are GET requests.
+  // Currently, we only classify http/https URLs that are GET requests.
   GURL url(frame->GetDocument().Url());
-  if (!url.SchemeIs(url::kHttpScheme)) {
-    RecordReasonForSkippingClassificationToUMA(SKIP_HTTPS);
+  if (!url.SchemeIsHTTPOrHTTPS()) {
+    RecordReasonForSkippingClassificationToUMA(SKIP_SCHEME_NOT_SUPPORTED);
     RunFailureCallback();
     return;
   }
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc b/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc
index 4ee3b99..148fcec 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc
+++ b/chrome/renderer/safe_browsing/phishing_classifier_browsertest.cc
@@ -9,30 +9,22 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/safe_browsing/client_model.pb.h"
+#include "chrome/renderer/chrome_content_renderer_client.h"
 #include "chrome/renderer/safe_browsing/features.h"
 #include "chrome/renderer/safe_browsing/mock_feature_extractor_clock.h"
 #include "chrome/renderer/safe_browsing/murmurhash3_util.h"
 #include "chrome/renderer/safe_browsing/scorer.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/base/chrome_render_view_test.h"
 #include "components/safe_browsing/csd.pb.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_switches.h"
 #include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_view.h"
 #include "crypto/sha2.h"
 #include "net/dns/mock_host_resolver.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/embedded_test_server/http_response.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "url/gurl.h"
 
 using ::testing::AllOf;
@@ -42,25 +34,35 @@
 
 namespace safe_browsing {
 
-class PhishingClassifierTest : public InProcessBrowserTest {
+class TestChromeContentRendererClient : public ChromeContentRendererClient {
+ public:
+  TestChromeContentRendererClient() {}
+  ~TestChromeContentRendererClient() override {}
+  // Since visited_link_slave_ in ChromeContentRenderClient never get initiated,
+  // overrides VisitedLinkedHash() function to prevent crashing.
+  unsigned long long VisitedLinkHash(const char* canonical_url,
+                                     size_t length) override {
+    return 0LL;
+  }
+};
+
+class PhishingClassifierTest : public ChromeRenderViewTest {
  protected:
   PhishingClassifierTest()
       : url_tld_token_net_(features::kUrlTldToken + std::string("net")),
         page_link_domain_phishing_(features::kPageLinkDomain +
                                    std::string("phishing.com")),
         page_term_login_(features::kPageTerm + std::string("login")),
-        page_text_(base::ASCIIToUTF16("login")) {
+        page_text_(base::ASCIIToUTF16("login")),
+        phishy_score_(PhishingClassifier::kInvalidScore) {}
+
+  void SetUp() override {
+    ChromeRenderViewTest::SetUp();
+    PrepareModel();
+    SetUpClassifier();
   }
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitch(switches::kSingleProcess);
-#if defined(OS_WIN)
-    // Don't want to try to create a GPU process.
-    command_line->AppendSwitch(switches::kDisableGpu);
-#endif
-  }
-
-  void SetUpOnMainThread() override {
+  void PrepareModel() {
     // Construct a model to test with.  We include one feature from each of
     // the feature extractors, which allows us to verify that they all ran.
     ClientSideModel model;
@@ -101,106 +103,50 @@
     scorer_.reset(Scorer::Create(model.SerializeAsString()));
     ASSERT_TRUE(scorer_.get());
 
-    content::WebContents* web_contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
-    content::RenderFrame* render_frame = content::RenderFrame::FromRoutingID(
-        web_contents->GetMainFrame()->GetRoutingID());
-    classifier_.reset(new PhishingClassifier(render_frame, clock_));
+    // These tests don't exercise the extraction timing.
+    EXPECT_CALL(*clock_, Now())
+        .WillRepeatedly(::testing::Return(base::TimeTicks::Now()));
+  }
 
-    embedded_test_server()->RegisterRequestHandler(
-        base::Bind(&PhishingClassifierTest::HandleRequest,
-                   base::Unretained(this)));
-    ASSERT_TRUE(embedded_test_server()->Start());
-
-    host_resolver()->AddRule("*", "127.0.0.1");
-
+  void SetUpClassifier() {
+    classifier_.reset(
+        new PhishingClassifier(view_->GetMainRenderFrame(), clock_));
     // No scorer yet, so the classifier is not ready.
     ASSERT_FALSE(classifier_->is_ready());
 
     // Now set the scorer.
     classifier_->set_phishing_scorer(scorer_.get());
     ASSERT_TRUE(classifier_->is_ready());
-
-    // These tests don't exercise the extraction timing.
-    EXPECT_CALL(*clock_, Now())
-        .WillRepeatedly(::testing::Return(base::TimeTicks::Now()));
   }
 
-  void TearDownOnMainThread() override {
-    content::RunAllPendingInMessageLoop();
-  }
+  // Helper method to start phishing classification.
+  void RunPhishingClassifier(const base::string16* page_text) {
+    feature_map_.Clear();
 
-  // Helper method to start phishing classification and wait for it to
-  // complete.  Returns the true if the page is classified as phishy and
-  // false otherwise.
-  bool RunPhishingClassifier(const base::string16* page_text,
-                             float* phishy_score,
-                             FeatureMap* features) {
-    ClientPhishingRequest verdict;
-    // The classifier accesses the RenderFrame and must run in the RenderThread.
-    PostTaskToInProcessRendererAndWait(
-        base::Bind(&PhishingClassifierTest::DoRunPhishingClassifier,
-                   base::Unretained(this),
-                   page_text, phishy_score, features, &verdict));
-    return verdict.is_phishing();
-  }
-
-  void DoRunPhishingClassifier(const base::string16* page_text,
-                               float* phishy_score,
-                               FeatureMap* features,
-                               ClientPhishingRequest* verdict) {
-    *phishy_score = PhishingClassifier::kInvalidScore;
-    features->Clear();
-
-    // Force synchronous behavior for ease of unittesting.
-    base::RunLoop run_loop;
     classifier_->BeginClassification(
-        page_text,
-        base::Bind(&PhishingClassifierTest::ClassificationFinished,
-                   base::Unretained(this), &run_loop, verdict));
-    content::RunThisRunLoop(&run_loop);
-
-    *phishy_score = verdict->client_score();
-    for (int i = 0; i < verdict->feature_map_size(); ++i) {
-      features->AddRealFeature(verdict->feature_map(i).name(),
-                               verdict->feature_map(i).value());
-    }
+        page_text, base::Bind(&PhishingClassifierTest::ClassificationFinished,
+                              base::Unretained(this)));
+    base::RunLoop().RunUntilIdle();
   }
 
   // Completion callback for classification.
-  void ClassificationFinished(base::RunLoop* run_loop,
-                              ClientPhishingRequest* verdict_out,
-                              const ClientPhishingRequest& verdict) {
-    *verdict_out = verdict;  // Copy the verdict.
-    run_loop->Quit();
+  void ClassificationFinished(const ClientPhishingRequest& verdict) {
+    phishy_score_ = verdict.client_score();
+    for (int i = 0; i < verdict.feature_map_size(); ++i) {
+      feature_map_.AddRealFeature(verdict.feature_map(i).name(),
+                                  verdict.feature_map(i).value());
+    }
+    is_phishing_ = verdict.is_phishing();
   }
 
-  void LoadHtml(const std::string& host, const std::string& content) {
-    GURL::Replacements replace_host;
-    replace_host.SetHostStr(host);
-    response_content_ = content;
-    ui_test_utils::NavigateToURL(
-        browser(),
-        embedded_test_server()->base_url().ReplaceComponents(replace_host));
+  void LoadHtml(const GURL& url, const std::string& content) {
+    LoadHTMLWithUrlOverride(content.c_str(), url.spec().c_str());
   }
 
-  void LoadHtmlPost(const std::string& host, const std::string& content) {
-    GURL::Replacements replace_host;
-    replace_host.SetHostStr(host);
-    response_content_ = content;
-    ui_test_utils::NavigateToURLWithPost(
-        browser(),
-        embedded_test_server()->base_url().ReplaceComponents(replace_host));
-  }
-
-  std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
-      const net::test_server::HttpRequest& request) {
-    std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
-        new net::test_server::BasicHttpResponse());
-    http_response->set_code(net::HTTP_OK);
-    http_response->set_content_type("text/html");
-    http_response->set_content(response_content_);
-    return std::move(http_response);
+  content::ContentRendererClient* CreateContentRendererClient() override {
+    ChromeContentRendererClient* client = new TestChromeContentRendererClient();
+    InitChromeContentRendererClient(client);
+    return client;
   }
 
   std::string response_content_;
@@ -212,151 +158,110 @@
   const std::string url_tld_token_net_;
   const std::string page_link_domain_phishing_;
   const std::string page_term_login_;
-  const base::string16 page_text_;
+  base::string16 page_text_;
+
+  // Outputs of phishing classifier.
+  FeatureMap feature_map_;
+  float phishy_score_;
+  bool is_phishing_;
 };
 
-// This test flakes on Mac with force compositing mode.
-// http://crbug.com/316709
-// Flaky on Chrome OS and Linux, running into a memory allocation error.
-// http://crbug.com/544085
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_LINUX)
-#define MAYBE_TestClassificationOfPhishingDotCom \
-  DISABLED_TestClassificationOfPhishingDotCom
-#else
-#define MAYBE_TestClassificationOfPhishingDotCom \
-  TestClassificationOfPhishingDotCom
-#endif
-IN_PROC_BROWSER_TEST_F(PhishingClassifierTest,
-                       MAYBE_TestClassificationOfPhishingDotCom) {
-  float phishy_score;
-  FeatureMap features;
-
-  LoadHtml("host.net",
+TEST_F(PhishingClassifierTest, TestClassificationOfPhishingDotComHttp) {
+  LoadHtml(
+      GURL("http://host.net"),
       "<html><body><a href=\"http://phishing.com/\">login</a></body></html>");
-  EXPECT_TRUE(RunPhishingClassifier(&page_text_, &phishy_score, &features));
+  RunPhishingClassifier(&page_text_);
+
   // Note: features.features() might contain other features that simply aren't
   // in the model.
-  EXPECT_THAT(features.features(),
+  EXPECT_THAT(feature_map_.features(),
               AllOf(Contains(Pair(url_tld_token_net_, 1.0)),
                     Contains(Pair(page_link_domain_phishing_, 1.0)),
                     Contains(Pair(page_term_login_, 1.0))));
-  EXPECT_FLOAT_EQ(0.5, phishy_score);
+  EXPECT_FLOAT_EQ(0.5, phishy_score_);
+  EXPECT_TRUE(is_phishing_);
 }
 
-// This test flakes on Mac with force compositing mode.
-// http://crbug.com/316709
-// Flaky on Chrome OS and Linux, running into a memory allocation error.
-// http://crbug.com/544085
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_LINUX)
-#define MAYBE_TestClassificationOfSafeDotCom \
-  DISABLED_TestClassificationOfSafeDotCom
-#else
-#define MAYBE_TestClassificationOfSafeDotCom TestClassificationOfSafeDotCom
-#endif
-IN_PROC_BROWSER_TEST_F(PhishingClassifierTest,
-                       MAYBE_TestClassificationOfSafeDotCom) {
-  float phishy_score;
-  FeatureMap features;
+TEST_F(PhishingClassifierTest, TestClassificationOfPhishingDotComHttps) {
+  // Host the target page on HTTPS.
+  LoadHtml(
+      GURL("https://host.net"),
+      "<html><body><a href=\"http://phishing.com/\">login</a></body></html>");
+  RunPhishingClassifier(&page_text_);
 
+  // Note: features.features() might contain other features that simply aren't
+  // in the model.
+  EXPECT_THAT(feature_map_.features(),
+              AllOf(Contains(Pair(url_tld_token_net_, 1.0)),
+                    Contains(Pair(page_link_domain_phishing_, 1.0)),
+                    Contains(Pair(page_term_login_, 1.0))));
+  EXPECT_FLOAT_EQ(0.5, phishy_score_);
+  EXPECT_TRUE(is_phishing_);
+}
+
+TEST_F(PhishingClassifierTest, TestClassificationOfSafeDotComHttp) {
   // Change the link domain to something non-phishy.
-  LoadHtml("host.net",
+  LoadHtml(GURL("http://host.net"),
            "<html><body><a href=\"http://safe.com/\">login</a></body></html>");
-  EXPECT_FALSE(RunPhishingClassifier(&page_text_, &phishy_score, &features));
-  EXPECT_THAT(features.features(),
+  RunPhishingClassifier(&page_text_);
+
+  EXPECT_THAT(feature_map_.features(),
               AllOf(Contains(Pair(url_tld_token_net_, 1.0)),
                     Contains(Pair(page_term_login_, 1.0))));
-  EXPECT_THAT(features.features(),
+  EXPECT_THAT(feature_map_.features(),
               Not(Contains(Pair(page_link_domain_phishing_, 1.0))));
-  EXPECT_GE(phishy_score, 0.0);
-  EXPECT_LT(phishy_score, 0.5);
+  EXPECT_GE(phishy_score_, 0.0);
+  EXPECT_LT(phishy_score_, 0.5);
+  EXPECT_FALSE(is_phishing_);
 }
 
-// This test flakes on Mac with force compositing mode.
-// http://crbug.com/316709
-// Flaky on Chrome OS and Linux, running into a memory allocation error.
-// http://crbug.com/544085
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_LINUX)
-#define MAYBE_TestClassificationWhenNoTld DISABLED_TestClassificationWhenNoTld
-#else
-#define MAYBE_TestClassificationWhenNoTld TestClassificationWhenNoTld
-#endif
-IN_PROC_BROWSER_TEST_F(PhishingClassifierTest,
-                       MAYBE_TestClassificationWhenNoTld) {
-  float phishy_score;
-  FeatureMap features;
+TEST_F(PhishingClassifierTest, TestClassificationOfSafeDotComHttps) {
+  // Host target page in HTTPS and change the link domain to something
+  // non-phishy.
+  LoadHtml(GURL("https://host.net"),
+           "<html><body><a href=\"http://safe.com/\">login</a></body></html>");
+  RunPhishingClassifier(&page_text_);
 
+  EXPECT_THAT(feature_map_.features(),
+              AllOf(Contains(Pair(url_tld_token_net_, 1.0)),
+                    Contains(Pair(page_term_login_, 1.0))));
+  EXPECT_THAT(feature_map_.features(),
+              Not(Contains(Pair(page_link_domain_phishing_, 1.0))));
+  EXPECT_GE(phishy_score_, 0.0);
+  EXPECT_LT(phishy_score_, 0.5);
+  EXPECT_FALSE(is_phishing_);
+}
+
+TEST_F(PhishingClassifierTest, TestClassificationWhenNoTld) {
   // Extraction should fail for this case since there is no TLD.
-  LoadHtml("localhost", "<html><body>content</body></html>");
-  EXPECT_FALSE(RunPhishingClassifier(&page_text_, &phishy_score, &features));
-  EXPECT_EQ(0U, features.features().size());
-  EXPECT_EQ(PhishingClassifier::kInvalidScore, phishy_score);
+  LoadHtml(GURL("http://localhost"), "<html><body>content</body></html>");
+  RunPhishingClassifier(&page_text_);
+
+  EXPECT_EQ(0U, feature_map_.features().size());
+  EXPECT_EQ(PhishingClassifier::kInvalidScore, phishy_score_);
+  EXPECT_FALSE(is_phishing_);
 }
 
-// This test flakes on Mac with force compositing mode.
-// http://crbug.com/316709
-// Flaky on Chrome OS and Linux, running into a memory allocation error.
-// http://crbug.com/544085
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_LINUX)
-#define MAYBE_TestClassificationWhenNotHttp \
-  DISABLED_TestClassificationWhenNotHttp
-#else
-#define MAYBE_TestClassificationWhenNotHttp TestClassificationWhenNotHttp
-#endif
-IN_PROC_BROWSER_TEST_F(PhishingClassifierTest,
-                       MAYBE_TestClassificationWhenNotHttp) {
-  float phishy_score;
-  FeatureMap features;
+TEST_F(PhishingClassifierTest, TestClassificationWhenSchemeNotSupported) {
+  // Extraction should also fail for this case because the URL is not http or
+  // https.
+  LoadHtml(GURL("file://host.net"), "<html><body>content</body></html>");
+  RunPhishingClassifier(&page_text_);
 
-  // Extraction should also fail for this case because the URL is not http.
-  net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
-  https_server.ServeFilesFromSourceDirectory("chrome/test/data");
-  ASSERT_TRUE(https_server.Start());
-  GURL::Replacements replace_host;
-  replace_host.SetHostStr("host.net");
-  GURL test_url = https_server.GetURL("/title1.html");
-  ui_test_utils::NavigateToURL(browser(),
-                               test_url.ReplaceComponents(replace_host));
-  EXPECT_FALSE(RunPhishingClassifier(&page_text_, &phishy_score, &features));
-  EXPECT_EQ(0U, features.features().size());
-  EXPECT_EQ(PhishingClassifier::kInvalidScore, phishy_score);
+  EXPECT_EQ(0U, feature_map_.features().size());
+  EXPECT_EQ(PhishingClassifier::kInvalidScore, phishy_score_);
+  EXPECT_FALSE(is_phishing_);
 }
 
-// This test flakes on Mac with force compositing mode.
-// http://crbug.com/316709
-// Flaky on Chrome OS and Linux, running into a memory allocation error.
-// http://crbug.com/544085
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_LINUX)
-#define MAYBE_TestClassificationWhenPostRequest \
-  DISABLED_TestClassificationWhenPostRequest
-#else
-#define MAYBE_TestClassificationWhenPostRequest \
-  TestClassificationWhenPostRequest
-#endif
-IN_PROC_BROWSER_TEST_F(PhishingClassifierTest,
-                       MAYBE_TestClassificationWhenPostRequest) {
-  float phishy_score;
-  FeatureMap features;
-
-  // Extraction should fail for this case because the URL is a POST request.
-  LoadHtmlPost("host.net", "<html><body>content</body></html>");
-  EXPECT_FALSE(RunPhishingClassifier(&page_text_, &phishy_score, &features));
-  EXPECT_EQ(0U, features.features().size());
-  EXPECT_EQ(PhishingClassifier::kInvalidScore, phishy_score);
-}
-
-// Test flakes with LSAN enabled. See http://crbug.com/373155.
-// Flaky on Linux. See http://crbug.com/638557.
-#if defined(LEAK_SANITIZER) || defined(OS_LINUX)
-#define MAYBE_DisableDetection DISABLED_DisableDetection
-#else
-#define MAYBE_DisableDetection DisableDetection
-#endif
-IN_PROC_BROWSER_TEST_F(PhishingClassifierTest, MAYBE_DisableDetection) {
+TEST_F(PhishingClassifierTest, DisableDetection) {
   EXPECT_TRUE(classifier_->is_ready());
-
   // Set a NULL scorer, which turns detection back off.
   classifier_->set_phishing_scorer(NULL);
   EXPECT_FALSE(classifier_->is_ready());
 }
 
+// TODO(jialiul): Add test to verify that classification only starts on GET
+// method. It seems there is no easy way to simulate a HTTP POST in
+// ChromeRenderViewTest.
+
 }  // namespace safe_browsing
diff --git a/components/crash/content/app/breakpad_win.cc b/components/crash/content/app/breakpad_win.cc
index 3324f1f..0604383e 100644
--- a/components/crash/content/app/breakpad_win.cc
+++ b/components/crash/content/app/breakpad_win.cc
@@ -547,7 +547,7 @@
   if (process_type == L"browser") {
     callback = &DumpDoneCallback;
     default_filter = &ChromeExceptionFilter;
-  } else if (process_type == L"cloud-print-service") {
+  } else if (process_type == L"service") {
     callback = &DumpDoneCallback;
     default_filter = &CloudPrintServiceExceptionFilter;
   }
diff --git a/components/download/internal/config.cc b/components/download/internal/config.cc
index 4aa195b..a25aa634 100644
--- a/components/download/internal/config.cc
+++ b/components/download/internal/config.cc
@@ -19,7 +19,7 @@
 const uint32_t kDefaultMaxConcurrentDownloads = 4;
 
 // Default value for maximum running downloads of the download service.
-const uint32_t kDefaultMaxRunningDownloads = 1;
+const uint32_t kDefaultMaxRunningDownloads = 2;
 
 // Default value for maximum scheduled downloads.
 const uint32_t kDefaultMaxScheduledDownloads = 15;
diff --git a/components/download/internal/config.h b/components/download/internal/config.h
index 8135020..9abd50e 100644
--- a/components/download/internal/config.h
+++ b/components/download/internal/config.h
@@ -54,8 +54,8 @@
   // only Active state.
   uint32_t max_running_downloads;
 
-  // The maximum number of downloads that are scheduled but not yet in Active
-  // state, for each client using the download service.
+  // The maximum number of downloads that are scheduled for each client using
+  // the download service.
   uint32_t max_scheduled_downloads;
 
   // The maximum number of retries before the download is aborted.
diff --git a/components/download/internal/controller_impl.cc b/components/download/internal/controller_impl.cc
index 2858f71..43fa783 100644
--- a/components/download/internal/controller_impl.cc
+++ b/components/download/internal/controller_impl.cc
@@ -786,7 +786,17 @@
   if (initializing_internals_)
     return;
 
-  // TODO(xingliu): Check the configuration to throttle downloads.
+  // Check the configuration to throttle number of downloads.
+  std::map<Entry::State, uint32_t> entries_states;
+  for (const auto* const entry : model_->PeekEntries())
+    entries_states[entry->state]++;
+  uint32_t paused_count = entries_states[Entry::State::PAUSED];
+  uint32_t active_count = entries_states[Entry::State::ACTIVE];
+  if (config_->max_concurrent_downloads <= paused_count + active_count ||
+      config_->max_running_downloads <= active_count) {
+    return;
+  }
+
   Entry* next = scheduler_->Next(
       model_->PeekEntries(), device_status_listener_->CurrentDeviceStatus());
 
diff --git a/components/download/internal/controller_impl_unittest.cc b/components/download/internal/controller_impl_unittest.cc
index 3206db1..5da8cdad7 100644
--- a/components/download/internal/controller_impl_unittest.cc
+++ b/components/download/internal/controller_impl_unittest.cc
@@ -122,6 +122,8 @@
     config_ = base::MakeUnique<Configuration>();
     config_->file_keep_alive_time = base::TimeDelta::FromMinutes(10);
     config_->file_cleanup_window = base::TimeDelta::FromMinutes(5);
+    config_->max_concurrent_downloads = 5;
+    config_->max_running_downloads = 5;
 
     client_ = client.get();
     driver_ = driver.get();
@@ -571,7 +573,7 @@
 }
 
 TEST_F(DownloadServiceControllerImplTest, Resume) {
-  // Setupd download service test data.
+  // Setup download service test data.
   Entry entry1 = test::BuildBasicEntry();
   Entry entry2 = test::BuildBasicEntry();
   entry1.state = Entry::State::PAUSED;
@@ -1109,4 +1111,63 @@
   EXPECT_EQ(1u, updated_entries.size());
 }
 
+// Ensures no more downloads are activated if the number of downloads exceeds
+// the max running download configuration.
+TEST_F(DownloadServiceControllerImplTest, ThrottlingConfigMaxRunning) {
+  Entry entry1 = test::BuildBasicEntry(Entry::State::AVAILABLE);
+  Entry entry2 = test::BuildBasicEntry(Entry::State::ACTIVE);
+  std::vector<Entry> entries = {entry1, entry2};
+
+  EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1);
+
+  // Setup the Configuration.
+  config_->max_concurrent_downloads = 1u;
+  config_->max_running_downloads = 1u;
+
+  // Setup the controller.
+  controller_->Initialize();
+  store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
+  store_->AutomaticallyTriggerAllFutureCallbacks(true);
+
+  // Hit the max running configuration threshold, nothing should be called.
+  EXPECT_CALL(*scheduler_, Next(_, _)).Times(0);
+  EXPECT_CALL(*scheduler_, Reschedule(_)).Times(0);
+  driver_->MakeReady();
+  task_runner_->RunUntilIdle();
+
+  EXPECT_EQ(Entry::State::AVAILABLE, model_->Get(entry1.guid)->state);
+}
+
+// Ensures max concurrent download configuration considers both active and
+// paused downloads.
+TEST_F(DownloadServiceControllerImplTest, ThrottlingConfigMaxConcurrent) {
+  Entry entry1 = test::BuildBasicEntry(Entry::State::AVAILABLE);
+  Entry entry2 = test::BuildBasicEntry(Entry::State::PAUSED);
+  std::vector<Entry> entries = {entry1, entry2};
+
+  EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1);
+
+  // Setup the Configuration.
+  config_->max_concurrent_downloads = 2u;
+  config_->max_running_downloads = 1u;
+
+  // Setup the controller.
+  controller_->Initialize();
+  store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
+  store_->AutomaticallyTriggerAllFutureCallbacks(true);
+
+  // Can have one more download due to max concurrent configuration.
+  testing::InSequence seq;
+  EXPECT_CALL(*scheduler_, Next(_, _))
+      .Times(1)
+      .WillOnce(Return(model_->Get(entry1.guid)))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*scheduler_, Next(_, _)).Times(1).RetiresOnSaturation();
+  EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
+  driver_->MakeReady();
+  task_runner_->RunUntilIdle();
+
+  EXPECT_EQ(Entry::State::ACTIVE, model_->Get(entry1.guid)->state);
+}
+
 }  // namespace download
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index e6043678..5ae9136 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -112,25 +112,11 @@
 }
 
 #if defined(OZONE_PLATFORM_GBM)
-void LinuxBufferParamsCreated(void* data,
-                              zwp_linux_buffer_params_v1* params,
-                              wl_buffer* new_buffer) {
-  ClientBase::Buffer* buffer = static_cast<ClientBase::Buffer*>(data);
-  buffer->buffer.reset(new_buffer);
-}
-
-void LinuxBufferParamsFailed(void* data, zwp_linux_buffer_params_v1* params) {
-  LOG(ERROR) << "Linux buffer params failed";
-}
-
 const GrGLInterface* GrGLCreateNativeInterface() {
   return GrGLAssembleInterface(nullptr, [](void* ctx, const char name[]) {
     return eglGetProcAddress(name);
   });
 }
-
-zwp_linux_buffer_params_v1_listener g_params_listener = {
-    LinuxBufferParamsCreated, LinuxBufferParamsFailed};
 #endif
 
 wl_registry_listener g_registry_listener = {RegistryHandler, RegistryRemover};
@@ -313,10 +299,11 @@
     buffers_.push_back(std::move(buffer));
   }
 
-  wl_display_roundtrip(display_.get());
   for (size_t i = 0; i < buffers_.size(); ++i) {
+    // If the buffer handle doesn't exist, we would either be killed by the
+    // server or die here.
     if (!buffers_[i]->buffer) {
-      LOG(ERROR) << "LinuxBufferParamsCreated was not called on the buffer.";
+      LOG(ERROR) << "buffer handle uninitialized.";
       return false;
     }
 
@@ -388,8 +375,6 @@
 
     buffer->params.reset(
         zwp_linux_dmabuf_v1_create_params(globals_.linux_dmabuf.get()));
-    zwp_linux_buffer_params_v1_add_listener(buffer->params.get(),
-                                            &g_params_listener, buffer.get());
     for (size_t i = 0; i < gbm_bo_get_num_planes(buffer->bo.get()); ++i) {
       base::ScopedFD fd(gbm_bo_get_plane_fd(buffer->bo.get(), i));
       uint32_t stride = gbm_bo_get_plane_stride(buffer->bo.get(), i);
@@ -397,8 +382,8 @@
       zwp_linux_buffer_params_v1_add(buffer->params.get(), fd.get(), i, offset,
                                      stride, 0, 0);
     }
-    zwp_linux_buffer_params_v1_create(buffer->params.get(), width_, height_,
-                                      drm_format, 0);
+    buffer->buffer.reset(zwp_linux_buffer_params_v1_create_immed(
+        buffer->params.get(), width_, height_, drm_format, 0));
 
     if (gbm_bo_get_num_planes(buffer->bo.get()) != 1)
       return buffer;
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index b0ddd35..d7246bd 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -658,19 +658,55 @@
   }
 }
 
+bool ValidateLinuxBufferParams(wl_resource* resource,
+                               int32_t width,
+                               int32_t height,
+                               gfx::BufferFormat format,
+                               uint32_t flags) {
+  if (width <= 0 || height <= 0) {
+    wl_resource_post_error(resource,
+                           ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
+                           "invalid width or height");
+    return false;
+  }
+
+  if (flags & (ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT |
+               ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED)) {
+    wl_resource_post_error(resource,
+                           ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+                           "flags not supported");
+    return false;
+  }
+
+  LinuxBufferParams* linux_buffer_params =
+      GetUserDataAs<LinuxBufferParams>(resource);
+  size_t num_planes = gfx::NumberOfPlanesForBufferFormat(format);
+
+  for (uint32_t i = 0; i < num_planes; ++i) {
+    auto plane_it = linux_buffer_params->planes.find(i);
+    if (plane_it == linux_buffer_params->planes.end()) {
+      wl_resource_post_error(resource,
+                             ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+                             "missing a plane");
+      return false;
+    }
+  }
+
+  if (linux_buffer_params->planes.size() != num_planes) {
+    wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
+                           "plane idx out of bounds");
+    return false;
+  }
+
+  return true;
+}
+
 void linux_buffer_params_create(wl_client* client,
                                 wl_resource* resource,
                                 int32_t width,
                                 int32_t height,
                                 uint32_t format,
                                 uint32_t flags) {
-  if (width <= 0 || height <= 0) {
-    wl_resource_post_error(resource,
-                           ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
-                           "invalid width or height");
-    return;
-  }
-
   const auto* supported_format = std::find_if(
       std::begin(dmabuf_supported_formats), std::end(dmabuf_supported_formats),
       [format](const dmabuf_supported_format& supported_format) {
@@ -683,13 +719,9 @@
     return;
   }
 
-  if (flags & (ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT |
-               ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED)) {
-    wl_resource_post_error(resource,
-                           ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
-                           "flags not supported");
+  if (!ValidateLinuxBufferParams(resource, width, height,
+                                 supported_format->buffer_format, flags))
     return;
-  }
 
   LinuxBufferParams* linux_buffer_params =
       GetUserDataAs<LinuxBufferParams>(resource);
@@ -697,23 +729,11 @@
   size_t num_planes =
       gfx::NumberOfPlanesForBufferFormat(supported_format->buffer_format);
 
-  if (linux_buffer_params->planes.size() != num_planes) {
-    wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
-                           "plane idx out of bounds");
-    return;
-  }
-
   std::vector<gfx::NativePixmapPlane> planes;
   std::vector<base::ScopedFD> fds;
 
   for (uint32_t i = 0; i < num_planes; ++i) {
     auto plane_it = linux_buffer_params->planes.find(i);
-    if (plane_it == linux_buffer_params->planes.end()) {
-      wl_resource_post_error(resource,
-                             ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
-                             "missing a plane");
-      return;
-    }
     LinuxBufferParams::Plane& plane = plane_it->second;
     planes.emplace_back(plane.stride, plane.offset, 0, 0);
     fds.push_back(std::move(plane.fd));
@@ -739,10 +759,71 @@
   zwp_linux_buffer_params_v1_send_created(resource, buffer_resource);
 }
 
+void linux_buffer_params_create_immed(wl_client* client,
+                                      wl_resource* resource,
+                                      uint32_t buffer_id,
+                                      int32_t width,
+                                      int32_t height,
+                                      uint32_t format,
+                                      uint32_t flags) {
+  const auto* supported_format = std::find_if(
+      std::begin(dmabuf_supported_formats), std::end(dmabuf_supported_formats),
+      [format](const dmabuf_supported_format& supported_format) {
+        return supported_format.dmabuf_format == format;
+      });
+  if (supported_format == std::end(dmabuf_supported_formats)) {
+    wl_resource_post_error(resource,
+                           ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT,
+                           "format not supported");
+    return;
+  }
+
+  if (!ValidateLinuxBufferParams(resource, width, height,
+                                 supported_format->buffer_format, flags))
+    return;
+
+  LinuxBufferParams* linux_buffer_params =
+      GetUserDataAs<LinuxBufferParams>(resource);
+
+  size_t num_planes =
+      gfx::NumberOfPlanesForBufferFormat(supported_format->buffer_format);
+
+  std::vector<gfx::NativePixmapPlane> planes;
+  std::vector<base::ScopedFD> fds;
+
+  for (uint32_t i = 0; i < num_planes; ++i) {
+    auto plane_it = linux_buffer_params->planes.find(i);
+    LinuxBufferParams::Plane& plane = plane_it->second;
+    planes.emplace_back(plane.stride, plane.offset, 0, 0);
+    fds.push_back(std::move(plane.fd));
+  }
+
+  std::unique_ptr<Buffer> buffer =
+      linux_buffer_params->display->CreateLinuxDMABufBuffer(
+          gfx::Size(width, height), supported_format->buffer_format, planes,
+          std::move(fds));
+  if (!buffer) {
+    // On import failure in case of a create_immed request, the protocol
+    // allows us to raise a fatal error from zwp_linux_dmabuf_v1 version 2+.
+    wl_resource_post_error(resource,
+                           ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
+                           "dmabuf import failed");
+    return;
+  }
+
+  wl_resource* buffer_resource =
+      wl_resource_create(client, &wl_buffer_interface, 1, buffer_id);
+
+  buffer->set_release_callback(base::Bind(&HandleBufferReleaseCallback,
+                                          base::Unretained(buffer_resource)));
+
+  SetImplementation(buffer_resource, &buffer_implementation, std::move(buffer));
+}
+
 const struct zwp_linux_buffer_params_v1_interface
-    linux_buffer_params_implementation = {linux_buffer_params_destroy,
-                                          linux_buffer_params_add,
-                                          linux_buffer_params_create};
+    linux_buffer_params_implementation = {
+        linux_buffer_params_destroy, linux_buffer_params_add,
+        linux_buffer_params_create, linux_buffer_params_create_immed};
 
 ////////////////////////////////////////////////////////////////////////////////
 // linux_dmabuf_interface:
@@ -758,7 +839,7 @@
       base::MakeUnique<LinuxBufferParams>(GetUserDataAs<Display>(resource));
 
   wl_resource* linux_buffer_params_resource =
-      wl_resource_create(client, &zwp_linux_buffer_params_v1_interface, 1, id);
+      wl_resource_create(client, &zwp_linux_buffer_params_v1_interface, 2, id);
 
   SetImplementation(linux_buffer_params_resource,
                     &linux_buffer_params_implementation,
@@ -773,7 +854,7 @@
                        uint32_t version,
                        uint32_t id) {
   wl_resource* resource =
-      wl_resource_create(client, &zwp_linux_dmabuf_v1_interface, 1, id);
+      wl_resource_create(client, &zwp_linux_dmabuf_v1_interface, version, id);
 
   wl_resource_set_implementation(resource, &linux_dmabuf_implementation, data,
                                  nullptr);
@@ -3996,7 +4077,7 @@
 #if defined(USE_OZONE)
   wl_global_create(wl_display_.get(), &wl_drm_interface, drm_version, display_,
                    bind_drm);
-  wl_global_create(wl_display_.get(), &zwp_linux_dmabuf_v1_interface, 1,
+  wl_global_create(wl_display_.get(), &zwp_linux_dmabuf_v1_interface, 2,
                    display_, bind_linux_dmabuf);
 #endif
   wl_global_create(wl_display_.get(), &wl_subcompositor_interface, 1, display_,
diff --git a/components/favicon/core/favicon_service.h b/components/favicon/core/favicon_service.h
index d361800..60552b1 100644
--- a/components/favicon/core/favicon_service.h
+++ b/components/favicon/core/favicon_service.h
@@ -139,6 +139,15 @@
   // Marks all types of favicon for the page as being out of date.
   virtual void SetFaviconOutOfDateForPage(const GURL& page_url) = 0;
 
+  // Mark that the on-demand favicon at |icon_url| was requested now. This
+  // postpones the automatic eviction of the favicon from the database. Not all
+  // calls end up in a write into the DB:
+  // - It is no-op if the bitmaps are not stored using SetOnDemandFavicons().
+  // - The updates of the "last requested time" have limited frequency for each
+  //   particular favicon (e.g. once per week). This limits the overhead of
+  //   cache management for on-demand favicons.
+  virtual void TouchOnDemandFavicon(const GURL& icon_url) = 0;
+
   // Allows the importer to set many favicons for many pages at once. The pages
   // must exist, any favicon sets for unknown pages will be discarded. Existing
   // favicons will not be overwritten.
@@ -171,19 +180,29 @@
                            favicon_base::IconType icon_type,
                            const gfx::Image& image) = 0;
 
-  // Same as SetFavicons() with three differences:
+  // Same as SetFavicons with three differences:
   // 1) It will be a no-op if there is an existing cached favicon for *any* type
   //    for |page_url|.
   // 2) If |icon_url| is known to the database, |bitmaps| will be ignored (i.e.
   //    the icon won't be overwritten) but the mappings from |page_url| to
   //    |icon_url| will be stored (conditioned to point 1 above).
-  // 3) If |icon_url| is stored, it will be marked as expired.
+  // 3) If |icon_url| is stored, it will be marked as "on-demand".
+  //
+  // On-demand favicons are those that are fetched without visiting their page.
+  // For this reason, their life-time cannot be bound to the life-time of the
+  // corresponding visit in history.
+  // - These bitmaps are evicted from the database based on the last time they
+  //   get requested. The last requested time is initially set to Now() and is
+  //   further updated by calling TouchOnDemandFavicon().
+  // - Furthermore, on-demand bitmaps are immediately marked as expired. Hence,
+  //   they are always replaced by standard favicons whenever their page gets
+  //   visited.
   // The callback will receive whether the write actually happened.
-  virtual void SetLastResortFavicons(const GURL& page_url,
-                                     const GURL& icon_url,
-                                     favicon_base::IconType icon_type,
-                                     const gfx::Image& image,
-                                     base::Callback<void(bool)> callback) = 0;
+  virtual void SetOnDemandFavicons(const GURL& page_url,
+                                   const GURL& icon_url,
+                                   favicon_base::IconType icon_type,
+                                   const gfx::Image& image,
+                                   base::Callback<void(bool)> callback) = 0;
 
   // Avoid repeated requests to download missing favicon.
   virtual void UnableToDownloadFavicon(const GURL& icon_url) = 0;
diff --git a/components/favicon/core/favicon_service_impl.cc b/components/favicon/core/favicon_service_impl.cc
index 55ac6b22..4522aad 100644
--- a/components/favicon/core/favicon_service_impl.cc
+++ b/components/favicon/core/favicon_service_impl.cc
@@ -209,6 +209,10 @@
   history_service_->SetFaviconsOutOfDateForPage(page_url);
 }
 
+void FaviconServiceImpl::TouchOnDemandFavicon(const GURL& icon_url) {
+  history_service_->TouchOnDemandFavicon(icon_url);
+}
+
 void FaviconServiceImpl::SetImportedFavicons(
     const favicon_base::FaviconUsageDataList& favicon_usage) {
   history_service_->SetImportedFavicons(favicon_usage);
@@ -232,13 +236,13 @@
                                 ExtractSkBitmapsToStore(image));
 }
 
-void FaviconServiceImpl::SetLastResortFavicons(
+void FaviconServiceImpl::SetOnDemandFavicons(
     const GURL& page_url,
     const GURL& icon_url,
     favicon_base::IconType icon_type,
     const gfx::Image& image,
     base::Callback<void(bool)> callback) {
-  history_service_->SetLastResortFavicons(
+  history_service_->SetOnDemandFavicons(
       page_url, icon_type, icon_url, ExtractSkBitmapsToStore(image), callback);
 }
 
diff --git a/components/favicon/core/favicon_service_impl.h b/components/favicon/core/favicon_service_impl.h
index e1cb63c..7ad2d0a 100644
--- a/components/favicon/core/favicon_service_impl.h
+++ b/components/favicon/core/favicon_service_impl.h
@@ -91,6 +91,7 @@
       const favicon_base::FaviconRawBitmapCallback& callback,
       base::CancelableTaskTracker* tracker) override;
   void SetFaviconOutOfDateForPage(const GURL& page_url) override;
+  void TouchOnDemandFavicon(const GURL& icon_url) override;
   void SetImportedFavicons(
       const favicon_base::FaviconUsageDataList& favicon_usage) override;
   void MergeFavicon(const GURL& page_url,
@@ -102,11 +103,11 @@
                    const GURL& icon_url,
                    favicon_base::IconType icon_type,
                    const gfx::Image& image) override;
-  void SetLastResortFavicons(const GURL& page_url,
-                             const GURL& icon_url,
-                             favicon_base::IconType icon_type,
-                             const gfx::Image& image,
-                             base::Callback<void(bool)> callback) override;
+  void SetOnDemandFavicons(const GURL& page_url,
+                           const GURL& icon_url,
+                           favicon_base::IconType icon_type,
+                           const gfx::Image& image,
+                           base::Callback<void(bool)> callback) override;
   void UnableToDownloadFavicon(const GURL& icon_url) override;
   bool WasUnableToDownloadFavicon(const GURL& icon_url) const override;
   void ClearUnableToDownloadFavicons() override;
diff --git a/components/favicon/core/large_icon_service.cc b/components/favicon/core/large_icon_service.cc
index 660b3a3..043678a 100644
--- a/components/favicon/core/large_icon_service.cc
+++ b/components/favicon/core/large_icon_service.cc
@@ -297,9 +297,9 @@
   // something else could've been written). By marking the icons initially
   // expired (out-of-date), they will be refetched when we visit the original
   // page any time in the future.
-  favicon_service->SetLastResortFavicons(page_url, GURL(original_icon_url),
-                                         favicon_base::IconType::TOUCH_ICON,
-                                         image, callback);
+  favicon_service->SetOnDemandFavicons(page_url, GURL(original_icon_url),
+                                       favicon_base::IconType::TOUCH_ICON,
+                                       image, callback);
 }
 
 }  // namespace
diff --git a/components/favicon/core/large_icon_service_unittest.cc b/components/favicon/core/large_icon_service_unittest.cc
index 7c65371..23a2a67 100644
--- a/components/favicon/core/large_icon_service_unittest.cc
+++ b/components/favicon/core/large_icon_service_unittest.cc
@@ -157,8 +157,8 @@
       .WillOnce(PostFetchReply(gfx::Image::CreateFrom1xBitmap(
           CreateTestSkBitmap(64, 64, kTestColor))));
   EXPECT_CALL(mock_favicon_service_,
-              SetLastResortFavicons(GURL(kDummyUrl), kExpectedServerUrl,
-                                    favicon_base::IconType::TOUCH_ICON, _, _))
+              SetOnDemandFavicons(GURL(kDummyUrl), kExpectedServerUrl,
+                                  favicon_base::IconType::TOUCH_ICON, _, _))
       .WillOnce(PostBoolReply(true));
 
   large_icon_service_
@@ -194,8 +194,8 @@
       .WillOnce(PostFetchReply(gfx::Image::CreateFrom1xBitmap(
           CreateTestSkBitmap(64, 64, kTestColor))));
   EXPECT_CALL(mock_favicon_service_,
-              SetLastResortFavicons(GURL(kDummyUrl), kExpectedServerUrl,
-                                    favicon_base::IconType::TOUCH_ICON, _, _))
+              SetOnDemandFavicons(GURL(kDummyUrl), kExpectedServerUrl,
+                                  favicon_base::IconType::TOUCH_ICON, _, _))
       .WillOnce(PostBoolReply(true));
 
   large_icon_service_
@@ -224,8 +224,8 @@
               CreateTestSkBitmap(64, 64, kTestColor)),
           expected_metadata));
   EXPECT_CALL(mock_favicon_service_,
-              SetLastResortFavicons(GURL(kDummyUrl), kExpectedOriginalUrl,
-                                    favicon_base::IconType::TOUCH_ICON, _, _))
+              SetOnDemandFavicons(GURL(kDummyUrl), kExpectedOriginalUrl,
+                                  favicon_base::IconType::TOUCH_ICON, _, _))
       .WillOnce(PostBoolReply(true));
 
   base::MockCallback<base::Callback<void(bool success)>> callback;
@@ -252,7 +252,7 @@
           CreateTestSkBitmap(64, 64, kTestColor))));
   // Verify that the non-trimmed page URL is used when writing to the database.
   EXPECT_CALL(mock_favicon_service_,
-              SetLastResortFavicons(_, kExpectedServerUrl, _, _, _));
+              SetOnDemandFavicons(_, kExpectedServerUrl, _, _, _));
 
   large_icon_service_
       .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
@@ -311,7 +311,7 @@
       "&check_seen=true&size=61&min_size=42&max_size=122"
       "&fallback_opts=TYPE,SIZE,URL&url=http://www.example.com/");
 
-  EXPECT_CALL(mock_favicon_service_, SetLastResortFavicons(_, _, _, _, _))
+  EXPECT_CALL(mock_favicon_service_, SetOnDemandFavicons(_, _, _, _, _))
       .Times(0);
 
   base::MockCallback<base::Callback<void(bool success)>> callback;
@@ -346,7 +346,7 @@
   EXPECT_CALL(mock_favicon_service_, UnableToDownloadFavicon(_)).Times(0);
   EXPECT_CALL(*mock_image_fetcher_, StartOrQueueNetworkRequest(_, _, _, _))
       .Times(0);
-  EXPECT_CALL(mock_favicon_service_, SetLastResortFavicons(_, _, _, _, _))
+  EXPECT_CALL(mock_favicon_service_, SetOnDemandFavicons(_, _, _, _, _))
       .Times(0);
 
   base::MockCallback<base::Callback<void(bool success)>> callback;
diff --git a/components/favicon/core/test/mock_favicon_service.h b/components/favicon/core/test/mock_favicon_service.h
index a4cace7..c9da0a1 100644
--- a/components/favicon/core/test/mock_favicon_service.h
+++ b/components/favicon/core/test/mock_favicon_service.h
@@ -89,6 +89,7 @@
                    const favicon_base::FaviconRawBitmapCallback& callback,
                    base::CancelableTaskTracker* tracker));
   MOCK_METHOD1(SetFaviconOutOfDateForPage, void(const GURL& page_url));
+  MOCK_METHOD1(TouchOnDemandFavicon, void(const GURL& icon_url));
   MOCK_METHOD1(SetImportedFavicons,
                void(const favicon_base::FaviconUsageDataList& favicon_usage));
   MOCK_METHOD5(MergeFavicon,
@@ -102,7 +103,7 @@
                     const GURL& icon_url,
                     favicon_base::IconType icon_type,
                     const gfx::Image& image));
-  MOCK_METHOD5(SetLastResortFavicons,
+  MOCK_METHOD5(SetOnDemandFavicons,
                void(const GURL& page_url,
                     const GURL& icon_url,
                     favicon_base::IconType icon_type,
diff --git a/components/history/core/browser/android/favicon_sql_handler.cc b/components/history/core/browser/android/favicon_sql_handler.cc
index dd7a094e..b630bae 100644
--- a/components/history/core/browser/android/favicon_sql_handler.cc
+++ b/components/history/core/browser/android/favicon_sql_handler.cc
@@ -39,7 +39,8 @@
   // icon is already in database, just create a new favicon.
   // TODO(pkotwicz): Pass in real pixel size.
   favicon_base::FaviconID favicon_id = thumbnail_db_->AddFavicon(
-      GURL(), favicon_base::FAVICON, row.favicon(), Time::Now(), gfx::Size());
+      GURL(), favicon_base::FAVICON, row.favicon(), FaviconBitmapType::ON_VISIT,
+      Time::Now(), gfx::Size());
 
   if (!favicon_id)
     return false;
@@ -104,7 +105,8 @@
   // Is it a problem to give a empty URL?
   // TODO(pkotwicz): Pass in real pixel size.
   favicon_base::FaviconID id = thumbnail_db_->AddFavicon(
-      GURL(), favicon_base::FAVICON, row->favicon(), Time::Now(), gfx::Size());
+      GURL(), favicon_base::FAVICON, row->favicon(),
+      FaviconBitmapType::ON_VISIT, Time::Now(), gfx::Size());
   if (!id)
     return false;
   return thumbnail_db_->AddIconMapping(row->url(), id);
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 1c4aa6a04..a05f7546 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -1636,8 +1636,9 @@
       thumbnail_db_->DeleteFaviconBitmap(bitmap_id_sizes[0].bitmap_id);
       favicon_sizes.erase(favicon_sizes.begin());
     }
-    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data, base::Time::Now(),
-                                    pixel_size);
+    thumbnail_db_->AddFaviconBitmap(favicon_id, bitmap_data,
+                                    FaviconBitmapType::ON_VISIT,
+                                    base::Time::Now(), pixel_size);
     favicon_sizes.push_back(pixel_size);
   }
 
@@ -1698,9 +1699,10 @@
 
       // Add the favicon bitmap as expired as it is not consistent with the
       // merged in data.
-      thumbnail_db_->AddFaviconBitmap(
-          favicon_id, bitmaps_to_copy[j].bitmap_data, base::Time(),
-          bitmaps_to_copy[j].pixel_size);
+      thumbnail_db_->AddFaviconBitmap(favicon_id,
+                                      bitmaps_to_copy[j].bitmap_data,
+                                      FaviconBitmapType::ON_VISIT, base::Time(),
+                                      bitmaps_to_copy[j].pixel_size);
       favicon_sizes.push_back(bitmaps_to_copy[j].pixel_size);
       favicon_bitmaps_copied = true;
 
@@ -1733,14 +1735,13 @@
                                  const GURL& icon_url,
                                  const std::vector<SkBitmap>& bitmaps) {
   SetFaviconsImpl(page_url, icon_type, icon_url, bitmaps,
-                  /*bitmaps_are_expired=*/false);
+                  FaviconBitmapType::ON_VISIT);
 }
 
-bool HistoryBackend::SetLastResortFavicons(
-    const GURL& page_url,
-    favicon_base::IconType icon_type,
-    const GURL& icon_url,
-    const std::vector<SkBitmap>& bitmaps) {
+bool HistoryBackend::SetOnDemandFavicons(const GURL& page_url,
+                                         favicon_base::IconType icon_type,
+                                         const GURL& icon_url,
+                                         const std::vector<SkBitmap>& bitmaps) {
   if (!thumbnail_db_ || !db_)
     return false;
 
@@ -1751,7 +1752,7 @@
   }
 
   return SetFaviconsImpl(page_url, icon_type, icon_url, bitmaps,
-                         /*bitmaps_are_expired=*/true);
+                         FaviconBitmapType::ON_DEMAND);
 }
 
 void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) {
@@ -1768,6 +1769,14 @@
   ScheduleCommit();
 }
 
+void HistoryBackend::TouchOnDemandFavicon(const GURL& icon_url) {
+  if (!thumbnail_db_)
+    return;
+
+  thumbnail_db_->TouchOnDemandFavicon(icon_url, Time::Now());
+  ScheduleCommit();
+}
+
 void HistoryBackend::SetImportedFavicons(
     const favicon_base::FaviconUsageDataList& favicon_usage) {
   if (!db_ || !thumbnail_db_)
@@ -1787,8 +1796,8 @@
       // TODO(pkotwicz): Pass in real pixel size.
       favicon_id = thumbnail_db_->AddFavicon(
           favicon_usage[i].favicon_url, favicon_base::FAVICON,
-          new base::RefCountedBytes(favicon_usage[i].png_data), now,
-          gfx::Size());
+          new base::RefCountedBytes(favicon_usage[i].png_data),
+          FaviconBitmapType::ON_VISIT, now, gfx::Size());
     }
 
     // Save the mapping from all the URLs to the favicon.
@@ -1833,7 +1842,7 @@
                                      favicon_base::IconType icon_type,
                                      const GURL& icon_url,
                                      const std::vector<SkBitmap>& bitmaps,
-                                     bool bitmaps_are_expired) {
+                                     FaviconBitmapType type) {
   if (!thumbnail_db_ || !db_)
     return false;
 
@@ -1849,11 +1858,9 @@
   }
 
   bool favicon_data_modified = false;
-  if (favicon_created || !bitmaps_are_expired)
-    favicon_data_modified = SetFaviconBitmaps(icon_id, bitmaps);
-
-  if (favicon_created && bitmaps_are_expired)
-    thumbnail_db_->SetFaviconOutOfDate(icon_id);
+  if (favicon_created || type == FaviconBitmapType::ON_VISIT) {
+    favicon_data_modified = SetFaviconBitmaps(icon_id, bitmaps, type);
+  }
 
   std::vector<favicon_base::FaviconID> icon_ids(1u, icon_id);
   bool mapping_changed =
@@ -1907,7 +1914,8 @@
 }
 
 bool HistoryBackend::SetFaviconBitmaps(favicon_base::FaviconID icon_id,
-                                       const std::vector<SkBitmap>& bitmaps) {
+                                       const std::vector<SkBitmap>& bitmaps,
+                                       FaviconBitmapType type) {
   std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
   thumbnail_db_->GetFaviconBitmapIDSizes(icon_id, &bitmap_id_sizes);
 
@@ -1944,11 +1952,12 @@
     } else {
       if (!favicon_bitmaps_changed &&
           IsFaviconBitmapDataEqual(bitmap_id, match_it->first)) {
-        thumbnail_db_->SetFaviconBitmapLastUpdateTime(bitmap_id,
-                                                      base::Time::Now());
+        thumbnail_db_->SetFaviconBitmapLastUpdateTime(
+            bitmap_id, base::Time::Now() /* new last updated time */);
       } else {
-        thumbnail_db_->SetFaviconBitmap(bitmap_id, match_it->first,
-                                        base::Time::Now());
+        thumbnail_db_->SetFaviconBitmap(
+            bitmap_id, match_it->first,
+            base::Time::Now() /* new last updated time */);
         favicon_bitmaps_changed = true;
       }
       to_add.erase(match_it);
@@ -1956,8 +1965,10 @@
   }
 
   for (size_t i = 0; i < to_add.size(); ++i) {
-    thumbnail_db_->AddFaviconBitmap(icon_id, to_add[i].first, base::Time::Now(),
-                                    to_add[i].second);
+    thumbnail_db_->AddFaviconBitmap(
+        icon_id, to_add[i].first, type,
+        base::Time::Now() /* new last updated / last requested time */,
+        to_add[i].second);
 
     favicon_bitmaps_changed = true;
   }
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h
index cae7870..85c5fb8 100644
--- a/components/history/core/browser/history_backend.h
+++ b/components/history/core/browser/history_backend.h
@@ -326,13 +326,15 @@
                    const GURL& icon_url,
                    const std::vector<SkBitmap>& bitmaps);
 
-  bool SetLastResortFavicons(const GURL& page_url,
-                             favicon_base::IconType icon_type,
-                             const GURL& icon_url,
-                             const std::vector<SkBitmap>& bitmaps);
+  bool SetOnDemandFavicons(const GURL& page_url,
+                           favicon_base::IconType icon_type,
+                           const GURL& icon_url,
+                           const std::vector<SkBitmap>& bitmaps);
 
   void SetFaviconsOutOfDateForPage(const GURL& page_url);
 
+  void TouchOnDemandFavicon(const GURL& icon_url);
+
   void SetImportedFavicons(
       const favicon_base::FaviconUsageDataList& favicon_usage);
 
@@ -528,11 +530,9 @@
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetFaviconsReplaceBitmapData);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
                            SetFaviconsSameFaviconURLForTwoPages);
-  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetLastResortFaviconsForEmptyDB);
-  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
-                           SetLastResortFaviconsForPageInDB);
-  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
-                           SetLastResortFaviconsForIconInDB);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetOnDemandFaviconsForEmptyDB);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetOnDemandFaviconsForPageInDB);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetOnDemandFaviconsForIconInDB);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
                            UpdateFaviconMappingsAndFetchNoChange);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, MergeFaviconPageURLNotInDB);
@@ -686,7 +686,7 @@
                        favicon_base::IconType icon_type,
                        const GURL& icon_url,
                        const std::vector<SkBitmap>& bitmaps,
-                       bool bitmaps_are_expired);
+                       FaviconBitmapType type);
 
   // Used by both UpdateFaviconMappingsAndFetch() and GetFavicon().
   // If |page_url| is non-null and there is a favicon stored in the database
@@ -699,16 +699,19 @@
       const std::vector<int>& desired_sizes,
       std::vector<favicon_base::FaviconRawBitmapResult>* results);
 
-  // Set the favicon bitmaps for |icon_id|.
+  // Set the favicon bitmaps of |type| for |icon_id|.
   // For each entry in |bitmaps|, if a favicon bitmap already exists at the
   // entry's pixel size, replace the favicon bitmap's data with the entry's
   // bitmap data. Otherwise add a new favicon bitmap.
   // Any favicon bitmaps already mapped to |icon_id| whose pixel size does not
   // match the pixel size of one of |bitmaps| is deleted.
+  // For bitmap type FaviconBitmapType::ON_DEMAND, this is legal to call only
+  // for a newly created |icon_id| (that has no bitmaps yet).
   // Returns true if any of the bitmap data at |icon_id| is changed as a result
   // of calling this method.
   bool SetFaviconBitmaps(favicon_base::FaviconID icon_id,
-                         const std::vector<SkBitmap>& bitmaps);
+                         const std::vector<SkBitmap>& bitmaps,
+                         FaviconBitmapType type);
 
   // Returns true if the bitmap data at |bitmap_id| equals |new_bitmap_data|.
   bool IsFaviconBitmapDataEqual(
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index 63dfe4b..c92e97e 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -593,18 +593,22 @@
 
   std::vector<unsigned char> data;
   data.push_back('a');
-  EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon1,
-      new base::RefCountedBytes(data), base::Time::Now(), kSmallSize));
+  EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(
+      favicon1, new base::RefCountedBytes(data), FaviconBitmapType::ON_VISIT,
+      base::Time::Now(), kSmallSize));
   data[0] = 'b';
-  EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon1,
-     new base::RefCountedBytes(data), base::Time::Now(), kLargeSize));
+  EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(
+      favicon1, new base::RefCountedBytes(data), FaviconBitmapType::ON_VISIT,
+      base::Time::Now(), kLargeSize));
 
   data[0] = 'c';
-  EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon2,
-      new base::RefCountedBytes(data), base::Time::Now(), kSmallSize));
+  EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(
+      favicon2, new base::RefCountedBytes(data), FaviconBitmapType::ON_VISIT,
+      base::Time::Now(), kSmallSize));
   data[0] = 'd';
-  EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon2,
-     new base::RefCountedBytes(data), base::Time::Now(), kLargeSize));
+  EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(
+      favicon2, new base::RefCountedBytes(data), FaviconBitmapType::ON_VISIT,
+      base::Time::Now(), kLargeSize));
 
   // First visit two URLs.
   URLRow row1(GURL("http://www.google.com/"));
@@ -737,7 +741,7 @@
   data.push_back('a');
   favicon_base::FaviconID favicon = backend_->thumbnail_db_->AddFavicon(
       kFaviconURL, favicon_base::FAVICON, new base::RefCountedBytes(data),
-      base::Time::Now(), kSmallSize);
+      FaviconBitmapType::ON_VISIT, base::Time::Now(), kSmallSize);
   backend_->thumbnail_db_->AddIconMapping(row.url(), favicon);
 
   history_client_.AddBookmark(kPageURL);
@@ -821,20 +825,14 @@
 
   std::vector<unsigned char> data;
   data.push_back('1');
-  favicon_base::FaviconID favicon1 =
-      backend_->thumbnail_db_->AddFavicon(favicon_url1,
-                                          favicon_base::FAVICON,
-                                          new base::RefCountedBytes(data),
-                                          base::Time::Now(),
-                                          gfx::Size());
+  favicon_base::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(
+      favicon_url1, favicon_base::FAVICON, new base::RefCountedBytes(data),
+      FaviconBitmapType::ON_VISIT, base::Time::Now(), gfx::Size());
 
   data[0] = '2';
-  favicon_base::FaviconID favicon2 =
-      backend_->thumbnail_db_->AddFavicon(favicon_url2,
-                                          favicon_base::FAVICON,
-                                          new base::RefCountedBytes(data),
-                                          base::Time::Now(),
-                                          gfx::Size());
+  favicon_base::FaviconID favicon2 = backend_->thumbnail_db_->AddFavicon(
+      favicon_url2, favicon_base::FAVICON, new base::RefCountedBytes(data),
+      FaviconBitmapType::ON_VISIT, base::Time::Now(), gfx::Size());
 
   // First visit two URLs.
   URLRow row1(GURL("http://www.google.com/"));
@@ -1171,11 +1169,9 @@
   std::vector<unsigned char> data;
   data.push_back('1');
   favicon_base::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(
-      favicon_url1,
-      favicon_base::FAVICON,
-      base::RefCountedBytes::TakeVector(&data),
-      base::Time::Now(),
-      gfx::Size());
+      favicon_url1, favicon_base::FAVICON,
+      base::RefCountedBytes::TakeVector(&data), FaviconBitmapType::ON_VISIT,
+      base::Time::Now(), gfx::Size());
   URLRow row1(GURL("http://www.google.com/"));
   row1.set_visit_count(1);
   row1.set_last_visit(base::Time::Now());
@@ -2076,18 +2072,18 @@
   EXPECT_EQ(2u, favicon_bitmaps.size());
 }
 
-// Tests calling SetLastResortFavicons(). Neither |page_url| nor |icon_url| are
+// Tests calling SetOnDemandFavicons(). Neither |page_url| nor |icon_url| are
 // known to the database.
-TEST_F(HistoryBackendTest, SetLastResortFaviconsForEmptyDB) {
+TEST_F(HistoryBackendTest, SetOnDemandFaviconsForEmptyDB) {
   GURL page_url("http://www.google.com");
   GURL icon_url("http:/www.google.com/favicon.ico");
 
   std::vector<SkBitmap> bitmaps;
   bitmaps.push_back(CreateBitmap(SK_ColorRED, kSmallEdgeSize));
 
-  // Call SetLastResortFavicons() with a different icon URL and bitmap data.
-  EXPECT_TRUE(backend_->SetLastResortFavicons(page_url, favicon_base::FAVICON,
-                                              icon_url, bitmaps));
+  // Call SetOnDemandFavicons() with a different icon URL and bitmap data.
+  EXPECT_TRUE(backend_->SetOnDemandFavicons(page_url, favicon_base::FAVICON,
+                                            icon_url, bitmaps));
 
   favicon_base::FaviconID favicon_id =
       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(icon_url,
@@ -2102,9 +2098,9 @@
   EXPECT_EQ(base::Time(), favicon_bitmap.last_updated);
 }
 
-// Tests calling SetLastResortFavicons(). |page_url| is known to the database
+// Tests calling SetOnDemandFavicons(). |page_url| is known to the database
 // but |icon_url| is not (the second should be irrelevant though).
-TEST_F(HistoryBackendTest, SetLastResortFaviconsForPageInDB) {
+TEST_F(HistoryBackendTest, SetOnDemandFaviconsForPageInDB) {
   GURL page_url("http://www.google.com");
   GURL icon_url1("http:/www.google.com/favicon1.ico");
   GURL icon_url2("http:/www.google.com/favicon2.ico");
@@ -2118,10 +2114,10 @@
                                                          favicon_base::FAVICON);
   ASSERT_NE(0, original_favicon_id);
 
-  // Call SetLastResortFavicons() with a different icon URL and bitmap data.
+  // Call SetOnDemandFavicons() with a different icon URL and bitmap data.
   bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize);
-  EXPECT_FALSE(backend_->SetLastResortFavicons(page_url, favicon_base::FAVICON,
-                                               icon_url2, bitmaps));
+  EXPECT_FALSE(backend_->SetOnDemandFavicons(page_url, favicon_base::FAVICON,
+                                             icon_url2, bitmaps));
   EXPECT_EQ(0, backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
                    icon_url2, favicon_base::FAVICON));
 
@@ -2133,9 +2129,9 @@
   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
 }
 
-// Tests calling SetLastResortFavicons(). |page_url| is not known to the
+// Tests calling SetOnDemandFavicons(). |page_url| is not known to the
 // database but |icon_url| is.
-TEST_F(HistoryBackendTest, SetLastResortFaviconsForIconInDB) {
+TEST_F(HistoryBackendTest, SetOnDemandFaviconsForIconInDB) {
   const GURL old_page_url("http://www.google.com/old");
   const GURL page_url("http://www.google.com/");
   const GURL icon_url("http://www.google.com/icon");
@@ -2149,10 +2145,10 @@
                                                          favicon_base::FAVICON);
   ASSERT_NE(0, original_favicon_id);
 
-  // Call SetLastResortFavicons() with a different bitmap.
+  // Call SetOnDemandFavicons() with a different bitmap.
   bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize);
-  EXPECT_FALSE(backend_->SetLastResortFavicons(page_url, favicon_base::FAVICON,
-                                               icon_url, bitmaps));
+  EXPECT_FALSE(backend_->SetOnDemandFavicons(page_url, favicon_base::FAVICON,
+                                             icon_url, bitmaps));
 
   EXPECT_EQ(original_favicon_id,
             backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
@@ -3048,7 +3044,8 @@
       base::RefCountedBytes::TakeVector(&data));
   base::Time last_updated = base::Time::FromTimeT(0);
   favicon_base::FaviconID icon_id = backend_->thumbnail_db_->AddFavicon(
-      icon_url, favicon_base::FAVICON, bitmap_data, last_updated, kSmallSize);
+      icon_url, favicon_base::FAVICON, bitmap_data, FaviconBitmapType::ON_VISIT,
+      last_updated, kSmallSize);
   EXPECT_NE(0, icon_id);
   EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id));
 
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index a9a3326..60a142f 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -625,12 +625,11 @@
                           page_url, icon_type, icon_url, bitmaps));
 }
 
-void HistoryService::SetLastResortFavicons(
-    const GURL& page_url,
-    favicon_base::IconType icon_type,
-    const GURL& icon_url,
-    const std::vector<SkBitmap>& bitmaps,
-    base::Callback<void(bool)> callback) {
+void HistoryService::SetOnDemandFavicons(const GURL& page_url,
+                                         favicon_base::IconType icon_type,
+                                         const GURL& icon_url,
+                                         const std::vector<SkBitmap>& bitmaps,
+                                         base::Callback<void(bool)> callback) {
   DCHECK(backend_task_runner_) << "History service being called after cleanup";
   DCHECK(thread_checker_.CalledOnValidThread());
   if (history_client_ && !history_client_->CanAddURL(page_url))
@@ -638,7 +637,7 @@
 
   PostTaskAndReplyWithResult(
       backend_task_runner_.get(), FROM_HERE,
-      base::Bind(&HistoryBackend::SetLastResortFavicons, history_backend_,
+      base::Bind(&HistoryBackend::SetOnDemandFavicons, history_backend_,
                  page_url, icon_type, icon_url, bitmaps),
       callback);
 }
@@ -651,6 +650,14 @@
                           history_backend_, page_url));
 }
 
+void HistoryService::TouchOnDemandFavicon(const GURL& icon_url) {
+  DCHECK(backend_task_runner_) << "History service being called after cleanup";
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ScheduleTask(PRIORITY_NORMAL,
+               base::Bind(&HistoryBackend::TouchOnDemandFavicon,
+                          history_backend_, icon_url));
+}
+
 void HistoryService::SetImportedFavicons(
     const favicon_base::FaviconUsageDataList& favicon_usage) {
   DCHECK(backend_task_runner_) << "History service being called after cleanup";
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index b1aedcd..425a043 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -756,18 +756,37 @@
   // 2) If |icon_url| is known to the database, |bitmaps| will be ignored (i.e.
   //    the icon won't be overwritten) but the mappings from |page_url| to
   //    |icon_url| will be stored (conditioned to point 1 above).
-  // 3) If |icon_url| is stored, it will be marked as expired.
+  // 3) If |icon_url| is stored, it will be marked as "on-demand".
+  //
+  // On-demand favicons are those that are fetched without visiting their page.
+  // For this reason, their life-time cannot be bound to the life-time of the
+  // corresponding visit in history.
+  // - These bitmaps are evicted from the database based on the last time they
+  //   get requested. The last requested time is initially set to Now() and is
+  //   further updated by calling TouchOnDemandFavicon().
+  // - Furthermore, on-demand bitmaps are immediately marked as expired. Hence,
+  //   they are always replaced by standard favicons whenever their page gets
+  //   visited.
   // The callback will receive whether the write actually happened.
-  void SetLastResortFavicons(const GURL& page_url,
-                             favicon_base::IconType icon_type,
-                             const GURL& icon_url,
-                             const std::vector<SkBitmap>& bitmaps,
-                             base::Callback<void(bool)> callback);
+  void SetOnDemandFavicons(const GURL& page_url,
+                           favicon_base::IconType icon_type,
+                           const GURL& icon_url,
+                           const std::vector<SkBitmap>& bitmaps,
+                           base::Callback<void(bool)> callback);
 
   // Used by the FaviconService to mark the favicon for the page as being out
   // of date.
   void SetFaviconsOutOfDateForPage(const GURL& page_url);
 
+  // Mark that the on-demand favicon at |icon_url| was requested now. This
+  // postpones the automatic eviction of the favicon from the database. Not all
+  // calls end up in a write into the DB:
+  // - it is no-op if the bitmaps are not stored using SetOnDemandFavicons();
+  // - the updates of the "last requested time" have limited frequency for each
+  //   particular favicon (e.g. once per week). This limits the overhead of
+  //   cache management for on-demand favicons.
+  void TouchOnDemandFavicon(const GURL& icon_url);
+
   // Used by the FaviconService for importing many favicons for many pages at
   // once. The pages must exist, any favicon sets for unknown pages will be
   // discarded. Existing favicons will not be overwritten.
diff --git a/components/history/core/browser/history_types.h b/components/history/core/browser/history_types.h
index 4346823..17b97b4 100644
--- a/components/history/core/browser/history_types.h
+++ b/components/history/core/browser/history_types.h
@@ -506,6 +506,24 @@
   gfx::Size pixel_size;
 };
 
+enum FaviconBitmapType {
+  // The bitmap gets downloaded while visiting its page. Their life-time is
+  // bound to the life-time of the corresponding visit in history.
+  //  - These bitmaps are re-downloaded when visiting the page again and the
+  //  last_updated timestamp is old enough.
+  ON_VISIT,
+
+  // The bitmap gets downloaded because it is demanded by some Chrome UI (while
+  // not visiting its page). For this reason, their life-time cannot be bound to
+  // the life-time of the corresponding visit in history.
+  // - These bitmaps are evicted from the database based on the last time they
+  //   were requested.
+  // - Furthermore, on-demand bitmaps are immediately marked as expired. Hence,
+  //   they are always replaced by ON_VISIT favicons whenever their page gets
+  //   visited.
+  ON_DEMAND
+};
+
 // Defines a favicon bitmap stored in the history backend.
 struct FaviconBitmap {
   FaviconBitmap();
diff --git a/components/history/core/browser/thumbnail_database.cc b/components/history/core/browser/thumbnail_database.cc
index 60445eb..c8b430f4 100644
--- a/components/history/core/browser/thumbnail_database.cc
+++ b/components/history/core/browser/thumbnail_database.cc
@@ -64,13 +64,17 @@
 //   icon_id          The ID of the favicon that the bitmap is associated to.
 //   last_updated     The time at which this favicon was inserted into the
 //                    table. This is used to determine if it needs to be
-//                    redownloaded from the web.
+//                    redownloaded from the web. Value 0 denotes that the bitmap
+//                    has been explicitly expired.
 //   image_data       PNG encoded data of the favicon.
 //   width            Pixel width of |image_data|.
 //   height           Pixel height of |image_data|.
-//   last_requested   The time at which this bitmap was last requested. This is
-//                    used to determine the priority with which the bitmap
-//                    should be retained on cleanup.
+//   last_requested   The time at which this bitmap was last requested. This
+//                    entry is non-zero iff the bitmap is of type ON_DEMAND.
+//                    This info is used for clearing old ON_DEMAND bitmaps.
+//                    (On-demand bitmaps cannot get cleared along with expired
+//                    visits in history DB because there is no corresponding
+//                    visit.)
 
 namespace {
 
@@ -503,12 +507,16 @@
 FaviconBitmapID ThumbnailDatabase::AddFaviconBitmap(
     favicon_base::FaviconID icon_id,
     const scoped_refptr<base::RefCountedMemory>& icon_data,
+    FaviconBitmapType type,
     base::Time time,
     const gfx::Size& pixel_size) {
   DCHECK(icon_id);
-  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "INSERT INTO favicon_bitmaps (icon_id, image_data, last_updated, width, "
-      "height) VALUES (?, ?, ?, ?, ?)"));
+
+  sql::Statement statement(db_.GetCachedStatement(
+      SQL_FROM_HERE,
+      "INSERT INTO favicon_bitmaps (icon_id, image_data, last_updated, "
+      "last_requested, width, height) VALUES (?, ?, ?, ?, ?, ?)"));
+
   statement.BindInt64(0, icon_id);
   if (icon_data.get() && icon_data->size()) {
     statement.BindBlob(1, icon_data->front(),
@@ -516,9 +524,19 @@
   } else {
     statement.BindNull(1);
   }
-  statement.BindInt64(2, time.ToInternalValue());
-  statement.BindInt(3, pixel_size.width());
-  statement.BindInt(4, pixel_size.height());
+
+  // On-visit bitmaps:
+  //  - keep track of last_updated: last write time is used for expiration;
+  //  - always have last_requested==0: no need to keep track of last read time.
+  statement.BindInt64(2, type == ON_VISIT ? time.ToInternalValue() : 0);
+  // On-demand bitmaps:
+  //  - always have last_updated==0: last write time is not stored as they are
+  //    always expired and thus ready to be replaced by ON_VISIT icons;
+  //  - keep track of last_requested: last read time is used for cache eviction.
+  statement.BindInt64(3, type == ON_DEMAND ? time.ToInternalValue() : 0);
+
+  statement.BindInt(4, pixel_size.width());
+  statement.BindInt(5, pixel_size.height());
 
   if (!statement.Run())
     return 0;
@@ -530,8 +548,13 @@
     scoped_refptr<base::RefCountedMemory> bitmap_data,
     base::Time time) {
   DCHECK(bitmap_id);
-  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "UPDATE favicon_bitmaps SET image_data=?, last_updated=? WHERE id=?"));
+  // By updating last_updated timestamp, we assume the icon is of type ON_VISIT.
+  // If it is ON_DEMAND, reset last_requested to 0 and thus silently change the
+  // type to ON_VISIT.
+  sql::Statement statement(
+      db_.GetCachedStatement(SQL_FROM_HERE,
+                             "UPDATE favicon_bitmaps SET image_data=?, "
+                             "last_updated=?, last_requested=? WHERE id=?"));
   if (bitmap_data.get() && bitmap_data->size()) {
     statement.BindBlob(0, bitmap_data->front(),
                        static_cast<int>(bitmap_data->size()));
@@ -539,7 +562,8 @@
     statement.BindNull(0);
   }
   statement.BindInt64(1, time.ToInternalValue());
-  statement.BindInt64(2, bitmap_id);
+  statement.BindInt64(2, 0);
+  statement.BindInt64(3, bitmap_id);
 
   return statement.Run();
 }
@@ -548,22 +572,47 @@
     FaviconBitmapID bitmap_id,
     base::Time time) {
   DCHECK(bitmap_id);
-  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "UPDATE favicon_bitmaps SET last_updated=? WHERE id=?"));
+  // By updating last_updated timestamp, we assume the icon is of type ON_VISIT.
+  // If it is ON_DEMAND, reset last_requested to 0 and thus silently change the
+  // type to ON_VISIT.
+  sql::Statement statement(
+      db_.GetCachedStatement(SQL_FROM_HERE,
+                             "UPDATE favicon_bitmaps SET last_updated=?, "
+                             "last_requested=? WHERE id=?"));
   statement.BindInt64(0, time.ToInternalValue());
-  statement.BindInt64(1, bitmap_id);
+  statement.BindInt64(1, 0);
+  statement.BindInt64(2, bitmap_id);
   return statement.Run();
 }
 
-bool ThumbnailDatabase::SetFaviconBitmapLastRequestedTime(
-    FaviconBitmapID bitmap_id,
-    base::Time time) {
-  DCHECK(bitmap_id);
-  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "UPDATE favicon_bitmaps SET last_requested=? WHERE id=?"));
-  statement.BindInt64(0, time.ToInternalValue());
-  statement.BindInt64(1, bitmap_id);
-  return statement.Run();
+bool ThumbnailDatabase::TouchOnDemandFavicon(const GURL& icon_url,
+                                             base::Time time) {
+  // Look up the icon ids for the url.
+  sql::Statement id_statement(db_.GetCachedStatement(
+      SQL_FROM_HERE, "SELECT id FROM favicons WHERE url=?"));
+  id_statement.BindString(0, URLDatabase::GURLToDatabaseURL(icon_url));
+
+  base::Time max_time =
+      time - base::TimeDelta::FromDays(kFaviconUpdateLastRequestedAfterDays);
+
+  while (id_statement.Step()) {
+    favicon_base::FaviconID icon_id = id_statement.ColumnInt64(0);
+
+    // Update the time only for ON_DEMAND bitmaps (i.e. with last_requested >
+    // 0). For performance reasons, update the time only if the currently stored
+    // time is old enough (UPDATEs where the WHERE condition does not match any
+    // entries are way faster than UPDATEs that really change some data).
+    sql::Statement statement(db_.GetCachedStatement(
+        SQL_FROM_HERE,
+        "UPDATE favicon_bitmaps SET last_requested=? WHERE icon_id=? AND "
+        "last_requested>0 AND last_requested<=?"));
+    statement.BindInt64(0, time.ToInternalValue());
+    statement.BindInt64(1, icon_id);
+    statement.BindInt64(2, max_time.ToInternalValue());
+    if (!statement.Run())
+      return false;
+  }
+  return true;
 }
 
 bool ThumbnailDatabase::DeleteFaviconBitmap(FaviconBitmapID bitmap_id) {
@@ -634,10 +683,11 @@
     const GURL& icon_url,
     favicon_base::IconType icon_type,
     const scoped_refptr<base::RefCountedMemory>& icon_data,
+    FaviconBitmapType type,
     base::Time time,
     const gfx::Size& pixel_size) {
   favicon_base::FaviconID icon_id = AddFavicon(icon_url, icon_type);
-  if (!icon_id || !AddFaviconBitmap(icon_id, icon_data, time, pixel_size))
+  if (!icon_id || !AddFaviconBitmap(icon_id, icon_data, type, time, pixel_size))
     return 0;
 
   return icon_id;
diff --git a/components/history/core/browser/thumbnail_database.h b/components/history/core/browser/thumbnail_database.h
index ec21369d..697faf3 100644
--- a/components/history/core/browser/thumbnail_database.h
+++ b/components/history/core/browser/thumbnail_database.h
@@ -26,6 +26,10 @@
 
 class HistoryBackendClient;
 
+// The minimum number of days after which last_requested field gets updated.
+// All earlier updates are ignored.
+static const int kFaviconUpdateLastRequestedAfterDays = 14;
+
 // This database interface is owned by the history backend and runs on the
 // history thread. It is a totally separate component from history partially
 // because we may want to move it to its own thread in the future. The
@@ -87,37 +91,36 @@
                         scoped_refptr<base::RefCountedMemory>* png_icon_data,
                         gfx::Size* pixel_size);
 
-  // Adds a bitmap component at |pixel_size| for the favicon with |icon_id|.
-  // Only favicons representing a .ico file should have multiple favicon bitmaps
-  // per favicon.
+  // Adds a bitmap component of |type| at |pixel_size| for the favicon with
+  // |icon_id|. Only favicons representing a .ico file should have multiple
+  // favicon bitmaps per favicon.
   // |icon_data| is the png encoded data.
-  // The |time| indicates the access time, and is used to detect when the
-  // favicon should be refreshed.
+  // The |type| indicates how the lifetime of this icon should be managed.
+  // The |time| is used for lifetime management of the bitmap (should be Now()).
   // |pixel_size| is the pixel dimensions of |icon_data|.
   // Returns the id of the added bitmap or 0 if unsuccessful.
   FaviconBitmapID AddFaviconBitmap(
       favicon_base::FaviconID icon_id,
       const scoped_refptr<base::RefCountedMemory>& icon_data,
+      FaviconBitmapType type,
       base::Time time,
       const gfx::Size& pixel_size);
 
   // Sets the bitmap data and the last updated time for the favicon bitmap at
-  // |bitmap_id|.
+  // |bitmap_id|. Should not be called for bitmaps of type ON_DEMAND as they
+  // should never get updated (the call silently changes the type to ON_VISIT).
   // Returns true if successful.
   bool SetFaviconBitmap(FaviconBitmapID bitmap_id,
                         scoped_refptr<base::RefCountedMemory> bitmap_data,
                         base::Time time);
 
-  // Sets the last updated time for the favicon bitmap at |bitmap_id|.
-  // Returns true if successful.
+  // Sets the last_updated time for the favicon bitmap at |bitmap_id|. Should
+  // not be called for bitmaps of type ON_DEMAND as last_updated time is only
+  // tracked for ON_VISIT bitmaps (the call silently changes the type to
+  // ON_VISIT). Returns true if successful.
   bool SetFaviconBitmapLastUpdateTime(FaviconBitmapID bitmap_id,
                                       base::Time time);
 
-  // Sets the last requested time for the favicon bitmap at |bitmap_id|.
-  // Returns true if successful.
-  bool SetFaviconBitmapLastRequestedTime(FaviconBitmapID bitmap_id,
-                                         base::Time time);
-
   // Deletes the favicon bitmap with |bitmap_id|.
   // Returns true if successful.
   bool DeleteFaviconBitmap(FaviconBitmapID bitmap_id);
@@ -128,6 +131,16 @@
   // of the bitmaps for |icon_id| to be out of date.
   bool SetFaviconOutOfDate(favicon_base::FaviconID icon_id);
 
+  // Mark all bitmaps of type ON_DEMAND at |icon_url| as requested at |time|.
+  // This postpones their automatic eviction from the database. Not all calls
+  // end up in a write into the DB:
+  // - it is no-op if the bitmaps are not of type ON_DEMAND;
+  // - the updates of the "last requested time" have limited frequency for each
+  //   particular bitmap (e.g. once per week). This limits the overhead of
+  //   cache management for on-demand favicons.
+  // Returns true if successful.
+  bool TouchOnDemandFavicon(const GURL& icon_url, base::Time time);
+
   // Returns the id of the entry in the favicon database with the specified url
   // and icon type.
   // Returns 0 if no entry exists for the specified url.
@@ -146,11 +159,12 @@
                                      favicon_base::IconType icon_type);
 
   // Adds a favicon with a single bitmap. This call is equivalent to calling
-  // AddFavicon and AddFaviconBitmap.
+  // AddFavicon and AddFaviconBitmap of type |type|.
   favicon_base::FaviconID AddFavicon(
       const GURL& icon_url,
       favicon_base::IconType icon_type,
       const scoped_refptr<base::RefCountedMemory>& icon_data,
+      FaviconBitmapType type,
       base::Time time,
       const gfx::Size& pixel_size);
 
diff --git a/components/history/core/browser/thumbnail_database_unittest.cc b/components/history/core/browser/thumbnail_database_unittest.cc
index 0ece892..4dbd0c6 100644
--- a/components/history/core/browser/thumbnail_database_unittest.cc
+++ b/components/history/core/browser/thumbnail_database_unittest.cc
@@ -85,7 +85,8 @@
   scoped_refptr<base::RefCountedStaticMemory> data(
       new base::RefCountedStaticMemory(kBlob1, sizeof(kBlob1)));
   favicon_base::FaviconID favicon_id =
-      db->AddFavicon(icon_url, icon_type, data, base::Time::Now(), gfx::Size());
+      db->AddFavicon(icon_url, icon_type, data, FaviconBitmapType::ON_VISIT,
+                     base::Time::Now(), gfx::Size());
   db->AddIconMapping(page_url, favicon_id);
 }
 
@@ -213,7 +214,8 @@
   GURL url("http://google.com");
   base::Time time = base::Time::Now();
   favicon_base::FaviconID id =
-      db.AddFavicon(url, favicon_base::TOUCH_ICON, favicon, time, gfx::Size());
+      db.AddFavicon(url, favicon_base::TOUCH_ICON, favicon,
+                    FaviconBitmapType::ON_VISIT, time, gfx::Size());
   EXPECT_NE(0, id);
 
   EXPECT_NE(0, db.AddIconMapping(url, id));
@@ -224,37 +226,145 @@
   EXPECT_EQ(id, icon_mappings.front().icon_id);
 }
 
-TEST_F(ThumbnailDatabaseTest, LastRequestedTime) {
-  ThumbnailDatabase db(NULL);
+TEST_F(ThumbnailDatabaseTest,
+       AddOnDemandFaviconBitmapCreatesCorrectTimestamps) {
+  ThumbnailDatabase db(nullptr);
   ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
   db.BeginTransaction();
 
+  base::Time add_time;
+  ASSERT_TRUE(
+      base::Time::FromUTCExploded({2017, 5, 0, 1, 0, 0, 0, 0}, &add_time));
   std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
   scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
 
   GURL url("http://google.com");
-  base::Time now = base::Time::Now();
-  favicon_base::FaviconID id =
-      db.AddFavicon(url, favicon_base::TOUCH_ICON, favicon, now, gfx::Size());
-  ASSERT_NE(0, id);
+  favicon_base::FaviconID icon = db.AddFavicon(url, favicon_base::FAVICON);
+  ASSERT_NE(0, icon);
+  FaviconBitmapID bitmap = db.AddFaviconBitmap(
+      icon, favicon, FaviconBitmapType::ON_DEMAND, add_time, gfx::Size());
+  ASSERT_NE(0, bitmap);
 
-  // Fetching the last requested time of a non-existent bitmap should fail.
-  base::Time last_requested = base::Time::UnixEpoch();
-  EXPECT_FALSE(db.GetFaviconBitmap(id + 1, NULL, &last_requested, NULL, NULL));
-  EXPECT_EQ(last_requested, base::Time::UnixEpoch());  // Remains unchanged.
+  base::Time last_updated;
+  base::Time last_requested;
+  ASSERT_TRUE(db.GetFaviconBitmap(bitmap, &last_updated, &last_requested,
+                                  nullptr, nullptr));
+  EXPECT_EQ(base::Time(), last_updated);
+  EXPECT_EQ(add_time, last_requested);
+}
 
-  // Fetching the last requested time of a bitmap that has no last request
-  // should return a null timestamp.
-  last_requested = base::Time::UnixEpoch();
-  EXPECT_TRUE(db.GetFaviconBitmap(id, NULL, &last_requested, NULL, NULL));
-  EXPECT_TRUE(last_requested.is_null());
+TEST_F(ThumbnailDatabaseTest, AddFaviconBitmapCreatesCorrectTimestamps) {
+  ThumbnailDatabase db(nullptr);
+  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
+  db.BeginTransaction();
 
-  // Setting the last requested time of an existing bitmap should succeed, and
-  // the set time should be returned by the corresponding "Get".
-  last_requested = base::Time::UnixEpoch();
-  EXPECT_TRUE(db.SetFaviconBitmapLastRequestedTime(id, now));
-  EXPECT_TRUE(db.GetFaviconBitmap(id, NULL, &last_requested, NULL, NULL));
-  EXPECT_EQ(last_requested, now);
+  base::Time add_time;
+  ASSERT_TRUE(
+      base::Time::FromUTCExploded({2017, 5, 0, 1, 0, 0, 0, 0}, &add_time));
+  std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+
+  GURL url("http://google.com");
+  favicon_base::FaviconID icon = db.AddFavicon(url, favicon_base::FAVICON);
+  ASSERT_NE(0, icon);
+  FaviconBitmapID bitmap = db.AddFaviconBitmap(
+      icon, favicon, FaviconBitmapType::ON_VISIT, add_time, gfx::Size());
+  ASSERT_NE(0, bitmap);
+
+  base::Time last_updated;
+  base::Time last_requested;
+  ASSERT_TRUE(db.GetFaviconBitmap(bitmap, &last_updated, &last_requested,
+                                  nullptr, nullptr));
+  EXPECT_EQ(add_time, last_updated);
+  EXPECT_EQ(base::Time(), last_requested);
+}
+
+TEST_F(ThumbnailDatabaseTest, TouchUpdatesOnDemandFavicons) {
+  ThumbnailDatabase db(nullptr);
+  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
+  db.BeginTransaction();
+
+  base::Time start;
+  ASSERT_TRUE(base::Time::FromUTCExploded({2017, 5, 0, 1, 0, 0, 0, 0}, &start));
+  std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+
+  // Create an on-demand favicon.
+  GURL url("http://google.com");
+  favicon_base::FaviconID icon = db.AddFavicon(url, favicon_base::FAVICON);
+  ASSERT_NE(0, icon);
+  FaviconBitmapID bitmap = db.AddFaviconBitmap(
+      icon, favicon, FaviconBitmapType::ON_DEMAND, start, gfx::Size());
+  ASSERT_NE(0, bitmap);
+
+  base::Time end =
+      start + base::TimeDelta::FromDays(kFaviconUpdateLastRequestedAfterDays);
+  EXPECT_TRUE(db.TouchOnDemandFavicon(url, end));
+
+  base::Time last_updated;
+  base::Time last_requested;
+  EXPECT_TRUE(db.GetFaviconBitmap(bitmap, &last_updated, &last_requested,
+                                  nullptr, nullptr));
+  // Does not mess with the last_updated field.
+  EXPECT_EQ(base::Time(), last_updated);
+  EXPECT_EQ(end, last_requested);  // Updates the last_requested field.
+}
+
+TEST_F(ThumbnailDatabaseTest, TouchUpdatesOnlyInfrequently) {
+  ThumbnailDatabase db(nullptr);
+  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
+  db.BeginTransaction();
+
+  base::Time start;
+  ASSERT_TRUE(base::Time::FromUTCExploded({2017, 5, 0, 1, 0, 0, 0, 0}, &start));
+  std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+
+  // Create an on-demand favicon.
+  GURL url("http://google.com");
+  favicon_base::FaviconID icon = db.AddFavicon(url, favicon_base::FAVICON);
+  ASSERT_NE(0, icon);
+  FaviconBitmapID bitmap = db.AddFaviconBitmap(
+      icon, favicon, FaviconBitmapType::ON_DEMAND, start, gfx::Size());
+  ASSERT_NE(0, bitmap);
+
+  base::Time end = start + base::TimeDelta::FromMinutes(1);
+  EXPECT_TRUE(db.TouchOnDemandFavicon(url, end));
+
+  base::Time last_requested;
+  EXPECT_TRUE(
+      db.GetFaviconBitmap(bitmap, nullptr, &last_requested, nullptr, nullptr));
+  EXPECT_EQ(start, last_requested);  // No update.
+}
+
+TEST_F(ThumbnailDatabaseTest, TouchDoesNotUpdateStandardFavicons) {
+  ThumbnailDatabase db(nullptr);
+  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
+  db.BeginTransaction();
+
+  base::Time start;
+  ASSERT_TRUE(base::Time::FromUTCExploded({2017, 5, 0, 1, 0, 0, 0, 0}, &start));
+  std::vector<unsigned char> data(kBlob1, kBlob1 + sizeof(kBlob1));
+  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
+
+  // Create a standard favicon.
+  GURL url("http://google.com");
+  favicon_base::FaviconID icon = db.AddFavicon(url, favicon_base::FAVICON);
+  EXPECT_NE(0, icon);
+  FaviconBitmapID bitmap = db.AddFaviconBitmap(
+      icon, favicon, FaviconBitmapType::ON_VISIT, start, gfx::Size());
+  EXPECT_NE(0, bitmap);
+
+  base::Time end =
+      start + base::TimeDelta::FromDays(kFaviconUpdateLastRequestedAfterDays);
+  db.TouchOnDemandFavicon(url, end);
+
+  base::Time last_updated;
+  base::Time last_requested;
+  EXPECT_TRUE(db.GetFaviconBitmap(bitmap, &last_updated, &last_requested,
+                                  nullptr, nullptr));
+  EXPECT_EQ(start, last_updated);           // Does not mess with last_updated.
+  EXPECT_EQ(base::Time(), last_requested);  // No update.
 }
 
 TEST_F(ThumbnailDatabaseTest, DeleteIconMappings) {
@@ -268,7 +378,8 @@
   GURL url("http://google.com");
   favicon_base::FaviconID id = db.AddFavicon(url, favicon_base::TOUCH_ICON);
   base::Time time = base::Time::Now();
-  db.AddFaviconBitmap(id, favicon, time, gfx::Size());
+  db.AddFaviconBitmap(id, favicon, FaviconBitmapType::ON_VISIT, time,
+                      gfx::Size());
   EXPECT_LT(0, db.AddIconMapping(url, id));
 
   favicon_base::FaviconID id2 = db.AddFavicon(url, favicon_base::FAVICON);
@@ -299,13 +410,16 @@
 
   favicon_base::FaviconID id1 = db.AddFavicon(url, favicon_base::TOUCH_ICON);
   base::Time time = base::Time::Now();
-  db.AddFaviconBitmap(id1, favicon, time, kSmallSize);
-  db.AddFaviconBitmap(id1, favicon, time, kLargeSize);
+  db.AddFaviconBitmap(id1, favicon, FaviconBitmapType::ON_VISIT, time,
+                      kSmallSize);
+  db.AddFaviconBitmap(id1, favicon, FaviconBitmapType::ON_VISIT, time,
+                      kLargeSize);
   EXPECT_LT(0, db.AddIconMapping(url, id1));
 
   favicon_base::FaviconID id2 = db.AddFavicon(url, favicon_base::FAVICON);
   EXPECT_NE(id1, id2);
-  db.AddFaviconBitmap(id2, favicon, time, kSmallSize);
+  db.AddFaviconBitmap(id2, favicon, FaviconBitmapType::ON_VISIT, time,
+                      kSmallSize);
   EXPECT_LT(0, db.AddIconMapping(url, id2));
 
   std::vector<IconMapping> icon_mappings;
@@ -341,19 +455,22 @@
 
   favicon_base::FaviconID kept_id1 =
       db.AddFavicon(kIconUrl1, favicon_base::FAVICON);
-  db.AddFaviconBitmap(kept_id1, favicon1, base::Time::Now(), kLargeSize);
+  db.AddFaviconBitmap(kept_id1, favicon1, FaviconBitmapType::ON_VISIT,
+                      base::Time::Now(), kLargeSize);
   db.AddIconMapping(kPageUrl1, kept_id1);
   db.AddIconMapping(kPageUrl3, kept_id1);
   db.AddIconMapping(kPageUrl4, kept_id1);
 
   favicon_base::FaviconID unkept_id =
       db.AddFavicon(kIconUrl2, favicon_base::FAVICON);
-  db.AddFaviconBitmap(unkept_id, favicon1, base::Time::Now(), kLargeSize);
+  db.AddFaviconBitmap(unkept_id, favicon1, FaviconBitmapType::ON_VISIT,
+                      base::Time::Now(), kLargeSize);
   db.AddIconMapping(kPageUrl2, unkept_id);
 
   favicon_base::FaviconID kept_id2 =
       db.AddFavicon(kIconUrl5, favicon_base::FAVICON);
-  db.AddFaviconBitmap(kept_id2, favicon2, base::Time::Now(), kLargeSize);
+  db.AddFaviconBitmap(kept_id2, favicon2, FaviconBitmapType::ON_VISIT,
+                      base::Time::Now(), kLargeSize);
   db.AddIconMapping(kPageUrl5, kept_id2);
 
   // RetainDataForPageUrls() uses schema manipulations for efficiency.
@@ -406,8 +523,8 @@
   scoped_refptr<base::RefCountedStaticMemory> favicon1(
       new base::RefCountedStaticMemory(kBlob1, sizeof(kBlob1)));
   favicon_base::FaviconID kept_id = db.AddFavicon(
-      kIconUrl1, favicon_base::FAVICON, favicon1, base::Time::Now(),
-      gfx::Size());
+      kIconUrl1, favicon_base::FAVICON, favicon1, FaviconBitmapType::ON_VISIT,
+      base::Time::Now(), gfx::Size());
   db.AddIconMapping(kPageUrl1, kept_id);
 
   EXPECT_TRUE(db.RetainDataForPageUrls(std::vector<GURL>(1u, kPageUrl1)));
@@ -439,8 +556,10 @@
   GURL url("http://google.com");
   favicon_base::FaviconID id = db.AddFavicon(url, favicon_base::FAVICON);
   base::Time last_updated = base::Time::Now();
-  db.AddFaviconBitmap(id, favicon1, last_updated, kSmallSize);
-  db.AddFaviconBitmap(id, favicon2, last_updated, kLargeSize);
+  db.AddFaviconBitmap(id, favicon1, FaviconBitmapType::ON_VISIT, last_updated,
+                      kSmallSize);
+  db.AddFaviconBitmap(id, favicon2, FaviconBitmapType::ON_VISIT, last_updated,
+                      kLargeSize);
 
   EXPECT_TRUE(db.GetFaviconBitmaps(id, NULL));
 
@@ -461,8 +580,9 @@
   GURL icon_url("http://google.com/favicon.ico");
   base::Time time = base::Time::Now();
 
-  favicon_base::FaviconID id = db.AddFavicon(
-      icon_url, favicon_base::FAVICON, favicon, time, gfx::Size());
+  favicon_base::FaviconID id =
+      db.AddFavicon(icon_url, favicon_base::FAVICON, favicon,
+                    FaviconBitmapType::ON_VISIT, time, gfx::Size());
   EXPECT_NE(0, db.AddIconMapping(page_url, id));
   std::vector<IconMapping> icon_mappings;
   EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url, &icon_mappings));
@@ -477,8 +597,9 @@
   scoped_refptr<base::RefCountedBytes> favicon2 =
       new base::RefCountedBytes(data);
 
-  favicon_base::FaviconID id2 = db.AddFavicon(
-      icon_url, favicon_base::TOUCH_ICON, favicon2, time, gfx::Size());
+  favicon_base::FaviconID id2 =
+      db.AddFavicon(icon_url, favicon_base::TOUCH_ICON, favicon2,
+                    FaviconBitmapType::ON_VISIT, time, gfx::Size());
   EXPECT_NE(0, db.AddIconMapping(page_url, id2));
 
   icon_mappings.clear();
@@ -494,11 +615,8 @@
       new base::RefCountedBytes(data2);
 
   favicon_base::FaviconID id3 =
-      db.AddFavicon(icon_url,
-                    favicon_base::TOUCH_PRECOMPOSED_ICON,
-                    favicon3,
-                    time,
-                    gfx::Size());
+      db.AddFavicon(icon_url, favicon_base::TOUCH_PRECOMPOSED_ICON, favicon3,
+                    FaviconBitmapType::ON_VISIT, time, gfx::Size());
   EXPECT_NE(0, db.AddIconMapping(page_url, id3));
 
   icon_mappings.clear();
@@ -548,31 +666,23 @@
 
   // Add a favicon which will have icon_mappings
   base::Time time = base::Time::Now();
-  favicon_base::FaviconID id1 = db.AddFavicon(GURL("http://google.com"),
-                                              favicon_base::FAVICON,
-                                              favicon,
-                                              time,
-                                              gfx::Size());
+  favicon_base::FaviconID id1 =
+      db.AddFavicon(GURL("http://google.com"), favicon_base::FAVICON, favicon,
+                    FaviconBitmapType::ON_VISIT, time, gfx::Size());
   EXPECT_NE(id1, 0);
 
   // Add another type of favicon
   time = base::Time::Now();
-  favicon_base::FaviconID id2 =
-      db.AddFavicon(GURL("http://www.google.com/icon"),
-                    favicon_base::TOUCH_ICON,
-                    favicon,
-                    time,
-                    gfx::Size());
+  favicon_base::FaviconID id2 = db.AddFavicon(
+      GURL("http://www.google.com/icon"), favicon_base::TOUCH_ICON, favicon,
+      FaviconBitmapType::ON_VISIT, time, gfx::Size());
   EXPECT_NE(id2, 0);
 
   // Add 3rd favicon
   time = base::Time::Now();
-  favicon_base::FaviconID id3 =
-      db.AddFavicon(GURL("http://www.google.com/icon"),
-                    favicon_base::TOUCH_ICON,
-                    favicon,
-                    time,
-                    gfx::Size());
+  favicon_base::FaviconID id3 = db.AddFavicon(
+      GURL("http://www.google.com/icon"), favicon_base::TOUCH_ICON, favicon,
+      FaviconBitmapType::ON_VISIT, time, gfx::Size());
   EXPECT_NE(id3, 0);
 
   // Add 2 icon mapping
diff --git a/components/location/android/java/src/org/chromium/components/location/LocationUtils.java b/components/location/android/java/src/org/chromium/components/location/LocationUtils.java
index c0de175..d9228d7 100644
--- a/components/location/android/java/src/org/chromium/components/location/LocationUtils.java
+++ b/components/location/android/java/src/org/chromium/components/location/LocationUtils.java
@@ -103,10 +103,13 @@
      *
      * <p>The callback is guaranteed to be called unless the user never replies to the prompt
      * dialog, which in practice happens very infrequently since the dialog is modal.
+     *
+     * TODO(crbug/730711): Add back @LocationSettingsDialogOutcome to the callback when type
+     *     annotations are allowed in Java 8.
      */
     public void promptToEnableSystemLocationSetting(
             @LocationSettingsDialogContext int promptContext, WindowAndroid window,
-            @LocationSettingsDialogOutcome Callback<Integer> callback) {
+            Callback<Integer> callback) {
         callback.onResult(LocationSettingsDialogOutcome.NO_PROMPT);
     }
 
diff --git a/components/nacl/browser/nacl_browser.cc b/components/nacl/browser/nacl_browser.cc
index 7d25812..ccafb43 100644
--- a/components/nacl/browser/nacl_browser.cc
+++ b/components/nacl/browser/nacl_browser.cc
@@ -280,11 +280,11 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   if (IsOk() && irt_state_ == NaClResourceUninitialized) {
     irt_state_ = NaClResourceRequested;
-    // TODO(ncbray) use blocking pool.
+    auto task_runner = base::CreateTaskRunnerWithTraits(
+        {base::MayBlock(), base::TaskPriority::BACKGROUND,
+         base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
     std::unique_ptr<base::FileProxy> file_proxy(
-        new base::FileProxy(content::BrowserThread::GetTaskRunnerForThread(
-                                content::BrowserThread::FILE)
-                                .get()));
+        new base::FileProxy(task_runner.get()));
     base::FileProxy* proxy = file_proxy.get();
     if (!proxy->CreateOrOpen(
             irt_filepath_, base::File::FLAG_OPEN | base::File::FLAG_READ,
diff --git a/components/omnibox/browser/autocomplete_classifier.cc b/components/omnibox/browser/autocomplete_classifier.cc
index b086d83..2386539 100644
--- a/components/omnibox/browser/autocomplete_classifier.cc
+++ b/components/omnibox/browser/autocomplete_classifier.cc
@@ -44,8 +44,7 @@
       AutocompleteProvider::TYPE_KEYWORD |
 #endif
 #if !defined(OS_IOS)
-      // "Builtin", "Shortcuts" and "Zero Suggest" are not supported on iOS.
-      AutocompleteProvider::TYPE_BUILTIN |
+      // "Shortcuts" and "Zero Suggest" are not supported on iOS.
       AutocompleteProvider::TYPE_SHORTCUTS |
       AutocompleteProvider::TYPE_ZERO_SUGGEST |
 #endif
@@ -53,6 +52,7 @@
            ? AutocompleteProvider::TYPE_CLIPBOARD_URL
            : 0) |
       AutocompleteProvider::TYPE_BOOKMARK |
+      AutocompleteProvider::TYPE_BUILTIN |
       AutocompleteProvider::TYPE_HISTORY_QUICK |
       AutocompleteProvider::TYPE_HISTORY_URL |
       AutocompleteProvider::TYPE_SEARCH;
diff --git a/components/pairing/bluetooth_host_pairing_controller.cc b/components/pairing/bluetooth_host_pairing_controller.cc
index 969efa5..6dfe60a 100644
--- a/components/pairing/bluetooth_host_pairing_controller.cc
+++ b/components/pairing/bluetooth_host_pairing_controller.cc
@@ -4,12 +4,15 @@
 
 #include "components/pairing/bluetooth_host_pairing_controller.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/hash.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/single_thread_task_runner.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/task_runner.h"
 #include "base/task_runner_util.h"
 #include "chromeos/system/devicetype.h"
 #include "components/pairing/bluetooth_pairing_constants.h"
@@ -86,14 +89,9 @@
 }  // namespace
 
 BluetoothHostPairingController::BluetoothHostPairingController(
-    const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
-    : current_stage_(STAGE_NONE),
-      connectivity_status_(CONNECTIVITY_UNTESTED),
-      update_status_(UPDATE_STATUS_UNKNOWN),
-      enrollment_status_(ENROLLMENT_STATUS_UNKNOWN),
-      proto_decoder_(new ProtoDecoder(this)),
-      file_task_runner_(file_task_runner),
-      ptr_factory_(this) {}
+    scoped_refptr<base::TaskRunner> input_service_task_runner)
+    : proto_decoder_(base::MakeUnique<ProtoDecoder>(this)),
+      input_service_task_runner_(std::move(input_service_task_runner)) {}
 
 BluetoothHostPairingController::~BluetoothHostPairingController() {
   Reset();
@@ -190,7 +188,7 @@
 
 void BluetoothHostPairingController::OnGetAdapter(
     scoped_refptr<device::BluetoothAdapter> adapter) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!adapter_.get());
   adapter_ = adapter;
 
@@ -203,7 +201,7 @@
 }
 
 void BluetoothHostPairingController::SetPowered() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (adapter_->IsPowered()) {
     was_powered_ = true;
     OnSetPowered();
@@ -218,7 +216,7 @@
 }
 
 void BluetoothHostPairingController::OnSetPowered() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   adapter_->AddPairingDelegate(
       this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
 
@@ -235,7 +233,7 @@
 
 void BluetoothHostPairingController::OnCreateService(
     scoped_refptr<device::BluetoothSocket> socket) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   service_socket_ = socket;
 
   service_socket_->Accept(
@@ -257,7 +255,7 @@
     scoped_refptr<device::BluetoothSocket> socket) {
   controller_device_address_ = device->GetAddress();
 
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   adapter_->SetDiscoverable(
       false,
       base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
@@ -277,7 +275,7 @@
 }
 
 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (change_stage) {
     DCHECK_EQ(current_stage_, STAGE_NONE);
     ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
@@ -288,7 +286,7 @@
 
 void BluetoothHostPairingController::OnReceiveComplete(
     int bytes, scoped_refptr<net::IOBuffer> io_buffer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   proto_decoder_->DecodeIOBuffer(bytes, io_buffer);
 
   if (controller_socket_.get()) {
@@ -372,7 +370,7 @@
     }
 
     base::PostTaskAndReplyWithResult(
-        file_task_runner_.get(), FROM_HERE, base::Bind(&GetDevices),
+        input_service_task_runner_.get(), FROM_HERE, base::Bind(&GetDevices),
         base::Bind(&BluetoothHostPairingController::PowerOffAdapterIfApplicable,
                    ptr_factory_.GetWeakPtr()));
   }
@@ -409,7 +407,7 @@
 
 void BluetoothHostPairingController::OnPairDevicesMessage(
     const pairing_api::PairDevices& message) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   enrollment_domain_ = message.parameters().enrolling_domain();
   ChangeStage(STAGE_ENROLLING);
   for (Observer& observer : observers_)
@@ -418,7 +416,7 @@
 
 void BluetoothHostPairingController::OnCompleteSetupMessage(
     const pairing_api::CompleteSetup& message) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (current_stage_ != STAGE_ENROLLMENT_SUCCESS) {
     ChangeStage(STAGE_ENROLLMENT_ERROR);
   } else {
@@ -435,14 +433,14 @@
 
 void BluetoothHostPairingController::OnRebootMessage(
     const pairing_api::Reboot& message) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   for (Observer& observer : observers_)
     observer.RebootHostRequested();
 }
 
 void BluetoothHostPairingController::OnAddNetworkMessage(
     const pairing_api::AddNetwork& message) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   for (Observer& observer : observers_)
     observer.AddNetworkRequested(message.parameters().onc_spec());
 }
@@ -518,7 +516,7 @@
 void BluetoothHostPairingController::OnEnrollmentStatusChanged(
     EnrollmentStatus enrollment_status) {
   DCHECK_EQ(current_stage_, STAGE_ENROLLING);
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   enrollment_status_ = enrollment_status;
   if (enrollment_status == ENROLLMENT_STATUS_SUCCESS) {
diff --git a/components/pairing/bluetooth_host_pairing_controller.h b/components/pairing/bluetooth_host_pairing_controller.h
index 8eabce0..5c01dcf 100644
--- a/components/pairing/bluetooth_host_pairing_controller.h
+++ b/components/pairing/bluetooth_host_pairing_controller.h
@@ -22,7 +22,7 @@
 #include "device/hid/input_service_linux.h"
 
 namespace base {
-class SingleThreadTaskRunner;
+class TaskRunner;
 }
 
 namespace device {
@@ -62,7 +62,7 @@
   };
 
   explicit BluetoothHostPairingController(
-      const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner);
+      scoped_refptr<base::TaskRunner> input_service_task_runner);
   ~BluetoothHostPairingController() override;
 
   // These functions should be only used in tests.
@@ -141,12 +141,12 @@
                       uint32_t passkey) override;
   void AuthorizePairing(device::BluetoothDevice* device) override;
 
-  Stage current_stage_;
+  Stage current_stage_ = STAGE_NONE;
   std::string confirmation_code_;
   std::string enrollment_domain_;
-  Connectivity connectivity_status_;
-  UpdateStatus update_status_;
-  EnrollmentStatus enrollment_status_;
+  Connectivity connectivity_status_ = CONNECTIVITY_UNTESTED;
+  UpdateStatus update_status_ = UPDATE_STATUS_UNKNOWN;
+  EnrollmentStatus enrollment_status_ = ENROLLMENT_STATUS_UNKNOWN;
   std::string permanent_id_;
   std::string controller_device_address_;
   bool was_powered_ = false;
@@ -168,10 +168,10 @@
   std::unique_ptr<ProtoDecoder> proto_decoder_;
   TestDelegate* delegate_ = nullptr;
 
-  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
-  base::ThreadChecker thread_checker_;
+  scoped_refptr<base::TaskRunner> input_service_task_runner_;
+  THREAD_CHECKER(thread_checker_);
   base::ObserverList<Observer> observers_;
-  base::WeakPtrFactory<BluetoothHostPairingController> ptr_factory_;
+  base::WeakPtrFactory<BluetoothHostPairingController> ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(BluetoothHostPairingController);
 };
diff --git a/components/pairing/shark_connection_listener.cc b/components/pairing/shark_connection_listener.cc
index 85c5541..e5eb97d 100644
--- a/components/pairing/shark_connection_listener.cc
+++ b/components/pairing/shark_connection_listener.cc
@@ -7,16 +7,18 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/task_runner.h"
 #include "base/threading/thread_restrictions.h"
 #include "components/pairing/bluetooth_host_pairing_controller.h"
 
 namespace pairing_chromeos {
 
 SharkConnectionListener::SharkConnectionListener(
-    const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner,
+    scoped_refptr<base::TaskRunner> input_service_task_runner,
     OnConnectedCallback callback)
     : callback_(callback) {
-  controller_.reset(new BluetoothHostPairingController(file_task_runner));
+  controller_.reset(
+      new BluetoothHostPairingController(std::move(input_service_task_runner)));
   controller_->AddObserver(this);
   controller_->StartPairing();
 }
diff --git a/components/pairing/shark_connection_listener.h b/components/pairing/shark_connection_listener.h
index e940fe0..9b0b49d 100644
--- a/components/pairing/shark_connection_listener.h
+++ b/components/pairing/shark_connection_listener.h
@@ -13,7 +13,7 @@
 #include "components/pairing/host_pairing_controller.h"
 
 namespace base {
-class SingleThreadTaskRunner;
+class TaskRunner;
 }
 
 namespace pairing_chromeos {
@@ -29,7 +29,7 @@
       base::Callback<void(std::unique_ptr<HostPairingController>)>;
 
   SharkConnectionListener(
-      const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner,
+      scoped_refptr<base::TaskRunner> input_service_task_runner,
       OnConnectedCallback callback);
   ~SharkConnectionListener() override;
 
diff --git a/components/password_manager/core/browser/hash_password_manager.cc b/components/password_manager/core/browser/hash_password_manager.cc
index 26aee4b..62d4596d 100644
--- a/components/password_manager/core/browser/hash_password_manager.cc
+++ b/components/password_manager/core/browser/hash_password_manager.cc
@@ -11,8 +11,6 @@
 
 namespace password_manager {
 
-HashPasswordManager::HashPasswordManager(PrefService* prefs) : prefs_(prefs) {}
-
 void HashPasswordManager::SavePasswordHash(const base::string16& password) {
   if (prefs_) {
     // TODO(crbug.com/657041) Implement creating a salt, hash calculation,
diff --git a/components/password_manager/core/browser/hash_password_manager.h b/components/password_manager/core/browser/hash_password_manager.h
index 6d535bec..dd30872 100644
--- a/components/password_manager/core/browser/hash_password_manager.h
+++ b/components/password_manager/core/browser/hash_password_manager.h
@@ -23,7 +23,7 @@
 // All methods should be called on UI thread.
 class HashPasswordManager {
  public:
-  explicit HashPasswordManager(PrefService* prefs);
+  HashPasswordManager() = default;
   ~HashPasswordManager() = default;
 
   void SavePasswordHash(const base::string16& password);
@@ -32,8 +32,10 @@
   // Returns empty if no hash is available.
   base::Optional<SyncPasswordData> RetrievePasswordHash();
 
+  void set_prefs(PrefService* prefs) { prefs_ = prefs; }
+
  private:
-  PrefService* const prefs_;
+  PrefService* prefs_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(HashPasswordManager);
 };
diff --git a/components/password_manager/core/browser/hash_password_manager_unittest.cc b/components/password_manager/core/browser/hash_password_manager_unittest.cc
index 1e2b57e..b647090 100644
--- a/components/password_manager/core/browser/hash_password_manager_unittest.cc
+++ b/components/password_manager/core/browser/hash_password_manager_unittest.cc
@@ -29,14 +29,16 @@
 
 TEST_F(HashPasswordManagerTest, Saving) {
   ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
-  HashPasswordManager hash_password_manager(&prefs_);
+  HashPasswordManager hash_password_manager;
+  hash_password_manager.set_prefs(&prefs_);
   hash_password_manager.SavePasswordHash(base::ASCIIToUTF16("sync_password"));
   EXPECT_TRUE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
 }
 
 TEST_F(HashPasswordManagerTest, Clearing) {
   ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
-  HashPasswordManager hash_password_manager(&prefs_);
+  HashPasswordManager hash_password_manager;
+  hash_password_manager.set_prefs(&prefs_);
   hash_password_manager.SavePasswordHash(base::ASCIIToUTF16("sync_password"));
   hash_password_manager.ClearSavedPasswordHash();
   EXPECT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
@@ -44,7 +46,8 @@
 
 TEST_F(HashPasswordManagerTest, Retrieving) {
   ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
-  HashPasswordManager hash_password_manager(&prefs_);
+  HashPasswordManager hash_password_manager;
+  hash_password_manager.set_prefs(&prefs_);
   hash_password_manager.SavePasswordHash(base::ASCIIToUTF16("sync_password"));
   // TODO(crbug.com/657041) Fix this text when hash calculation is implemented.
   EXPECT_FALSE(hash_password_manager.RetrievePasswordHash());
diff --git a/components/password_manager/core/browser/password_reuse_detector.cc b/components/password_manager/core/browser/password_reuse_detector.cc
index 33da0da..51eb81d 100644
--- a/components/password_manager/core/browser/password_reuse_detector.cc
+++ b/components/password_manager/core/browser/password_reuse_detector.cc
@@ -5,13 +5,12 @@
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/browser/password_reuse_detector_consumer.h"
 #include "components/password_manager/core/browser/psl_matching_helper.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_service.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "url/origin.h"
@@ -45,8 +44,7 @@
                                       rhs.rend());
 }
 
-PasswordReuseDetector::PasswordReuseDetector(PrefService* prefs)
-    : prefs_(prefs) {}
+PasswordReuseDetector::PasswordReuseDetector() {}
 
 PasswordReuseDetector::~PasswordReuseDetector() {}
 
@@ -84,23 +82,15 @@
     const base::string16& input,
     const std::string& domain,
     PasswordReuseDetectorConsumer* consumer) {
-  if (!sync_password_hash_.has_value())
+  if (!sync_password_data_.has_value())
     return false;
 
   const Origin gaia_origin(GaiaUrls::GetInstance()->gaia_url().GetOrigin());
   if (Origin(GURL(domain)).IsSameOriginWith(gaia_origin))
     return false;
 
-  // Check that some suffix of |input| has the same hash as the sync password.
-  for (size_t i = 0; i + kMinPasswordLengthToCheck <= input.size(); ++i) {
-    base::StringPiece16 input_suffix(input.c_str() + i, input.size() - i);
-    if (password_manager_util::Calculate37BitsOfSHA256Hash(input_suffix) ==
-        sync_password_hash_.value()) {
-      consumer->OnReuseFound(input_suffix.as_string(),
-                             std::string(kSyncPasswordDomain), 1, 0);
-      return true;
-    }
-  }
+  // TODO(crbug.com/657041): Implement checking a hash of |input| with
+  // |sync_password_data_|.
 
   return false;
 }
@@ -128,21 +118,13 @@
   return false;
 }
 
-void PasswordReuseDetector::SaveSyncPasswordHash(
-    const base::string16& password) {
-  sync_password_hash_ =
-      password_manager_util::Calculate37BitsOfSHA256Hash(password);
-  if (prefs_) {
-    // TODO(crbug.com/657041) Implement encrypting and saving of
-    // |sync_password_hash_| into preference kSyncPasswordHash.
-    prefs_->SetString(prefs::kSyncPasswordHash, std::string());
-  }
+void PasswordReuseDetector::UseSyncPasswordHash(
+    base::Optional<SyncPasswordData> sync_password_data) {
+  sync_password_data_ = std::move(sync_password_data);
 }
 
 void PasswordReuseDetector::ClearSyncPasswordHash() {
-  sync_password_hash_.reset();
-  if (prefs_)
-    prefs_->ClearPref(prefs::kSyncPasswordHash);
+  sync_password_data_.reset();
 }
 
 void PasswordReuseDetector::AddPassword(const autofill::PasswordForm& form) {
diff --git a/components/password_manager/core/browser/password_reuse_detector.h b/components/password_manager/core/browser/password_reuse_detector.h
index f6d2d49d..4453deb 100644
--- a/components/password_manager/core/browser/password_reuse_detector.h
+++ b/components/password_manager/core/browser/password_reuse_detector.h
@@ -15,11 +15,10 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
+#include "components/password_manager/core/browser/hash_password_manager.h"
 #include "components/password_manager/core/browser/password_store_change.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 
-class PrefService;
-
 namespace password_manager {
 
 class PasswordReuseDetectorConsumer;
@@ -39,7 +38,7 @@
 // a password reuse.
 class PasswordReuseDetector : public PasswordStoreConsumer {
  public:
-  explicit PasswordReuseDetector(PrefService* prefs);
+  PasswordReuseDetector();
   ~PasswordReuseDetector() override;
 
   // PasswordStoreConsumer
@@ -58,8 +57,8 @@
                   const std::string& domain,
                   PasswordReuseDetectorConsumer* consumer);
 
-  // Saves a hash of |password| for password reuse checking.
-  void SaveSyncPasswordHash(const base::string16& password);
+  // Stores internal |sync_password_data| for password reuse checking.
+  void UseSyncPasswordHash(base::Optional<SyncPasswordData> sync_password_data);
 
   // Clears a sync password hash if it was saved.
   void ClearSyncPasswordHash();
@@ -99,8 +98,7 @@
   // of times how many different sites it's saved on.
   int saved_passwords_ = 0;
 
-  base::Optional<uint64_t> sync_password_hash_;
-  PrefService* const prefs_;
+  base::Optional<SyncPasswordData> sync_password_data_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordReuseDetector);
 };
diff --git a/components/password_manager/core/browser/password_reuse_detector_unittest.cc b/components/password_manager/core/browser/password_reuse_detector_unittest.cc
index 2f45d16d..6266693 100644
--- a/components/password_manager/core/browser/password_reuse_detector_unittest.cc
+++ b/components/password_manager/core/browser/password_reuse_detector_unittest.cc
@@ -10,10 +10,8 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/hash_password_manager.h"
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -63,7 +61,7 @@
 }
 
 TEST(PasswordReuseDetectorTest, TypingPasswordOnDifferentSite) {
-  PasswordReuseDetector reuse_detector(nullptr);
+  PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
@@ -94,7 +92,7 @@
 }
 
 TEST(PasswordReuseDetectorTest, PSLMatchNoReuseEvent) {
-  PasswordReuseDetector reuse_detector(nullptr);
+  PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
@@ -104,7 +102,7 @@
 }
 
 TEST(PasswordReuseDetectorTest, NoPSLMatchReuseEvent) {
-  PasswordReuseDetector reuse_detector(nullptr);
+  PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
@@ -117,7 +115,7 @@
 }
 
 TEST(PasswordReuseDetectorTest, TooShortPasswordNoReuseEvent) {
-  PasswordReuseDetector reuse_detector(nullptr);
+  PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
@@ -126,7 +124,7 @@
 }
 
 TEST(PasswordReuseDetectorTest, PasswordNotInputSuffixNoReuseEvent) {
-  PasswordReuseDetector reuse_detector(nullptr);
+  PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
@@ -141,7 +139,7 @@
   for (PasswordStoreChange::Type type :
        {PasswordStoreChange::ADD, PasswordStoreChange::UPDATE,
         PasswordStoreChange::REMOVE}) {
-    PasswordReuseDetector reuse_detector(nullptr);
+    PasswordReuseDetector reuse_detector;
     PasswordStoreChangeList changes =
         GetChangeList(type, GetForms(GetTestDomainsPasswords()));
     reuse_detector.OnLoginsChanged(changes);
@@ -165,7 +163,7 @@
       {"https://example3.com", "1234567890"},
   };
 
-  PasswordReuseDetector reuse_detector(nullptr);
+  PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(domain_passwords));
 
   MockPasswordReuseDetectorConsumer mockConsumer;
@@ -187,12 +185,15 @@
                             &mockConsumer);
 }
 
-TEST(PasswordReuseDetectorTest, SyncPasswordNoReuse) {
-  PasswordReuseDetector reuse_detector(nullptr);
+// TODO(crbug.com/657041): Enable when hash calculation is implemented.
+TEST(PasswordReuseDetectorTest, DISABLED_SyncPasswordNoReuse) {
+  PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
-  reuse_detector.SaveSyncPasswordHash(ASCIIToUTF16("sync_password"));
+  // TODO(crbug.com/657041): Pass a password hash when hash calculation is
+  // implemented.
+  reuse_detector.UseSyncPasswordHash(base::Optional<SyncPasswordData>());
 
   EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
   reuse_detector.CheckReuse(ASCIIToUTF16("sync_password"),
@@ -202,12 +203,15 @@
                             "https://evil.com", &mockConsumer);
 }
 
-TEST(PasswordReuseDetectorTest, SyncPasswordReuseFound) {
-  PasswordReuseDetector reuse_detector(nullptr);
+// TODO(crbug.com/657041): Enable when hash calculation is implemented.
+TEST(PasswordReuseDetectorTest, DISABLED_SyncPasswordReuseFound) {
+  PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
-  reuse_detector.SaveSyncPasswordHash(ASCIIToUTF16("sync_password"));
+  // TODO(crbug.com/657041): Pass a password hash when hash calculation is
+  // implemented.
+  reuse_detector.UseSyncPasswordHash(base::Optional<SyncPasswordData>());
 
   EXPECT_CALL(mockConsumer,
               OnReuseFound(ASCIIToUTF16("sync_password"),
@@ -216,14 +220,18 @@
                             &mockConsumer);
 }
 
-TEST(PasswordReuseDetectorTest, SavedPasswordsReuseSyncPasswordAvailable) {
+// TODO(crbug.com/657041): Enable when hash calculation is implemented.
+TEST(PasswordReuseDetectorTest,
+     DISABLED_SavedPasswordsReuseSyncPasswordAvailable) {
   // Check that reuse of saved passwords is detected also if the sync password
   // hash is saved.
-  PasswordReuseDetector reuse_detector(nullptr);
+  PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
-  reuse_detector.SaveSyncPasswordHash(ASCIIToUTF16("sync_password"));
+  // TODO(crbug.com/657041): Pass a password hash when hash calculation is
+  // implemented.
+  reuse_detector.UseSyncPasswordHash(base::Optional<SyncPasswordData>());
 
   EXPECT_CALL(mockConsumer,
               OnReuseFound(ASCIIToUTF16("password"), "google.com", 5, 1));
@@ -231,16 +239,6 @@
                             &mockConsumer);
 }
 
-TEST(PasswordReuseDetectorTest, CheckThatSyncPasswordIsStoredIntoPreferences) {
-  TestingPrefServiceSimple prefs;
-  prefs.registry()->RegisterStringPref(prefs::kSyncPasswordHash, std::string(),
-                                       PrefRegistry::NO_REGISTRATION_FLAGS);
-  ASSERT_FALSE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
-  PasswordReuseDetector reuse_detector(&prefs);
-  reuse_detector.SaveSyncPasswordHash(ASCIIToUTF16("sync_password"));
-  EXPECT_TRUE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
-}
-
 }  // namespace
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 378e4a8..35fccbc 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -113,8 +113,13 @@
 
 bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare,
                          PrefService* prefs) {
+  ScheduleTask(base::Bind(&PasswordStore::InitOnBackgroundThread, this, flare));
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  hash_password_manager_.set_prefs(prefs);
   ScheduleTask(
-      base::Bind(&PasswordStore::InitOnBackgroundThread, this, flare, prefs));
+      base::Bind(&PasswordStore::SaveSyncPasswordHashImpl, this,
+                 base::Passed(hash_password_manager_.RetrievePasswordHash())));
+#endif
   return true;
 }
 
@@ -329,11 +334,15 @@
 }
 
 void PasswordStore::SaveSyncPasswordHash(const base::string16& password) {
-  ScheduleTask(
-      base::Bind(&PasswordStore::SaveSyncPasswordHashImpl, this, password));
+  hash_password_manager_.SavePasswordHash(password);
+  base::Optional<SyncPasswordData> sync_password_data =
+      hash_password_manager_.RetrievePasswordHash();
+  ScheduleTask(base::Bind(&PasswordStore::SaveSyncPasswordHashImpl, this,
+                          std::move(sync_password_data)));
 }
 
 void PasswordStore::ClearSyncPasswordHash() {
+  hash_password_manager_.ClearSavedPasswordHash();
   ScheduleTask(base::Bind(&PasswordStore::ClearSyncPasswordHashImpl, this));
 }
 #endif
@@ -419,9 +428,10 @@
     reuse_detector_->CheckReuse(input, domain, request.get());
 }
 
-void PasswordStore::SaveSyncPasswordHashImpl(const base::string16& password) {
+void PasswordStore::SaveSyncPasswordHashImpl(
+    base::Optional<SyncPasswordData> sync_password_data) {
   if (reuse_detector_)
-    reuse_detector_->SaveSyncPasswordHash(password);
+    reuse_detector_->UseSyncPasswordHash(std::move(sync_password_data));
 }
 
 void PasswordStore::ClearSyncPasswordHashImpl() {
@@ -744,15 +754,14 @@
 }
 
 void PasswordStore::InitOnBackgroundThread(
-    const syncer::SyncableService::StartSyncFlare& flare,
-    PrefService* prefs) {
+    const syncer::SyncableService::StartSyncFlare& flare) {
   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
   DCHECK(!syncable_service_);
   syncable_service_.reset(new PasswordSyncableService(this));
   syncable_service_->InjectStartSyncFlare(flare);
 // TODO(crbug.com/706392): Fix password reuse detection for Android.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
-  reuse_detector_ = base::MakeUnique<PasswordReuseDetector>(prefs);
+  reuse_detector_ = base::MakeUnique<PasswordReuseDetector>();
   GetAutofillableLoginsImpl(
       base::MakeUnique<GetLoginsRequest>(reuse_detector_.get()));
 #endif
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 40ecd07..0518991 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -23,6 +23,7 @@
 
 // TODO(crbug.com/706392): Fix password reuse detection for Android.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#include "components/password_manager/core/browser/hash_password_manager.h"
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 #include "components/password_manager/core/browser/password_reuse_detector_consumer.h"
 #endif
@@ -432,7 +433,8 @@
                       const std::string& domain);
 
   // Synchronous implementation of SaveSyncPasswordHash().
-  void SaveSyncPasswordHashImpl(const base::string16& password);
+  void SaveSyncPasswordHashImpl(
+      base::Optional<SyncPasswordData> sync_password_data);
 
   // Synchronous implementation of ClearSyncPasswordHash().
   void ClearSyncPasswordHashImpl();
@@ -584,8 +586,7 @@
   // Creates PasswordSyncableService and PasswordReuseDetector instances on the
   // background thread.
   void InitOnBackgroundThread(
-      const syncer::SyncableService::StartSyncFlare& flare,
-      PrefService* prefs);
+      const syncer::SyncableService::StartSyncFlare& flare);
 
   // Deletes objest that should be destroyed on the background thread.
   void DestroyOnBackgroundThread();
@@ -598,6 +599,7 @@
 // TODO(crbug.com/706392): Fix password reuse detection for Android.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
   std::unique_ptr<PasswordReuseDetector> reuse_detector_;
+  HashPasswordManager hash_password_manager_;
 #endif
   bool is_propagating_password_changes_to_web_credentials_enabled_;
 
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index 29ba50f13..3329dba3 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -31,6 +31,9 @@
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "components/password_manager/core/browser/password_store_default.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -981,28 +984,28 @@
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
       base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
       base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
-  store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
+
+  TestingPrefServiceSimple prefs;
+  prefs.registry()->RegisterStringPref(prefs::kSyncPasswordHash, std::string(),
+                                       PrefRegistry::NO_REGISTRATION_FLAGS);
+  ASSERT_FALSE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
+  store->Init(syncer::SyncableService::StartSyncFlare(), &prefs);
 
   const base::string16 sync_password = base::ASCIIToUTF16("password");
   const base::string16 input = base::ASCIIToUTF16("123password");
   store->SaveSyncPasswordHash(sync_password);
   base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
 
-  // Check that sync password reuse is found.
-  MockPasswordReuseDetectorConsumer mock_consumer;
-  EXPECT_CALL(
-      mock_consumer,
-      OnReuseFound(sync_password, std::string(kSyncPasswordDomain), 1, 0));
-  store->CheckReuse(input, "https://facebook.com", &mock_consumer);
-  base::RunLoop().RunUntilIdle();
-  testing::Mock::VerifyAndClearExpectations(&mock_consumer);
+  // TODO(crbug.com/657041): Check that password reuse works when sync hash
+  // calculation is implemented.
 
   // Check that no sync password reuse is found after clearing the saved sync
   // password hash.
   store->ClearSyncPasswordHash();
-  EXPECT_CALL(mock_consumer, OnReuseFound(_, _, _, _)).Times(0);
-  store->CheckReuse(input, "https://facebook.com", &mock_consumer);
-  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
+  // TODO(crbug.com/657041): Check that no password reuse happens here when sync
+  // hash calculation is implemented.
 
   store->ShutdownOnUIThread();
   base::RunLoop().RunUntilIdle();
diff --git a/components/payments/core/payment_request_data_util.cc b/components/payments/core/payment_request_data_util.cc
index 7f68941..8a9585f7 100644
--- a/components/payments/core/payment_request_data_util.cc
+++ b/components/payments/core/payment_request_data_util.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/string16.h"
 #include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_data_util.h"
@@ -191,6 +192,26 @@
                            PhoneNumberUtil::PhoneNumberFormat::E164);
 }
 
+base::string16 FormatCardNumberForDisplay(const base::string16& card_number) {
+  base::string16 number = autofill::CreditCard::StripSeparators(card_number);
+  if (number.empty() || !base::IsAsciiDigit(number[0]))
+    return card_number;
+
+  std::vector<size_t> positions = {4U, 9U, 14U};
+  if (autofill::CreditCard::GetCardNetwork(number) ==
+      autofill::kAmericanExpressCard) {
+    positions = {4U, 11U};
+  }
+
+  static const base::char16 kSeparator = base::ASCIIToUTF16(" ")[0];
+  for (size_t i : positions) {
+    if (number.size() > i)
+      number.insert(i, 1U, kSeparator);
+  }
+
+  return number;
+}
+
 std::string GetCountryCodeWithFallback(const autofill::AutofillProfile* profile,
                                        const std::string& app_locale) {
   std::string country_code =
diff --git a/components/payments/core/payment_request_data_util.h b/components/payments/core/payment_request_data_util.h
index c301946d..c3c1adb 100644
--- a/components/payments/core/payment_request_data_util.h
+++ b/components/payments/core/payment_request_data_util.h
@@ -71,6 +71,11 @@
 std::string FormatPhoneForResponse(const std::string& phone_number,
                                    const std::string& country_code);
 
+// Formats |card_number| for display. For example, "4111111111111111" is
+// formatted into "4111 1111 1111 1111". This method does not format masked card
+// numbers, which start with a letter.
+base::string16 FormatCardNumberForDisplay(const base::string16& card_number);
+
 // Returns a country code to be used when validating this profile. If the
 // profile has a valid country code set, it is returned. If not, a country code
 // associated with |app_locale| is used as a fallback.
diff --git a/components/policy/core/common/BUILD.gn b/components/policy/core/common/BUILD.gn
index 17217b1..d509384 100644
--- a/components/policy/core/common/BUILD.gn
+++ b/components/policy/core/common/BUILD.gn
@@ -157,6 +157,7 @@
       "ntdsapi.lib",
     ]
   }
+
   # Compile on Linux for fuzzer and since code is reused on Chrome OS.
   if (is_win || is_linux) {
     sources += [
@@ -188,6 +189,8 @@
   }
   if (is_chromeos) {
     sources += [
+      "policy_scheduler.cc",
+      "policy_scheduler.h",
       "proxy_policy_provider.cc",
       "proxy_policy_provider.h",
     ]
@@ -305,7 +308,10 @@
     ]
   }
   if (is_chromeos) {
-    sources += [ "proxy_policy_provider_unittest.cc" ]
+    sources += [
+      "policy_scheduler_unittest.cc",
+      "proxy_policy_provider_unittest.cc",
+    ]
   } else {
     sources += [
       "cloud/user_cloud_policy_manager_unittest.cc",
diff --git a/components/policy/core/common/policy_scheduler.cc b/components/policy/core/common/policy_scheduler.cc
new file mode 100644
index 0000000..b4c4bd1
--- /dev/null
+++ b/components/policy/core/common/policy_scheduler.cc
@@ -0,0 +1,74 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/policy/core/common/policy_scheduler.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace policy {
+
+PolicyScheduler::PolicyScheduler(Task task,
+                                 SchedulerCallback callback,
+                                 base::TimeDelta interval)
+    : task_(task), callback_(callback), interval_(interval) {
+  ScheduleTaskNow();
+}
+
+PolicyScheduler::~PolicyScheduler() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void PolicyScheduler::ScheduleTaskNow() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  ScheduleDelayedTask(base::TimeDelta());
+}
+
+void PolicyScheduler::ScheduleDelayedTask(base::TimeDelta delay) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (job_) {
+    job_->Cancel();
+  }
+  job_ = base::MakeUnique<base::CancelableClosure>(base::Bind(
+      &PolicyScheduler::RunScheduledTask, weak_ptr_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE,
+                                                       job_->callback(), delay);
+}
+
+void PolicyScheduler::ScheduleNextTask() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  base::TimeDelta interval = overlap_ ? base::TimeDelta() : interval_;
+  const base::TimeTicks now(base::TimeTicks::Now());
+  // Time uses saturated arithmetics thus no under/overflow possible.
+  const base::TimeDelta delay = last_task_ + interval - now;
+  // Clamping delay to non-negative values just to be on the safe side.
+  ScheduleDelayedTask(std::max(base::TimeDelta(), delay));
+}
+
+void PolicyScheduler::RunScheduledTask() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (task_in_progress_) {
+    overlap_ = true;
+    return;
+  }
+
+  overlap_ = false;
+  task_in_progress_ = true;
+  task_.Run(base::BindOnce(&PolicyScheduler::OnTaskDone,
+                           weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PolicyScheduler::OnTaskDone(bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  task_in_progress_ = false;
+  last_task_ = base::TimeTicks::Now();
+  callback_.Run(success);
+  ScheduleNextTask();
+}
+
+}  // namespace policy
diff --git a/components/policy/core/common/policy_scheduler.h b/components/policy/core/common/policy_scheduler.h
new file mode 100644
index 0000000..a570143
--- /dev/null
+++ b/components/policy/core/common/policy_scheduler.h
@@ -0,0 +1,95 @@
+// 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 COMPONENTS_POLICY_CORE_COMMON_POLICY_SCHEDULER_H_
+#define COMPONENTS_POLICY_CORE_COMMON_POLICY_SCHEDULER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/cancelable_callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/time/time.h"
+#include "components/policy/policy_export.h"
+
+namespace policy {
+
+// Scheduler for driving repeated asynchronous tasks such as e.g. policy
+// fetches. Subsequent tasks are guaranteed not to overlap. Tasks are posted to
+// the current thread and therefore must not block (suitable e.g. for
+// asynchronous D-Bus calls).
+// Tasks scheduling begins immediately after instantiation of the class. Upon
+// destruction, scheduled but not yet started tasks are cancelled. The result of
+// started but not finished tasks is NOT reported.
+class POLICY_EXPORT PolicyScheduler {
+ public:
+  // Callback for the task to report success or failure.
+  using TaskCallback = base::OnceCallback<void(bool success)>;
+
+  // Task to be performed at regular intervals. The task takes a |callback| to
+  // return success or failure.
+  using Task = base::RepeatingCallback<void(TaskCallback callback)>;
+
+  // Callback for PolicyScheduler to report success or failure of the tasks.
+  using SchedulerCallback = base::RepeatingCallback<void(bool success)>;
+
+  // Defines the |task| to be run every |interval| and the |callback| for the
+  // scheduler to report the result. (Intervals are computed as the time
+  // difference between the end of the previous and the start of the subsequent
+  // task.) Calling the constructor starts the loop and schedules the first task
+  // to be run without delay.
+  PolicyScheduler(Task task,
+                  SchedulerCallback callback,
+                  base::TimeDelta interval);
+  ~PolicyScheduler();
+
+  // Schedules a task to run immediately. Deletes any previously scheduled but
+  // not yet started tasks. In case a task is running currently, the new task is
+  // scheduled to run immediately after the end of the currently running task.
+  void ScheduleTaskNow();
+
+ private:
+  // Schedules next task to run in |delay|. Deletes any previously scheduled
+  // tasks.
+  void ScheduleDelayedTask(base::TimeDelta delay);
+
+  // Schedules next task to run in |interval_| or immediately in case of
+  // overlap. Deletes any previously scheduled tasks.
+  void ScheduleNextTask();
+
+  // Actually executes the scheduled task.
+  void RunScheduledTask();
+
+  // Reports back the |result| of the previous task and schedules the next one.
+  void OnTaskDone(bool result);
+
+  Task task_;
+  SchedulerCallback callback_;
+  const base::TimeDelta interval_;
+
+  // Whether a task is in progress.
+  bool task_in_progress_ = false;
+
+  // Whether there had been an overlap of tasks and thus the next task needs to
+  // be scheduled without delay.
+  bool overlap_ = false;
+
+  // End time of the previous task. Zero in case no task has ended yet.
+  base::TimeTicks last_task_;
+
+  std::unique_ptr<base::CancelableClosure> job_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  // Must be last member.
+  base::WeakPtrFactory<PolicyScheduler> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyScheduler);
+};
+
+}  // namespace policy
+
+#endif  // COMPONENTS_POLICY_CORE_COMMON_POLICY_SCHEDULER_H_
\ No newline at end of file
diff --git a/components/policy/core/common/policy_scheduler_unittest.cc b/components/policy/core/common/policy_scheduler_unittest.cc
new file mode 100644
index 0000000..cb5758c
--- /dev/null
+++ b/components/policy/core/common/policy_scheduler_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/policy/core/common/policy_scheduler.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+class PolicySchedulerTest : public testing::Test {
+ public:
+  void DoTask(PolicyScheduler::TaskCallback callback) {
+    do_counter_++;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), true));
+  }
+
+  void OnTaskDone(bool success) {
+    done_counter_++;
+
+    // Terminate PolicyScheduler after 5 iterations.
+    if (done_counter_ >= 5) {
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::BindOnce(&PolicySchedulerTest::Terminate,
+                                    base::Unretained(this)));
+    }
+  }
+
+  // To simulate a slow task the callback is captured instead of running it.
+  void CaptureCallbackForSlowTask(PolicyScheduler::TaskCallback callback) {
+    do_counter_++;
+    slow_callback_ = std::move(callback);
+  }
+
+  // Runs the captured callback to simulate the end of the slow task.
+  void PostSlowTaskCallback() {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(slow_callback_), true));
+  }
+
+  void Terminate() { scheduler_.reset(); }
+
+ protected:
+  int do_counter_ = 0;
+  int done_counter_ = 0;
+  std::unique_ptr<PolicyScheduler> scheduler_;
+
+  PolicyScheduler::TaskCallback slow_callback_;
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
+TEST_F(PolicySchedulerTest, Run) {
+  scheduler_ = base::MakeUnique<PolicyScheduler>(
+      base::BindRepeating(&PolicySchedulerTest::DoTask, base::Unretained(this)),
+      base::BindRepeating(&PolicySchedulerTest::OnTaskDone,
+                          base::Unretained(this)),
+      base::TimeDelta::Max());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, done_counter_);
+}
+
+TEST_F(PolicySchedulerTest, Loop) {
+  scheduler_ = base::MakeUnique<PolicyScheduler>(
+      base::BindRepeating(&PolicySchedulerTest::DoTask, base::Unretained(this)),
+      base::BindRepeating(&PolicySchedulerTest::OnTaskDone,
+                          base::Unretained(this)),
+      base::TimeDelta());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(5, done_counter_);
+}
+
+TEST_F(PolicySchedulerTest, Reschedule) {
+  scheduler_ = base::MakeUnique<PolicyScheduler>(
+      base::BindRepeating(&PolicySchedulerTest::DoTask, base::Unretained(this)),
+      base::BindRepeating(&PolicySchedulerTest::OnTaskDone,
+                          base::Unretained(this)),
+      base::TimeDelta::Max());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, done_counter_);
+
+  // Delayed action is not run.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, done_counter_);
+
+  // Rescheduling with 0 delay causes it to run.
+  scheduler_->ScheduleTaskNow();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2, done_counter_);
+}
+
+TEST_F(PolicySchedulerTest, OverlappingTasks) {
+  scheduler_ = base::MakeUnique<PolicyScheduler>(
+      base::BindRepeating(&PolicySchedulerTest::CaptureCallbackForSlowTask,
+                          base::Unretained(this)),
+      base::BindRepeating(&PolicySchedulerTest::OnTaskDone,
+                          base::Unretained(this)),
+      base::TimeDelta::Max());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, do_counter_);
+  EXPECT_EQ(0, done_counter_);
+
+  // Second action doesn't start while first is still pending.
+  scheduler_->ScheduleTaskNow();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, do_counter_);
+  EXPECT_EQ(0, done_counter_);
+
+  // After first action has finished, the second is started.
+  PostSlowTaskCallback();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2, do_counter_);
+  EXPECT_EQ(1, done_counter_);
+
+  // Let the second action finish.
+  PostSlowTaskCallback();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2, do_counter_);
+  EXPECT_EQ(2, done_counter_);
+}
+
+}  // namespace policy
\ No newline at end of file
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index ecb8291d..f42cb4d 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -26,6 +26,8 @@
     "display_compositor/gpu_display_provider.h",
     "display_compositor/host_shared_bitmap_manager.cc",
     "display_compositor/host_shared_bitmap_manager.h",
+    "display_compositor/in_process_gpu_memory_buffer_manager.cc",
+    "display_compositor/in_process_gpu_memory_buffer_manager.h",
     "frame_sinks/frame_eviction_manager.cc",
     "frame_sinks/frame_eviction_manager.h",
     "frame_sinks/frame_evictor.cc",
@@ -44,6 +46,13 @@
 
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
+  deps = [
+    # Note that dependency on //gpu/ipc/client is for GpuMemoryBufferImpl. This
+    # dependency should not be in public_deps.
+    "//gpu/ipc/client",
+    "//gpu/ipc/service",
+  ]
+
   public_deps = [
     "//base",
     "//cc",
diff --git a/components/viz/service/display_compositor/gpu_display_provider.cc b/components/viz/service/display_compositor/gpu_display_provider.cc
index 8526c010..49f1376 100644
--- a/components/viz/service/display_compositor/gpu_display_provider.cc
+++ b/components/viz/service/display_compositor/gpu_display_provider.cc
@@ -17,23 +17,36 @@
 #include "cc/surfaces/display_scheduler.h"
 #include "components/viz/service/display_compositor/display_output_surface.h"
 #include "components/viz/service/display_compositor/host_shared_bitmap_manager.h"
+#include "components/viz/service/display_compositor/in_process_gpu_memory_buffer_manager.h"
 #include "gpu/command_buffer/client/shared_memory_limits.h"
 #include "gpu/command_buffer/service/image_factory.h"
+#include "gpu/ipc/service/gpu_channel_manager.h"
+#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
 
 #if defined(USE_OZONE)
 #include "components/viz/service/display_compositor/display_output_surface_ozone.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #endif
 
+namespace {
+
+gpu::ImageFactory* GetImageFactory(gpu::GpuChannelManager* channel_manager) {
+  auto* buffer_factory = channel_manager->gpu_memory_buffer_factory();
+  return buffer_factory ? buffer_factory->AsImageFactory() : nullptr;
+}
+
+}  // namespace
+
 namespace viz {
 
 GpuDisplayProvider::GpuDisplayProvider(
     scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
-    std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
-    gpu::ImageFactory* image_factory)
+    gpu::GpuChannelManager* gpu_channel_manager)
     : gpu_service_(std::move(gpu_service)),
-      gpu_memory_buffer_manager_(std::move(gpu_memory_buffer_manager)),
-      image_factory_(image_factory),
+      gpu_memory_buffer_manager_(
+          base::MakeUnique<InProcessGpuMemoryBufferManager>(
+              gpu_channel_manager)),
+      image_factory_(GetImageFactory(gpu_channel_manager)),
       task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
 
 GpuDisplayProvider::~GpuDisplayProvider() = default;
diff --git a/components/viz/service/display_compositor/gpu_display_provider.h b/components/viz/service/display_compositor/gpu_display_provider.h
index 1afb34a..ab936fe 100644
--- a/components/viz/service/display_compositor/gpu_display_provider.h
+++ b/components/viz/service/display_compositor/gpu_display_provider.h
@@ -18,6 +18,7 @@
 #include "gpu/ipc/in_process_command_buffer.h"
 
 namespace gpu {
+class GpuChannelManager;
 class ImageFactory;
 }
 
@@ -29,8 +30,7 @@
  public:
   GpuDisplayProvider(
       scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
-      std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
-      gpu::ImageFactory* image_factory);
+      gpu::GpuChannelManager* gpu_channel_manager);
   ~GpuDisplayProvider() override;
 
   // DisplayProvider:
diff --git a/components/viz/service/display_compositor/in_process_gpu_memory_buffer_manager.cc b/components/viz/service/display_compositor/in_process_gpu_memory_buffer_manager.cc
new file mode 100644
index 0000000..26f0015f
--- /dev/null
+++ b/components/viz/service/display_compositor/in_process_gpu_memory_buffer_manager.cc
@@ -0,0 +1,51 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/service/display_compositor/in_process_gpu_memory_buffer_manager.h"
+
+#include "gpu/ipc/client/gpu_memory_buffer_impl.h"
+#include "gpu/ipc/service/gpu_channel_manager.h"
+#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
+
+namespace viz {
+
+InProcessGpuMemoryBufferManager::InProcessGpuMemoryBufferManager(
+    gpu::GpuChannelManager* channel_manager)
+    : client_id_(1), channel_manager_(channel_manager), weak_factory_(this) {
+  weak_ptr_ = weak_factory_.GetWeakPtr();
+}
+
+InProcessGpuMemoryBufferManager::~InProcessGpuMemoryBufferManager() {}
+
+std::unique_ptr<gfx::GpuMemoryBuffer>
+InProcessGpuMemoryBufferManager::CreateGpuMemoryBuffer(
+    const gfx::Size& size,
+    gfx::BufferFormat format,
+    gfx::BufferUsage usage,
+    gpu::SurfaceHandle surface_handle) {
+  gfx::GpuMemoryBufferId id(next_gpu_memory_id_++);
+  gfx::GpuMemoryBufferHandle buffer_handle =
+      channel_manager_->gpu_memory_buffer_factory()->CreateGpuMemoryBuffer(
+          id, size, format, usage, client_id_, surface_handle);
+  return gpu::GpuMemoryBufferImpl::CreateFromHandle(
+      buffer_handle, size, format, usage,
+      base::Bind(&InProcessGpuMemoryBufferManager::DestroyGpuMemoryBuffer,
+                 weak_ptr_, id, client_id_));
+}
+
+void InProcessGpuMemoryBufferManager::SetDestructionSyncToken(
+    gfx::GpuMemoryBuffer* buffer,
+    const gpu::SyncToken& sync_token) {
+  static_cast<gpu::GpuMemoryBufferImpl*>(buffer)->set_destruction_sync_token(
+      sync_token);
+}
+
+void InProcessGpuMemoryBufferManager::DestroyGpuMemoryBuffer(
+    gfx::GpuMemoryBufferId id,
+    int client_id,
+    const gpu::SyncToken& sync_token) {
+  channel_manager_->DestroyGpuMemoryBuffer(id, client_id, sync_token);
+}
+
+}  // namespace viz
diff --git a/components/viz/service/display_compositor/in_process_gpu_memory_buffer_manager.h b/components/viz/service/display_compositor/in_process_gpu_memory_buffer_manager.h
new file mode 100644
index 0000000..4be5c8c
--- /dev/null
+++ b/components/viz/service/display_compositor/in_process_gpu_memory_buffer_manager.h
@@ -0,0 +1,47 @@
+// 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 COMPONENTS_VIZ_SERVICE_DISPLAY_COMPOSITOR_IN_PROCESS_GPU_MEMORY_BUFFER_MANAGER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_COMPOSITOR_IN_PROCESS_GPU_MEMORY_BUFFER_MANAGER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+
+namespace gpu {
+class GpuChannelManager;
+}
+
+namespace viz {
+
+class InProcessGpuMemoryBufferManager : public gpu::GpuMemoryBufferManager {
+ public:
+  explicit InProcessGpuMemoryBufferManager(
+      gpu::GpuChannelManager* channel_manager);
+
+  ~InProcessGpuMemoryBufferManager() override;
+
+  // gpu::GpuMemoryBufferManager:
+  std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
+      const gfx::Size& size,
+      gfx::BufferFormat format,
+      gfx::BufferUsage usage,
+      gpu::SurfaceHandle surface_handle) override;
+  void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
+                               const gpu::SyncToken& sync_token) override;
+
+ private:
+  void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+                              int client_id,
+                              const gpu::SyncToken& sync_token);
+  const int client_id_;
+  int next_gpu_memory_id_ = 1;
+  gpu::GpuChannelManager* channel_manager_;
+  base::WeakPtr<InProcessGpuMemoryBufferManager> weak_ptr_;
+  base::WeakPtrFactory<InProcessGpuMemoryBufferManager> weak_factory_;
+  DISALLOW_COPY_AND_ASSIGN(InProcessGpuMemoryBufferManager);
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_COMPOSITOR_IN_PROCESS_GPU_MEMORY_BUFFER_MANAGER_H_
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn
index 675733f6..1b4bd035 100644
--- a/content/app/BUILD.gn
+++ b/content/app/BUILD.gn
@@ -124,6 +124,8 @@
         "android/app_jni_registrar.h",
         "android/child_process_service_impl.cc",
         "android/child_process_service_impl.h",
+        "android/content_child_process_service_delegate.cc",
+        "android/content_child_process_service_delegate.h",
         "android/content_jni_onload.cc",
         "android/content_main.cc",
         "android/content_main.h",
diff --git a/content/app/android/app_jni_registrar.cc b/content/app/android/app_jni_registrar.cc
index f8557b1b..5d4c4470 100644
--- a/content/app/android/app_jni_registrar.cc
+++ b/content/app/android/app_jni_registrar.cc
@@ -8,13 +8,16 @@
 #include "base/android/jni_registrar.h"
 #include "base/macros.h"
 #include "content/app/android/child_process_service_impl.h"
+#include "content/app/android/content_child_process_service_delegate.h"
 #include "content/app/android/content_main.h"
 
 namespace {
 
 base::android::RegistrationMethod kContentRegisteredMethods[] = {
-  { "ContentMain", content::RegisterContentMain },
-  { "ChildProcessServiceImpl", content::RegisterChildProcessServiceImpl },
+    {"ContentChildProcessServiceDelegate",
+     content::RegisterContentChildProcessServiceDelegate},
+    {"ContentMain", content::RegisterContentMain},
+    {"ChildProcessServiceImpl", content::RegisterChildProcessServiceImpl},
 };
 
 }  // namespace
diff --git a/content/app/android/child_process_service_impl.cc b/content/app/android/child_process_service_impl.cc
index 08be4443..69f0dec 100644
--- a/content/app/android/child_process_service_impl.cc
+++ b/content/app/android/child_process_service_impl.cc
@@ -4,127 +4,23 @@
 
 #include "content/app/android/child_process_service_impl.h"
 
-#include <android/native_window_jni.h>
-#include <cpu-features.h>
-
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/android/library_loader/library_loader_hooks.h"
-#include "base/android/memory_pressure_listener_android.h"
-#include "base/android/unguessable_token_android.h"
+#include "base/command_line.h"
 #include "base/file_descriptor_store.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/posix/global_descriptors.h"
-#include "base/unguessable_token.h"
-#include "content/child/child_thread_impl.h"
-#include "content/public/common/content_descriptors.h"
-#include "content/public/common/content_switches.h"
-#include "gpu/ipc/common/android/scoped_surface_request_conduit.h"
-#include "gpu/ipc/common/gpu_surface_lookup.h"
 #include "jni/ChildProcessServiceImpl_jni.h"
 #include "services/service_manager/embedder/shared_file_util.h"
 #include "services/service_manager/embedder/switches.h"
-#include "ui/gl/android/scoped_java_surface.h"
-#include "ui/gl/android/surface_texture.h"
 
-using base::android::AttachCurrentThread;
-using base::android::CheckException;
 using base::android::JavaIntArrayToIntVector;
 using base::android::JavaParamRef;
 
 namespace content {
 
-namespace {
-
-// TODO(sievers): Use two different implementations of this depending on if
-// we're in a renderer or gpu process.
-class ChildProcessSurfaceManager : public gpu::ScopedSurfaceRequestConduit,
-                                   public gpu::GpuSurfaceLookup {
- public:
-  ChildProcessSurfaceManager() {}
-  ~ChildProcessSurfaceManager() override {}
-
-  // |service impl| is the instance of
-  // org.chromium.content.app.ChildProcessServiceImpl.
-  void SetServiceImpl(const base::android::JavaRef<jobject>& service_impl) {
-    service_impl_.Reset(service_impl);
-  }
-
-  // Overriden from ScopedSurfaceRequestConduit:
-  void ForwardSurfaceTextureForSurfaceRequest(
-      const base::UnguessableToken& request_token,
-      const gl::SurfaceTexture* surface_texture) override {
-    JNIEnv* env = base::android::AttachCurrentThread();
-
-    content::
-        Java_ChildProcessServiceImpl_forwardSurfaceTextureForSurfaceRequest(
-            env, service_impl_,
-            base::android::UnguessableTokenAndroid::Create(env, request_token),
-            surface_texture->j_surface_texture());
-  }
-
-  // Overridden from GpuSurfaceLookup:
-  gfx::AcceleratedWidget AcquireNativeWidget(int surface_id) override {
-    JNIEnv* env = base::android::AttachCurrentThread();
-    gl::ScopedJavaSurface surface(
-        content::Java_ChildProcessServiceImpl_getViewSurface(env, service_impl_,
-                                                             surface_id));
-
-    if (surface.j_surface().is_null())
-      return NULL;
-
-    // Note: This ensures that any local references used by
-    // ANativeWindow_fromSurface are released immediately. This is needed as a
-    // workaround for https://code.google.com/p/android/issues/detail?id=68174
-    base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
-    ANativeWindow* native_window =
-        ANativeWindow_fromSurface(env, surface.j_surface().obj());
-
-    return native_window;
-  }
-
-  // Overridden from GpuSurfaceLookup:
-  gl::ScopedJavaSurface AcquireJavaSurface(int surface_id) override {
-    JNIEnv* env = base::android::AttachCurrentThread();
-    return gl::ScopedJavaSurface(
-        content::Java_ChildProcessServiceImpl_getViewSurface(env, service_impl_,
-                                                             surface_id));
-  }
-
- private:
-  friend struct base::LazyInstanceTraitsBase<ChildProcessSurfaceManager>;
-  // The instance of org.chromium.content.app.ChildProcessServiceImpl.
-  base::android::ScopedJavaGlobalRef<jobject> service_impl_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChildProcessSurfaceManager);
-};
-
-static base::LazyInstance<ChildProcessSurfaceManager>::Leaky
-    g_child_process_surface_manager = LAZY_INSTANCE_INITIALIZER;
-
-// Chrome actually uses the renderer code path for all of its child
-// processes such as renderers, plugins, etc.
-void InternalInitChildProcessImpl(JNIEnv* env,
-                                  const JavaParamRef<jobject>& service_impl,
-                                  jint cpu_count,
-                                  jlong cpu_features) {
-  // Set the CPU properties.
-  android_setCpu(cpu_count, cpu_features);
-
-  g_child_process_surface_manager.Get().SetServiceImpl(service_impl);
-
-  gpu::GpuSurfaceLookup::InitInstance(
-      g_child_process_surface_manager.Pointer());
-  gpu::ScopedSurfaceRequestConduit::SetInstance(
-      g_child_process_surface_manager.Pointer());
-
-  base::android::MemoryPressureListenerAndroid::RegisterSystemCallback(env);
-}
-
-}  // namespace <anonymous>
-
 void RegisterFileDescriptors(JNIEnv* env,
                              const JavaParamRef<jclass>& clazz,
                              const JavaParamRef<jintArray>& j_ids,
@@ -170,14 +66,6 @@
   }
 }
 
-void InitChildProcessImpl(JNIEnv* env,
-                          const JavaParamRef<jclass>& clazz,
-                          const JavaParamRef<jobject>& service_impl,
-                          jint cpu_count,
-                          jlong cpu_features) {
-  InternalInitChildProcessImpl(env, service_impl, cpu_count, cpu_features);
-}
-
 void ExitChildProcess(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
   VLOG(0) << "ChildProcessServiceImpl: Exiting child process.";
   base::android::LibraryLoaderExitHook();
@@ -188,8 +76,4 @@
   return RegisterNativesImpl(env);
 }
 
-void ShutdownMainThread(JNIEnv* env, const JavaParamRef<jobject>& obj) {
-  ChildThreadImpl::ShutdownThread();
-}
-
 }  // namespace content
diff --git a/content/app/android/content_child_process_service_delegate.cc b/content/app/android/content_child_process_service_delegate.cc
new file mode 100644
index 0000000..fc7757d
--- /dev/null
+++ b/content/app/android/content_child_process_service_delegate.cc
@@ -0,0 +1,137 @@
+// 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/app/android/content_child_process_service_delegate.h"
+
+#include <android/native_window_jni.h>
+#include <cpu-features.h>
+
+#include "base/android/library_loader/library_loader_hooks.h"
+#include "base/android/memory_pressure_listener_android.h"
+#include "base/android/unguessable_token_android.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/unguessable_token.h"
+#include "content/child/child_thread_impl.h"
+#include "content/public/common/content_descriptors.h"
+#include "content/public/common/content_switches.h"
+#include "gpu/ipc/common/android/scoped_surface_request_conduit.h"
+#include "gpu/ipc/common/gpu_surface_lookup.h"
+#include "jni/ContentChildProcessServiceDelegate_jni.h"
+#include "services/service_manager/embedder/shared_file_util.h"
+#include "services/service_manager/embedder/switches.h"
+#include "ui/gl/android/scoped_java_surface.h"
+#include "ui/gl/android/surface_texture.h"
+
+using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
+
+namespace content {
+
+namespace {
+
+// TODO(sievers): Use two different implementations of this depending on if
+// we're in a renderer or gpu process.
+class ChildProcessSurfaceManager : public gpu::ScopedSurfaceRequestConduit,
+                                   public gpu::GpuSurfaceLookup {
+ public:
+  ChildProcessSurfaceManager() {}
+  ~ChildProcessSurfaceManager() override {}
+
+  // |service impl| is the instance of
+  // org.chromium.content.app.ChildProcessServiceImpl.
+  void SetServiceImpl(const base::android::JavaRef<jobject>& service_impl) {
+    service_impl_.Reset(service_impl);
+  }
+
+  // Overriden from ScopedSurfaceRequestConduit:
+  void ForwardSurfaceTextureForSurfaceRequest(
+      const base::UnguessableToken& request_token,
+      const gl::SurfaceTexture* surface_texture) override {
+    JNIEnv* env = base::android::AttachCurrentThread();
+
+    content::
+        Java_ContentChildProcessServiceDelegate_forwardSurfaceTextureForSurfaceRequest(
+            env, service_impl_,
+            base::android::UnguessableTokenAndroid::Create(env, request_token),
+            surface_texture->j_surface_texture());
+  }
+
+  // Overridden from GpuSurfaceLookup:
+  gfx::AcceleratedWidget AcquireNativeWidget(int surface_id) override {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    gl::ScopedJavaSurface surface(
+        content::Java_ContentChildProcessServiceDelegate_getViewSurface(
+            env, service_impl_, surface_id));
+
+    if (surface.j_surface().is_null())
+      return NULL;
+
+    // Note: This ensures that any local references used by
+    // ANativeWindow_fromSurface are released immediately. This is needed as a
+    // workaround for https://code.google.com/p/android/issues/detail?id=68174
+    base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
+    ANativeWindow* native_window =
+        ANativeWindow_fromSurface(env, surface.j_surface().obj());
+
+    return native_window;
+  }
+
+  // Overridden from GpuSurfaceLookup:
+  gl::ScopedJavaSurface AcquireJavaSurface(int surface_id) override {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    return gl::ScopedJavaSurface(
+        content::Java_ContentChildProcessServiceDelegate_getViewSurface(
+            env, service_impl_, surface_id));
+  }
+
+ private:
+  friend struct base::LazyInstanceTraitsBase<ChildProcessSurfaceManager>;
+  // The instance of org.chromium.content.app.ChildProcessServiceImpl.
+  base::android::ScopedJavaGlobalRef<jobject> service_impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChildProcessSurfaceManager);
+};
+
+base::LazyInstance<ChildProcessSurfaceManager>::Leaky
+    g_child_process_surface_manager = LAZY_INSTANCE_INITIALIZER;
+
+// Chrome actually uses the renderer code path for all of its child
+// processes such as renderers, plugins, etc.
+void InternalInitChildProcess(JNIEnv* env,
+                              const JavaParamRef<jobject>& service_impl,
+                              jint cpu_count,
+                              jlong cpu_features) {
+  // Set the CPU properties.
+  android_setCpu(cpu_count, cpu_features);
+
+  g_child_process_surface_manager.Get().SetServiceImpl(service_impl);
+
+  gpu::GpuSurfaceLookup::InitInstance(
+      g_child_process_surface_manager.Pointer());
+  gpu::ScopedSurfaceRequestConduit::SetInstance(
+      g_child_process_surface_manager.Pointer());
+
+  base::android::MemoryPressureListenerAndroid::RegisterSystemCallback(env);
+}
+
+}  // namespace
+
+void InitChildProcess(JNIEnv* env,
+                      const JavaParamRef<jobject>& obj,
+                      jint cpu_count,
+                      jlong cpu_features) {
+  InternalInitChildProcess(env, obj, cpu_count, cpu_features);
+}
+
+void ShutdownMainThread(JNIEnv* env, const JavaParamRef<jobject>& obj) {
+  ChildThreadImpl::ShutdownThread();
+}
+
+bool RegisterContentChildProcessServiceDelegate(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace content
diff --git a/content/app/android/content_child_process_service_delegate.h b/content/app/android/content_child_process_service_delegate.h
new file mode 100644
index 0000000..f338fb5
--- /dev/null
+++ b/content/app/android/content_child_process_service_delegate.h
@@ -0,0 +1,14 @@
+// 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 CONTENT_APP_ANDROID_CONTENT_CHILD_PROCESS_SERVICE_DELEGATE_H_
+#define CONTENT_APP_ANDROID_CONTENT_CHILD_PROCESS_SERVICE_DELEGATE_H_
+
+#include <jni.h>
+
+namespace content {
+bool RegisterContentChildProcessServiceDelegate(JNIEnv* env);
+}  // namespace content
+
+#endif  // CONTENT_APP_ANDROID_CONTENT_CHILD_PROCESS_SERVICE_DELEGATE_H_
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 3ba593b..bdb1b14 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -76,9 +76,12 @@
 
   java_files = [
     "java/src/org/chromium/content/app/ChildProcessService.java",
+    "java/src/org/chromium/content/app/ChildProcessServiceDelegate.java",
     "java/src/org/chromium/content/app/ChildProcessServiceImpl.java",
     "java/src/org/chromium/content/app/ChromiumLinkerParams.java",
     "java/src/org/chromium/content/app/ContentApplication.java",
+    "java/src/org/chromium/content/app/ContentChildProcessService.java",
+    "java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java",
     "java/src/org/chromium/content/app/ContentMain.java",
     "java/src/org/chromium/content/app/KillChildUncaughtExceptionHandler.java",
     "java/src/org/chromium/content/app/PrivilegedProcessService.java",
@@ -322,6 +325,7 @@
 generate_jni("content_jni_headers") {
   sources = [
     "java/src/org/chromium/content/app/ChildProcessServiceImpl.java",
+    "java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java",
     "java/src/org/chromium/content/app/ContentMain.java",
     "java/src/org/chromium/content/browser/AppWebMessagePort.java",
     "java/src/org/chromium/content/browser/AudioFocusDelegate.java",
diff --git a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
index 4bce955..5590871 100644
--- a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
+++ b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
@@ -8,8 +8,6 @@
 import android.content.Intent;
 import android.os.IBinder;
 
-import org.chromium.base.annotations.JNINamespace;
-
 /**
  * This is the base class for child services; the [Sandboxed|Privileged]ProcessService0, 1.. etc
  * subclasses provide the concrete service entry points, to enable the browser to connect
@@ -23,16 +21,21 @@
  * and then N entries of the form:
  *     <service android:name="org.chromium.content.app.[Sandboxed|Privileged]ProcessServiceX"
  *              android:process=":[sandboxed|privileged]_processX" />
+ *
+ * Subclasses must also provide a delegate in this class constructor. That delegate is responsible
+ * for loading native libraries and running the main entry point of the service.
  */
-@JNINamespace("content")
-public class ChildProcessService extends Service {
-    private final ChildProcessServiceImpl mChildProcessServiceImpl = new ChildProcessServiceImpl();
+public abstract class ChildProcessService extends Service {
+    private final ChildProcessServiceImpl mChildProcessServiceImpl;
+
+    protected ChildProcessService(ChildProcessServiceDelegate delegate) {
+        mChildProcessServiceImpl = new ChildProcessServiceImpl(delegate);
+    }
 
     @Override
     public void onCreate() {
         super.onCreate();
-        mChildProcessServiceImpl.create(getApplicationContext(),
-                getApplicationContext());
+        mChildProcessServiceImpl.create(getApplicationContext(), getApplicationContext());
     }
 
     @Override
diff --git a/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceDelegate.java b/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceDelegate.java
new file mode 100644
index 0000000..7b917f26
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceDelegate.java
@@ -0,0 +1,51 @@
+// 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.
+
+package org.chromium.content.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/**
+ * The interface that embedders should implement to specialize child service creation.
+ */
+public interface ChildProcessServiceDelegate {
+    /** Invoked when the service was created. This is the first method invoked on the delegate. */
+    void onServiceCreated();
+
+    /**
+     * Called when the service is bound. Invoked on a background thread.
+     * @param intent the intent that started the service.
+     */
+    void onServiceBound(Intent intent);
+
+    /**
+     * Called once the connection has been setup. Invoked on a background thread.
+     * @param connectionBundle the bundle pass to the setupConnection call
+     * @param callback the IBinder provided by the client
+     */
+    void onConnectionSetup(Bundle connectionBundle, IBinder callback);
+
+    /** Called when the service gets destroyed. */
+    void onDestroy();
+
+    /**
+     * Called when the delegate should load the native library.
+     * @param hostContext The host context the library should be loaded with (i.e. Chrome).
+     * @return true if the library was loaded successfully, false otherwise in which case the
+     * service stops.
+     */
+    boolean loadNativeLibrary(Context hostContext);
+
+    /** Called before the main method is invoked. */
+    void onBeforeMain();
+
+    /**
+     * The main entry point for the service. This method should block as long as the service should
+     * be running.
+     */
+    void runMain();
+}
diff --git a/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceImpl.java b/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceImpl.java
index 9d170093..33b72f07 100644
--- a/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceImpl.java
+++ b/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceImpl.java
@@ -6,7 +6,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.SurfaceTexture;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -14,30 +13,18 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
-import android.view.Surface;
 
 import org.chromium.base.BaseSwitches;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
-import org.chromium.base.JNIUtils;
 import org.chromium.base.Log;
-import org.chromium.base.UnguessableToken;
-import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.MainDex;
 import org.chromium.base.annotations.SuppressFBWarnings;
-import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.base.library_loader.Linker;
-import org.chromium.base.library_loader.ProcessInitException;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.process_launcher.FileDescriptorInfo;
 import org.chromium.base.process_launcher.ICallbackInt;
 import org.chromium.base.process_launcher.IChildProcessService;
 import org.chromium.content.browser.ChildProcessConstants;
-import org.chromium.content.common.ContentSwitches;
-import org.chromium.content.common.IGpuProcessCallback;
-import org.chromium.content.common.SurfaceWrapper;
-import org.chromium.content_public.common.ContentProcessInfo;
 
 import java.util.concurrent.Semaphore;
 
@@ -49,7 +36,6 @@
  * It makes it possible for other consumer services (such as WebAPKs) to reuse that logic.
  */
 @JNINamespace("content")
-@SuppressWarnings("SynchronizeOnNonFinalField")
 @MainDex
 public class ChildProcessServiceImpl {
     private static final String MAIN_THREAD_NAME = "ChildProcessMain";
@@ -58,6 +44,8 @@
     // Only for a check that create is only called once.
     private static boolean sCreateCalled;
 
+    private final ChildProcessServiceDelegate mDelegate;
+
     private final Object mBinderLock = new Object();
     private final Object mLibraryInitializedLock = new Object();
 
@@ -71,22 +59,13 @@
 
     // This is the native "Main" thread for the renderer / utility process.
     private Thread mMainThread;
+
     // Parameters received via IPC, only accessed while holding the mMainThread monitor.
     private String[] mCommandLineParams;
-    private IGpuProcessCallback mGpuCallback;
-    private int mCpuCount;
-    private long mCpuFeatures;
+
     // File descriptors that should be registered natively.
     private FileDescriptorInfo[] mFdInfos;
 
-    // Linker-specific parameters for this child process service.
-    // Only set once in bind(), does not require synchronization.
-    private ChromiumLinkerParams mLinkerParams;
-
-    // Child library process type.
-    // Only set once in bind(), does not require synchronization.
-    private int mLibraryProcessType;
-
     @GuardedBy("mLibraryInitializedLock")
     private boolean mLibraryInitialized;
 
@@ -104,21 +83,9 @@
 
     private final Semaphore mActivitySemaphore = new Semaphore(1);
 
-    public ChildProcessServiceImpl() {
+    public ChildProcessServiceImpl(ChildProcessServiceDelegate delegate) {
         KillChildUncaughtExceptionHandler.maybeInstallHandler();
-    }
-
-    // Return a Linker instance. If testing, the Linker needs special setup.
-    private Linker getLinker() {
-        if (Linker.areTestsEnabled()) {
-            // For testing, set the Linker implementation and the test runner
-            // class name to match those used by the parent.
-            assert mLinkerParams != null;
-            Linker.setupForTesting(
-                    mLinkerParams.mLinkerImplementationForTesting,
-                    mLinkerParams.mTestRunnerClassNameForTesting);
-        }
-        return Linker.getInstance();
+        mDelegate = delegate;
     }
 
     // Binder object used by clients for this service.
@@ -142,7 +109,7 @@
         }
 
         @Override
-        public void setupConnection(Bundle args, ICallbackInt pidCallback, IBinder gpuCallback)
+        public void setupConnection(Bundle args, ICallbackInt pidCallback, IBinder callback)
                 throws RemoteException {
             assert mServiceBound;
             synchronized (mBinderLock) {
@@ -154,9 +121,7 @@
             }
 
             pidCallback.call(Process.myPid());
-            mGpuCallback =
-                    gpuCallback != null ? IGpuProcessCallback.Stub.asInterface(gpuCallback) : null;
-            processConnectionBundle(args);
+            processConnectionBundle(args, callback);
         }
 
         @Override
@@ -196,7 +161,8 @@
             throw new RuntimeException("Illegal child process reuse.");
         }
         sCreateCalled = true;
-        ContentProcessInfo.setInChildProcess(true);
+
+        mDelegate.onServiceCreated();
 
         // Initialize the context for the application that owns this ChildProcessServiceImpl object.
         ContextUtils.initApplicationContext(context);
@@ -215,60 +181,21 @@
                     assert mServiceBound;
                     CommandLine.init(mCommandLineParams);
 
-                    if (ContentSwitches.SWITCH_RENDERER_PROCESS.equals(
-                            CommandLine.getInstance().getSwitchValue(
-                                    ContentSwitches.SWITCH_PROCESS_TYPE))) {
-                        JNIUtils.enableSelectiveJniRegistration();
-                    }
-
-                    Linker linker = null;
-                    boolean requestedSharedRelro = false;
-                    if (Linker.isUsed()) {
-                        assert mLinkerParams != null;
-                        linker = getLinker();
-                        if (mLinkerParams.mWaitForSharedRelro) {
-                            requestedSharedRelro = true;
-                            linker.initServiceProcess(mLinkerParams.mBaseLoadAddress);
-                        } else {
-                            linker.disableSharedRelros();
-                        }
-                    }
                     if (CommandLine.getInstance().hasSwitch(
                             BaseSwitches.RENDERER_WAIT_FOR_JAVA_DEBUGGER)) {
                         android.os.Debug.waitForDebugger();
                     }
 
-                    LibraryLoader libraryLoader = null;
-                    boolean loadAtFixedAddressFailed = false;
-                    boolean isLoaded = false;
+                    boolean nativeLibraryLoaded = false;
                     try {
-                        libraryLoader = LibraryLoader.get(mLibraryProcessType);
-                        libraryLoader.loadNowOverrideApplicationContext(hostContext);
-                        isLoaded = true;
-                    } catch (ProcessInitException e) {
-                        if (requestedSharedRelro) {
-                            Log.w(TAG, "Failed to load native library with shared RELRO, "
-                                    + "retrying without");
-                            loadAtFixedAddressFailed = true;
-                        } else {
-                            Log.e(TAG, "Failed to load native library", e);
-                        }
+                        nativeLibraryLoaded = mDelegate.loadNativeLibrary(hostContext);
+                    } catch (Exception e) {
+                        Log.e(TAG, "Failed to load native library.", e);
                     }
-                    if (!isLoaded && libraryLoader != null && requestedSharedRelro) {
-                        linker.disableSharedRelros();
-                        try {
-                            libraryLoader.loadNowOverrideApplicationContext(hostContext);
-                            isLoaded = true;
-                        } catch (ProcessInitException e) {
-                            Log.e(TAG, "Failed to load native library on retry", e);
-                        }
-                    }
-                    if (!isLoaded) {
+                    if (!nativeLibraryLoaded) {
                         System.exit(-1);
                     }
-                    libraryLoader.registerRendererProcessHistogram(
-                            requestedSharedRelro, loadAtFixedAddressFailed);
-                    libraryLoader.initialize();
+
                     synchronized (mLibraryInitializedLock) {
                         mLibraryInitialized = true;
                         mLibraryInitializedLock.notifyAll();
@@ -292,16 +219,14 @@
                         regionSizes[i] = fdInfo.size;
                     }
                     nativeRegisterFileDescriptors(fileIds, fds, regionOffsets, regionSizes);
-                    nativeInitChildProcessImpl(ChildProcessServiceImpl.this, mCpuCount,
-                            mCpuFeatures);
+
+                    mDelegate.onBeforeMain();
                     if (mActivitySemaphore.tryAcquire()) {
-                        ContentMain.start();
+                        mDelegate.runMain();
                         nativeExitChildProcess();
                     }
                 } catch (InterruptedException e) {
                     Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e);
-                } catch (ProcessInitException e) {
-                    Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e);
                 }
             }
         }, MAIN_THREAD_NAME);
@@ -330,9 +255,7 @@
                 // Ignore
             }
         }
-        // Try to shutdown the MainThread gracefully, but it might not
-        // have chance to exit normally.
-        nativeShutdownMainThread();
+        mDelegate.onDestroy();
     }
 
     /*
@@ -349,17 +272,14 @@
     public IBinder bind(Intent intent, int authorizedCallerUid) {
         assert !mServiceBound;
         mAuthorizedCallerUid = authorizedCallerUid;
-        // mLinkerParams is never used if Linker.isUsed() returns false. See create().
-        mLinkerParams = (ChromiumLinkerParams) intent.getParcelableExtra(
-                ChildProcessConstants.EXTRA_LINKER_PARAMS);
-        mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessType(intent);
         mBindToCallerCheck =
                 intent.getBooleanExtra(ChildProcessConstants.EXTRA_BIND_TO_CALLER, false);
         mServiceBound = true;
+        mDelegate.onServiceBound(intent);
         return mBinder;
     }
 
-    private void processConnectionBundle(Bundle bundle) {
+    private void processConnectionBundle(Bundle bundle, IBinder callback) {
         // Required to unparcel FileDescriptorInfo.
         bundle.setClassLoader(mHostClassLoader);
         synchronized (mMainThread) {
@@ -370,9 +290,6 @@
             }
             // We must have received the command line by now
             assert mCommandLineParams != null;
-            mCpuCount = bundle.getInt(ChildProcessConstants.EXTRA_CPU_COUNT);
-            mCpuFeatures = bundle.getLong(ChildProcessConstants.EXTRA_CPU_FEATURES);
-            assert mCpuCount > 0;
             Parcelable[] fdInfosAsParcelable =
                     bundle.getParcelableArray(ChildProcessConstants.EXTRA_FILES);
             if (fdInfosAsParcelable != null) {
@@ -381,53 +298,11 @@
                 mFdInfos = new FileDescriptorInfo[fdInfosAsParcelable.length];
                 System.arraycopy(fdInfosAsParcelable, 0, mFdInfos, 0, fdInfosAsParcelable.length);
             }
-            Bundle sharedRelros = bundle.getBundle(Linker.EXTRA_LINKER_SHARED_RELROS);
-            if (sharedRelros != null) {
-                getLinker().useSharedRelros(sharedRelros);
-                sharedRelros = null;
-            }
+            mDelegate.onConnectionSetup(bundle, callback);
             mMainThread.notifyAll();
         }
     }
 
-    @SuppressWarnings("unused")
-    @CalledByNative
-    private void forwardSurfaceTextureForSurfaceRequest(
-            UnguessableToken requestToken, SurfaceTexture surfaceTexture) {
-        if (mGpuCallback == null) {
-            Log.e(TAG, "No callback interface has been provided.");
-            return;
-        }
-
-        Surface surface = new Surface(surfaceTexture);
-
-        try {
-            mGpuCallback.forwardSurfaceForSurfaceRequest(requestToken, surface);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Unable to call forwardSurfaceForSurfaceRequest: %s", e);
-            return;
-        } finally {
-            surface.release();
-        }
-    }
-
-    @SuppressWarnings("unused")
-    @CalledByNative
-    private Surface getViewSurface(int surfaceId) {
-        if (mGpuCallback == null) {
-            Log.e(TAG, "No callback interface has been provided.");
-            return null;
-        }
-
-        try {
-            SurfaceWrapper wrapper = mGpuCallback.getViewSurface(surfaceId);
-            return wrapper != null ? wrapper.getSurface() : null;
-        } catch (RemoteException e) {
-            Log.e(TAG, "Unable to call getViewSurface: %s", e);
-            return null;
-        }
-    }
-
     /**
      * Helper for registering FileDescriptorInfo objects with GlobalFileDescriptors or
      * FileDescriptorStore.
@@ -438,19 +313,7 @@
             int[] id, int[] fd, long[] offset, long[] size);
 
     /**
-     * The main entry point for a child process. This should be called from a new thread since
-     * it will not return until the child process exits. See child_process_service.{h,cc}
-     *
-     * @param serviceImpl The current ChildProcessServiceImpl object.
-     * renderer.
-     */
-    private static native void nativeInitChildProcessImpl(
-            ChildProcessServiceImpl serviceImpl, int cpuCount, long cpuFeatures);
-
-    /**
      * Force the child process to exit.
      */
     private static native void nativeExitChildProcess();
-
-    private native void nativeShutdownMainThread();
 }
diff --git a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessService.java b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessService.java
new file mode 100644
index 0000000..5a0cb86e
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessService.java
@@ -0,0 +1,12 @@
+// Copyright 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.
+
+package org.chromium.content.app;
+
+/** Implementation of ChildProcessService that uses the content specific delegate. */
+public class ContentChildProcessService extends ChildProcessService {
+    public ContentChildProcessService() {
+        super(new ContentChildProcessServiceDelegate());
+    }
+}
diff --git a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
new file mode 100644
index 0000000..afbb488
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
@@ -0,0 +1,216 @@
+// 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.
+
+package org.chromium.content.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.Surface;
+
+import org.chromium.base.CommandLine;
+import org.chromium.base.JNIUtils;
+import org.chromium.base.Log;
+import org.chromium.base.UnguessableToken;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.MainDex;
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.library_loader.Linker;
+import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.base.process_launcher.ChildProcessCreationParams;
+import org.chromium.content.browser.ChildProcessConstants;
+import org.chromium.content.common.ContentSwitches;
+import org.chromium.content.common.IGpuProcessCallback;
+import org.chromium.content.common.SurfaceWrapper;
+import org.chromium.content_public.common.ContentProcessInfo;
+
+/**
+ * This implementation of {@link ChildProcessServiceDelegate} loads the native library potentially
+ * using the custom linker, provides access to view surfaces.
+ */
+@JNINamespace("content")
+@MainDex
+public class ContentChildProcessServiceDelegate implements ChildProcessServiceDelegate {
+    private static final String TAG = "ContentCPSDelegate";
+
+    // Linker-specific parameters for this child process service.
+    private ChromiumLinkerParams mLinkerParams;
+
+    // Child library process type.
+    private int mLibraryProcessType;
+
+    private IGpuProcessCallback mGpuCallback;
+
+    private int mCpuCount;
+    private long mCpuFeatures;
+
+    @Override
+    public void onServiceCreated() {
+        ContentProcessInfo.setInChildProcess(true);
+    }
+
+    @Override
+    public void onServiceBound(Intent intent) {
+        mLinkerParams = (ChromiumLinkerParams) intent.getParcelableExtra(
+                ChildProcessConstants.EXTRA_LINKER_PARAMS);
+        mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessType(intent);
+    }
+
+    @Override
+    public void onConnectionSetup(Bundle connectionBundle, IBinder callback) {
+        mGpuCallback = callback != null ? IGpuProcessCallback.Stub.asInterface(callback) : null;
+
+        mCpuCount = connectionBundle.getInt(ChildProcessConstants.EXTRA_CPU_COUNT);
+        mCpuFeatures = connectionBundle.getLong(ChildProcessConstants.EXTRA_CPU_FEATURES);
+        assert mCpuCount > 0;
+
+        Bundle sharedRelros = connectionBundle.getBundle(Linker.EXTRA_LINKER_SHARED_RELROS);
+        if (sharedRelros != null) {
+            getLinker().useSharedRelros(sharedRelros);
+            sharedRelros = null;
+        }
+    }
+
+    @Override
+    public boolean loadNativeLibrary(Context hostContext) {
+        String processType =
+                CommandLine.getInstance().getSwitchValue(ContentSwitches.SWITCH_PROCESS_TYPE);
+        if (ContentSwitches.SWITCH_RENDERER_PROCESS.equals(processType)) {
+            JNIUtils.enableSelectiveJniRegistration();
+        }
+
+        Linker linker = null;
+        boolean requestedSharedRelro = false;
+        if (Linker.isUsed()) {
+            assert mLinkerParams != null;
+            linker = getLinker();
+            if (mLinkerParams.mWaitForSharedRelro) {
+                requestedSharedRelro = true;
+                linker.initServiceProcess(mLinkerParams.mBaseLoadAddress);
+            } else {
+                linker.disableSharedRelros();
+            }
+        }
+        LibraryLoader libraryLoader = null;
+        boolean isLoaded = false;
+        boolean loadAtFixedAddressFailed = false;
+        try {
+            libraryLoader = LibraryLoader.get(mLibraryProcessType);
+            libraryLoader.loadNowOverrideApplicationContext(hostContext);
+            isLoaded = true;
+        } catch (ProcessInitException e) {
+            if (requestedSharedRelro) {
+                Log.w(TAG,
+                        "Failed to load native library with shared RELRO, "
+                                + "retrying without");
+                loadAtFixedAddressFailed = true;
+            } else {
+                Log.e(TAG, "Failed to load native library", e);
+            }
+        }
+        if (!isLoaded && libraryLoader != null && requestedSharedRelro) {
+            linker.disableSharedRelros();
+            try {
+                libraryLoader.loadNowOverrideApplicationContext(hostContext);
+                isLoaded = true;
+            } catch (ProcessInitException e) {
+                Log.e(TAG, "Failed to load native library on retry", e);
+            }
+        }
+        if (!isLoaded) {
+            return false;
+        }
+        libraryLoader.registerRendererProcessHistogram(
+                requestedSharedRelro, loadAtFixedAddressFailed);
+        try {
+            libraryLoader.initialize();
+        } catch (ProcessInitException e) {
+            Log.w(TAG, "startup failed: %s", e);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public void onBeforeMain() {
+        nativeInitChildProcess(mCpuCount, mCpuFeatures);
+    }
+
+    @Override
+    public void onDestroy() {
+        // Try to shutdown the MainThread gracefully, but it might not have a
+        // chance to exit normally.
+        nativeShutdownMainThread();
+    }
+
+    @Override
+    public void runMain() {
+        ContentMain.start();
+    }
+
+    // Return a Linker instance. If testing, the Linker needs special setup.
+    private Linker getLinker() {
+        if (Linker.areTestsEnabled()) {
+            // For testing, set the Linker implementation and the test runner
+            // class name to match those used by the parent.
+            assert mLinkerParams != null;
+            Linker.setupForTesting(mLinkerParams.mLinkerImplementationForTesting,
+                    mLinkerParams.mTestRunnerClassNameForTesting);
+        }
+        return Linker.getInstance();
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void forwardSurfaceTextureForSurfaceRequest(
+            UnguessableToken requestToken, SurfaceTexture surfaceTexture) {
+        if (mGpuCallback == null) {
+            Log.e(TAG, "No callback interface has been provided.");
+            return;
+        }
+
+        Surface surface = new Surface(surfaceTexture);
+
+        try {
+            mGpuCallback.forwardSurfaceForSurfaceRequest(requestToken, surface);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to call forwardSurfaceForSurfaceRequest: %s", e);
+            return;
+        } finally {
+            surface.release();
+        }
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private Surface getViewSurface(int surfaceId) {
+        if (mGpuCallback == null) {
+            Log.e(TAG, "No callback interface has been provided.");
+            return null;
+        }
+
+        try {
+            SurfaceWrapper wrapper = mGpuCallback.getViewSurface(surfaceId);
+            return wrapper != null ? wrapper.getSurface() : null;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to call getViewSurface: %s", e);
+            return null;
+        }
+    }
+
+    /**
+     * Initializes the native parts of the service.
+     *
+     * @param serviceImpl This ChildProcessServiceImpl object.
+     * @param cpuCount The number of CPUs.
+     * @param cpuFeatures The CPU features.
+     */
+    private native void nativeInitChildProcess(int cpuCount, long cpuFeatures);
+
+    private native void nativeShutdownMainThread();
+}
diff --git a/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService.java b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService.java
index 5cff15b..a7c96d35 100644
--- a/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService.java
+++ b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService.java
@@ -8,6 +8,4 @@
  * Privileged (unsandboxed) Services inherit from this class. We enforce the
  * privileged/sandboxed distinction by type-checking objects against this parent class.
  */
-public class PrivilegedProcessService extends ChildProcessService {
-
-}
+public class PrivilegedProcessService extends ContentChildProcessService {}
diff --git a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java
index 3a9830f..b7ad8b36 100644
--- a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java
+++ b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java
@@ -8,6 +8,4 @@
  * Sandboxed Services inherit from this class. We enforce the privileged/sandboxed
  * distinction by type-checking objects against this parent class.
  */
-public class SandboxedProcessService extends ChildProcessService {
-
-}
+public class SandboxedProcessService extends ContentChildProcessService {}
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 97e626c..7250836 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -71,6 +71,8 @@
     self.Fail('conformance2/rendering/' +
         'draw-with-integer-texture-base-level.html',
         ['win', 'nvidia', 'd3d11'], bug=679639)
+    self.Flaky('deqp/functional/gles3/textureshadow/*.html',
+        ['win', 'nvidia', 'd3d11'], bug=735464)
 
     # Win10 / NVIDIA Quadro P400 / D3D11 flaky failures
     self.Fail('deqp/functional/gles3/transformfeedback/' +
diff --git a/headless/public/util/testing/generic_url_request_mocks.cc b/headless/public/util/testing/generic_url_request_mocks.cc
index 54f1ed9..a4053dc 100644
--- a/headless/public/util/testing/generic_url_request_mocks.cc
+++ b/headless/public/util/testing/generic_url_request_mocks.cc
@@ -84,6 +84,14 @@
   CHECK(false);
 }
 
+void MockCookieStore::SetCanonicalCookieAsync(
+    std::unique_ptr<net::CanonicalCookie> cookie,
+    bool secure_source,
+    bool can_modify_httponly,
+    const SetCookiesCallback& callback) {
+  CHECK(false);
+}
+
 void MockCookieStore::GetCookiesWithOptionsAsync(
     const GURL& url,
     const net::CookieOptions& options,
diff --git a/headless/public/util/testing/generic_url_request_mocks.h b/headless/public/util/testing/generic_url_request_mocks.h
index 94e0e5c0..98f5e9d 100644
--- a/headless/public/util/testing/generic_url_request_mocks.h
+++ b/headless/public/util/testing/generic_url_request_mocks.h
@@ -74,6 +74,11 @@
                                  net::CookiePriority priority,
                                  const SetCookiesCallback& callback) override;
 
+  void SetCanonicalCookieAsync(std::unique_ptr<net::CanonicalCookie> cookie,
+                               bool secure_source,
+                               bool modify_http_only,
+                               const SetCookiesCallback& callback) override;
+
   void GetCookiesWithOptionsAsync(const GURL& url,
                                   const net::CookieOptions& options,
                                   const GetCookiesCallback& callback) override;
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc
index 345b7a2..66c213b 100644
--- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc
+++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc
@@ -119,14 +119,21 @@
 }
 
 std::vector<base::string16> AutocompleteProviderClientImpl::GetBuiltinURLs() {
-  // iOS does not supports BuiltinProvider.
-  return std::vector<base::string16>();
+  std::vector<std::string> chrome_builtins(
+      kChromeHostURLs, kChromeHostURLs + kNumberOfChromeHostURLs);
+  std::sort(chrome_builtins.begin(), chrome_builtins.end());
+
+  std::vector<base::string16> builtins;
+  for (auto& url : chrome_builtins) {
+    builtins.push_back(base::ASCIIToUTF16(url));
+  }
+  return builtins;
 }
 
 std::vector<base::string16>
 AutocompleteProviderClientImpl::GetBuiltinsToProvideAsUserTypes() {
-  // iOS does not supports BuiltinProvider.
-  return std::vector<base::string16>();
+  return {base::ASCIIToUTF16(kChromeUIChromeURLsURL),
+          base::ASCIIToUTF16(kChromeUIVersionURL)};
 }
 
 bool AutocompleteProviderClientImpl::IsOffTheRecord() const {
diff --git a/ios/chrome/browser/ui/dialogs/dialog_presenter.h b/ios/chrome/browser/ui/dialogs/dialog_presenter.h
index b3e7a424..33d38b8 100644
--- a/ios/chrome/browser/ui/dialogs/dialog_presenter.h
+++ b/ios/chrome/browser/ui/dialogs/dialog_presenter.h
@@ -86,8 +86,8 @@
 // The dialog currently being shown.
 @property(nonatomic, readonly) AlertCoordinator* presentedDialogCoordinator;
 
-// Called when a button in |dialog| is tapped.
-- (void)buttonWasTappedForCoordinator:(AlertCoordinator*)coordinator;
+// Called when |coordinator| is stopped.
+- (void)dialogCoordinatorWasStopped:(AlertCoordinator*)coordinator;
 
 @end
 
diff --git a/ios/chrome/browser/ui/dialogs/dialog_presenter.mm b/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
index 1d7094f..05749db 100644
--- a/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
+++ b/ios/chrome/browser/ui/dialogs/dialog_presenter.mm
@@ -73,8 +73,8 @@
 // Shows the dialog associated with the next context in |contextQueue|.
 - (void)showNextDialog;
 
-// Called when a button in |coordinator| is tapped.
-- (void)buttonWasTappedForCoordinator:(AlertCoordinator*)coordinator;
+// Called when |coordinator| is stopped.
+- (void)dialogCoordinatorWasStopped:(AlertCoordinator*)coordinator;
 
 // Adds buttons to |alertCoordinator|.  A confirmation button with |label| as
 // the text will be added for |confirmAction|, and a cancel button will be added
@@ -153,7 +153,7 @@
   ProceduralBlock OKHandler = ^{
     if (completionHandler)
       completionHandler();
-    [weakSelf buttonWasTappedForCoordinator:weakCoordinator];
+    [weakSelf dialogCoordinatorWasStopped:weakCoordinator];
   };
 
   // Add button.
@@ -312,15 +312,24 @@
 }
 
 - (void)cancelDialogForWebState:(web::WebState*)webState {
-  DCHECK_NE(webState, self.presentedDialogWebState);
-  AlertCoordinator* dialogToCancel = _dialogCoordinatorsForWebStates[webState];
-  if (dialogToCancel) {
+  BOOL cancelingPresentedDialog = webState == self.presentedDialogWebState;
+  AlertCoordinator* dialogToCancel =
+      cancelingPresentedDialog ? self.presentedDialogCoordinator
+                               : _dialogCoordinatorsForWebStates[webState];
+  DCHECK(!cancelingPresentedDialog || dialogToCancel);
+  [dialogToCancel executeCancelHandler];
+  [dialogToCancel stop];
+
+  if (cancelingPresentedDialog) {
+    DCHECK(_dialogCoordinatorsForWebStates[webState] == nil);
+    // Simulate a button tap to trigger showing the next dialog.
+    [self dialogCoordinatorWasStopped:dialogToCancel];
+  } else if (dialogToCancel) {
+    // Clean up queued state.
     auto it =
         std::find(_queuedWebStates.begin(), _queuedWebStates.end(), webState);
     DCHECK(it != _queuedWebStates.end());
     _queuedWebStates.erase(it);
-    [dialogToCancel executeCancelHandler];
-    [dialogToCancel stop];
     _dialogCoordinatorsForWebStates.erase(webState);
   }
 }
@@ -386,7 +395,7 @@
   [self.presentedDialogCoordinator start];
 }
 
-- (void)buttonWasTappedForCoordinator:(AlertCoordinator*)coordinator {
+- (void)dialogCoordinatorWasStopped:(AlertCoordinator*)coordinator {
   if (coordinator != self.presentedDialogCoordinator)
     return;
   self.presentedDialogWebState = nil;
@@ -407,13 +416,13 @@
   ProceduralBlock confirmHandler = ^{
     if (confirmAction)
       confirmAction();
-    [weakSelf buttonWasTappedForCoordinator:weakCoordinator];
+    [weakSelf dialogCoordinatorWasStopped:weakCoordinator];
   };
 
   ProceduralBlock cancelHandler = ^{
     if (cancelAction)
       cancelAction();
-    [weakSelf buttonWasTappedForCoordinator:weakCoordinator];
+    [weakSelf dialogCoordinatorWasStopped:weakCoordinator];
   };
 
   // Add buttons.
@@ -485,12 +494,12 @@
       if (!strongSelf)
         return;
       DialogBlockingOptionSelected([strongSelf presentedDialogWebState]);
-      [strongSelf buttonWasTappedForCoordinator:weakCoordinator];
+      [strongSelf dialogCoordinatorWasStopped:weakCoordinator];
     };
     ProceduralBlock cancelHandler = ^{
       if (cancelAction)
         cancelAction();
-      [weakSelf buttonWasTappedForCoordinator:weakCoordinator];
+      [weakSelf dialogCoordinatorWasStopped:weakCoordinator];
     };
     NSString* blockingOptionTitle =
         l10n_util::GetNSString(IDS_IOS_JAVA_SCRIPT_DIALOG_BLOCKING_BUTTON_TEXT);
diff --git a/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm b/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm
index 2a566bf9..2bd6df4 100644
--- a/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm
+++ b/ios/chrome/browser/ui/dialogs/dialog_presenter_unittest.mm
@@ -120,7 +120,7 @@
   // showing the dialog for |webState2|.
   [presenter().presentedDialogCoordinator stop];
   [presenter()
-      buttonWasTappedForCoordinator:presenter().presentedDialogCoordinator];
+      dialogCoordinatorWasStopped:presenter().presentedDialogCoordinator];
   EXPECT_EQ(2U, delegate().presentedWebStates.size());
   EXPECT_EQ(&webState1, delegate().presentedWebStates.front());
   EXPECT_EQ(&webState2, delegate().presentedWebStates.back());
diff --git a/ios/chrome/browser/ui/payments/address_edit_coordinator.mm b/ios/chrome/browser/ui/payments/address_edit_coordinator.mm
index c6708818..77865e8 100644
--- a/ios/chrome/browser/ui/payments/address_edit_coordinator.mm
+++ b/ios/chrome/browser/ui/payments/address_edit_coordinator.mm
@@ -9,6 +9,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_constants.h"
@@ -147,8 +148,10 @@
                                                autofill::kSettingsOrigin);
 
   for (EditorField* field in fields) {
-    address.SetRawInfo(AutofillTypeFromAutofillUIType(field.autofillUIType),
-                       base::SysNSStringToUTF16(field.value));
+    address.SetInfo(autofill::AutofillType(
+                        AutofillTypeFromAutofillUIType(field.autofillUIType)),
+                    base::SysNSStringToUTF16(field.value),
+                    GetApplicationContext()->GetApplicationLocale());
   }
 
   if (!self.address) {
diff --git a/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm
index f46eaf9..7d39c51c 100644
--- a/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm
@@ -11,6 +11,7 @@
 #include "base/test/ios/wait_util.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/country_names.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/autofill/core/browser/test_region_data_loader.h"
 #include "components/payments/core/payments_profile_comparator.h"
@@ -102,6 +103,7 @@
  protected:
   PaymentRequestAddressEditCoordinatorTest()
       : pref_service_(autofill::test::PrefServiceForTesting()) {
+    autofill::CountryNames::SetLocaleString("en-US");
     personal_data_manager_.SetTestingPrefService(pref_service_.get());
     payment_request_ = base::MakeUnique<MockTestPaymentRequest>(
         payment_request_test_util::CreateTestWebPaymentRequest(),
@@ -193,12 +195,12 @@
   // Expect an autofill profile to be added to the PaymentRequest.
   EXPECT_CALL(*payment_request_,
               AddAutofillProfile(ProfileMatches("John Doe", "CA" /* Canada */,
-                                                "Quebec", "16502111111")))
+                                                "Quebec", "1 650-211-1111")))
       .Times(1);
   // Expect an autofill profile to be added to the PersonalDataManager.
   EXPECT_CALL(personal_data_manager_,
               AddProfile(ProfileMatches("John Doe", "CA" /* Canada */, "Quebec",
-                                        "16502111111")))
+                                        "1 650-211-1111")))
       .Times(1);
   // No autofill profile should get updated in the PersonalDataManager.
   EXPECT_CALL(personal_data_manager_, UpdateProfile(_)).Times(0);
@@ -261,12 +263,12 @@
   // Expect an autofill profile to be updated in the PersonalDataManager.
   EXPECT_CALL(personal_data_manager_,
               UpdateProfile(ProfileMatches("John Doe", "CA" /* Canada */,
-                                           "Quebec", "16502111111")))
+                                           "Quebec", "1 650-211-1111")))
       .Times(1);
   // Expect an autofill profile to be invalidated in PaymentsProfileComparator.
   EXPECT_CALL(*profile_comparator_,
               Invalidate(ProfileMatches("John Doe", "CA" /* Canada */, "Quebec",
-                                        "16502111111")))
+                                        "1 650-211-1111")))
       .Times(1);
 
   // Call the controller delegate method.
diff --git a/ios/chrome/browser/ui/payments/address_edit_mediator.mm b/ios/chrome/browser/ui/payments/address_edit_mediator.mm
index 19a2834e..2dbc06b4 100644
--- a/ios/chrome/browser/ui/payments/address_edit_mediator.mm
+++ b/ios/chrome/browser/ui/payments/address_edit_mediator.mm
@@ -21,6 +21,7 @@
 #include "components/autofill/core/browser/country_combobox_model.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/payments/core/payment_request_data_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/payments/payment_request.h"
@@ -119,6 +120,15 @@
   return NO;
 }
 
+- (void)formatValueForEditorField:(EditorField*)field {
+  if (field.autofillUIType == AutofillUITypeProfileHomePhoneWholeNumber) {
+    field.value =
+        base::SysUTF8ToNSString(payments::data_util::FormatPhoneForDisplay(
+            base::SysNSStringToUTF8(field.value),
+            base::SysNSStringToUTF8(self.selectedCountryCode)));
+  }
+}
+
 - (UIImage*)iconIdentifyingEditorField:(EditorField*)field {
   return nil;
 }
@@ -299,8 +309,12 @@
   EditorField* field = self.fieldsMap[phoneNumberFieldKey];
   if (!field) {
     NSString* value =
-        [self fieldValueFromProfile:self.address
-                          fieldType:autofill::PHONE_HOME_WHOLE_NUMBER];
+        self.address
+            ? base::SysUTF16ToNSString(
+                  payments::data_util::GetFormattedPhoneNumberForDisplay(
+                      *self.address,
+                      GetApplicationContext()->GetApplicationLocale()))
+            : nil;
     field = [[EditorField alloc]
         initWithAutofillUIType:AutofillUITypeProfileHomePhoneWholeNumber
                      fieldType:EditorFieldTypeTextField
diff --git a/ios/chrome/browser/ui/payments/contact_info_edit_coordinator.mm b/ios/chrome/browser/ui/payments/contact_info_edit_coordinator.mm
index fce47e0..aa06914 100644
--- a/ios/chrome/browser/ui/payments/contact_info_edit_coordinator.mm
+++ b/ios/chrome/browser/ui/payments/contact_info_edit_coordinator.mm
@@ -9,6 +9,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_constants.h"
@@ -136,8 +137,10 @@
                                                autofill::kSettingsOrigin);
 
   for (EditorField* field in fields) {
-    profile.SetRawInfo(AutofillTypeFromAutofillUIType(field.autofillUIType),
-                       base::SysNSStringToUTF16(field.value));
+    profile.SetInfo(autofill::AutofillType(
+                        AutofillTypeFromAutofillUIType(field.autofillUIType)),
+                    base::SysNSStringToUTF16(field.value),
+                    GetApplicationContext()->GetApplicationLocale());
   }
 
   if (!self.profile) {
diff --git a/ios/chrome/browser/ui/payments/contact_info_edit_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/contact_info_edit_coordinator_unittest.mm
index 2244182..791d0e1 100644
--- a/ios/chrome/browser/ui/payments/contact_info_edit_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/contact_info_edit_coordinator_unittest.mm
@@ -184,12 +184,12 @@
   // Expect an autofill profile to be added to the PaymentRequest.
   EXPECT_CALL(*payment_request_,
               AddAutofillProfile(
-                  ProfileMatches("John Doe", "john@doe.com", "16502111111")))
+                  ProfileMatches("John Doe", "john@doe.com", "1 650-211-1111")))
       .Times(1);
   // Expect an autofill profile to be added to the PersonalDataManager.
   EXPECT_CALL(
       personal_data_manager_,
-      AddProfile(ProfileMatches("John Doe", "john@doe.com", "16502111111")))
+      AddProfile(ProfileMatches("John Doe", "john@doe.com", "1 650-211-1111")))
       .Times(1);
   // No autofill profile should get updated in the PersonalDataManager.
   EXPECT_CALL(personal_data_manager_, UpdateProfile(_)).Times(0);
@@ -250,14 +250,14 @@
   // No autofill profile should get added to the PersonalDataManager.
   EXPECT_CALL(personal_data_manager_, AddProfile(_)).Times(0);
   // Expect an autofill profile to be updated in the PersonalDataManager.
-  EXPECT_CALL(
-      personal_data_manager_,
-      UpdateProfile(ProfileMatches("John Doe", "john@doe.com", "16502111111")))
+  EXPECT_CALL(personal_data_manager_,
+              UpdateProfile(
+                  ProfileMatches("John Doe", "john@doe.com", "1 650-211-1111")))
       .Times(1);
   // Expect an autofill profile to be invalidated in PaymentsProfileComparator.
   EXPECT_CALL(
       *profile_comparator_,
-      Invalidate(ProfileMatches("John Doe", "john@doe.com", "16502111111")))
+      Invalidate(ProfileMatches("John Doe", "john@doe.com", "1 650-211-1111")))
       .Times(1);
 
   // Call the controller delegate method.
diff --git a/ios/chrome/browser/ui/payments/contact_info_edit_mediator.mm b/ios/chrome/browser/ui/payments/contact_info_edit_mediator.mm
index 6444603..98e20b8 100644
--- a/ios/chrome/browser/ui/payments/contact_info_edit_mediator.mm
+++ b/ios/chrome/browser/ui/payments/contact_info_edit_mediator.mm
@@ -6,9 +6,11 @@
 
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
+#include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/payments/core/payment_request_data_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/payments/payment_request.h"
@@ -74,6 +76,17 @@
   return NO;
 }
 
+- (void)formatValueForEditorField:(EditorField*)field {
+  if (field.autofillUIType == AutofillUITypeProfileHomePhoneWholeNumber) {
+    const std::string countryCode =
+        autofill::AutofillCountry::CountryCodeForLocale(
+            GetApplicationContext()->GetApplicationLocale());
+    field.value =
+        base::SysUTF8ToNSString(payments::data_util::FormatPhoneForDisplay(
+            base::SysNSStringToUTF8(field.value), countryCode));
+  }
+}
+
 - (UIImage*)iconIdentifyingEditorField:(EditorField*)field {
   return nil;
 }
@@ -99,8 +112,12 @@
 
   if (_paymentRequest->request_payer_phone()) {
     NSString* phone =
-        [self fieldValueFromProfile:self.profile
-                          fieldType:autofill::PHONE_HOME_WHOLE_NUMBER];
+        self.profile
+            ? base::SysUTF16ToNSString(
+                  payments::data_util::GetFormattedPhoneNumberForDisplay(
+                      *self.profile,
+                      GetApplicationContext()->GetApplicationLocale()))
+            : nil;
     EditorField* phoneField = [[EditorField alloc]
         initWithAutofillUIType:AutofillUITypeProfileHomePhoneWholeNumber
                      fieldType:EditorFieldTypeTextField
diff --git a/ios/chrome/browser/ui/payments/contact_info_edit_mediator_unittest.mm b/ios/chrome/browser/ui/payments/contact_info_edit_mediator_unittest.mm
index 639fbed..9b2d54d 100644
--- a/ios/chrome/browser/ui/payments/contact_info_edit_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/contact_info_edit_mediator_unittest.mm
@@ -105,7 +105,7 @@
     field = fields[1];
     EXPECT_TRUE([field isKindOfClass:[EditorField class]]);
     editor_field = base::mac::ObjCCastStrict<EditorField>(field);
-    EXPECT_TRUE([editor_field.value isEqualToString:@"16502111111"]);
+    EXPECT_TRUE([editor_field.value isEqualToString:@"+1 650-211-1111"]);
 
     field = fields[2];
     EXPECT_TRUE([field isKindOfClass:[EditorField class]]);
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.mm b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.mm
index 63f1c2e4..4fceb55 100644
--- a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.mm
+++ b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.mm
@@ -8,12 +8,14 @@
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #import "components/autofill/ios/browser/credit_card_util.h"
 #include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/payments/payment_request.h"
 #import "ios/chrome/browser/ui/autofill/autofill_ui_type_util.h"
 #import "ios/chrome/browser/ui/payments/credit_card_edit_mediator.h"
@@ -187,9 +189,10 @@
     } else if (field.autofillUIType == AutofillUITypeCreditCardBillingAddress) {
       creditCard.set_billing_address_id(base::SysNSStringToUTF8(field.value));
     } else {
-      creditCard.SetRawInfo(
-          AutofillTypeFromAutofillUIType(field.autofillUIType),
-          base::SysNSStringToUTF16(field.value));
+      creditCard.SetInfo(autofill::AutofillType(AutofillTypeFromAutofillUIType(
+                             field.autofillUIType)),
+                         base::SysNSStringToUTF16(field.value),
+                         GetApplicationContext()->GetApplicationLocale());
     }
   }
 
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_mediator.mm b/ios/chrome/browser/ui/payments/credit_card_edit_mediator.mm
index 3630dd38..2f82561 100644
--- a/ios/chrome/browser/ui/payments/credit_card_edit_mediator.mm
+++ b/ios/chrome/browser/ui/payments/credit_card_edit_mediator.mm
@@ -10,6 +10,7 @@
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #import "components/autofill/ios/browser/credit_card_util.h"
+#include "components/payments/core/payment_request_data_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/payments/payment_request.h"
@@ -153,6 +154,14 @@
   return !_creditCard || autofill::IsCreditCardLocal(*_creditCard);
 }
 
+- (void)formatValueForEditorField:(EditorField*)field {
+  if (field.autofillUIType == AutofillUITypeCreditCardNumber) {
+    field.value = base::SysUTF16ToNSString(
+        payments::data_util::FormatCardNumberForDisplay(
+            base::SysNSStringToUTF16(field.value)));
+  }
+}
+
 - (UIImage*)iconIdentifyingEditorField:(EditorField*)field {
   // Early return if the field is not the credit card number field.
   if (field.autofillUIType != AutofillUITypeCreditCardNumber)
@@ -253,7 +262,10 @@
 
   // Credit Card number field.
   NSString* creditCardNumber =
-      _creditCard ? base::SysUTF16ToNSString(_creditCard->number()) : nil;
+      _creditCard ? base::SysUTF16ToNSString(
+                        payments::data_util::FormatCardNumberForDisplay(
+                            _creditCard->number()))
+                  : nil;
   fieldKey = [NSNumber numberWithInt:AutofillUITypeCreditCardNumber];
   EditorField* creditCardNumberField = self.fieldsMap[fieldKey];
   if (!creditCardNumberField) {
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm
index bd63f8c..1a134d3 100644
--- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm
@@ -384,7 +384,7 @@
 }
 
 // This method is called as the text is being typed in, pasted, or deleted. Asks
-// the delegate if the text should be changed. Should always return YES. During
+// the delegate if the text should be changed. Should always return NO. During
 // typing/pasting text, |newText| contains one or more new characters. When user
 // deletes text, |newText| is empty. |range| is the range of characters to be
 // replaced.
@@ -401,24 +401,29 @@
   AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>(
       [model itemAtIndexPath:indexPath]);
 
-  // Find the respective editor field and update its value.
+  // Find the respective editor field and update its value to the proposed text.
   NSNumber* key = [NSNumber numberWithInt:sectionIdentifier];
   EditorField* field = self.fieldsMap[key];
   DCHECK(field);
-  // Obtain the text being typed.
-  NSString* updatedText =
-      [textField.text stringByReplacingCharactersInRange:range
-                                              withString:newText];
-  field.value = updatedText;
+  field.value = [textField.text stringByReplacingCharactersInRange:range
+                                                        withString:newText];
+
+  // Format the proposed text if necessary.
+  [_dataSource formatValueForEditorField:field];
+
+  // Since this method is returning NO, update the text field's value now.
+  textField.text = field.value;
 
   // Get the icon that identifies the field value and reload the cell if the
   // icon changes.
   UIImage* oldIcon = item.identifyingIcon;
   item.identifyingIcon = [_dataSource iconIdentifyingEditorField:field];
-  if (item.identifyingIcon != oldIcon)
+  if (item.identifyingIcon != oldIcon) {
+    item.textFieldValue = field.value;
     [self reconfigureCellsForItems:@[ item ]];
+  }
 
-  return YES;
+  return NO;
 }
 
 #pragma mark - AutofillEditAccessoryDelegate
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h
index d3bc084..9393b6e 100644
--- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h
+++ b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h
@@ -30,6 +30,9 @@
 // Returns whether the header item should hide its background.
 - (BOOL)shouldHideBackgroundForHeaderItem;
 
+// Formats the editor field value, if necessary.
+- (void)formatValueForEditorField:(EditorField*)field;
+
 // Returns an icon that identifies |field| or its current value. May be nil.
 - (UIImage*)iconIdentifyingEditorField:(EditorField*)field;
 
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_unittest.mm b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_unittest.mm
index 21524ff4..b2c19ac 100644
--- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_unittest.mm
@@ -42,6 +42,9 @@
   return NO;
 }
 
+- (void)formatValueForEditorField:(EditorField*)field {
+}
+
 - (UIImage*)iconIdentifyingEditorField:(EditorField*)field {
   return nil;
 }
diff --git a/ios/net/cookies/cookie_store_ios.h b/ios/net/cookies/cookie_store_ios.h
index 85671c9..68ac20f 100644
--- a/ios/net/cookies/cookie_store_ios.h
+++ b/ios/net/cookies/cookie_store_ios.h
@@ -89,6 +89,10 @@
                                  CookieSameSite same_site,
                                  CookiePriority priority,
                                  const SetCookiesCallback& callback) override;
+  void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+                               bool secure_source,
+                               bool modify_http_only,
+                               const SetCookiesCallback& callback) override;
   void GetCookiesWithOptionsAsync(const GURL& url,
                                   const net::CookieOptions& options,
                                   const GetCookiesCallback& callback) override;
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 2ea0715..f24def3 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -25,6 +25,7 @@
 #include "base/task_runner_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
 #include "ios/net/cookies/cookie_creation_time_manager.h"
 #include "ios/net/cookies/cookie_store_ios_client.h"
 #include "ios/net/cookies/system_cookie_util.h"
@@ -404,8 +405,6 @@
   cookie_path = std::string(canon_path.data() + canon_path_component.begin,
                             canon_path_component.len);
 
-  // First create a CanonicalCookie, to normalize the arguments,
-  // particularly domain and path, and perform validation.
   std::unique_ptr<net::CanonicalCookie> canonical_cookie =
       base::MakeUnique<net::CanonicalCookie>(
           name, value, cookie_domain, cookie_path, creation_time,
@@ -428,6 +427,40 @@
     callback.Run(success);
 }
 
+void CookieStoreIOS::SetCanonicalCookieAsync(
+    std::unique_ptr<net::CanonicalCookie> cookie,
+    bool secure_source,
+    bool modify_http_only,
+    const SetCookiesCallback& callback) {
+  DCHECK(cookie->IsCanonical());
+  // The exclude_httponly() option would only be used by a javascript
+  // engine.
+  DCHECK(modify_http_only);
+
+  if (cookie->IsSecure() && !secure_source) {
+    if (!callback.is_null())
+      callback.Run(false);
+    return;
+  }
+
+  NSHTTPCookie* ns_cookie = SystemCookieFromCanonicalCookie(*cookie.get());
+
+  if (ns_cookie != nil) {
+    [system_store_ setCookie:ns_cookie];
+    creation_time_manager_->SetCreationTime(
+        ns_cookie,
+        creation_time_manager_->MakeUniqueCreationTime(
+            cookie->CreationDate().is_null() ? base::Time::Now()
+                                             : cookie->CreationDate()));
+    if (!callback.is_null())
+      callback.Run(true);
+    return;
+  }
+
+  if (!callback.is_null())
+    callback.Run(false);
+}
+
 void CookieStoreIOS::GetCookiesWithOptionsAsync(
     const GURL& url,
     const net::CookieOptions& options,
diff --git a/ios/net/cookies/cookie_store_ios_persistent.h b/ios/net/cookies/cookie_store_ios_persistent.h
index ce3bd470..18dba8fb 100644
--- a/ios/net/cookies/cookie_store_ios_persistent.h
+++ b/ios/net/cookies/cookie_store_ios_persistent.h
@@ -53,6 +53,10 @@
                                  CookieSameSite same_site,
                                  CookiePriority priority,
                                  const SetCookiesCallback& callback) override;
+  void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+                               bool secure_source,
+                               bool modify_http_only,
+                               const SetCookiesCallback& callback) override;
   void GetCookiesWithOptionsAsync(const GURL& url,
                                   const net::CookieOptions& options,
                                   const GetCookiesCallback& callback) override;
diff --git a/ios/net/cookies/cookie_store_ios_persistent.mm b/ios/net/cookies/cookie_store_ios_persistent.mm
index a0ed1ada..9a8527c 100644
--- a/ios/net/cookies/cookie_store_ios_persistent.mm
+++ b/ios/net/cookies/cookie_store_ios_persistent.mm
@@ -57,6 +57,18 @@
       WrapSetCallback(callback));
 }
 
+void CookieStoreIOSPersistent::SetCanonicalCookieAsync(
+    std::unique_ptr<CanonicalCookie> cookie,
+    bool secure_source,
+    bool modify_http_only,
+    const SetCookiesCallback& callback) {
+  DCHECK(thread_checker().CalledOnValidThread());
+
+  cookie_monster()->SetCanonicalCookieAsync(std::move(cookie), secure_source,
+                                            modify_http_only,
+                                            WrapSetCallback(callback));
+}
+
 void CookieStoreIOSPersistent::GetCookiesWithOptionsAsync(
     const GURL& url,
     const net::CookieOptions& options,
diff --git a/ios/showcase/payments/sc_payments_editor_coordinator.mm b/ios/showcase/payments/sc_payments_editor_coordinator.mm
index c1db284..2f451a10 100644
--- a/ios/showcase/payments/sc_payments_editor_coordinator.mm
+++ b/ios/showcase/payments/sc_payments_editor_coordinator.mm
@@ -105,6 +105,9 @@
   return NO;
 }
 
+- (void)formatValueForEditorField:(EditorField*)field {
+}
+
 - (UIImage*)iconIdentifyingEditorField:(EditorField*)field {
   return nil;
 }
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 7da17ca..c3996e8 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -57,6 +57,8 @@
     "navigation/crw_session_controller+private_constructors.h",
     "navigation/crw_session_controller.h",
     "navigation/crw_session_controller.mm",
+    "navigation/legacy_navigation_manager_impl.h",
+    "navigation/legacy_navigation_manager_impl.mm",
     "navigation/navigation_item_impl.h",
     "navigation/navigation_item_impl.mm",
     "navigation/navigation_item_impl_list.h",
@@ -65,7 +67,6 @@
     "navigation/navigation_item_storage_builder.mm",
     "navigation/navigation_manager_delegate.h",
     "navigation/navigation_manager_impl.h",
-    "navigation/navigation_manager_impl.mm",
     "navigation/navigation_manager_util.h",
     "navigation/navigation_manager_util.mm",
     "navigation/nscoder_util.h",
diff --git a/ios/web/navigation/legacy_navigation_manager_impl.h b/ios/web/navigation/legacy_navigation_manager_impl.h
new file mode 100644
index 0000000..04951cf
--- /dev/null
+++ b/ios/web/navigation/legacy_navigation_manager_impl.h
@@ -0,0 +1,125 @@
+// 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 IOS_WEB_NAVIGATION_LEGACY_NAVIGATION_MANAGER_IMPL_H_
+#define IOS_WEB_NAVIGATION_LEGACY_NAVIGATION_MANAGER_IMPL_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <vector>
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
+#import "ios/web/navigation/navigation_manager_impl.h"
+#import "ios/web/public/navigation_item_list.h"
+#include "ios/web/public/reload_type.h"
+#include "ui/base/page_transition_types.h"
+#include "url/gurl.h"
+
+@class CRWSessionController;
+
+namespace web {
+class BrowserState;
+class NavigationItem;
+struct Referrer;
+class NavigationManagerDelegate;
+class SessionStorageBuilder;
+
+// Implementation of NavigationManagerImpl.
+class LegacyNavigationManagerImpl : public NavigationManagerImpl {
+ public:
+  LegacyNavigationManagerImpl();
+  ~LegacyNavigationManagerImpl() override;
+
+  // NavigationManagerImpl:
+  void SetDelegate(NavigationManagerDelegate* delegate) override;
+  void SetBrowserState(BrowserState* browser_state) override;
+  void SetSessionController(CRWSessionController* session_controller) override;
+  void InitializeSession() override;
+  void ReplaceSessionHistory(std::vector<std::unique_ptr<NavigationItem>> items,
+                             int current_index) override;
+  void OnNavigationItemsPruned(size_t pruned_item_count) override;
+  void OnNavigationItemChanged() override;
+  void OnNavigationItemCommitted() override;
+  CRWSessionController* GetSessionController() const override;
+  void AddTransientItem(const GURL& url) override;
+  void AddPendingItem(
+      const GURL& url,
+      const web::Referrer& referrer,
+      ui::PageTransition navigation_type,
+      NavigationInitiationType initiation_type,
+      UserAgentOverrideOption user_agent_override_option) override;
+  void CommitPendingItem() override;
+  std::unique_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
+  GetTransientURLRewriters() override;
+  void RemoveTransientURLRewriters() override;
+  int GetIndexForOffset(int offset) const override;
+
+  // NavigationManager:
+  BrowserState* GetBrowserState() const override;
+  WebState* GetWebState() const override;
+  NavigationItem* GetVisibleItem() const override;
+  NavigationItem* GetLastCommittedItem() const override;
+  NavigationItem* GetPendingItem() const override;
+  NavigationItem* GetTransientItem() const override;
+  void DiscardNonCommittedItems() override;
+  void LoadURLWithParams(const NavigationManager::WebLoadParams&) override;
+  void AddTransientURLRewriter(
+      BrowserURLRewriter::URLRewriter rewriter) override;
+  int GetItemCount() const override;
+  NavigationItem* GetItemAtIndex(size_t index) const override;
+  int GetIndexOfItem(const NavigationItem* item) const override;
+  int GetPendingItemIndex() const override;
+  int GetLastCommittedItemIndex() const override;
+  bool RemoveItemAtIndex(int index) override;
+  bool CanGoBack() const override;
+  bool CanGoForward() const override;
+  bool CanGoToOffset(int offset) const override;
+  void GoBack() override;
+  void GoForward() override;
+  void GoToIndex(int index) override;
+  void Reload(ReloadType reload_type, bool check_for_reposts) override;
+  NavigationItemList GetBackwardItems() const override;
+  NavigationItemList GetForwardItems() const override;
+  void CopyStateFromAndPrune(const NavigationManager* source) override;
+  bool CanPruneAllButLastCommittedItem() const override;
+
+ private:
+  // The SessionStorageBuilder functions require access to private variables of
+  // NavigationManagerImpl.
+  friend SessionStorageBuilder;
+
+  // NavigationManagerImpl methods used by SessionStorageBuilder.
+  NavigationItemImpl* GetNavigationItemImplAtIndex(size_t index) const override;
+  size_t GetPreviousItemIndex() const override;
+
+  // Returns true if the PageTransition for the underlying navigation item at
+  // |index| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
+  bool IsRedirectItemAtIndex(int index) const;
+
+  // Returns the most recent NavigationItem that does not have an app-specific
+  // URL.
+  NavigationItem* GetLastCommittedNonAppSpecificItem() const;
+
+  // The primary delegate for this manager.
+  NavigationManagerDelegate* delegate_;
+
+  // The BrowserState that is associated with this instance.
+  BrowserState* browser_state_;
+
+  // CRWSessionController that backs this instance.
+  // TODO(stuartmorgan): Fold CRWSessionController into this class.
+  base::scoped_nsobject<CRWSessionController> session_controller_;
+
+  // List of transient url rewriters added by |AddTransientURLRewriter()|.
+  std::unique_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
+      transient_url_rewriters_;
+
+  DISALLOW_COPY_AND_ASSIGN(LegacyNavigationManagerImpl);
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_NAVIGATION_LEGACY_NAVIGATION_MANAGER_IMPL_H_
diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/legacy_navigation_manager_impl.mm
similarity index 77%
rename from ios/web/navigation/navigation_manager_impl.mm
rename to ios/web/navigation/legacy_navigation_manager_impl.mm
index 46f7e40..8609620 100644
--- a/ios/web/navigation/navigation_manager_impl.mm
+++ b/ios/web/navigation/legacy_navigation_manager_impl.mm
@@ -1,8 +1,8 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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.
 
-#import "ios/web/navigation/navigation_manager_impl.h"
+#import "ios/web/navigation/legacy_navigation_manager_impl.h"
 
 #include <stddef.h>
 
@@ -71,34 +71,35 @@
   return *this;
 }
 
-NavigationManagerImpl::NavigationManagerImpl()
+LegacyNavigationManagerImpl::LegacyNavigationManagerImpl()
     : delegate_(nullptr), browser_state_(nullptr) {}
 
-NavigationManagerImpl::~NavigationManagerImpl() {
+LegacyNavigationManagerImpl::~LegacyNavigationManagerImpl() {
   [session_controller_ setNavigationManager:nullptr];
 }
 
-void NavigationManagerImpl::SetDelegate(NavigationManagerDelegate* delegate) {
+void LegacyNavigationManagerImpl::SetDelegate(
+    NavigationManagerDelegate* delegate) {
   delegate_ = delegate;
 }
 
-void NavigationManagerImpl::SetBrowserState(BrowserState* browser_state) {
+void LegacyNavigationManagerImpl::SetBrowserState(BrowserState* browser_state) {
   browser_state_ = browser_state;
   [session_controller_ setBrowserState:browser_state];
 }
 
-void NavigationManagerImpl::SetSessionController(
+void LegacyNavigationManagerImpl::SetSessionController(
     CRWSessionController* session_controller) {
   session_controller_.reset(session_controller);
   [session_controller_ setNavigationManager:this];
 }
 
-void NavigationManagerImpl::InitializeSession() {
+void LegacyNavigationManagerImpl::InitializeSession() {
   SetSessionController(
       [[CRWSessionController alloc] initWithBrowserState:browser_state_]);
 }
 
-void NavigationManagerImpl::ReplaceSessionHistory(
+void LegacyNavigationManagerImpl::ReplaceSessionHistory(
     std::vector<std::unique_ptr<web::NavigationItem>> items,
     int lastCommittedItemIndex) {
   SetSessionController([[CRWSessionController alloc]
@@ -107,15 +108,16 @@
       lastCommittedItemIndex:lastCommittedItemIndex]);
 }
 
-void NavigationManagerImpl::OnNavigationItemsPruned(size_t pruned_item_count) {
+void LegacyNavigationManagerImpl::OnNavigationItemsPruned(
+    size_t pruned_item_count) {
   delegate_->OnNavigationItemsPruned(pruned_item_count);
 }
 
-void NavigationManagerImpl::OnNavigationItemChanged() {
+void LegacyNavigationManagerImpl::OnNavigationItemChanged() {
   delegate_->OnNavigationItemChanged();
 }
 
-void NavigationManagerImpl::OnNavigationItemCommitted() {
+void LegacyNavigationManagerImpl::OnNavigationItemCommitted() {
   LoadCommittedDetails details;
   details.item = GetLastCommittedItem();
   DCHECK(details.item);
@@ -133,11 +135,12 @@
   delegate_->OnNavigationItemCommitted(details);
 }
 
-CRWSessionController* NavigationManagerImpl::GetSessionController() {
+CRWSessionController* LegacyNavigationManagerImpl::GetSessionController()
+    const {
   return session_controller_;
 }
 
-void NavigationManagerImpl::AddTransientItem(const GURL& url) {
+void LegacyNavigationManagerImpl::AddTransientItem(const GURL& url) {
   [session_controller_ addTransientItemWithURL:url];
 
   // TODO(crbug.com/676129): Transient item is only supposed to be added for
@@ -150,7 +153,7 @@
   GetTransientItem()->SetUserAgentType(item->GetUserAgentType());
 }
 
-void NavigationManagerImpl::AddPendingItem(
+void LegacyNavigationManagerImpl::AddPendingItem(
     const GURL& url,
     const web::Referrer& referrer,
     ui::PageTransition navigation_type,
@@ -204,44 +207,44 @@
   }
 }
 
-void NavigationManagerImpl::CommitPendingItem() {
+void LegacyNavigationManagerImpl::CommitPendingItem() {
   [session_controller_ commitPendingItem];
 }
 
-BrowserState* NavigationManagerImpl::GetBrowserState() const {
+BrowserState* LegacyNavigationManagerImpl::GetBrowserState() const {
   return browser_state_;
 }
 
-WebState* NavigationManagerImpl::GetWebState() const {
+WebState* LegacyNavigationManagerImpl::GetWebState() const {
   return delegate_->GetWebState();
 }
 
-NavigationItem* NavigationManagerImpl::GetVisibleItem() const {
+NavigationItem* LegacyNavigationManagerImpl::GetVisibleItem() const {
   return [session_controller_ visibleItem];
 }
 
-NavigationItem* NavigationManagerImpl::GetLastCommittedItem() const {
+NavigationItem* LegacyNavigationManagerImpl::GetLastCommittedItem() const {
   return [session_controller_ lastCommittedItem];
 }
 
-NavigationItem* NavigationManagerImpl::GetPendingItem() const {
+NavigationItem* LegacyNavigationManagerImpl::GetPendingItem() const {
   return [session_controller_ pendingItem];
 }
 
-NavigationItem* NavigationManagerImpl::GetTransientItem() const {
+NavigationItem* LegacyNavigationManagerImpl::GetTransientItem() const {
   return [session_controller_ transientItem];
 }
 
-void NavigationManagerImpl::DiscardNonCommittedItems() {
+void LegacyNavigationManagerImpl::DiscardNonCommittedItems() {
   [session_controller_ discardNonCommittedItems];
 }
 
-void NavigationManagerImpl::LoadURLWithParams(
+void LegacyNavigationManagerImpl::LoadURLWithParams(
     const NavigationManager::WebLoadParams& params) {
   delegate_->LoadURLWithParams(params);
 }
 
-void NavigationManagerImpl::AddTransientURLRewriter(
+void LegacyNavigationManagerImpl::AddTransientURLRewriter(
     BrowserURLRewriter::URLRewriter rewriter) {
   DCHECK(rewriter);
   if (!transient_url_rewriters_) {
@@ -251,20 +254,26 @@
   transient_url_rewriters_->push_back(rewriter);
 }
 
-int NavigationManagerImpl::GetItemCount() const {
+int LegacyNavigationManagerImpl::GetItemCount() const {
   return [session_controller_ items].size();
 }
 
-NavigationItem* NavigationManagerImpl::GetItemAtIndex(size_t index) const {
+NavigationItem* LegacyNavigationManagerImpl::GetItemAtIndex(
+    size_t index) const {
+  return GetNavigationItemImplAtIndex(index);
+}
+
+NavigationItemImpl* LegacyNavigationManagerImpl::GetNavigationItemImplAtIndex(
+    size_t index) const {
   return [session_controller_ itemAtIndex:index];
 }
 
-int NavigationManagerImpl::GetIndexOfItem(
+int LegacyNavigationManagerImpl::GetIndexOfItem(
     const web::NavigationItem* item) const {
   return [session_controller_ indexOfItem:item];
 }
 
-int NavigationManagerImpl::GetPendingItemIndex() const {
+int LegacyNavigationManagerImpl::GetPendingItemIndex() const {
   if (GetPendingItem()) {
     if ([session_controller_ pendingItemIndex] != -1) {
       return [session_controller_ pendingItemIndex];
@@ -276,13 +285,13 @@
   return -1;
 }
 
-int NavigationManagerImpl::GetLastCommittedItemIndex() const {
+int LegacyNavigationManagerImpl::GetLastCommittedItemIndex() const {
   if (GetItemCount() == 0)
     return -1;
   return [session_controller_ lastCommittedItemIndex];
 }
 
-bool NavigationManagerImpl::RemoveItemAtIndex(int index) {
+bool LegacyNavigationManagerImpl::RemoveItemAtIndex(int index) {
   if (index == GetLastCommittedItemIndex() || index == GetPendingItemIndex())
     return false;
 
@@ -293,41 +302,41 @@
   return true;
 }
 
-bool NavigationManagerImpl::CanGoBack() const {
+bool LegacyNavigationManagerImpl::CanGoBack() const {
   return CanGoToOffset(-1);
 }
 
-bool NavigationManagerImpl::CanGoForward() const {
+bool LegacyNavigationManagerImpl::CanGoForward() const {
   return CanGoToOffset(1);
 }
 
-bool NavigationManagerImpl::CanGoToOffset(int offset) const {
+bool LegacyNavigationManagerImpl::CanGoToOffset(int offset) const {
   int index = GetIndexForOffset(offset);
   return 0 <= index && index < GetItemCount();
 }
 
-void NavigationManagerImpl::GoBack() {
+void LegacyNavigationManagerImpl::GoBack() {
   delegate_->GoToIndex(GetIndexForOffset(-1));
 }
 
-void NavigationManagerImpl::GoForward() {
+void LegacyNavigationManagerImpl::GoForward() {
   delegate_->GoToIndex(GetIndexForOffset(1));
 }
 
-void NavigationManagerImpl::GoToIndex(int index) {
+void LegacyNavigationManagerImpl::GoToIndex(int index) {
   delegate_->GoToIndex(index);
 }
 
-NavigationItemList NavigationManagerImpl::GetBackwardItems() const {
+NavigationItemList LegacyNavigationManagerImpl::GetBackwardItems() const {
   return [session_controller_ backwardItems];
 }
 
-NavigationItemList NavigationManagerImpl::GetForwardItems() const {
+NavigationItemList LegacyNavigationManagerImpl::GetForwardItems() const {
   return [session_controller_ forwardItems];
 }
 
-void NavigationManagerImpl::Reload(ReloadType reload_type,
-                                   bool check_for_reposts) {
+void LegacyNavigationManagerImpl::Reload(ReloadType reload_type,
+                                         bool check_for_reposts) {
   if (!GetTransientItem() && !GetPendingItem() && !GetLastCommittedItem())
     return;
 
@@ -355,28 +364,29 @@
   delegate_->Reload();
 }
 
-void NavigationManagerImpl::CopyStateFromAndPrune(
+void LegacyNavigationManagerImpl::CopyStateFromAndPrune(
     const NavigationManager* manager) {
   DCHECK(manager);
   CRWSessionController* other_session =
-      static_cast<const NavigationManagerImpl*>(manager)->session_controller_;
+      static_cast<const NavigationManagerImpl*>(manager)
+          ->GetSessionController();
   [session_controller_ copyStateFromSessionControllerAndPrune:other_session];
 }
 
-bool NavigationManagerImpl::CanPruneAllButLastCommittedItem() const {
+bool LegacyNavigationManagerImpl::CanPruneAllButLastCommittedItem() const {
   return [session_controller_ canPruneAllButLastCommittedItem];
 }
 
 std::unique_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
-NavigationManagerImpl::GetTransientURLRewriters() {
+LegacyNavigationManagerImpl::GetTransientURLRewriters() {
   return std::move(transient_url_rewriters_);
 }
 
-void NavigationManagerImpl::RemoveTransientURLRewriters() {
+void LegacyNavigationManagerImpl::RemoveTransientURLRewriters() {
   transient_url_rewriters_.reset();
 }
 
-int NavigationManagerImpl::GetIndexForOffset(int offset) const {
+int LegacyNavigationManagerImpl::GetIndexForOffset(int offset) const {
   int result = [session_controller_ pendingItemIndex] == -1
                    ? GetLastCommittedItemIndex()
                    : static_cast<int>([session_controller_ pendingItemIndex]);
@@ -424,15 +434,15 @@
   return result;
 }
 
-bool NavigationManagerImpl::IsRedirectItemAtIndex(int index) const {
+bool LegacyNavigationManagerImpl::IsRedirectItemAtIndex(int index) const {
   DCHECK_GE(index, 0);
   DCHECK_LT(index, GetItemCount());
   ui::PageTransition transition = GetItemAtIndex(index)->GetTransitionType();
   return transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK;
 }
 
-NavigationItem* NavigationManagerImpl::GetLastCommittedNonAppSpecificItem()
-    const {
+NavigationItem*
+LegacyNavigationManagerImpl::GetLastCommittedNonAppSpecificItem() const {
   int index = GetLastCommittedItemIndex();
   if (index == -1)
     return nullptr;
@@ -446,4 +456,8 @@
   return nullptr;
 }
 
+size_t LegacyNavigationManagerImpl::GetPreviousItemIndex() const {
+  return [session_controller_ previousItemIndex];
+}
+
 }  // namespace web
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index fb4fc7d..0e2a9e3 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -12,6 +12,7 @@
 
 #import "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
+#import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/public/navigation_item_list.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/reload_type.h"
@@ -23,7 +24,6 @@
 namespace web {
 class BrowserState;
 class NavigationItem;
-struct Referrer;
 class NavigationManagerDelegate;
 class SessionStorageBuilder;
 
@@ -49,12 +49,11 @@
 // Generally mirrors upstream's NavigationController.
 class NavigationManagerImpl : public NavigationManager {
  public:
-  NavigationManagerImpl();
-  ~NavigationManagerImpl() override;
+  ~NavigationManagerImpl() override {}
 
   // Setters for NavigationManagerDelegate and BrowserState.
-  void SetDelegate(NavigationManagerDelegate* delegate);
-  void SetBrowserState(BrowserState* browser_state);
+  virtual void SetDelegate(NavigationManagerDelegate* delegate) = 0;
+  virtual void SetBrowserState(BrowserState* browser_state) = 0;
 
   // Sets the CRWSessionController that backs this object.
   // Keeps a strong reference to |session_controller|.
@@ -64,121 +63,80 @@
   // TODO(stuartmorgan): Also move deserialization of CRWSessionControllers
   // under the control of this class, and move the bulk of CRWSessionController
   // logic into it.
-  void SetSessionController(CRWSessionController* session_controller);
+  virtual void SetSessionController(
+      CRWSessionController* session_controller) = 0;
 
   // Initializes a new session history.
-  void InitializeSession();
+  virtual void InitializeSession() = 0;
 
   // Replace the session history with a new one, where |items| is the
   // complete set of navigation items in the new history, and |current_index|
   // is the index of the currently active item.
-  void ReplaceSessionHistory(std::vector<std::unique_ptr<NavigationItem>> items,
-                             int current_index);
+  virtual void ReplaceSessionHistory(
+      std::vector<std::unique_ptr<NavigationItem>> items,
+      int current_index) = 0;
 
   // Helper functions for notifying WebStateObservers of changes.
   // TODO(stuartmorgan): Make these private once the logic triggering them moves
   // into this layer.
-  void OnNavigationItemsPruned(size_t pruned_item_count);
-  void OnNavigationItemChanged();
-  void OnNavigationItemCommitted();
+  virtual void OnNavigationItemsPruned(size_t pruned_item_count) = 0;
+  virtual void OnNavigationItemChanged() = 0;
+  virtual void OnNavigationItemCommitted() = 0;
 
   // Temporary accessors and content/ class pass-throughs.
   // TODO(stuartmorgan): Re-evaluate this list once the refactorings have
   // settled down.
-  CRWSessionController* GetSessionController();
+  virtual CRWSessionController* GetSessionController() const = 0;
 
   // Adds a transient item with the given URL. A transient item will be
   // discarded on any navigation.
-  void AddTransientItem(const GURL& url);
+  virtual void AddTransientItem(const GURL& url) = 0;
 
   // Adds a new item with the given url, referrer, navigation type, initiation
   // type and user agent override option, making it the pending item. If pending
   // item is the same as the current item, this does nothing. |referrer| may be
   // nil if there isn't one. The item starts out as pending, and will be lost
   // unless |-commitPendingItem| is called.
-  void AddPendingItem(const GURL& url,
-                      const web::Referrer& referrer,
-                      ui::PageTransition navigation_type,
-                      NavigationInitiationType initiation_type,
-                      UserAgentOverrideOption user_agent_override_option);
+  virtual void AddPendingItem(
+      const GURL& url,
+      const web::Referrer& referrer,
+      ui::PageTransition navigation_type,
+      NavigationInitiationType initiation_type,
+      UserAgentOverrideOption user_agent_override_option) = 0;
 
   // Commits the pending item, if any.
-  void CommitPendingItem();
-
-  // NavigationManager:
-  BrowserState* GetBrowserState() const override;
-  WebState* GetWebState() const override;
-  NavigationItem* GetVisibleItem() const override;
-  NavigationItem* GetLastCommittedItem() const override;
-  NavigationItem* GetPendingItem() const override;
-  NavigationItem* GetTransientItem() const override;
-  void DiscardNonCommittedItems() override;
-  void LoadURLWithParams(const NavigationManager::WebLoadParams&) override;
-  void AddTransientURLRewriter(
-      BrowserURLRewriter::URLRewriter rewriter) override;
-  int GetItemCount() const override;
-  NavigationItem* GetItemAtIndex(size_t index) const override;
-  int GetIndexOfItem(const NavigationItem* item) const override;
-  int GetPendingItemIndex() const override;
-  int GetLastCommittedItemIndex() const override;
-  bool RemoveItemAtIndex(int index) override;
-  bool CanGoBack() const override;
-  bool CanGoForward() const override;
-  bool CanGoToOffset(int offset) const override;
-  void GoBack() override;
-  void GoForward() override;
-  void GoToIndex(int index) override;
-  void Reload(ReloadType reload_type, bool check_for_reposts) override;
-  NavigationItemList GetBackwardItems() const override;
-  NavigationItemList GetForwardItems() const override;
-  void CopyStateFromAndPrune(const NavigationManager* source) override;
-  bool CanPruneAllButLastCommittedItem() const override;
+  virtual void CommitPendingItem() = 0;
 
   // Returns the current list of transient url rewriters, passing ownership to
   // the caller.
   // TODO(crbug.com/546197): remove once NavigationItem creation occurs in this
   // class.
-  std::unique_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
-  GetTransientURLRewriters();
+  virtual std::unique_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
+  GetTransientURLRewriters() = 0;
 
   // Called to reset the transient url rewriter list.
-  void RemoveTransientURLRewriters();
+  virtual void RemoveTransientURLRewriters() = 0;
 
   // Returns the navigation index that differs from the current item (or pending
   // item if it exists) by the specified |offset|, skipping redirect navigation
   // items. The index returned is not guaranteed to be valid.
   // TODO(crbug.com/661316): Make this method private once navigation code is
   // moved from CRWWebController to NavigationManagerImpl.
-  int GetIndexForOffset(int offset) const;
+  virtual int GetIndexForOffset(int offset) const = 0;
 
- private:
+ protected:
   // The SessionStorageBuilder functions require access to private variables of
   // NavigationManagerImpl.
   friend SessionStorageBuilder;
 
-  // Returns true if the PageTransition for the underlying navigation item at
-  // |index| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
-  bool IsRedirectItemAtIndex(int index) const;
+  // Identical to GetItemAtIndex() but returns the underlying NavigationItemImpl
+  // instead of the public NavigationItem interface. This is used by
+  // SessionStorageBuilder to persist session state.
+  virtual NavigationItemImpl* GetNavigationItemImplAtIndex(
+      size_t index) const = 0;
 
-  // Returns the most recent NavigationItem that does not have an app-specific
-  // URL.
-  NavigationItem* GetLastCommittedNonAppSpecificItem() const;
-
-  // The primary delegate for this manager.
-  NavigationManagerDelegate* delegate_;
-
-  // The BrowserState that is associated with this instance.
-  BrowserState* browser_state_;
-
-  // CRWSessionController that backs this instance.
-  // TODO(stuartmorgan): Fold CRWSessionController into this class.
-  base::scoped_nsobject<CRWSessionController> session_controller_;
-
-  // List of transient url rewriters added by |AddTransientURLRewriter()|.
-  std::unique_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
-      transient_url_rewriters_;
-
-  DISALLOW_COPY_AND_ASSIGN(NavigationManagerImpl);
+  // Returns the index of the previous item. Only used by SessionStorageBuilder.
+  virtual size_t GetPreviousItemIndex() const = 0;
 };
 
 }  // namespace web
diff --git a/ios/web/navigation/navigation_manager_impl_unittest.mm b/ios/web/navigation/navigation_manager_impl_unittest.mm
index 899d7e3..e57607ae 100644
--- a/ios/web/navigation/navigation_manager_impl_unittest.mm
+++ b/ios/web/navigation/navigation_manager_impl_unittest.mm
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/mac/bind_objc_block.h"
 #import "ios/web/navigation/crw_session_controller+private_constructors.h"
+#import "ios/web/navigation/legacy_navigation_manager_impl.h"
 #import "ios/web/navigation/navigation_manager_delegate.h"
 #include "ios/web/public/navigation_item.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
@@ -56,10 +57,20 @@
 };
 }  // namespace
 
-// Test fixture for NavigationManagerImpl testing.
-class NavigationManagerTest : public PlatformTest {
+// Programmatic test fixture for NavigationManagerImpl testing.
+// GetParam() chooses whether to run tests on LegacyNavigationManagerImpl or
+// (the soon-to-be-implemented) WKBasedNavigationManagerImpl.
+// TODO(crbug.com/734150): cleanup the LegacyNavigationManagerImpl use case.
+class NavigationManagerTest : public PlatformTest,
+                              public ::testing::WithParamInterface<bool> {
  protected:
-  NavigationManagerTest() : manager_(new NavigationManagerImpl()) {
+  NavigationManagerTest() {
+    bool test_legacy_navigation_manager = GetParam();
+    if (test_legacy_navigation_manager) {
+      manager_.reset(new LegacyNavigationManagerImpl);
+    } else {
+      DCHECK(false) << "Not implemented.";
+    }
     // Setup rewriter.
     BrowserURLRewriter::GetInstance()->AddURLRewriter(UrlRewriter);
     url::AddStandardScheme(kSchemeToRewrite, url::SCHEME_WITHOUT_PORT);
@@ -72,6 +83,7 @@
   }
   CRWSessionController* session_controller() { return controller_; }
   NavigationManagerImpl* navigation_manager() { return manager_.get(); }
+
   TestNavigationManagerDelegate navigation_manager_delegate() {
     return delegate_;
   }
@@ -84,7 +96,7 @@
 };
 
 // Tests state of an empty navigation manager.
-TEST_F(NavigationManagerTest, EmptyManager) {
+TEST_P(NavigationManagerTest, EmptyManager) {
   EXPECT_EQ(0, navigation_manager()->GetItemCount());
   EXPECT_EQ(-1, navigation_manager()->GetLastCommittedItemIndex());
   EXPECT_EQ(-1, navigation_manager()->GetLastCommittedItemIndex());
@@ -94,7 +106,7 @@
 }
 
 // Tests that GetPendingItemIndex() returns -1 if there is no pending entry.
-TEST_F(NavigationManagerTest, GetPendingItemIndexWithoutPendingEntry) {
+TEST_P(NavigationManagerTest, GetPendingItemIndexWithoutPendingEntry) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -105,7 +117,7 @@
 
 // Tests that GetPendingItemIndex() returns current item index if there is a
 // pending entry.
-TEST_F(NavigationManagerTest, GetPendingItemIndexWithPendingEntry) {
+TEST_P(NavigationManagerTest, GetPendingItemIndexWithPendingEntry) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -120,7 +132,7 @@
 
 // Tests that GetPendingItemIndex() returns same index as was set by
 // -[CRWSessionController setPendingItemIndex:].
-TEST_F(NavigationManagerTest, GetPendingItemIndexWithIndexedPendingEntry) {
+TEST_P(NavigationManagerTest, GetPendingItemIndexWithIndexedPendingEntry) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -139,14 +151,14 @@
 
 // Tests that going back or negative offset is not possible without a committed
 // item.
-TEST_F(NavigationManagerTest, CanGoBackWithoutCommitedItem) {
+TEST_P(NavigationManagerTest, CanGoBackWithoutCommitedItem) {
   EXPECT_FALSE(navigation_manager()->CanGoBack());
   EXPECT_FALSE(navigation_manager()->CanGoToOffset(-1));
 }
 
 // Tests that going back or negative offset is not possible if there is a
 // transient item, but not committed items.
-TEST_F(NavigationManagerTest, CanGoBackWithTransientItem) {
+TEST_P(NavigationManagerTest, CanGoBackWithTransientItem) {
   [session_controller() addTransientItemWithURL:GURL("http://www.url.com")];
 
   EXPECT_FALSE(navigation_manager()->CanGoBack());
@@ -155,7 +167,7 @@
 
 // Tests that going back or negative offset is possible if there is a transient
 // item and at least one committed item.
-TEST_F(NavigationManagerTest, CanGoBackWithTransientItemAndCommittedItem) {
+TEST_P(NavigationManagerTest, CanGoBackWithTransientItemAndCommittedItem) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -169,7 +181,7 @@
 
 // Tests that going back or negative offset is not possible if there is ony one
 // committed item and no transient item.
-TEST_F(NavigationManagerTest, CanGoBackWithSingleCommitedItem) {
+TEST_P(NavigationManagerTest, CanGoBackWithSingleCommitedItem) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -181,7 +193,7 @@
 }
 
 // Tests going back possibility with multiple committed items.
-TEST_F(NavigationManagerTest, CanGoBackWithMultipleCommitedItems) {
+TEST_P(NavigationManagerTest, CanGoBackWithMultipleCommitedItems) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -216,14 +228,14 @@
 
 // Tests that going forward or positive offset is not possible without a
 // committed item.
-TEST_F(NavigationManagerTest, CanGoForwardWithoutCommitedItem) {
+TEST_P(NavigationManagerTest, CanGoForwardWithoutCommitedItem) {
   EXPECT_FALSE(navigation_manager()->CanGoForward());
   EXPECT_FALSE(navigation_manager()->CanGoToOffset(1));
 }
 
 // Tests that going forward or positive offset is not possible if there is ony
 // one committed item and no transient item.
-TEST_F(NavigationManagerTest, CanGoForwardWithSingleCommitedItem) {
+TEST_P(NavigationManagerTest, CanGoForwardWithSingleCommitedItem) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -235,7 +247,7 @@
 }
 
 // Tests going forward possibility with multiple committed items.
-TEST_F(NavigationManagerTest, CanGoForwardWithMultipleCommitedEntries) {
+TEST_P(NavigationManagerTest, CanGoForwardWithMultipleCommitedEntries) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -275,7 +287,7 @@
 // Tests CanGoToOffset API for positive, negative and zero delta. Tested
 // navigation manager will have redirect entries to make sure they are
 // appropriately skipped.
-TEST_F(NavigationManagerTest, OffsetsWithoutPendingIndex) {
+TEST_P(NavigationManagerTest, OffsetsWithoutPendingIndex) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com/0"), Referrer(), ui::PAGE_TRANSITION_LINK,
       web::NavigationInitiationType::USER_INITIATED,
@@ -502,7 +514,7 @@
 // Tests offsets with pending transient entries (specifically gong back and
 // forward from a pending navigation entry that is added to the middle of the
 // navigation stack).
-TEST_F(NavigationManagerTest, OffsetsWithPendingTransientEntry) {
+TEST_P(NavigationManagerTest, OffsetsWithPendingTransientEntry) {
   // Create a transient item in the middle of the navigation stack and go back
   // to it (pending index is 1, current index is 2).
   navigation_manager()->AddPendingItem(
@@ -542,7 +554,7 @@
 
 // Tests that when given a pending item, adding a new pending item replaces the
 // existing pending item if their URLs are different.
-TEST_F(NavigationManagerTest, ReplacePendingItemIfDiffernetURL) {
+TEST_P(NavigationManagerTest, ReplacePendingItemIfDiffernetURL) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -565,7 +577,7 @@
 // Tests that when given a pending item, adding a new pending item with the same
 // URL doesn't replace the existing pending item if new pending item is not a
 // form submission.
-TEST_F(NavigationManagerTest, NotReplaceSameUrlPendingItemIfNotFormSubmission) {
+TEST_P(NavigationManagerTest, NotReplaceSameUrlPendingItemIfNotFormSubmission) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -591,7 +603,7 @@
 // Tests that when given a pending item, adding a new pending item with the same
 // URL replaces the existing pending item if new pending item is a form
 // submission while existing pending item is not.
-TEST_F(NavigationManagerTest, ReplaceSameUrlPendingItemIfFormSubmission) {
+TEST_P(NavigationManagerTest, ReplaceSameUrlPendingItemIfFormSubmission) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -617,7 +629,7 @@
 // Tests that when given a pending item, adding a new pending item with the same
 // URL doesn't replace the existing pending item if the user agent override
 // option is INHERIT.
-TEST_F(NavigationManagerTest, NotReplaceSameUrlPendingItemIfOverrideInherit) {
+TEST_P(NavigationManagerTest, NotReplaceSameUrlPendingItemIfOverrideInherit) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -644,7 +656,7 @@
 // Tests that when given a pending item, adding a new pending item with the same
 // URL replaces the existing pending item if the user agent override option is
 // DESKTOP.
-TEST_F(NavigationManagerTest, ReplaceSameUrlPendingItemIfOverrideDesktop) {
+TEST_P(NavigationManagerTest, ReplaceSameUrlPendingItemIfOverrideDesktop) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -672,7 +684,7 @@
 // Tests that when given a pending item, adding a new pending item with the same
 // URL replaces the existing pending item if the user agent override option is
 // MOBILE.
-TEST_F(NavigationManagerTest, ReplaceSameUrlPendingItemIfOverrideMobile) {
+TEST_P(NavigationManagerTest, ReplaceSameUrlPendingItemIfOverrideMobile) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -699,7 +711,7 @@
 
 // Tests that when the last committed item exists, adding a pending item
 // succeeds if the new item's URL is different from the last committed item.
-TEST_F(NavigationManagerTest, AddPendingItemIfDiffernetURL) {
+TEST_P(NavigationManagerTest, AddPendingItemIfDiffernetURL) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -723,7 +735,7 @@
 
 // Tests that when the last committed item exists, adding a pending item with
 // the same URL fails if the new item is not form submission.
-TEST_F(NavigationManagerTest, NotAddSameUrlPendingItemIfNotFormSubmission) {
+TEST_P(NavigationManagerTest, NotAddSameUrlPendingItemIfNotFormSubmission) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -748,7 +760,7 @@
 // Tests that when the last committed item exists, adding a pending item with
 // the same URL succeeds if the new item is a form submission while the last
 // committed item is not.
-TEST_F(NavigationManagerTest, AddSameUrlPendingItemIfFormSubmission) {
+TEST_P(NavigationManagerTest, AddSameUrlPendingItemIfFormSubmission) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -777,7 +789,7 @@
 // Tests that when the last committed item exists, adding a pending item with
 // the same URL fails if both the new item and the last committed item are form
 // submissions.
-TEST_F(NavigationManagerTest,
+TEST_P(NavigationManagerTest,
        NotAddSameUrlPendingItemIfDuplicateFormSubmission) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
@@ -799,7 +811,7 @@
 
 // Tests that when the last committed item exists, adding a pending item with
 // the same URL fails if the user agent override option is INHERIT.
-TEST_F(NavigationManagerTest, NotAddSameUrlPendingItemIfOverrideInherit) {
+TEST_P(NavigationManagerTest, NotAddSameUrlPendingItemIfOverrideInherit) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -822,7 +834,7 @@
 
 // Tests that when the last committed item exists, adding a pending item with
 // the same URL succeeds if the user agent override option is DESKTOP.
-TEST_F(NavigationManagerTest, AddSameUrlPendingItemIfOverrideDesktop) {
+TEST_P(NavigationManagerTest, AddSameUrlPendingItemIfOverrideDesktop) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -851,7 +863,7 @@
 
 // Tests that when the last committed item exists, adding a pending item with
 // the same URL succeeds if the user agent override option is MOBILE.
-TEST_F(NavigationManagerTest, AddSameUrlPendingItemIfOverrideMobile) {
+TEST_P(NavigationManagerTest, AddSameUrlPendingItemIfOverrideMobile) {
   GURL existing_url = GURL("http://www.existing.com");
   navigation_manager()->AddPendingItem(
       existing_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -879,7 +891,7 @@
 
 // Tests that desktop user agent can be enforced to use for next pending item
 // when UserAgentOverrideOption is DESKTOP.
-TEST_F(NavigationManagerTest, OverrideUserAgentWithDesktop) {
+TEST_P(NavigationManagerTest, OverrideUserAgentWithDesktop) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.1.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -902,7 +914,7 @@
 
 // Tests that mobile user agent can be enforced to use for next pending item
 // when UserAgentOverrideOption is MOBILE.
-TEST_F(NavigationManagerTest, OverrideUserAgentWithMobile) {
+TEST_P(NavigationManagerTest, OverrideUserAgentWithMobile) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.1.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -924,7 +936,7 @@
 
 // Tests that the UserAgentType of an INHERIT item is propagated to subsequent
 // item when UserAgentOverrideOption is INHERIT
-TEST_F(NavigationManagerTest, OverrideUserAgentWithInheritAfterInherit) {
+TEST_P(NavigationManagerTest, OverrideUserAgentWithInheritAfterInherit) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.1.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -946,7 +958,7 @@
 
 // Tests that the UserAgentType of a MOBILE item is propagated to subsequent
 // item when UserAgentOverrideOption is INHERIT
-TEST_F(NavigationManagerTest, OverrideUserAgentWithInheritAfterMobile) {
+TEST_P(NavigationManagerTest, OverrideUserAgentWithInheritAfterMobile) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.1.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -968,7 +980,7 @@
 
 // Tests that the UserAgentType of a DESKTOP item is propagated to subsequent
 // item when UserAgentOverrideOption is INHERIT
-TEST_F(NavigationManagerTest, OverrideUserAgentWithInheritAfterDesktop) {
+TEST_P(NavigationManagerTest, OverrideUserAgentWithInheritAfterDesktop) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.1.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -990,7 +1002,7 @@
 
 // Tests that the UserAgentType is propagated to subsequent NavigationItems if
 // a native URL exists in between naviations.
-TEST_F(NavigationManagerTest, UserAgentTypePropagationPastNativeItems) {
+TEST_P(NavigationManagerTest, UserAgentTypePropagationPastNativeItems) {
   // GURL::Replacements that will replace a GURL's scheme with the test native
   // scheme.
   GURL::Replacements native_scheme_replacement;
@@ -1047,7 +1059,7 @@
 
 // Tests that adding transient item for a pending item with mobile user agent
 // type results in a transient item with mobile user agent type.
-TEST_F(NavigationManagerTest, AddTransientItemForMobilePendingItem) {
+TEST_P(NavigationManagerTest, AddTransientItemForMobilePendingItem) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -1066,7 +1078,7 @@
 
 // Tests that adding transient item for a pending item with desktop user agent
 // type results in a transient item with desktop user agent type.
-TEST_F(NavigationManagerTest, AddTransientItemForDesktopPendingItem) {
+TEST_P(NavigationManagerTest, AddTransientItemForDesktopPendingItem) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -1085,7 +1097,7 @@
 
 // Tests that calling |Reload| with web::ReloadType::NORMAL is no-op when there
 // are no transient, pending and committed items.
-TEST_F(NavigationManagerTest, ReloadEmptyWithNormalType) {
+TEST_P(NavigationManagerTest, ReloadEmptyWithNormalType) {
   ASSERT_FALSE(navigation_manager()->GetTransientItem());
   ASSERT_FALSE(navigation_manager()->GetPendingItem());
   ASSERT_FALSE(navigation_manager()->GetLastCommittedItem());
@@ -1101,7 +1113,7 @@
 
 // Tests that calling |Reload| with web::ReloadType::NORMAL leaves the url of
 // the renderer initiated pending item unchanged when there is one.
-TEST_F(NavigationManagerTest, ReloadRendererPendingItemWithNormalType) {
+TEST_P(NavigationManagerTest, ReloadRendererPendingItemWithNormalType) {
   GURL url_before_reload = GURL("http://www.url.com");
   navigation_manager()->AddPendingItem(
       url_before_reload, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -1119,7 +1131,7 @@
 
 // Tests that calling |Reload| with web::ReloadType::NORMAL leaves the url of
 // the user initiated pending item unchanged when there is one.
-TEST_F(NavigationManagerTest, ReloadUserPendingItemWithNormalType) {
+TEST_P(NavigationManagerTest, ReloadUserPendingItemWithNormalType) {
   GURL url_before_reload = GURL("http://www.url.com");
   navigation_manager()->AddPendingItem(
       url_before_reload, Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -1137,7 +1149,7 @@
 
 // Tests that calling |Reload| with web::ReloadType::NORMAL leaves the url of
 // the last committed item unchanged when there is no pending item.
-TEST_F(NavigationManagerTest, ReloadLastCommittedItemWithNormalType) {
+TEST_P(NavigationManagerTest, ReloadLastCommittedItemWithNormalType) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com/0"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -1163,7 +1175,7 @@
 // Tests that calling |Reload| with web::ReloadType::NORMAL leaves the url of
 // the last committed item unchanged when there is no pending item, but there
 // forward items after last committed item.
-TEST_F(NavigationManagerTest,
+TEST_P(NavigationManagerTest,
        ReloadLastCommittedItemWithNormalTypeWithForwardItems) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com/0"), Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -1198,7 +1210,7 @@
 
 // Tests that calling |Reload| with web::ReloadType::ORIGINAL_REQUEST_URL is
 // no-op when there are no transient, pending and committed items.
-TEST_F(NavigationManagerTest, ReloadEmptyWithOriginalType) {
+TEST_P(NavigationManagerTest, ReloadEmptyWithOriginalType) {
   ASSERT_FALSE(navigation_manager()->GetTransientItem());
   ASSERT_FALSE(navigation_manager()->GetPendingItem());
   ASSERT_FALSE(navigation_manager()->GetLastCommittedItem());
@@ -1215,7 +1227,7 @@
 // Tests that calling |Reload| with web::ReloadType::ORIGINAL_REQUEST_URL
 // changes the renderer initiated pending item's url to its original request url
 // when there is one.
-TEST_F(NavigationManagerTest, ReloadRendererPendingItemWithOriginalType) {
+TEST_P(NavigationManagerTest, ReloadRendererPendingItemWithOriginalType) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::RENDERER_INITIATED,
@@ -1237,7 +1249,7 @@
 // Tests that calling |Reload| with web::ReloadType::ORIGINAL_REQUEST_URL
 // changes the user initiated pending item's url to its original request url
 // when there is one.
-TEST_F(NavigationManagerTest, ReloadUserPendingItemWithOriginalType) {
+TEST_P(NavigationManagerTest, ReloadUserPendingItemWithOriginalType) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -1259,7 +1271,7 @@
 // Tests that calling |Reload| with web::ReloadType::ORIGINAL_REQUEST_URL
 // changes the last committed item's url to its original request url when there
 // is no pending item.
-TEST_F(NavigationManagerTest, ReloadLastCommittedItemWithOriginalType) {
+TEST_P(NavigationManagerTest, ReloadLastCommittedItemWithOriginalType) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com/0"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
@@ -1288,7 +1300,7 @@
 // Tests that calling |Reload| with web::ReloadType::ORIGINAL_REQUEST_URL
 // changes the last committed item's url to its original request url when there
 // is no pending item, but there are forward items after last committed item.
-TEST_F(NavigationManagerTest,
+TEST_P(NavigationManagerTest,
        ReloadLastCommittedItemWithOriginalTypeWithForwardItems) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com/0"), Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -1326,7 +1338,7 @@
 
 // Tests that app-specific URLs are not rewritten for renderer-initiated loads
 // unless requested by a page with app-specific url.
-TEST_F(NavigationManagerTest, RewritingAppSpecificUrls) {
+TEST_P(NavigationManagerTest, RewritingAppSpecificUrls) {
   // URL should not be rewritten as there is no committed URL.
   GURL url1(url::SchemeHostPort(kSchemeToRewrite, "test", 0).Serialize());
   navigation_manager()->AddPendingItem(
@@ -1367,7 +1379,7 @@
 }
 
 // Tests that GetIndexOfItem() returns the correct values.
-TEST_F(NavigationManagerTest, GetIndexOfItem) {
+TEST_P(NavigationManagerTest, GetIndexOfItem) {
   // Create two items and add them to the NavigationManagerImpl.
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com/0"), Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -1390,4 +1402,9 @@
   EXPECT_EQ(-1, navigation_manager()->GetIndexOfItem(item_not_found.get()));
 }
 
+INSTANTIATE_TEST_CASE_P(
+    ProgrammaticNavigationManagerTest,
+    NavigationManagerTest,
+    ::testing::Values(true /* test_legacy_navigation_manager */));
+
 }  // namespace web
diff --git a/ios/web/navigation/navigation_manager_util_unittest.mm b/ios/web/navigation/navigation_manager_util_unittest.mm
index 83b3b18..4b343cb 100644
--- a/ios/web/navigation/navigation_manager_util_unittest.mm
+++ b/ios/web/navigation/navigation_manager_util_unittest.mm
@@ -7,7 +7,7 @@
 #include "base/memory/ptr_util.h"
 #import "ios/web/navigation/crw_session_controller+private_constructors.h"
 #import "ios/web/navigation/crw_session_controller.h"
-#import "ios/web/navigation/navigation_manager_impl.h"
+#import "ios/web/navigation/legacy_navigation_manager_impl.h"
 #import "ios/web/public/navigation_item.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
 #include "testing/platform_test.h"
@@ -18,16 +18,26 @@
 
 namespace web {
 
-// Test fixture testing navigation_manager_util.h functions.
-class NavigationManagerUtilTest : public PlatformTest {
+// Parameterized fixture testing navigation_manager_util.h functions.
+// GetParam() chooses whether to run the tests on LegacyNavigationManagerImpl
+// or (the soon-to-be-added) WKBasedNavigationManagerImpl.
+// TODO(crbug.com/734150): cleanup LegacyNavigationManagerImpl use case.
+class NavigationManagerUtilTest : public PlatformTest,
+                                  public ::testing::WithParamInterface<bool> {
  protected:
   NavigationManagerUtilTest()
       : controller_([[CRWSessionController alloc]
             initWithBrowserState:&browser_state_]) {
-    manager_.SetSessionController(controller_);
+    bool test_legacy_navigation_manager = GetParam();
+    if (test_legacy_navigation_manager) {
+      manager_.reset(new LegacyNavigationManagerImpl);
+      manager_->SetSessionController(controller_);
+    } else {
+      DCHECK(false) << "Not yet implemented.";
+    }
   }
 
-  NavigationManagerImpl manager_;
+  std::unique_ptr<NavigationManagerImpl> manager_;
   CRWSessionController* controller_;
 
  private:
@@ -38,36 +48,41 @@
 // GetItemWithUniqueID functions.
 // TODO(crbug.com/733658): test was incorrectly moved to a separate target
 // and not run and a refactoring broke it. Disable until the issue is fixed.
-TEST_F(NavigationManagerUtilTest, DISABLED_GetCommittedItemWithUniqueID) {
+TEST_P(NavigationManagerUtilTest, DISABLED_GetCommittedItemWithUniqueID) {
   // Start with NavigationManager that only has a pending item.
-  manager_.AddPendingItem(
+  manager_->AddPendingItem(
       GURL("http://chromium.org"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::USER_INITIATED,
       web::NavigationManager::UserAgentOverrideOption::INHERIT);
-  NavigationItem* item = manager_.GetPendingItem();
+  NavigationItem* item = manager_->GetPendingItem();
   int unique_id = item->GetUniqueID();
-  EXPECT_FALSE(GetCommittedItemWithUniqueID(&manager_, unique_id));
-  EXPECT_EQ(item, GetItemWithUniqueID(&manager_, unique_id));
-  EXPECT_EQ(-1, GetCommittedItemIndexWithUniqueID(&manager_, unique_id));
+  EXPECT_FALSE(GetCommittedItemWithUniqueID(manager_.get(), unique_id));
+  EXPECT_EQ(item, GetItemWithUniqueID(manager_.get(), unique_id));
+  EXPECT_EQ(-1, GetCommittedItemIndexWithUniqueID(manager_.get(), unique_id));
 
   // Commit that pending item.
   [controller_ commitPendingItem];
-  EXPECT_EQ(item, GetCommittedItemWithUniqueID(&manager_, unique_id));
-  EXPECT_EQ(item, GetItemWithUniqueID(&manager_, unique_id));
-  EXPECT_EQ(0, GetCommittedItemIndexWithUniqueID(&manager_, unique_id));
+  EXPECT_EQ(item, GetCommittedItemWithUniqueID(manager_.get(), unique_id));
+  EXPECT_EQ(item, GetItemWithUniqueID(manager_.get(), unique_id));
+  EXPECT_EQ(0, GetCommittedItemIndexWithUniqueID(manager_.get(), unique_id));
 
   // Remove committed item.
-  manager_.RemoveItemAtIndex(0);
-  EXPECT_FALSE(GetCommittedItemWithUniqueID(&manager_, unique_id));
-  EXPECT_FALSE(GetItemWithUniqueID(&manager_, unique_id));
-  EXPECT_EQ(-1, GetCommittedItemIndexWithUniqueID(&manager_, unique_id));
+  manager_->RemoveItemAtIndex(0);
+  EXPECT_FALSE(GetCommittedItemWithUniqueID(manager_.get(), unique_id));
+  EXPECT_FALSE(GetItemWithUniqueID(manager_.get(), unique_id));
+  EXPECT_EQ(-1, GetCommittedItemIndexWithUniqueID(manager_.get(), unique_id));
 
   // Add transient item.
   [controller_ addTransientItemWithURL:GURL("http://chromium.org")];
-  item = manager_.GetTransientItem();
-  EXPECT_FALSE(GetCommittedItemWithUniqueID(&manager_, unique_id));
-  EXPECT_EQ(item, GetItemWithUniqueID(&manager_, unique_id));
-  EXPECT_EQ(-1, GetCommittedItemIndexWithUniqueID(&manager_, unique_id));
+  item = manager_->GetTransientItem();
+  EXPECT_FALSE(GetCommittedItemWithUniqueID(manager_.get(), unique_id));
+  EXPECT_EQ(item, GetItemWithUniqueID(manager_.get(), unique_id));
+  EXPECT_EQ(-1, GetCommittedItemIndexWithUniqueID(manager_.get(), unique_id));
 }
 
+INSTANTIATE_TEST_CASE_P(
+    ProgrammaticNavigationManagerUtilTest,
+    NavigationManagerUtilTest,
+    ::testing::Values(true /* test_legacy_navigation_manager */));
+
 }  // namespace web
diff --git a/ios/web/navigation/session_storage_builder.mm b/ios/web/navigation/session_storage_builder.mm
index 24ff60e..323fd82 100644
--- a/ios/web/navigation/session_storage_builder.mm
+++ b/ios/web/navigation/session_storage_builder.mm
@@ -11,6 +11,7 @@
 #include "base/memory/ptr_util.h"
 #import "ios/web/navigation/crw_session_controller+private_constructors.h"
 #import "ios/web/navigation/crw_session_controller.h"
+#import "ios/web/navigation/legacy_navigation_manager_impl.h"
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_item_storage_builder.h"
 #include "ios/web/navigation/navigation_manager_impl.h"
@@ -42,15 +43,18 @@
   DCHECK(navigation_manager);
   CRWSessionStorage* session_storage = [[CRWSessionStorage alloc] init];
   session_storage.hasOpener = web_state->HasOpener();
-  CRWSessionController* session_controller =
-      navigation_manager->GetSessionController();
   session_storage.lastCommittedItemIndex =
-      session_controller.lastCommittedItemIndex;
-  session_storage.previousItemIndex = session_controller.previousItemIndex;
+      navigation_manager->GetLastCommittedItemIndex();
+  session_storage.previousItemIndex =
+      static_cast<NSInteger>(navigation_manager->GetPreviousItemIndex());
   NSMutableArray* item_storages = [[NSMutableArray alloc] init];
   NavigationItemStorageBuilder item_storage_builder;
-  for (size_t index = 0; index < session_controller.items.size(); ++index) {
-    web::NavigationItemImpl* item = session_controller.items[index].get();
+  for (size_t index = 0;
+       index < static_cast<size_t>(navigation_manager->GetItemCount());
+       ++index) {
+    web::NavigationItemImpl* item =
+        navigation_manager->GetNavigationItemImplAtIndex(index);
+    ;
     [item_storages addObject:item_storage_builder.BuildStorage(item)];
   }
   session_storage.itemStorages = item_storages;
@@ -85,8 +89,11 @@
                  navigationItems:std::move(items)
           lastCommittedItemIndex:last_committed_item_index]);
   [session_controller setPreviousItemIndex:storage.previousItemIndex];
-  web_state->navigation_manager_.reset(new NavigationManagerImpl());
-  web_state->navigation_manager_->SetSessionController(session_controller);
+
+  auto navigation_manager = base::MakeUnique<LegacyNavigationManagerImpl>();
+  navigation_manager->SetSessionController(session_controller);
+  web_state->navigation_manager_.reset(navigation_manager.release());
+
   SessionCertificatePolicyCacheStorageBuilder cert_builder;
   std::unique_ptr<SessionCertificatePolicyCacheImpl> cert_policy_cache =
       cert_builder.BuildSessionCertificatePolicyCache(
diff --git a/ios/web/net/crw_ssl_status_updater_unittest.mm b/ios/web/net/crw_ssl_status_updater_unittest.mm
index dc9d4878..e2021876b 100644
--- a/ios/web/net/crw_ssl_status_updater_unittest.mm
+++ b/ios/web/net/crw_ssl_status_updater_unittest.mm
@@ -9,6 +9,7 @@
 #include "base/strings/sys_string_conversions.h"
 #import "ios/web/navigation/crw_session_controller+private_constructors.h"
 #import "ios/web/navigation/crw_session_controller.h"
+#import "ios/web/navigation/legacy_navigation_manager_impl.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #import "ios/web/public/navigation_item.h"
 #include "ios/web/public/ssl_status.h"
@@ -86,7 +87,7 @@
     delegate_ =
         [OCMockObject mockForProtocol:@protocol(CRWSSLStatusUpdaterDelegate)];
 
-    nav_manager_.reset(new NavigationManagerImpl());
+    nav_manager_.reset(new LegacyNavigationManagerImpl());
     nav_manager_->SetBrowserState(GetBrowserState());
 
     ssl_status_updater_ =
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index de5e4b97..d973508 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -13,6 +13,7 @@
 #include "base/strings/sys_string_conversions.h"
 #import "ios/web/interstitials/web_interstitial_impl.h"
 #import "ios/web/navigation/crw_session_controller.h"
+#import "ios/web/navigation/legacy_navigation_manager_impl.h"
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/session_storage_builder.h"
 #include "ios/web/public/browser_state.h"
@@ -80,7 +81,8 @@
     SessionStorageBuilder session_storage_builder;
     session_storage_builder.ExtractSessionState(this, session_storage);
   } else {
-    navigation_manager_ = base::MakeUnique<NavigationManagerImpl>();
+    navigation_manager_ = base::WrapUnique<NavigationManagerImpl>(
+        new LegacyNavigationManagerImpl);
     certificate_policy_cache_ =
         base::MakeUnique<SessionCertificatePolicyCacheImpl>();
   }
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc
index e55f96f..d4b2b641 100644
--- a/mojo/edk/system/node_controller.cc
+++ b/mojo/edk/system/node_controller.cc
@@ -998,6 +998,8 @@
   }
 
   node_->AcceptEvent(std::move(event));
+
+  AttemptShutdownIfRequested();
 }
 
 void NodeController::OnRequestPortMerge(
diff --git a/net/android/java/src/org/chromium/net/X509Util.java b/net/android/java/src/org/chromium/net/X509Util.java
index ffe25d7..8536b2d 100644
--- a/net/android/java/src/org/chromium/net/X509Util.java
+++ b/net/android/java/src/org/chromium/net/X509Util.java
@@ -143,9 +143,10 @@
         }
 
         @Override
-        public List<X509Certificate> checkServerTrusted(X509Certificate[] chain,
-                                                        String authType,
-                                                        String host) throws CertificateException {
+        @SuppressLint("NewApi")
+        public List<X509Certificate> checkServerTrusted(
+                X509Certificate[] chain, String authType, String host) throws CertificateException {
+            // API Level 17: android.net.http.X509TrustManagerExtensions#checkServerTrusted
             return mTrustManagerExtensions.checkServerTrusted(chain, authType, host);
         }
     }
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 8e3158a..4372bde3 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -226,6 +226,7 @@
   if (options.has_server_time())
     server_time = options.server_time();
 
+  DCHECK(!creation_time.is_null());
   Time cookie_expires = CanonicalCookie::CanonExpiration(parsed_cookie,
                                                          creation_time,
                                                          server_time);
@@ -447,6 +448,11 @@
   return true;
 }
 
+void CanonicalCookie::SetCreationDate(base::Time new_creation_date) {
+  DCHECK(CreationDate().is_null());
+  creation_date_ = new_creation_date;
+}
+
 // static
 CanonicalCookie::CookiePrefix CanonicalCookie::GetCookiePrefix(
     const std::string& name) {
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index 1d3b3ed5..78870ec 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -47,8 +47,8 @@
   // Supports the default copy constructor.
 
   // Creates a new |CanonicalCookie| from the |cookie_line| and the
-  // |creation_time|. Canonicalizes and validates inputs. May return NULL if
-  // an attribute value is invalid.
+  // |creation_time|.  Canonicalizes and validates inputs. May return NULL if
+  // an attribute value is invalid.  |creation_time| may not be null.
   static std::unique_ptr<CanonicalCookie> Create(
       const GURL& url,
       const std::string& cookie_line,
@@ -159,6 +159,11 @@
   // greater than the last access time.
   bool IsCanonical() const;
 
+  // Sets the creation date of the cookie to the specified value.  It
+  // is only valid to call this method if the existing creation date
+  // is null.
+  void SetCreationDate(base::Time new_creation_date);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(CanonicalCookieTest, TestPrefixHistograms);
 
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index aaa9c69d..a2f3cf7 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -864,6 +864,17 @@
                    .IsCanonical());
 }
 
+TEST(CanonicalCookieTest, TestSetCreationDate) {
+  CanonicalCookie cookie("A", "B", "x.y", "/path", base::Time(), base::Time(),
+                         base::Time(), false, false,
+                         CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW);
+  EXPECT_TRUE(cookie.CreationDate().is_null());
+
+  base::Time now(base::Time::Now());
+  cookie.SetCreationDate(now);
+  EXPECT_EQ(now, cookie.CreationDate());
+}
+
 TEST(CanonicalCookieTest, TestPrefixHistograms) {
   base::HistogramTester histograms;
   const char kCookiePrefixHistogram[] = "Cookie.CookiePrefix";
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 7ccf452..60eccfe 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -694,6 +694,42 @@
   return this->cookie_monster()->DeleteCanonicalCookie(cookie_);
 }
 
+// Task class for SetCanonicalCookie call.
+class CookieMonster::SetCanonicalCookieTask : public CookieMonsterTask {
+ public:
+  SetCanonicalCookieTask(CookieMonster* cookie_monster,
+                         std::unique_ptr<CanonicalCookie> cookie,
+                         bool secure_source,
+                         bool modify_http_only,
+                         const SetCookiesCallback& callback)
+      : CookieMonsterTask(cookie_monster),
+        cookie_(std::move(cookie)),
+        secure_source_(secure_source),
+        modify_http_only_(modify_http_only),
+        callback_(callback) {}
+
+  // CookieMonsterTask:
+  void Run() override;
+
+ protected:
+  ~SetCanonicalCookieTask() override {}
+
+ private:
+  std::unique_ptr<CanonicalCookie> cookie_;
+  bool secure_source_;
+  bool modify_http_only_;
+  SetCookiesCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(SetCanonicalCookieTask);
+};
+
+void CookieMonster::SetCanonicalCookieTask::Run() {
+  bool result = this->cookie_monster()->SetCanonicalCookie(
+      std::move(cookie_), secure_source_, modify_http_only_);
+  if (!callback_.is_null())
+    callback_.Run(result);
+}
+
 // Task class for SetCookieWithOptions call.
 class CookieMonster::SetCookieWithOptionsTask : public CookieMonsterTask {
  public:
@@ -902,6 +938,22 @@
   DoCookieTask(task);
 }
 
+void CookieMonster::SetCanonicalCookieAsync(
+    std::unique_ptr<CanonicalCookie> cookie,
+    bool secure_source,
+    bool modify_http_only,
+    const SetCookiesCallback& callback) {
+  DCHECK(cookie->IsCanonical());
+  scoped_refptr<SetCanonicalCookieTask> task = new SetCanonicalCookieTask(
+      this, std::move(cookie), secure_source, modify_http_only, callback);
+
+  // TODO(rdsmith): Switch to DoCookieTaskForURL (or the equivalent).
+  // This is tricky because we don't have the scheme in this routine
+  // and DoCookieTaskForURL uses cookie_util::GetEffectiveDomain(scheme, host)
+  // to generate the database key to block behind.
+  DoCookieTask(task);
+}
+
 void CookieMonster::SetCookieWithOptionsAsync(
     const GURL& url,
     const std::string& cookie_line,
@@ -1067,16 +1119,6 @@
   if (!HasCookieableScheme(url))
     return false;
 
-  // TODO(mmenke): This class assumes each cookie to have a unique creation
-  // time. Allowing the caller to set the creation time violates that
-  // assumption. Worth fixing? Worth noting that time changes between browser
-  // restarts can cause the same issue.
-  base::Time actual_creation_time = creation_time;
-  if (creation_time.is_null()) {
-    actual_creation_time = CurrentTime();
-    last_time_seen_ = actual_creation_time;
-  }
-
   // Validate consistency of passed arguments.
   if (ParsedCookie::ParseTokenString(name) != name ||
       ParsedCookie::ParseValueString(value) != value ||
@@ -1103,9 +1145,8 @@
                             canon_path_component.len);
 
   std::unique_ptr<CanonicalCookie> cc(base::MakeUnique<CanonicalCookie>(
-      name, value, cookie_domain, cookie_path, actual_creation_time,
-      expiration_time, last_access_time, secure, http_only, same_site,
-      priority));
+      name, value, cookie_domain, cookie_path, creation_time, expiration_time,
+      last_access_time, secure, http_only, same_site, priority));
 
   return SetCanonicalCookie(std::move(cc), url.SchemeIsCryptographic(), true);
 }
@@ -1765,9 +1806,19 @@
   if (cc->IsSecure() && !secure_source)
     return false;
 
-  Time creation_time = cc->CreationDate();
   const std::string key(GetKey(cc->Domain()));
-  bool already_expired = cc->IsExpired(creation_time);
+
+  // TODO(mmenke): This class assumes each cookie to have a unique creation
+  // time. Allowing the caller to set the creation time violates that
+  // assumption. Worth fixing? Worth noting that time changes between browser
+  // restarts can cause the same issue.
+  base::Time creation_date = cc->CreationDate();
+  if (creation_date.is_null()) {
+    creation_date = CurrentTime();
+    cc->SetCreationDate(creation_date);
+    last_time_seen_ = creation_date;
+  }
+  bool already_expired = cc->IsExpired(creation_date);
 
   if (DeleteAnyEquivalentCookie(key, *cc, secure_source, !modify_http_only,
                                 already_expired)) {
@@ -1789,7 +1840,7 @@
     // See InitializeHistograms() for details.
     if (cc->IsPersistent()) {
       histogram_expiration_duration_minutes_->Add(
-          (cc->ExpiryDate() - creation_time).InMinutes());
+          (cc->ExpiryDate() - creation_date).InMinutes());
     }
 
     // Histogram the type of scheme used on URLs that set cookies. This
@@ -1817,7 +1868,7 @@
   // make sure that we garbage collect...  We can also make the assumption that
   // if a cookie was set, in the common case it will be used soon after,
   // and we will purge the expired cookies in GetCookies().
-  GarbageCollect(creation_time, key);
+  GarbageCollect(creation_date, key);
 
   return true;
 }
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 42afd9a..9382e935 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -176,6 +176,10 @@
                                  CookieSameSite same_site,
                                  CookiePriority priority,
                                  const SetCookiesCallback& callback) override;
+  void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+                               bool secure_source,
+                               bool modify_http_only,
+                               const SetCookiesCallback& callback) override;
   void GetCookiesWithOptionsAsync(const GURL& url,
                                   const CookieOptions& options,
                                   const GetCookiesCallback& callback) override;
@@ -247,6 +251,7 @@
   class SetAllCookiesTask;
   class SetCookieWithDetailsTask;
   class SetCookieWithOptionsTask;
+  class SetCanonicalCookieTask;
   class DeleteSessionCookiesTask;
 
   // Testing support.
@@ -427,6 +432,15 @@
                             CookieSameSite same_site,
                             CookiePriority priority);
 
+  // Sets a canonical cookie, deletes equivalents and performs garbage
+  // collection.  |source_secure| indicates if the cookie is being set
+  // from a secure source (e.g. a cryptographic scheme).
+  // |modify_http_only| indicates if this setting operation is allowed
+  // to affect http_only cookies.
+  bool SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cookie,
+                          bool secure_source,
+                          bool can_modify_httponly);
+
   CookieList GetAllCookies();
 
   CookieList GetCookieListWithOptions(const GURL& url,
@@ -545,15 +559,6 @@
                                            const base::Time& creation_time,
                                            const CookieOptions& options);
 
-  // Sets a canonical cookie, deletes equivalents and performs garbage
-  // collection.  |source_secure| indicates if the cookie is being set
-  // from a secure source (e.g. a cryptographic scheme).
-  // |modify_http_only| indicates if this setting operation is allowed
-  // to affect http_only cookies.
-  bool SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cookie,
-                          bool secure_source,
-                          bool can_modify_httponly);
-
   // Sets all cookies from |list| after deleting any equivalent cookie.
   // For data gathering purposes, this routine is treated as if it is
   // restoring saved cookies; some statistics are not gathered in this case.
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 0b60812a..6878898 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -148,6 +148,20 @@
     return callback.result();
   }
 
+  bool SetCanonicalCookie(std::unique_ptr<CookieMonster> cm,
+                          std::unique_ptr<CanonicalCookie> cookie,
+                          bool secure_source,
+                          bool modify_http_only) {
+    DCHECK(cm);
+    ResultSavingCookieCallback<bool> callback;
+    cm->SetCanonicalCookieAsync(
+        std::move(cookie), secure_source, modify_http_only,
+        base::Bind(&ResultSavingCookieCallback<bool>::Run,
+                   base::Unretained(&callback)));
+    callback.WaitUntilDone();
+    return callback.result();
+  }
+
   int DeleteAllCreatedBetween(CookieMonster* cm,
                               const base::Time& delete_begin,
                               const base::Time& delete_end) {
@@ -2303,7 +2317,7 @@
   // When passed to the CookieMonster, it takes ownership of the pointed to
   // cookies.
   cookies.push_back(
-      CanonicalCookie::Create(kUrl, "a=b", base::Time(), CookieOptions()));
+      CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), CookieOptions()));
   ASSERT_TRUE(cookies[0]);
   store->commands()[0].loaded_callback.Run(std::move(cookies));
 
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
index a2be255..931b2ea1 100644
--- a/net/cookies/cookie_store.h
+++ b/net/cookies/cookie_store.h
@@ -127,6 +127,18 @@
       CookiePriority priority,
       const SetCookiesCallback& callback) = 0;
 
+  // TODO(rdsmith): Remove SetCookieWithDetailsAsync in favor of this.
+  // Set the cookie on the cookie store.  |cookie.IsCanonical()| must
+  // be true.  |secure_source| indicates if the source of the setting
+  // may be considered secure (if from a URL, the scheme is
+  // cryptographic), and |modify_http_only| indicates if the source of
+  // the setting may modify http_only cookies.  The current time will
+  // be used in place of a null creation time.
+  virtual void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+                                       bool secure_source,
+                                       bool modify_http_only,
+                                       const SetCookiesCallback& callback) = 0;
+
   // TODO(???): what if the total size of all the cookies >4k, can we have a
   // header that big or do we need multiple Cookie: headers?
   // Note: Some sites, such as Facebook, occasionally use Cookie headers >4k.
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index bed506f1..d1c1ed5 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -92,6 +92,14 @@
   NOTREACHED();
 }
 
+void DelayedCookieMonster::SetCanonicalCookieAsync(
+    std::unique_ptr<CanonicalCookie> cookie,
+    bool secure_source,
+    bool modify_http_only,
+    const SetCookiesCallback& callback) {
+  NOTREACHED();
+}
+
 void DelayedCookieMonster::GetCookiesWithOptionsAsync(
     const GURL& url,
     const CookieOptions& options,
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
index bb6d656b..7a9c34c 100644
--- a/net/cookies/cookie_store_test_helpers.h
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -45,6 +45,11 @@
                                  CookiePriority priority,
                                  const SetCookiesCallback& callback) override;
 
+  void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+                               bool secure_source,
+                               bool modify_http_only,
+                               const SetCookiesCallback& callback) override;
+
   void GetCookiesWithOptionsAsync(
       const GURL& url,
       const CookieOptions& options,
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 14aa3e9..4aa2a3c 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -181,6 +181,20 @@
     return callback.result();
   }
 
+  bool SetCanonicalCookie(CookieStore* cs,
+                          std::unique_ptr<CanonicalCookie> cookie,
+                          bool secure_source,
+                          bool can_modify_httponly) {
+    DCHECK(cs);
+    ResultSavingCookieCallback<bool> callback;
+    cs->SetCanonicalCookieAsync(
+        std::move(cookie), secure_source, can_modify_httponly,
+        base::Bind(&ResultSavingCookieCallback<bool>::Run,
+                   base::Unretained(&callback)));
+    callback.WaitUntilDone();
+    return callback.result();
+  }
+
   bool SetCookieWithServerTime(CookieStore* cs,
                                const GURL& url,
                                const std::string& cookie_line,
@@ -465,6 +479,131 @@
   EXPECT_TRUE(++it == cookies.end());
 }
 
+TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) {
+  CookieStore* cs = this->GetCookieStore();
+
+  base::Time two_hours_ago = base::Time::Now() - base::TimeDelta::FromHours(2);
+  base::Time one_hour_ago = base::Time::Now() - base::TimeDelta::FromHours(1);
+  base::Time one_hour_from_now =
+      base::Time::Now() + base::TimeDelta::FromHours(1);
+
+  std::string foo_foo_host(this->www_foo_foo_.url().host());
+  std::string foo_bar_domain(this->www_foo_bar_.domain());
+  std::string http_foo_host(this->http_www_foo_.url().host());
+  std::string https_foo_host(this->https_www_foo_.url().host());
+
+  EXPECT_TRUE(this->SetCanonicalCookie(
+      cs,
+      base::MakeUnique<CanonicalCookie>(
+          "A", "B", foo_foo_host, "/foo", one_hour_ago, one_hour_from_now,
+          base::Time(), false, false, CookieSameSite::DEFAULT_MODE,
+          COOKIE_PRIORITY_DEFAULT),
+      false, true));
+  // Note that for the creation time to be set exactly, without modification,
+  // it must be different from the one set by the line above.
+  EXPECT_TRUE(this->SetCanonicalCookie(
+      cs,
+      base::MakeUnique<CanonicalCookie>(
+          "C", "D", "." + foo_bar_domain, "/bar", two_hours_ago, base::Time(),
+          one_hour_ago, false, true, CookieSameSite::DEFAULT_MODE,
+          COOKIE_PRIORITY_DEFAULT),
+      false, true));
+
+  // A secure source is required for creating secure cookies.
+  EXPECT_FALSE(this->SetCanonicalCookie(
+      cs,
+      base::MakeUnique<CanonicalCookie>(
+          "E", "F", http_foo_host, "/", base::Time(), base::Time(),
+          base::Time(), true, false, CookieSameSite::DEFAULT_MODE,
+          COOKIE_PRIORITY_DEFAULT),
+      false, true));
+
+  // A secure source is also required for overwriting secure cookies.  Writing
+  // a secure cookie then overwriting it from a non-secure source should fail.
+  EXPECT_TRUE(this->SetCanonicalCookie(
+      cs,
+      base::MakeUnique<CanonicalCookie>(
+          "E", "F", http_foo_host, "/", base::Time(), base::Time(),
+          base::Time(), true, false, CookieSameSite::DEFAULT_MODE,
+          COOKIE_PRIORITY_DEFAULT),
+      true, true));
+
+  EXPECT_FALSE(this->SetCanonicalCookie(
+      cs,
+      base::MakeUnique<CanonicalCookie>(
+          "E", "F", http_foo_host, "/", base::Time(), base::Time(),
+          base::Time(), true, false, CookieSameSite::DEFAULT_MODE,
+          COOKIE_PRIORITY_DEFAULT),
+      false, true));
+
+  // Get all the cookies for a given URL, regardless of properties. This 'get()'
+  // operation shouldn't update the access time, as the test checks that the
+  // access time is set properly upon creation. Updating the access time would
+  // make that difficult.
+  CookieOptions options;
+  options.set_include_httponly();
+  options.set_same_site_cookie_mode(
+      CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
+  options.set_do_not_update_access_time();
+
+  CookieList cookies =
+      this->GetCookieListWithOptions(cs, this->www_foo_foo_.url(), options);
+  CookieList::iterator it = cookies.begin();
+
+  ASSERT_EQ(1u, cookies.size());
+  EXPECT_EQ("A", it->Name());
+  EXPECT_EQ("B", it->Value());
+  EXPECT_EQ(this->www_foo_foo_.host(), it->Domain());
+  EXPECT_EQ("/foo", it->Path());
+  EXPECT_EQ(one_hour_ago, it->CreationDate());
+  EXPECT_TRUE(it->IsPersistent());
+  // Expect expiration date is in the right range.  Some cookie implementations
+  // may not record it with millisecond accuracy.
+  EXPECT_LE((one_hour_from_now - it->ExpiryDate()).magnitude().InSeconds(), 5);
+  // Some CookieStores don't store last access date.
+  if (!it->LastAccessDate().is_null())
+    EXPECT_EQ(one_hour_ago, it->LastAccessDate());
+  EXPECT_FALSE(it->IsSecure());
+  EXPECT_FALSE(it->IsHttpOnly());
+
+  // Get the cookie using the wide open |options|:
+  cookies =
+      this->GetCookieListWithOptions(cs, this->www_foo_bar_.url(), options);
+  ASSERT_EQ(1u, cookies.size());
+  it = cookies.begin();
+
+  EXPECT_EQ("C", it->Name());
+  EXPECT_EQ("D", it->Value());
+  EXPECT_EQ(this->www_foo_bar_.Format(".%D"), it->Domain());
+  EXPECT_EQ("/bar", it->Path());
+  EXPECT_EQ(two_hours_ago, it->CreationDate());
+  EXPECT_FALSE(it->IsPersistent());
+  // Some CookieStores don't store last access date.
+  if (!it->LastAccessDate().is_null())
+    EXPECT_EQ(one_hour_ago, it->LastAccessDate());
+  EXPECT_FALSE(it->IsSecure());
+  EXPECT_TRUE(it->IsHttpOnly());
+
+  cookies =
+      this->GetCookieListWithOptions(cs, this->https_www_foo_.url(), options);
+  ASSERT_EQ(1u, cookies.size());
+  it = cookies.begin();
+
+  EXPECT_EQ("E", it->Name());
+  EXPECT_EQ("F", it->Value());
+  EXPECT_EQ("/", it->Path());
+  EXPECT_EQ(this->https_www_foo_.host(), it->Domain());
+  // Cookie should have its creation time set, and be in a reasonable range.
+  EXPECT_LE((base::Time::Now() - it->CreationDate()).magnitude().InMinutes(),
+            2);
+  EXPECT_FALSE(it->IsPersistent());
+  // Some CookieStores don't store last access date.
+  if (!it->LastAccessDate().is_null())
+    EXPECT_EQ(it->CreationDate(), it->LastAccessDate());
+  EXPECT_TRUE(it->IsSecure());
+  EXPECT_FALSE(it->IsHttpOnly());
+}
+
 // Test enforcement around setting secure cookies.
 TYPED_TEST_P(CookieStoreTest, SetCookieWithDetailsSecureEnforcement) {
   CookieStore* cs = this->GetCookieStore();
@@ -1476,6 +1615,7 @@
 
 REGISTER_TYPED_TEST_CASE_P(CookieStoreTest,
                            SetCookieWithDetailsAsync,
+                           SetCanonicalCookieTest,
                            SetCookieWithDetailsSecureEnforcement,
                            EmptyKeyTest,
                            DomainTest,
diff --git a/services/service_manager/embedder/switches.cc b/services/service_manager/embedder/switches.cc
index a4559d08..4e42a51 100644
--- a/services/service_manager/embedder/switches.cc
+++ b/services/service_manager/embedder/switches.cc
@@ -32,7 +32,7 @@
 const char kEnableLogging[] = "enable-logging";
 
 // Indicates the type of process to run. This may be "service-manager",
-// "service", or any other arbitrary value supported by the embedder.
+// "service-runner", or any other arbitrary value supported by the embedder.
 const char kProcessType[] = "type";
 
 // The value of the |kProcessType| switch which tells the executable to assume
@@ -41,7 +41,7 @@
 
 // The value of the |kProcessType| switch which tells the executable to assume
 // the role of a service instance.
-const char kProcessTypeService[] = "service";
+const char kProcessTypeService[] = "service-runner";
 
 // Describes the file descriptors passed to a child process in the following
 // list format:
diff --git a/services/ui/gpu/BUILD.gn b/services/ui/gpu/BUILD.gn
index c7b669f..6deaf4b 100644
--- a/services/ui/gpu/BUILD.gn
+++ b/services/ui/gpu/BUILD.gn
@@ -21,7 +21,6 @@
 
   deps = [
     "//cc",
-    "//components/viz/common",
     "//components/viz/service",
     "//gpu/ipc:command_buffer",
     "//gpu/ipc/common",
diff --git a/services/ui/gpu/gpu_main.cc b/services/ui/gpu/gpu_main.cc
index e590b355..dd40807 100644
--- a/services/ui/gpu/gpu_main.cc
+++ b/services/ui/gpu/gpu_main.cc
@@ -9,7 +9,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/power_monitor/power_monitor_device_source.h"
 #include "base/single_thread_task_runner.h"
-#include "components/viz/common/server_gpu_memory_buffer_manager.h"
 #include "components/viz/service/display_compositor/gpu_display_provider.h"
 #include "components/viz/service/frame_sinks/mojo_frame_sink_manager.h"
 #include "gpu/command_buffer/common/activity_flags.h"
@@ -174,37 +173,22 @@
       gpu_thread_task_runner_, gpu_service_->sync_point_manager(),
       gpu_service_->mailbox_manager(), gpu_service_->share_group());
 
-  gpu::ImageFactory* image_factory = gpu_service_->gpu_image_factory();
-
-  // If the FrameSinkManager creation was delayed because GpuService had not
-  // been created yet, then this is called, in gpu thread, right after
-  // GpuService is created.
-  mojom::GpuServicePtr gpu_service;
-  BindGpuInternalOnGpuThread(mojo::MakeRequest(&gpu_service));
   compositor_thread_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&GpuMain::CreateFrameSinkManagerOnCompositorThread,
-                            base::Unretained(this), image_factory,
-                            base::Passed(gpu_service.PassInterface()),
-                            base::Passed(std::move(request)),
-                            base::Passed(std::move(client_info))));
+      FROM_HERE,
+      base::Bind(&GpuMain::CreateFrameSinkManagerOnCompositorThread,
+                 base::Unretained(this), base::Passed(std::move(request)),
+                 base::Passed(std::move(client_info))));
 }
 
 void GpuMain::CreateFrameSinkManagerOnCompositorThread(
-    gpu::ImageFactory* image_factory,
-    mojom::GpuServicePtrInfo gpu_service_info,
     cc::mojom::FrameSinkManagerRequest request,
     cc::mojom::FrameSinkManagerClientPtrInfo client_info) {
   DCHECK(!frame_sink_manager_);
   cc::mojom::FrameSinkManagerClientPtr client;
   client.Bind(std::move(client_info));
 
-  gpu_internal_.Bind(std::move(gpu_service_info));
-
   display_provider_ = base::MakeUnique<viz::GpuDisplayProvider>(
-      gpu_command_service_,
-      base::MakeUnique<viz::ServerGpuMemoryBufferManager>(gpu_internal_.get(),
-                                                          1 /* client_id */),
-      image_factory);
+      gpu_command_service_, gpu_service_->gpu_channel_manager());
 
   frame_sink_manager_ = base::MakeUnique<viz::MojoFrameSinkManager>(
       true, display_provider_.get());
@@ -215,7 +199,6 @@
 void GpuMain::TearDownOnCompositorThread() {
   frame_sink_manager_.reset();
   display_provider_.reset();
-  gpu_internal_.reset();
 }
 
 void GpuMain::TearDownOnGpuThread() {
@@ -242,10 +225,6 @@
   }
 }
 
-void GpuMain::BindGpuInternalOnGpuThread(mojom::GpuServiceRequest request) {
-  gpu_service_->Bind(std::move(request));
-}
-
 void GpuMain::PreSandboxStartup() {
   // TODO(sad): https://crbug.com/645602
 }
diff --git a/services/ui/gpu/gpu_main.h b/services/ui/gpu/gpu_main.h
index 4b87174..bfc3c27 100644
--- a/services/ui/gpu/gpu_main.h
+++ b/services/ui/gpu/gpu_main.h
@@ -15,7 +15,6 @@
 
 namespace gpu {
 class GpuMemoryBufferFactory;
-class ImageFactory;
 }
 
 namespace viz {
@@ -55,15 +54,12 @@
       cc::mojom::FrameSinkManagerRequest request,
       cc::mojom::FrameSinkManagerClientPtrInfo client_info);
   void CreateFrameSinkManagerOnCompositorThread(
-      gpu::ImageFactory* image_factory,
-      mojom::GpuServicePtrInfo gpu_service_info,
       cc::mojom::FrameSinkManagerRequest request,
       cc::mojom::FrameSinkManagerClientPtrInfo client_info);
   void CreateGpuServiceOnGpuThread(mojom::GpuServiceRequest request,
                                    mojom::GpuHostPtr gpu_host,
                                    const gpu::GpuPreferences& preferences,
                                    gpu::GpuProcessActivityFlags activity_flags);
-  void BindGpuInternalOnGpuThread(mojom::GpuServiceRequest request);
 
   void TearDownOnCompositorThread();
   void TearDownOnGpuThread();
@@ -76,10 +72,6 @@
   std::unique_ptr<gpu::GpuInit> gpu_init_;
   std::unique_ptr<GpuService> gpu_service_;
 
-  // The message-pipe used by the FrameSinkManager to request gpu memory
-  // buffers.
-  mojom::GpuServicePtr gpu_internal_;
-
   // The InCommandCommandBuffer::Service used by the frame sink manager.
   scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_command_service_;
 
diff --git a/services/ui/gpu/gpu_service.h b/services/ui/gpu/gpu_service.h
index 0cf5d3c..21b6c24e 100644
--- a/services/ui/gpu/gpu_service.h
+++ b/services/ui/gpu/gpu_service.h
@@ -73,6 +73,9 @@
   }
 
   gpu::ImageFactory* gpu_image_factory();
+  gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory() {
+    return gpu_memory_buffer_factory_.get();
+  }
 
   gpu::GpuWatchdogThread* watchdog_thread() { return watchdog_thread_.get(); }
 
diff --git a/testing/buildbot/filters/fuchsia.base_unittests.filter b/testing/buildbot/filters/fuchsia.base_unittests.filter
index e2f8f85..8242149bc 100644
--- a/testing/buildbot/filters/fuchsia.base_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.base_unittests.filter
@@ -149,7 +149,6 @@
 -ProcessTest.TerminateCurrentProcessImmediatelyWithNonZeroExitCode
 -ProcessTest.TerminateCurrentProcessImmediatelyWithZeroExitCode
 -ProcessTest.WaitForExitWithTimeout
--ProcessUtilTest.CurrentDirectory
 -ProcessUtilTest.DelayedTermination
 -ProcessUtilTest.FDRemapping
 -ProcessUtilTest.GetAppOutput
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 6ae40072..b2bd6b07 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -18704,9 +18704,8 @@
 crbug.com/591099 overflow/overflow-basic-005.html [ Failure Pass ]
 crbug.com/591099 overflow/overflow-basic-006.html [ Failure Pass ]
 crbug.com/591099 overflow/overflow-bug-chrome-ng-001.html [ Failure ]
-crbug.com/591099 overflow/overflow-position-001.html [ Failure ]
-crbug.com/591099 overflow/overflow-position-002.html [ Failure ]
 crbug.com/591099 overflow/overflow-position-003.html [ Failure ]
+crbug.com/591099 overflow/overflow-position-004.html [ Failure ]
 crbug.com/591099 overflow/overflow-transform-001.html [ Failure Pass ]
 crbug.com/591099 paint/background/background-and-shadow.html [ Failure ]
 crbug.com/591099 paint/background/fieldset-legend-background-shadow-border-radius.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
index ac84c2b..24ea5cf 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
@@ -709,6 +709,11 @@
 Bug(none) external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest.https.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/payment-request/historical.https.html [ Failure Timeout ]
 Bug(none) external/wpt/payment-request/interfaces.https.html [ Failure Timeout ]
+Bug(none) external/wpt/payment-request/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html [ Timeout ]
+Bug(none) external/wpt/payment-request/payment-allowed-by-feature-policy-attribute.https.sub.html [ Timeout ]
+Bug(none) external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html [ Timeout ]
+Bug(none) external/wpt/payment-request/payment-default-feature-policy.https.sub.html [ Timeout ]
+Bug(none) external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html [ Timeout ] 
 Bug(none) external/wpt/payment-request/payment-request-abort-method.https.html [ Failure Timeout ]
 Bug(none) external/wpt/payment-request/payment-request-constructor-crash.https.html [ Failure Timeout ]
 Bug(none) external/wpt/payment-request/payment-request-constructor.https.html [ Failure Timeout ]
@@ -1497,6 +1502,7 @@
 Bug(none) external/wpt/websockets/Secure-Send-binary-blob.htm [ Failure Timeout ]
 Bug(none) external/wpt/websockets/Send-binary-blob.htm [ Failure Timeout ]
 Bug(none) external/wpt/webusb/idlharness.https.html [ Failure Timeout ]
+Bug(none) external/wpt/webusb/usb-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html [ Timeout ]
 Bug(none) external/wpt/webusb/usb-allowed-by-feature-policy-attribute.https.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/webusb/usb-allowed-by-feature-policy.https.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/webusb/usb-default-feature-policy.https.sub.html [ Failure Timeout ]
@@ -3312,6 +3318,7 @@
 Bug(none) webaudio/unit-tests/audit.html [ Timeout ]
 Bug(none) webshare/share-arity.html [ Timeout ]
 Bug(none) webshare/share-error.html [ Timeout ]
+Bug(none) webshare/share-nonutf8-encoding.html [ Timeout ]
 Bug(none) webshare/share-success.html [ Timeout ]
 Bug(none) webshare/share-types.html [ Timeout ]
 Bug(none) webshare/share-without-user-gesture.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index c5f934ba..59114103 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -759,9 +759,8 @@
 crbug.com/724701 virtual/layout_ng/overflow/overflow-basic-004.html [ Failure ]
 crbug.com/728378 virtual/layout_ng/overflow/overflow-bug-chrome-ng-001.html [ Failure ]
 crbug.com/728378 virtual/layout_ng/overflow/overflow-transform-002.html [ Failure ]
-crbug.com/728378 virtual/layout_ng/overflow/overflow-position-001.html [ Failure ]
-crbug.com/728378 virtual/layout_ng/overflow/overflow-position-002.html [ Failure ]
 crbug.com/728378 virtual/layout_ng/overflow/overflow-position-003.html [ Failure ]
+crbug.com/728378 virtual/layout_ng/overflow/overflow-position-004.html [ Failure ]
 
 # ====== LayoutNG-only failures until here ======
 
diff --git a/third_party/WebKit/LayoutTests/overflow/overflow-position-004.html b/third_party/WebKit/LayoutTests/overflow/overflow-position-004.html
new file mode 100644
index 0000000..33347c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/overflow/overflow-position-004.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<style>
+html, body {
+  margin: 0; padding: 0;
+}
+#container {
+  overflow: scroll;
+  direction: rtl;
+  position: relative;
+  width: 200px;
+  height: 200px;
+  box-shadow: 0px 0px 12px 0px black;
+}
+#target {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+<p>Overflow: origin of absolutely positioned child with rtl parent with scrollbars should be next to scrollbar</p>
+<div id="container">
+  <div id="target">foo</div>
+</div>
+<script>
+
+var container = document.querySelector('#container');
+var target = document.querySelector('#target');
+
+function getTargetOffset() {
+  var containerRect = container.getBoundingClientRect();
+  var targetRect = target.getBoundingClientRect();
+  return {
+    top: targetRect.top - containerRect.top,
+    left: targetRect.left - containerRect.left
+  }
+}
+
+test(function() {
+  var targetOffset = getTargetOffset();
+  assert_equals(targetOffset.top, container.clientTop, "top");
+  assert_equals(targetOffset.left, container.clientLeft, "left");
+}, "absolute position with rtl scrollbars");
+
+</script>
+
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
index 3f9bd30..84fd9da 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -314,13 +314,12 @@
   // TODO(crbug.com/729196): Trace why LocalFrameView::DetachFromLayout crashes.
   // It seems to crash because Frame is detached before LocalFrameView.
   // Verify here that any LocalFrameView has been detached by now.
-  CHECK(!view_->IsAttached());
-  if (HTMLFrameOwnerElement* owner = DeprecatedLocalOwner()) {
-    if (EmbeddedContentView* owner_view = owner->OwnedEmbeddedContentView()) {
-      CHECK(!owner_view->IsAttached());
-      CHECK_EQ(owner_view, view_);
-    }
+  if (view_->IsAttached()) {
+    CHECK(DeprecatedLocalOwner());
+    CHECK(DeprecatedLocalOwner()->OwnedEmbeddedContentView());
+    CHECK_EQ(view_, DeprecatedLocalOwner()->OwnedEmbeddedContentView());
   }
+  CHECK(!view_->IsAttached());
 
   SetView(nullptr);
 
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameClient.h b/third_party/WebKit/Source/core/frame/LocalFrameClient.h
index 979bc3a..0ebbbbe 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameClient.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameClient.h
@@ -225,11 +225,6 @@
   virtual WebRemotePlaybackClient* CreateWebRemotePlaybackClient(
       HTMLMediaElement&) = 0;
 
-  virtual ObjectContentType GetObjectContentType(
-      const KURL&,
-      const String& mime_type,
-      bool should_prefer_plug_ins_for_images) = 0;
-
   virtual void DidCreateNewDocument() = 0;
   virtual void DispatchDidClearWindowObjectInMainWorld() = 0;
   virtual void DocumentElementAvailable() = 0;
diff --git a/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp b/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp
index 891cff3..1a88683 100644
--- a/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp
@@ -175,7 +175,7 @@
     service_type_ = "text/html";
   }
 
-  RequestObject(url_, service_type_, param_names, param_values);
+  RequestObject(param_names, param_values);
 }
 
 bool HTMLEmbedElement::LayoutObjectIsNeeded(const ComputedStyle& style) {
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
index e961096..d31992b 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
@@ -241,6 +241,12 @@
     return;
 
   if (embedded_content_view_) {
+    // TODO(crbug.com/729196): Trace why LocalFrameView::DetachFromLayout
+    // crashes.  Perhaps view is getting reattached while document is shutting
+    // down.
+    if (doc) {
+      CHECK_NE(doc->Lifecycle().GetState(), DocumentLifecycle::kStopping);
+    }
     layout_embedded_content_item.UpdateOnEmbeddedContentViewChange();
 
     DCHECK_EQ(GetDocument().View(),
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
index 24d4f76..30cf907 100644
--- a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
@@ -148,11 +148,8 @@
 // TODO(schenney): crbug.com/572908 This function should not deal with url or
 // serviceType!
 void HTMLObjectElement::ParametersForPlugin(Vector<String>& param_names,
-                                            Vector<String>& param_values,
-                                            String& url,
-                                            String& service_type) {
+                                            Vector<String>& param_values) {
   HashSet<StringImpl*, CaseFoldingHash> unique_param_names;
-  String url_parameter;
 
   // Scan the PARAM children and store their name/value pairs.
   // Get the URL and type from the params if we don't already have them.
@@ -168,35 +165,25 @@
 
     // TODO(schenney): crbug.com/572908 url adjustment does not belong in this
     // function.
-    if (url.IsEmpty() && url_parameter.IsEmpty() &&
-        (DeprecatedEqualIgnoringCase(name, "src") ||
-         DeprecatedEqualIgnoringCase(name, "movie") ||
-         DeprecatedEqualIgnoringCase(name, "code") ||
-         DeprecatedEqualIgnoringCase(name, "url")))
-      url_parameter = StripLeadingAndTrailingHTMLSpaces(p->Value());
+    // HTML5 says that an object resource's URL is specified by the object's
+    // data attribute, not by a param element. However, for compatibility, allow
+    // the resource's URL to be given by a param named "src", "movie", "code" or
+    // "url" if we know that resource points to a plugin.
+    if (url_.IsEmpty() && (DeprecatedEqualIgnoringCase(name, "src") ||
+                           DeprecatedEqualIgnoringCase(name, "movie") ||
+                           DeprecatedEqualIgnoringCase(name, "code") ||
+                           DeprecatedEqualIgnoringCase(name, "url"))) {
+      url_ = StripLeadingAndTrailingHTMLSpaces(p->Value());
+    }
     // TODO(schenney): crbug.com/572908 serviceType calculation does not belong
     // in this function.
-    if (service_type.IsEmpty() && DeprecatedEqualIgnoringCase(name, "type")) {
-      service_type = p->Value();
-      size_t pos = service_type.Find(";");
+    if (service_type_.IsEmpty() && DeprecatedEqualIgnoringCase(name, "type")) {
+      size_t pos = p->Value().Find(";");
       if (pos != kNotFound)
-        service_type = service_type.Left(pos);
+        service_type_ = p->Value().GetString().Left(pos);
     }
   }
 
-  // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE
-  // attribute in the tag points to the Java plugin itself (an ActiveX
-  // component) while the actual applet CODEBASE is in a PARAM tag. See
-  // <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means we
-  // have to explicitly suppress the tag's CODEBASE attribute if there is none
-  // in a PARAM, else our Java plugin will misinterpret it. [4004531]
-  String codebase;
-  if (MIMETypeRegistry::IsJavaAppletMIMEType(service_type)) {
-    codebase = "codebase";
-    unique_param_names.insert(
-        codebase.Impl());  // pretend we found it in a PARAM already
-  }
-
   // Turn the attributes of the <object> element into arrays, but don't override
   // <param> values.
   AttributeCollection attributes = this->Attributes();
@@ -209,17 +196,6 @@
   }
 
   MapDataParamToSrc(&param_names, &param_values);
-
-  // HTML5 says that an object resource's URL is specified by the object's data
-  // attribute, not by a param element. However, for compatibility, allow the
-  // resource's URL to be given by a param named "src", "movie", "code" or "url"
-  // if we know that resource points to a plugin.
-  if (url.IsEmpty() && !url_parameter.IsEmpty()) {
-    KURL completed_url = GetDocument().CompleteURL(url_parameter);
-    bool use_fallback;
-    if (ShouldUsePlugin(completed_url, service_type, false, use_fallback))
-      url = url_parameter;
-  }
 }
 
 bool HTMLObjectElement::HasFallbackContent() const {
@@ -292,17 +268,14 @@
     return;
   }
 
-  String url = this->Url();
-  String service_type = service_type_;
-
   // TODO(schenney): crbug.com/572908 These should be joined into a
   // PluginParameters class.
   Vector<String> param_names;
   Vector<String> param_values;
-  ParametersForPlugin(param_names, param_values, url, service_type);
+  ParametersForPlugin(param_names, param_values);
 
   // Note: url is modified above by parametersForPlugin.
-  if (!AllowedToLoadFrameURL(url)) {
+  if (!AllowedToLoadFrameURL(url_)) {
     DispatchErrorEvent();
     return;
   }
@@ -317,13 +290,12 @@
       GetDocument().GetFrame()->Loader().Client()->OverrideFlashEmbedWithHTML(
           GetDocument().CompleteURL(url_));
   if (!overriden_url.IsEmpty()) {
-    url = url_ = overriden_url.GetString();
-    service_type = service_type_ = "text/html";
+    url_ = overriden_url.GetString();
+    service_type_ = "text/html";
   }
 
-  if (!HasValidClassId() ||
-      !RequestObject(url, service_type, param_names, param_values)) {
-    if (!url.IsEmpty())
+  if (!HasValidClassId() || !RequestObject(param_names, param_values)) {
+    if (!url_.IsEmpty())
       DispatchErrorEvent();
     if (HasFallbackContent())
       RenderFallbackContent();
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.h b/third_party/WebKit/Source/core/html/HTMLObjectElement.h
index 673f1a4..ee887df 100644
--- a/third_party/WebKit/Source/core/html/HTMLObjectElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.h
@@ -110,9 +110,7 @@
   // FIXME: This function should not deal with url or serviceType
   // so that we can better share code between <object> and <embed>.
   void ParametersForPlugin(Vector<String>& param_names,
-                           Vector<String>& param_values,
-                           String& url,
-                           String& service_type);
+                           Vector<String>& param_values);
 
   bool HasValidClassId() const;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
index 660e159..0dd0ce0 100644
--- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
@@ -118,23 +118,22 @@
 }
 
 bool HTMLPlugInElement::RequestObjectInternal(
-    const String& url,
-    const String& mime_type,
     const Vector<String>& param_names,
     const Vector<String>& param_values) {
-  if (url.IsEmpty() && mime_type.IsEmpty())
+  if (url_.IsEmpty() && service_type_.IsEmpty())
     return false;
 
-  if (ProtocolIsJavaScript(url))
+  if (ProtocolIsJavaScript(url_))
     return false;
 
-  KURL completed_url = url.IsEmpty() ? KURL() : GetDocument().CompleteURL(url);
-  if (!AllowedToLoadObject(completed_url, mime_type))
+  KURL completed_url =
+      url_.IsEmpty() ? KURL() : GetDocument().CompleteURL(url_);
+  if (!AllowedToLoadObject(completed_url, service_type_))
     return false;
 
-  bool use_fallback;
-  if (!ShouldUsePlugin(completed_url, mime_type, HasFallbackContent(),
-                       use_fallback)) {
+  ObjectContentType object_type = GetObjectContentType();
+  if (object_type == ObjectContentType::kFrame ||
+      object_type == ObjectContentType::kImage) {
     // If the plugin element already contains a subframe,
     // loadOrRedirectSubframe will re-use it. Otherwise, it will create a
     // new frame and set it as the LayoutEmbeddedContent's EmbeddedContentView,
@@ -142,7 +141,11 @@
     return LoadOrRedirectSubframe(completed_url, GetNameAttribute(), true);
   }
 
-  return LoadPlugin(completed_url, mime_type, param_names, param_values,
+  // If an object's content can't be handled and it has no fallback, let
+  // it be handled as a plugin to show the broken plugin icon.
+  bool use_fallback =
+      object_type == ObjectContentType::kNone && HasFallbackContent();
+  return LoadPlugin(completed_url, service_type_, param_names, param_values,
                     use_fallback, true);
 }
 
@@ -194,7 +197,7 @@
     image_loader_->UpdateFromElement();
   } else if (NeedsPluginUpdate() && !GetLayoutEmbeddedItem().IsNull() &&
              !GetLayoutEmbeddedItem().ShowsUnavailablePluginIndicator() &&
-             !WouldLoadAsNetscapePlugin(url_, service_type_) &&
+             GetObjectContentType() != ObjectContentType::kPlugin &&
              !is_delaying_load_event_) {
     is_delaying_load_event_ = true;
     GetDocument().IncrementLoadEventDelayCount();
@@ -485,17 +488,46 @@
   return plugin_is_available_;
 }
 
+HTMLPlugInElement::ObjectContentType HTMLPlugInElement::GetObjectContentType() {
+  String mime_type = service_type_;
+  KURL url = GetDocument().CompleteURL(url_);
+  if (mime_type.IsEmpty()) {
+    // Try to guess the MIME type based off the extension.
+    String filename = url.LastPathComponent();
+    int extension_pos = filename.ReverseFind('.');
+    if (extension_pos >= 0) {
+      String extension = filename.Substring(extension_pos + 1);
+      mime_type = MIMETypeRegistry::GetWellKnownMIMETypeForExtension(extension);
+    }
+
+    if (mime_type.IsEmpty())
+      return ObjectContentType::kFrame;
+  }
+
+  // If Chrome is started with the --disable-plugins switch, pluginData is 0.
+  PluginData* plugin_data = GetDocument().GetFrame()->GetPluginData();
+  bool plugin_supports_mime_type =
+      plugin_data && plugin_data->SupportsMimeType(mime_type);
+
+  if (MIMETypeRegistry::IsSupportedImageMIMEType(mime_type)) {
+    return should_prefer_plug_ins_for_images_ && plugin_supports_mime_type
+               ? ObjectContentType::kPlugin
+               : ObjectContentType::kImage;
+  }
+
+  if (plugin_supports_mime_type)
+    return ObjectContentType::kPlugin;
+  if (MIMETypeRegistry::IsSupportedNonImageMIMEType(mime_type))
+    return ObjectContentType::kFrame;
+  return ObjectContentType::kNone;
+}
+
 bool HTMLPlugInElement::IsImageType() {
   if (service_type_.IsEmpty() && ProtocolIs(url_, "data"))
     service_type_ = MimeTypeFromDataURL(url_);
 
-  if (LocalFrame* frame = GetDocument().GetFrame()) {
-    KURL completed_url = GetDocument().CompleteURL(url_);
-    return frame->Loader().Client()->GetObjectContentType(
-               completed_url, service_type_, ShouldPreferPlugInsForImages()) ==
-           kObjectContentImage;
-  }
-
+  if (GetDocument().GetFrame())
+    return GetObjectContentType() == ObjectContentType::kImage;
   return Image::SupportsType(service_type_);
 }
 
@@ -516,25 +548,9 @@
                ContentFrame()->GetSecurityContext()->GetSecurityOrigin()));
 }
 
-// We don't use m_url, or m_serviceType as they may not be the final values
-// that <object> uses depending on <param> values.
-bool HTMLPlugInElement::WouldLoadAsNetscapePlugin(const String& url,
-                                                  const String& service_type) {
-  DCHECK(GetDocument().GetFrame());
-  KURL completed_url;
-  if (!url.IsEmpty())
-    completed_url = GetDocument().CompleteURL(url);
-  return GetDocument().GetFrame()->Loader().Client()->GetObjectContentType(
-             completed_url, service_type, ShouldPreferPlugInsForImages()) ==
-         kObjectContentNetscapePlugin;
-}
-
-bool HTMLPlugInElement::RequestObject(const String& url,
-                                      const String& mime_type,
-                                      const Vector<String>& param_names,
+bool HTMLPlugInElement::RequestObject(const Vector<String>& param_names,
                                       const Vector<String>& param_values) {
-  bool result =
-      RequestObjectInternal(url, mime_type, param_names, param_values);
+  bool result = RequestObjectInternal(param_names, param_values);
 
   DEFINE_STATIC_LOCAL(
       EnumerationHistogram, result_histogram,
@@ -609,20 +625,6 @@
   return true;
 }
 
-bool HTMLPlugInElement::ShouldUsePlugin(const KURL& url,
-                                        const String& mime_type,
-                                        bool has_fallback,
-                                        bool& use_fallback) {
-  ObjectContentType object_type =
-      GetDocument().GetFrame()->Loader().Client()->GetObjectContentType(
-          url, mime_type, ShouldPreferPlugInsForImages());
-  // If an object's content can't be handled and it has no fallback, let
-  // it be handled as a plugin to show the broken plugin icon.
-  use_fallback = object_type == kObjectContentNone && has_fallback;
-  return object_type == kObjectContentNone ||
-         object_type == kObjectContentNetscapePlugin;
-}
-
 void HTMLPlugInElement::DispatchErrorEvent() {
   if (GetDocument().IsPluginDocument() && GetDocument().LocalOwner())
     GetDocument().LocalOwner()->DispatchEvent(
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
index 6e41930..0176d2f8 100644
--- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
@@ -109,19 +109,10 @@
   virtual LayoutEmbeddedContent* LayoutEmbeddedContentForJSBindings() const;
 
   bool IsImageType();
-  bool ShouldPreferPlugInsForImages() const {
-    return should_prefer_plug_ins_for_images_;
-  }
   LayoutEmbeddedItem GetLayoutEmbeddedItem() const;
   bool AllowedToLoadFrameURL(const String& url);
-  bool RequestObject(const String& url,
-                     const String& mime_type,
-                     const Vector<String>& param_names,
+  bool RequestObject(const Vector<String>& param_names,
                      const Vector<String>& param_values);
-  bool ShouldUsePlugin(const KURL&,
-                       const String& mime_type,
-                       bool has_fallback,
-                       bool& use_fallback);
 
   void DispatchErrorEvent();
   bool IsErrorplaceholder();
@@ -176,13 +167,18 @@
   bool AllowedToLoadPlugin(const KURL&, const String& mime_type);
   // Perform checks based on the URL and MIME-type of the object to load.
   bool AllowedToLoadObject(const KURL&, const String& mime_type);
-  bool WouldLoadAsNetscapePlugin(const String& url, const String& service_type);
+
+  enum class ObjectContentType {
+    kNone,
+    kImage,
+    kFrame,
+    kPlugin,
+  };
+  ObjectContentType GetObjectContentType();
 
   void SetPersistedPlugin(PluginView*);
 
-  bool RequestObjectInternal(const String& url,
-                             const String& mime_type,
-                             const Vector<String>& param_names,
+  bool RequestObjectInternal(const Vector<String>& param_names,
                              const Vector<String>& param_values);
 
   v8::Global<v8::Object> plugin_wrapper_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 8747903..d9ca861b 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -172,7 +172,7 @@
   if (known_fragment_offset)
     return known_fragment_offset.value() - ContainerBfcOffset();
   LayoutUnit inline_offset =
-      border_and_padding_.inline_start + child_margins.inline_start;
+      border_scrollbar_padding_.inline_start + child_margins.inline_start;
   // TODO(ikilpatrick): Using the content_size_ here looks suspicious - check.
   return {inline_offset, content_size_};
 }
@@ -182,9 +182,9 @@
   if (NeedMinMaxContentSize(ConstraintSpace(), Style()))
     min_max_size = ComputeMinMaxContentSize();
 
-  border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) +
-                        ComputePadding(ConstraintSpace(), Style());
-
+  border_scrollbar_padding_ = ComputeBorders(ConstraintSpace(), Style()) +
+                              ComputePadding(ConstraintSpace(), Style()) +
+                              GetScrollbarSizes(Node().GetLayoutObject());
   // TODO(layout-ng): For quirks mode, should we pass blockSize instead of -1?
   NGLogicalSize size(
       ComputeInlineSizeForFragment(ConstraintSpace(), Style(), min_max_size),
@@ -195,10 +195,13 @@
   // If so, just leave the size as NGSizeIndefinite instead of subtracting
   // borders and padding.
   NGLogicalSize adjusted_size(size);
-  if (size.block_size == NGSizeIndefinite)
-    adjusted_size.inline_size -= border_and_padding_.InlineSum();
-  else
-    adjusted_size -= border_and_padding_;
+  if (size.block_size == NGSizeIndefinite) {
+    adjusted_size.inline_size -= border_scrollbar_padding_.InlineSum();
+  } else {
+    adjusted_size -= border_scrollbar_padding_;
+    adjusted_size.block_size = std::max(adjusted_size.block_size, LayoutUnit());
+  }
+  adjusted_size.inline_size = std::max(adjusted_size.inline_size, LayoutUnit());
 
   child_available_size_ = adjusted_size;
   child_percentage_size_ = adjusted_size;
@@ -216,7 +219,8 @@
 
   // If we are resuming from a break token our start border and padding is
   // within a previous fragment.
-  content_size_ = BreakToken() ? LayoutUnit() : border_and_padding_.block_start;
+  content_size_ =
+      BreakToken() ? LayoutUnit() : border_scrollbar_padding_.block_start;
 
   NGMarginStrut input_margin_strut = ConstraintSpace().MarginStrut();
   LayoutUnit input_bfc_block_offset =
@@ -225,7 +229,7 @@
   // Margins collapsing:
   //   Do not collapse margins between parent and its child if there is
   //   border/padding between them.
-  if (border_and_padding_.block_start) {
+  if (border_scrollbar_padding_.block_start) {
     input_bfc_block_offset += input_margin_strut.Sum();
     MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset,
                                  &container_builder_);
@@ -285,8 +289,8 @@
   //   Bottom margins of an in-flow block box doesn't collapse with its last
   //   in-flow block-level child's bottom margin if the box has bottom
   //   border/padding.
-  content_size_ += border_and_padding_.block_end;
-  if (border_and_padding_.block_end ||
+  content_size_ += border_scrollbar_padding_.block_end;
+  if (border_scrollbar_padding_.block_end ||
       ConstraintSpace().IsNewFormattingContext()) {
     content_size_ += end_margin_strut.Sum();
     end_margin_strut = NGMarginStrut();
@@ -318,7 +322,6 @@
     end_margin_strut = NGMarginStrut();
   }
   container_builder_.SetEndMarginStrut(end_margin_strut);
-
   container_builder_.SetOverflowSize(
       NGLogicalSize(max_inline_size_, content_size_));
 
@@ -335,7 +338,7 @@
 void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned(
     const NGPreviousInflowPosition& previous_inflow_position,
     NGBlockNode child) {
-  NGLogicalOffset offset = {border_and_padding_.inline_start,
+  NGLogicalOffset offset = {border_scrollbar_padding_.inline_start,
                             previous_inflow_position.logical_block_offset};
 
   // We only include the margin strut in the OOF static-position if we know we
@@ -354,7 +357,7 @@
   NGBoxStrut margins = CalculateMargins(child);
 
   NGLogicalOffset origin_offset = constraint_space_->BfcOffset();
-  origin_offset.inline_offset += border_and_padding_.inline_start;
+  origin_offset.inline_offset += border_scrollbar_padding_.inline_start;
   RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create(
       child_available_size_, child_percentage_size_, origin_offset,
       constraint_space_->BfcOffset(), margins, child, token);
@@ -410,7 +413,7 @@
 
   NGLogicalOffset child_bfc_offset = {
       ConstraintSpace().BfcOffset().inline_offset +
-          border_and_padding_.inline_start + margins.inline_start,
+          border_scrollbar_padding_.inline_start + margins.inline_start,
       bfc_block_offset};
 
   bool is_new_fc = IsNewFormattingContextForBlockLevelChild(Style(), child);
@@ -485,7 +488,7 @@
         content_size_, logical_offset.block_offset + fragment.BlockSize());
   max_inline_size_ = std::max(
       max_inline_size_, fragment.InlineSize() + child_data.margins.InlineSum() +
-                            border_and_padding_.InlineSum());
+                            border_scrollbar_padding_.InlineSum());
 
   container_builder_.AddChild(layout_result, logical_offset);
 
@@ -530,7 +533,7 @@
                  container_builder_.UnpositionedFloats(), tmp_space.Get());
 
   NGLogicalOffset origin_offset = {ConstraintSpace().BfcOffset().inline_offset +
-                                       border_and_padding_.inline_start,
+                                       border_scrollbar_padding_.inline_start,
                                    child_bfc_offset_estimate};
   AdjustToClearance(
       GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()),
@@ -557,7 +560,7 @@
                         MutableConstraintSpace());
 
   origin_offset = {ConstraintSpace().BfcOffset().inline_offset +
-                       border_and_padding_.inline_start,
+                       border_scrollbar_padding_.inline_start,
                    child_bfc_offset_estimate};
   AdjustToClearance(
       GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()),
@@ -597,7 +600,8 @@
 
   NGLogicalOffset bfc_offset = {
       ConstraintSpace().BfcOffset().inline_offset +
-          border_and_padding_.inline_start + child_data.margins.inline_start,
+          border_scrollbar_padding_.inline_start +
+          child_data.margins.inline_start,
       child_data.bfc_offset_estimate.block_offset + margin_strut.Sum()};
   AdjustToClearance(space.ClearanceOffset(), &bfc_offset);
   PositionPendingFloatsFromOffset(bfc_offset.block_offset,
@@ -610,7 +614,7 @@
     const NGConstraintSpace& child_space,
     const NGInflowChildData& child_data) {
   NGLogicalOffset bfc_offset = {ConstraintSpace().BfcOffset().inline_offset +
-                                    border_and_padding_.inline_start +
+                                    border_scrollbar_padding_.inline_start +
                                     child_data.margins.inline_start,
                                 child_data.bfc_offset_estimate.block_offset};
   AdjustToClearance(child_space.ClearanceOffset(), &bfc_offset);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
index d77086d..1e1a584 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -131,7 +131,7 @@
   NGLogicalSize child_available_size_;
   NGLogicalSize child_percentage_size_;
 
-  NGBoxStrut border_and_padding_;
+  NGBoxStrut border_scrollbar_padding_;
   LayoutUnit content_size_;
   LayoutUnit max_inline_size_;
 };
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
index aa69d04..645a908 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
@@ -250,18 +250,18 @@
     NGLayoutResult* layout_result) {
   NGPhysicalBoxFragment* physical_fragment =
       ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get());
-
   if (box_->Style()->SpecifiesColumns())
     UpdateLegacyMultiColumnFlowThread(box_, physical_fragment);
   box_->SetWidth(physical_fragment->Size().width);
   box_->SetHeight(physical_fragment->Size().height);
-  NGBoxStrut border_and_padding = ComputeBorders(constraint_space, Style()) +
-                                  ComputePadding(constraint_space, Style());
+  NGBoxStrut border_scrollbar_padding =
+      ComputeBorders(constraint_space, Style()) +
+      ComputePadding(constraint_space, Style()) + GetScrollbarSizes(box_);
   LayoutUnit intrinsic_logical_height =
       box_->Style()->IsHorizontalWritingMode()
           ? physical_fragment->OverflowSize().height
           : physical_fragment->OverflowSize().width;
-  intrinsic_logical_height -= border_and_padding.BlockSum();
+  intrinsic_logical_height -= border_scrollbar_padding.BlockSum();
   box_->SetIntrinsicContentLogicalHeight(intrinsic_logical_height);
 
   // TODO(ikilpatrick) is this the right thing to do?
@@ -289,7 +289,7 @@
         FromPlatformWritingMode(Style().GetWritingMode());
     NGBoxFragment fragment(writing_mode, physical_fragment);
     ToLayoutBlock(box_)->ComputeOverflow(fragment.OverflowSize().block_size -
-                                         border_and_padding.block_end);
+                                         border_scrollbar_padding.block_end);
   }
 
   box_->UpdateAfterLayout();
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
index c42696b5..368e872 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -181,6 +181,7 @@
 
   NGLogicalSize available_size{inline_size, block_size};
 
+  // TODO(atotic) will need to be adjusted for scrollbars.
   NGConstraintSpaceBuilder builder(writing_mode);
   builder.SetAvailableSize(available_size);
   builder.SetPercentageResolutionSize(container_size);
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index d66d8e41..7fc7ecf 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -340,12 +340,6 @@
   WebRemotePlaybackClient* CreateWebRemotePlaybackClient(
       HTMLMediaElement&) override;
 
-  ObjectContentType GetObjectContentType(const KURL&,
-                                         const String&,
-                                         bool) override {
-    return ObjectContentType();
-  }
-
   void DidCreateNewDocument() override {}
   void DispatchDidClearWindowObjectInMainWorld() override {}
   void DocumentElementAvailable() override {}
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderTypes.h b/third_party/WebKit/Source/core/loader/FrameLoaderTypes.h
index 97a514633..67fff48 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoaderTypes.h
+++ b/third_party/WebKit/Source/core/loader/FrameLoaderTypes.h
@@ -51,13 +51,6 @@
   kNavigationTypeOther
 };
 
-enum ObjectContentType {
-  kObjectContentNone,
-  kObjectContentImage,
-  kObjectContentFrame,
-  kObjectContentNetscapePlugin,
-};
-
 enum ShouldSendReferrer { kMaybeSendReferrer, kNeverSendReferrer };
 
 enum ShouldSetOpener { kMaybeSetOpener, kNeverSetOpener };
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
index 067834f1..5e3ad60 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
@@ -497,23 +497,11 @@
     if (it == resources_.end())
       continue;
 
-    if (it->value->image_) {
-      if (it->value->image_->HasMailbox()) {
-        it->value->image_->UpdateSyncToken(resource.sync_token);
-      } else if (SharedGpuContext::IsValid() && resource.sync_token.HasData()) {
-        // Although image has MailboxTextureHolder at the time when it is
-        // inserted to m_cachedImages, the
-        // OffscreenCanvasPlaceHolder::placeholderFrame() exposes this image
-        // to everyone accessing the placeholder canvas as an image source,
-        // some of which may want to consume the image as a SkImage, thereby
-        // converting the MailTextureHolder to a SkiaTextureHolder. In this
-        // case, we need to wait for the new sync token passed by
-        // CompositorFrameSink.
-        SharedGpuContext::Gl()->WaitSyncTokenCHROMIUM(
-            resource.sync_token.GetConstData());
-      }
-      ReclaimResourceInternal(it);
+    if (SharedGpuContext::IsValid() && resource.sync_token.HasData()) {
+      SharedGpuContext::Gl()->WaitSyncTokenCHROMIUM(
+          resource.sync_token.GetConstData());
     }
+    ReclaimResourceInternal(it);
   }
 }
 
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
index 8eaa0b6..3dc9df2 100644
--- a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
+++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
@@ -81,7 +81,6 @@
 #include "platform/feature_policy/FeaturePolicy.h"
 #include "platform/loader/fetch/ResourceFetcher.h"
 #include "platform/network/HTTPParsers.h"
-#include "platform/network/mime/MIMETypeRegistry.h"
 #include "platform/plugins/PluginData.h"
 #include "platform/wtf/PtrUtil.h"
 #include "platform/wtf/StringExtras.h"
@@ -854,47 +853,6 @@
   return HTMLMediaElementRemotePlayback::remote(html_media_element);
 }
 
-ObjectContentType LocalFrameClientImpl::GetObjectContentType(
-    const KURL& url,
-    const String& explicit_mime_type,
-    bool should_prefer_plug_ins_for_images) {
-  // This code is based on Apple's implementation from
-  // WebCoreSupport/WebFrameBridge.mm.
-
-  String mime_type = explicit_mime_type;
-  if (mime_type.IsEmpty()) {
-    // Try to guess the MIME type based off the extension.
-    String filename = url.LastPathComponent();
-    int extension_pos = filename.ReverseFind('.');
-    if (extension_pos >= 0) {
-      String extension = filename.Substring(extension_pos + 1);
-      mime_type = MIMETypeRegistry::GetWellKnownMIMETypeForExtension(extension);
-    }
-
-    if (mime_type.IsEmpty())
-      return kObjectContentFrame;
-  }
-
-  // If Chrome is started with the --disable-plugins switch, pluginData is 0.
-  PluginData* plugin_data = web_frame_->GetFrame()->GetPluginData();
-  bool plug_in_supports_mime_type =
-      plugin_data && plugin_data->SupportsMimeType(mime_type);
-
-  if (MIMETypeRegistry::IsSupportedImageMIMEType(mime_type)) {
-    return should_prefer_plug_ins_for_images && plug_in_supports_mime_type
-               ? kObjectContentNetscapePlugin
-               : kObjectContentImage;
-  }
-
-  if (plug_in_supports_mime_type)
-    return kObjectContentNetscapePlugin;
-
-  if (MIMETypeRegistry::IsSupportedNonImageMIMEType(mime_type))
-    return kObjectContentFrame;
-
-  return kObjectContentNone;
-}
-
 WebCookieJar* LocalFrameClientImpl::CookieJar() const {
   if (!web_frame_->Client())
     return 0;
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.h b/third_party/WebKit/Source/web/LocalFrameClientImpl.h
index 5ef26bd..f96edc5 100644
--- a/third_party/WebKit/Source/web/LocalFrameClientImpl.h
+++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.h
@@ -169,10 +169,6 @@
       WebMediaPlayerClient*) override;
   WebRemotePlaybackClient* CreateWebRemotePlaybackClient(
       HTMLMediaElement&) override;
-  ObjectContentType GetObjectContentType(
-      const KURL&,
-      const WTF::String& mime_type,
-      bool should_prefer_plug_ins_for_images) override;
   void DidChangeScrollOffset() override;
   void DidUpdateCurrentHistoryItem() override;
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py
index 91a8f17..fada685 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py
@@ -60,6 +60,9 @@
         self._server_process.broken_pipes.append(self)
         raise IOError
 
+    def read(self):
+        return ''
+
     def close(self):
         self.closed = True
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 196c83b..ceabedd0 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -32360,8 +32360,9 @@
 
 <enum name="SBClientPhishingSkipClassificationReason">
   <int value="0" label="Not skipped"/>
-  <int value="1" label="Skipped: HTTPS"/>
+  <int value="1" label="(Deprecated) Skipped: HTTPS"/>
   <int value="2" label="Skipped: Not a GET request"/>
+  <int value="3" label="Skipped: Unsupported scheme"/>
 </enum>
 
 <enum name="SBDownloadFeedbackUploadResult">
@@ -35962,7 +35963,7 @@
   <int value="3" label="Infobar dismissed"/>
 </enum>
 
-<enum name="ThumbnailTopSitesEvent" type="int">
+<enum name="ThumbnailTopSitesEvent">
   <int value="0" label="Not added: Failure"/>
   <int value="1" label="Not added: TopSites is full"/>
   <int value="2" label="Not added: Existing thumbnail is better"/>
diff --git a/ui/gfx/icc_profile_mac.mm b/ui/gfx/icc_profile_mac.mm
index 1aa768cc..70b899a 100644
--- a/ui/gfx/icc_profile_mac.mm
+++ b/ui/gfx/icc_profile_mac.mm
@@ -4,9 +4,20 @@
 
 #include "ui/gfx/icc_profile.h"
 
+#include <AvailabilityMacros.h>
+
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_cftyperef.h"
 
+#if defined(MAC_OS_X_VERSION_10_13) && \
+    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
+// https://crbug.com/729896, https://openradar.appspot.com/32883726
+#undef CGColorSpaceCopyICCProfile
+extern "C" {
+CFDataRef CGColorSpaceCopyICCProfile(CGColorSpaceRef);
+}  // extern "C"
+#endif  // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
+
 namespace gfx {
 
 // static
diff --git a/ui/gfx/mac/io_surface.cc b/ui/gfx/mac/io_surface.cc
index 606c345a..3cf9b60 100644
--- a/ui/gfx/mac/io_surface.cc
+++ b/ui/gfx/mac/io_surface.cc
@@ -4,6 +4,7 @@
 
 #include "ui/gfx/mac/io_surface.h"
 
+#include <AvailabilityMacros.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -17,6 +18,15 @@
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/color_space_switches.h"
 
+#if defined(MAC_OS_X_VERSION_10_13) && \
+    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
+// https://crbug.com/729896, https://openradar.appspot.com/32883726
+#undef CGColorSpaceCopyICCProfile
+extern "C" {
+CFDataRef CGColorSpaceCopyICCProfile(CGColorSpaceRef);
+}  // extern "C"
+#endif  // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
+
 namespace gfx {
 
 namespace {
diff --git a/ui/ozone/demo/BUILD.gn b/ui/ozone/demo/BUILD.gn
index b284dc9..ad191666 100644
--- a/ui/ozone/demo/BUILD.gn
+++ b/ui/ozone/demo/BUILD.gn
@@ -25,6 +25,7 @@
   deps = [
     "//base",
     "//build/config:exe_and_shlib_deps",
+    "//components/tracing:startup_tracing",
     "//skia",
     "//ui/display/types",
     "//ui/events",
diff --git a/ui/ozone/demo/DEPS b/ui/ozone/demo/DEPS
index f59fd384..2dbcda8 100644
--- a/ui/ozone/demo/DEPS
+++ b/ui/ozone/demo/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
+  "+components/tracing",
   "+ui/gl",
 ]
diff --git a/ui/ozone/demo/ozone_demo.cc b/ui/ozone/demo/ozone_demo.cc
index d14c60cc..1977457 100644
--- a/ui/ozone/demo/ozone_demo.cc
+++ b/ui/ozone/demo/ozone_demo.cc
@@ -12,6 +12,9 @@
 #include "base/run_loop.h"
 #include "base/task_scheduler/task_scheduler.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
+#include "components/tracing/common/trace_to_console.h"
+#include "components/tracing/common/tracing_switches.h"
 #include "ui/display/types/display_snapshot.h"
 #include "ui/display/types/native_display_delegate.h"
 #include "ui/display/types/native_display_observer.h"
@@ -338,6 +341,15 @@
   logging::LoggingSettings settings;
   logging::InitLogging(settings);
 
+  // Initialize tracing.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTraceToConsole)) {
+    base::trace_event::TraceConfig trace_config =
+        tracing::GetConfigForTraceToConsole();
+    base::trace_event::TraceLog::GetInstance()->SetEnabled(
+        trace_config, base::trace_event::TraceLog::RECORDING_MODE);
+  }
+
   // Build UI thread message loop. This is used by platform
   // implementations for event polling & running background tasks.
   base::MessageLoopForUI message_loop;
diff --git a/ui/ozone/platform/drm/gpu/drm_buffer.cc b/ui/ozone/platform/drm/gpu/drm_buffer.cc
index d511661b..784549f 100644
--- a/ui/ozone/platform/drm/gpu/drm_buffer.cc
+++ b/ui/ozone/platform/drm/gpu/drm_buffer.cc
@@ -107,6 +107,10 @@
   return fb_pixel_format_;
 }
 
+uint64_t DrmBuffer::GetFormatModifier() const {
+  return DRM_FORMAT_MOD_NONE;
+}
+
 uint32_t DrmBuffer::GetHandle() const {
   return handle_;
 }
diff --git a/ui/ozone/platform/drm/gpu/drm_buffer.h b/ui/ozone/platform/drm/gpu/drm_buffer.h
index dd162198..dc6ed49 100644
--- a/ui/ozone/platform/drm/gpu/drm_buffer.h
+++ b/ui/ozone/platform/drm/gpu/drm_buffer.h
@@ -40,6 +40,7 @@
   uint32_t GetFramebufferPixelFormat() const override;
   uint32_t GetOpaqueFramebufferId() const override;
   uint32_t GetOpaqueFramebufferPixelFormat() const override;
+  uint64_t GetFormatModifier() const override;
   uint32_t GetHandle() const override;
   gfx::Size GetSize() const override;
   const DrmDevice* GetDrmDevice() const override;
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.cc b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
index dff2d96..85b22c28 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
@@ -83,11 +83,6 @@
   return planes_[index].size;
 }
 
-uint64_t GbmBuffer::GetFormatModifier(size_t index) const {
-  DCHECK_LT(index, planes_.size());
-  return planes_[index].modifier;
-}
-
 // TODO(reveman): This should not be needed once crbug.com/597932 is fixed,
 // as the size would be queried directly from the underlying bo.
 gfx::Size GbmBuffer::GetSize() const {
@@ -168,7 +163,8 @@
   gbm_bo* bo =
       gbm_bo_create(gbm->device(), size.width(), size.height(), format, flags);
 
-  return CreateBufferForBO(gbm, bo, format, size, flags, 0, 0);
+  return CreateBufferForBO(gbm, bo, format, size, flags,
+                           gbm_bo_get_format_modifier(bo), 0);
 }
 
 // static
@@ -250,7 +246,7 @@
     }
     handle.planes.emplace_back(buffer_->GetStride(i), buffer_->GetOffset(i),
                                buffer_->GetSize(i),
-                               buffer_->GetFormatModifier(i));
+                               buffer_->GetFormatModifier());
   }
   return handle;
 }
@@ -283,7 +279,7 @@
 }
 
 uint64_t GbmPixmap::GetDmaBufModifier(size_t plane) const {
-  return buffer_->GetFormatModifier(plane);
+  return buffer_->GetFormatModifier();
 }
 
 gfx::BufferFormat GbmPixmap::GetBufferFormat() const {
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.h b/ui/ozone/platform/drm/gpu/gbm_buffer.h
index 2823243..da9b687 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer.h
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.h
@@ -48,7 +48,6 @@
   int GetStride(size_t plane) const;
   int GetOffset(size_t plane) const;
   size_t GetSize(size_t plane) const;
-  uint64_t GetFormatModifier(size_t plane) const;
   gfx::Size GetSize() const override;
 
  private:
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer_base.cc b/ui/ozone/platform/drm/gpu/gbm_buffer_base.cc
index 7dac027..8af49a8d 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer_base.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer_base.cc
@@ -24,6 +24,7 @@
     framebuffer_pixel_format_ = format;
     opaque_framebuffer_pixel_format_ = GetFourCCFormatForOpaqueFramebuffer(
         GetBufferFormatFromFourCCFormat(format));
+    format_modifier_ = modifier;
 
     uint32_t handles[4] = {0};
     uint32_t strides[4] = {0};
@@ -86,6 +87,11 @@
   return opaque_framebuffer_pixel_format_;
 }
 
+uint64_t GbmBufferBase::GetFormatModifier() const {
+  DCHECK(framebuffer_);
+  return format_modifier_;
+}
+
 const DrmDevice* GbmBufferBase::GetDrmDevice() const {
   return drm_.get();
 }
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer_base.h b/ui/ozone/platform/drm/gpu/gbm_buffer_base.h
index 1aca1bb..48a15253 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer_base.h
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer_base.h
@@ -32,6 +32,7 @@
   gfx::Size GetSize() const override;
   uint32_t GetFramebufferPixelFormat() const override;
   uint32_t GetOpaqueFramebufferPixelFormat() const override;
+  uint64_t GetFormatModifier() const override;
   const DrmDevice* GetDrmDevice() const override;
   bool RequiresGlFinish() const override;
 
@@ -54,6 +55,7 @@
   // otherwise it is set to 0.
   uint32_t opaque_framebuffer_ = 0;
   uint32_t opaque_framebuffer_pixel_format_ = 0;
+  uint64_t format_modifier_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(GbmBufferBase);
 };
diff --git a/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.cc b/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.cc
index 409ac445..ec26ff8 100644
--- a/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.cc
+++ b/ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.cc
@@ -18,6 +18,7 @@
     const std::vector<uint32_t>& crtcs,
     uint32_t planes_per_crtc) {
   const int kPlaneBaseId = 50;
+  const struct drm_format_modifier linear_modifier { 0x1, DRM_FORMAT_MOD_NONE };
   drm_ = drm;
   crtcs_ = crtcs;
   for (size_t crtc_idx = 0; crtc_idx < crtcs_.size(); crtc_idx++) {
@@ -25,7 +26,7 @@
       std::unique_ptr<HardwareDisplayPlane> plane(
           new HardwareDisplayPlane(kPlaneBaseId + i, 1 << crtc_idx));
       plane->Initialize(drm, std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888),
-                        std::vector<drm_format_modifier>(),  // modifiers
+                        std::vector<drm_format_modifier>(1, linear_modifier),
                         false, true);
       planes_.push_back(std::move(plane));
     }
diff --git a/ui/ozone/platform/drm/gpu/mock_scanout_buffer.cc b/ui/ozone/platform/drm/gpu/mock_scanout_buffer.cc
index 91c0082d..fd15615 100644
--- a/ui/ozone/platform/drm/gpu/mock_scanout_buffer.cc
+++ b/ui/ozone/platform/drm/gpu/mock_scanout_buffer.cc
@@ -3,16 +3,30 @@
 // found in the LICENSE file.
 
 #include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h"
+#include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
 
 namespace ui {
 
-MockScanoutBuffer::MockScanoutBuffer(const gfx::Size& size, uint32_t format)
-    : size_(size), format_(format) {}
+namespace {
+
+uint32_t g_current_framebuffer_id = 1;
+
+}  // namespace
+
+MockScanoutBuffer::MockScanoutBuffer(const gfx::Size& size,
+                                     uint32_t format,
+                                     uint64_t modifier,
+                                     const scoped_refptr<DrmDevice>& drm)
+    : size_(size),
+      format_(format),
+      modifier_(modifier),
+      id_(g_current_framebuffer_id++),
+      drm_(drm) {}
 
 MockScanoutBuffer::~MockScanoutBuffer() {}
 
 uint32_t MockScanoutBuffer::GetFramebufferId() const {
-  return 1;
+  return id_;
 }
 
 uint32_t MockScanoutBuffer::GetOpaqueFramebufferId() const {
@@ -35,8 +49,12 @@
   return format_;
 }
 
+uint64_t MockScanoutBuffer::GetFormatModifier() const {
+  return modifier_;
+}
+
 const DrmDevice* MockScanoutBuffer::GetDrmDevice() const {
-  return nullptr;
+  return drm_.get();
 }
 
 bool MockScanoutBuffer::RequiresGlFinish() const {
diff --git a/ui/ozone/platform/drm/gpu/mock_scanout_buffer.h b/ui/ozone/platform/drm/gpu/mock_scanout_buffer.h
index e2e9046..33f5977 100644
--- a/ui/ozone/platform/drm/gpu/mock_scanout_buffer.h
+++ b/ui/ozone/platform/drm/gpu/mock_scanout_buffer.h
@@ -16,7 +16,9 @@
 class MockScanoutBuffer : public ScanoutBuffer {
  public:
   MockScanoutBuffer(const gfx::Size& size,
-                    uint32_t format = DRM_FORMAT_XRGB8888);
+                    uint32_t format = DRM_FORMAT_XRGB8888,
+                    uint64_t modifier = DRM_FORMAT_MOD_NONE,
+                    const scoped_refptr<DrmDevice>& drm = nullptr);
 
   // ScanoutBuffer:
   uint32_t GetFramebufferId() const override;
@@ -25,6 +27,7 @@
   gfx::Size GetSize() const override;
   uint32_t GetFramebufferPixelFormat() const override;
   uint32_t GetOpaqueFramebufferPixelFormat() const override;
+  uint64_t GetFormatModifier() const override;
   const DrmDevice* GetDrmDevice() const override;
   bool RequiresGlFinish() const override;
 
@@ -33,6 +36,9 @@
 
   gfx::Size size_;
   uint32_t format_;
+  uint64_t modifier_;
+  uint32_t id_;
+  scoped_refptr<DrmDevice> drm_;
 
   DISALLOW_COPY_AND_ASSIGN(MockScanoutBuffer);
 };
diff --git a/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.cc b/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.cc
index ccf53a3..08cd50a 100644
--- a/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.cc
+++ b/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.cc
@@ -17,10 +17,19 @@
     const scoped_refptr<DrmDevice>& drm,
     uint32_t format,
     const gfx::Size& size) {
+  return CreateWithModifier(drm, format, DRM_FORMAT_MOD_NONE, size);
+}
+
+scoped_refptr<ScanoutBuffer> MockScanoutBufferGenerator::CreateWithModifier(
+    const scoped_refptr<DrmDevice>& drm,
+    uint32_t format,
+    uint64_t modifier,
+    const gfx::Size& size) {
   if (allocation_failure_)
     return nullptr;
 
-  scoped_refptr<MockScanoutBuffer> buffer(new MockScanoutBuffer(size, format));
+  scoped_refptr<MockScanoutBuffer> buffer(
+      new MockScanoutBuffer(size, format, modifier, drm));
 
   return buffer;
 }
diff --git a/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h b/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h
index fde77e3..2cb3161 100644
--- a/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h
+++ b/ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h
@@ -21,6 +21,12 @@
                                       uint32_t format,
                                       const gfx::Size& size) override;
 
+  scoped_refptr<ScanoutBuffer> CreateWithModifier(
+      const scoped_refptr<DrmDevice>& drm,
+      uint32_t format,
+      uint64_t modifier,
+      const gfx::Size& size);
+
   void set_allocation_failure(bool allocation_failure) {
     allocation_failure_ = allocation_failure;
   }
diff --git a/ui/ozone/platform/drm/gpu/scanout_buffer.h b/ui/ozone/platform/drm/gpu/scanout_buffer.h
index 8a5cd13c..b6b58856 100644
--- a/ui/ozone/platform/drm/gpu/scanout_buffer.h
+++ b/ui/ozone/platform/drm/gpu/scanout_buffer.h
@@ -34,6 +34,9 @@
   // scanout when used as an opaque buffer.
   virtual uint32_t GetOpaqueFramebufferPixelFormat() const = 0;
 
+  // Returns format modifier for buffer.
+  virtual uint64_t GetFormatModifier() const = 0;
+
   // Handle for the buffer. This is received when allocating the buffer.
   virtual uint32_t GetHandle() const = 0;
 
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.cc b/ui/ozone/platform/drm/gpu/screen_manager.cc
index 5dd2666..899f0a5 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager.cc
+++ b/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -348,17 +348,30 @@
     HardwareDisplayController* controller,
     const gfx::Rect& bounds) {
   DrmWindow* window = FindWindowAt(bounds);
+
+  gfx::BufferFormat format = display::DisplaySnapshot::PrimaryFormat();
+  uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(format);
+
   if (window) {
     const OverlayPlane* primary = window->GetLastModesetBuffer();
     const DrmDevice* drm = controller->GetAllocationDrmDevice().get();
     if (primary && primary->buffer->GetSize() == bounds.size() &&
-        primary->buffer->GetDrmDevice() == drm)
-      return *primary;
+        primary->buffer->GetDrmDevice() == drm) {
+      // If the controller doesn't advertise modifiers, wont have a
+      // modifier either and we can reuse the buffer. Otherwise, check
+      // to see if the controller supports the buffers format
+      // modifier.
+      const auto& modifiers = controller->GetFormatModifiers(fourcc_format);
+      if (modifiers.empty())
+        return *primary;
+      for (const uint64_t modifier : modifiers) {
+        if (modifier == primary->buffer->GetFormatModifier())
+          return *primary;
+      }
+    }
   }
 
-  gfx::BufferFormat format = display::DisplaySnapshot::PrimaryFormat();
   scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice();
-  uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(format);
   scoped_refptr<ScanoutBuffer> buffer =
       buffer_generator_->Create(drm, fourcc_format, bounds.size());
   if (!buffer) {
diff --git a/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
index c35b3808c..de0c717 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
@@ -16,7 +16,7 @@
 #include "ui/ozone/platform/drm/gpu/drm_window.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
-#include "ui/ozone/platform/drm/gpu/mock_dumb_buffer_generator.h"
+#include "ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h"
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 
 namespace {
@@ -51,9 +51,10 @@
   }
 
   void SetUp() override {
-    drm_ = new ui::MockDrmDevice();
+    drm_ = new ui::MockDrmDevice(false, std::vector<uint32_t>(1, kPrimaryCrtc),
+                                 4 /* planes per crtc */);
     device_manager_.reset(new ui::DrmDeviceManager(nullptr));
-    buffer_generator_.reset(new ui::MockDumbBufferGenerator());
+    buffer_generator_.reset(new ui::MockScanoutBufferGenerator());
     screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
   }
   void TearDown() override {
@@ -64,7 +65,7 @@
  protected:
   scoped_refptr<ui::MockDrmDevice> drm_;
   std::unique_ptr<ui::DrmDeviceManager> device_manager_;
-  std::unique_ptr<ui::MockDumbBufferGenerator> buffer_generator_;
+  std::unique_ptr<ui::MockScanoutBufferGenerator> buffer_generator_;
   std::unique_ptr<ui::ScreenManager> screen_manager_;
 
  private:
@@ -516,3 +517,33 @@
   window = screen_manager_->RemoveWindow(1);
   window->Shutdown();
 }
+
+TEST_F(ScreenManagerTest, RejectBufferWithIncompatibleModifiers) {
+  std::unique_ptr<ui::DrmWindow> window(
+      new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+  window->Initialize(buffer_generator_.get());
+  window->SetBounds(GetPrimaryBounds());
+  scoped_refptr<ui::ScanoutBuffer> buffer =
+      buffer_generator_->CreateWithModifier(drm_, DRM_FORMAT_XRGB8888,
+                                            I915_FORMAT_MOD_X_TILED,
+                                            GetPrimaryBounds().size());
+
+  window->SchedulePageFlip(
+      std::vector<ui::OverlayPlane>(1, ui::OverlayPlane(buffer)),
+      base::Bind(&EmptySwapCallback));
+  screen_manager_->AddWindow(1, std::move(window));
+
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->ConfigureDisplayController(
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      kDefaultMode);
+
+  // ScreenManager::GetModesetBuffer (called to get a buffer to
+  // modeset the new controller) should reject the buffer with
+  // I915_FORMAT_MOD_X_TILED modifier we created above and the two
+  // framebuffer IDs should be different.
+  EXPECT_NE(buffer->GetFramebufferId(), drm_->current_framebuffer());
+
+  window = screen_manager_->RemoveWindow(1);
+  window->Shutdown();
+}