diff --git a/BUILD.gn b/BUILD.gn
index b1fd306..04dde8d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -273,6 +273,7 @@
       "//base/android/linker:chromium_android_linker",
       "//build/android/gyp/test:hello_world",
       "//build/android/gyp/test:hello_world",
+      "//build/android/stacktrace:java_deobfuscate",
       "//chrome/android/webapk/shell_apk:webapk",
       "//chrome/test/vr/perf:motopho_latency_test",
       "//components/invalidation/impl:components_invalidation_impl_junit_tests",
diff --git a/DEPS b/DEPS
index 6ede7f92..99e5dd5 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '9d5dcda7818abfb1443400b391d3b35f18ffd96a',
+  'skia_revision': 'fe11e458b0282bf5ebb7943d3bb9455cb46adf9e',
   # 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': 'd98fa02005a2439cae36c36f6e19c867bc07f43d',
+  'v8_revision': '0119b296ffa860518b215487ce89d442e0967938',
   # 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.
@@ -235,7 +235,7 @@
     Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '9677ff7f09e4265be6e387f513f68e78202d2f34', # commit position 18894
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'eb8eec46f7c57ab1bc38111c70ae08eb16b8793d', # commit position 18901
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/base/metrics/histogram_samples.cc b/base/metrics/histogram_samples.cc
index 59f38fc..965d1783 100644
--- a/base/metrics/histogram_samples.cc
+++ b/base/metrics/histogram_samples.cc
@@ -164,17 +164,6 @@
   memset(this, 0, sizeof(*this));
 }
 
-// Don't try to delegate behavior to the constructor below that accepts a
-// Matadata pointer by passing &local_meta_. Such cannot be reliably passed
-// because it has not yet been constructed -- no member variables have; the
-// class itself is in the middle of being constructed. Using it to
-// initialize meta_ is okay because the object now exists and local_meta_
-// is before meta_ in the construction order.
-HistogramSamples::HistogramSamples(uint64_t id)
-    : meta_(&local_meta_) {
-  meta_->id = id;
-}
-
 HistogramSamples::HistogramSamples(uint64_t id, Metadata* meta)
     : meta_(meta) {
   DCHECK(meta_->id == 0 || meta_->id == id);
@@ -185,6 +174,8 @@
     meta_->id = id;
 }
 
+// This mustn't do anything with |meta_|. It was passed to the ctor and may
+// be invalid by the time this dtor gets called.
 HistogramSamples::~HistogramSamples() {}
 
 void HistogramSamples::Add(const HistogramSamples& other) {
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h
index cc27d3dd..e6257da 100644
--- a/base/metrics/histogram_samples.h
+++ b/base/metrics/histogram_samples.h
@@ -128,7 +128,6 @@
     LocalMetadata();
   };
 
-  explicit HistogramSamples(uint64_t id);
   HistogramSamples(uint64_t id, Metadata* meta);
   virtual ~HistogramSamples();
 
@@ -180,11 +179,9 @@
     return meta_->single_sample;
   }
 
+  Metadata* meta() { return meta_; }
+
  private:
-  // In order to support histograms shared through an external memory segment,
-  // meta values may be the local storage or external storage depending on the
-  // wishes of the derived class.
-  LocalMetadata local_meta_;
   Metadata* meta_;
 
   DISALLOW_COPY_AND_ASSIGN(HistogramSamples);
diff --git a/base/metrics/sample_map.cc b/base/metrics/sample_map.cc
index f0e4e5ed..08fe032 100644
--- a/base/metrics/sample_map.cc
+++ b/base/metrics/sample_map.cc
@@ -79,9 +79,11 @@
 
 SampleMap::SampleMap() : SampleMap(0) {}
 
-SampleMap::SampleMap(uint64_t id) : HistogramSamples(id) {}
+SampleMap::SampleMap(uint64_t id) : HistogramSamples(id, new LocalMetadata()) {}
 
-SampleMap::~SampleMap() {}
+SampleMap::~SampleMap() {
+  delete static_cast<LocalMetadata*>(meta());
+}
 
 void SampleMap::Accumulate(Sample value, Count count) {
   sample_counts_[value] += count;
diff --git a/base/metrics/sample_vector.cc b/base/metrics/sample_vector.cc
index 5306c3e..98214f2 100644
--- a/base/metrics/sample_vector.cc
+++ b/base/metrics/sample_vector.cc
@@ -24,12 +24,6 @@
 typedef HistogramBase::Sample Sample;
 
 SampleVectorBase::SampleVectorBase(uint64_t id,
-                                   const BucketRanges* bucket_ranges)
-    : HistogramSamples(id), bucket_ranges_(bucket_ranges) {
-  CHECK_GE(bucket_ranges_->bucket_count(), 1u);
-}
-
-SampleVectorBase::SampleVectorBase(uint64_t id,
                                    Metadata* meta,
                                    const BucketRanges* bucket_ranges)
     : HistogramSamples(id, meta), bucket_ranges_(bucket_ranges) {
@@ -286,9 +280,11 @@
     : SampleVector(0, bucket_ranges) {}
 
 SampleVector::SampleVector(uint64_t id, const BucketRanges* bucket_ranges)
-    : SampleVectorBase(id, bucket_ranges) {}
+    : SampleVectorBase(id, new LocalMetadata(), bucket_ranges) {}
 
-SampleVector::~SampleVector() {}
+SampleVector::~SampleVector() {
+  delete static_cast<LocalMetadata*>(meta());
+}
 
 bool SampleVector::MountExistingCountsStorage() const {
   // There is never any existing storage other than what is already in use.
diff --git a/base/metrics/sample_vector.h b/base/metrics/sample_vector.h
index 8e28e29..622bf2c 100644
--- a/base/metrics/sample_vector.h
+++ b/base/metrics/sample_vector.h
@@ -29,7 +29,6 @@
 
 class BASE_EXPORT SampleVectorBase : public HistogramSamples {
  public:
-  SampleVectorBase(uint64_t id, const BucketRanges* bucket_ranges);
   SampleVectorBase(uint64_t id,
                    Metadata* meta,
                    const BucketRanges* bucket_ranges);
diff --git a/build/android/adb_command_line.py b/build/android/adb_command_line.py
index bf6a65e..78e9e50 100755
--- a/build/android/adb_command_line.py
+++ b/build/android/adb_command_line.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/build/android/binary_size/apk_downloader.py b/build/android/binary_size/apk_downloader.py
index e6d7082..062930d 100755
--- a/build/android/binary_size/apk_downloader.py
+++ b/build/android/binary_size/apk_downloader.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # 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.
diff --git a/build/android/emma_coverage_stats.py b/build/android/emma_coverage_stats.py
index 20ec8ea..fe1775a 100755
--- a/build/android/emma_coverage_stats.py
+++ b/build/android/emma_coverage_stats.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/build/android/emma_coverage_stats_test.py b/build/android/emma_coverage_stats_test.py
index 30b409e2..44f6dc3 100755
--- a/build/android/emma_coverage_stats_test.py
+++ b/build/android/emma_coverage_stats_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/build/android/pylib/utils/decorators_test.py b/build/android/pylib/utils/decorators_test.py
index d31db9c..60f4811 100755
--- a/build/android/pylib/utils/decorators_test.py
+++ b/build/android/pylib/utils/decorators_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # 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.
diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py
index 0a942a3..c93f675 100755
--- a/build/android/resource_sizes.py
+++ b/build/android/resource_sizes.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/build/android/stacktrace/BUILD.gn b/build/android/stacktrace/BUILD.gn
new file mode 100644
index 0000000..a3957fec
--- /dev/null
+++ b/build/android/stacktrace/BUILD.gn
@@ -0,0 +1,17 @@
+# 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("//build/config/android/rules.gni")
+
+java_binary("java_deobfuscate") {
+  main_class = "org.chromium.build.FlushingReTrace"
+  java_files = [ "java/org/chromium/build/FlushingReTrace.java" ]
+  deps = [
+    "//third_party/proguard:retrace_java",
+  ]
+  data = [
+    "$root_build_dir/lib.java/build/android/stacktrace/java_deobfuscate.jar",
+    "$root_build_dir/bin/java_deobfuscate",
+  ]
+}
diff --git a/build/android/stacktrace/README.md b/build/android/stacktrace/README.md
new file mode 100644
index 0000000..fb4c035c
--- /dev/null
+++ b/build/android/stacktrace/README.md
@@ -0,0 +1,18 @@
+# java_deobfuscate
+
+A wrapper around ProGuard's ReTrace tool, which:
+
+1) Updates the regular expression used to identify stack lines, and
+2) Streams its output.
+
+The second point here is what allows you to run:
+
+    adb logcat | out/Default/bin/java_deobfuscate
+
+And have it actually show output without logcat terminating.
+
+
+# stackwalker.py
+
+Extracts Breakpad microdumps from a log file and uses `stackwalker` to symbolize
+them.
diff --git a/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
new file mode 100644
index 0000000..1402511
--- /dev/null
+++ b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
@@ -0,0 +1,60 @@
+// 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.build;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import proguard.retrace.ReTrace;
+
+/**
+ * A wrapper around ReTrace that:
+ *  1. Hardcodes a more useful line regular expression
+ *  2. Disables output buffering
+ */
+public class FlushingReTrace {
+    // This regex is based on the one from:
+    // http://proguard.sourceforge.net/manual/retrace/usage.html.
+    // But with the "at" part changed to "(?::|\bat)", to account for lines like:
+    //     06-22 13:58:02.895  4674  4674 E THREAD_STATE:     bLA.a(PG:173)
+    // Normal stack trace lines look like:
+    // java.lang.RuntimeException: Intentional Java Crash
+    //     at org.chromium.chrome.browser.tab.Tab.handleJavaCrash(Tab.java:682)
+    //     at org.chromium.chrome.browser.tab.Tab.loadUrl(Tab.java:644)
+    private static final String LINE_PARSE_REGEX =
+            "(?:.*?(?::|\\bat)\\s+%c\\.%m\\s*\\(%s(?::%l)?\\)\\s*)|(?:(?:.*?[:\"]\\s+)?%c(?::.*)?)";
+
+    public static void main(String[] args) {
+        if (args.length != 1) {
+            System.err.println("Usage: retrace Foo.apk.map < foo.log > bar.log");
+            System.exit(1);
+        }
+
+        File mappingFile = new File(args[0]);
+        try {
+            LineNumberReader reader = new LineNumberReader(
+                    new BufferedReader(new InputStreamReader(System.in, "UTF-8")));
+
+            // Enabling autoFlush is the main difference from ReTrace.main().
+            boolean autoFlush = true;
+            PrintWriter writer =
+                    new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"), autoFlush);
+
+            boolean verbose = false;
+            new ReTrace(LINE_PARSE_REGEX, verbose, mappingFile).retrace(reader, writer);
+        } catch (IOException ex) {
+            // Print a verbose stack trace.
+            ex.printStackTrace();
+            System.exit(1);
+        }
+
+        System.exit(0);
+    }
+}
diff --git a/build/android/stacktrace/java_deobfuscate.py b/build/android/stacktrace/java_deobfuscate.py
deleted file mode 100755
index 1c73300..0000000
--- a/build/android/stacktrace/java_deobfuscate.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A tool to deobfuscate Java stack traces.
-
-Utility wrapper around ReTrace to deobfuscate stack traces that have been
-mangled by ProGuard. Takes stack traces from stdin (eg. adb logcat |
-java_deobfuscate.py proguard.mapping) and files.
-"""
-
-import argparse
-import os
-
-_SRC_DIR = os.path.normpath(
-    os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))
-
-# This regex is based on the one from:
-# http://proguard.sourceforge.net/manual/retrace/usage.html.
-# But with the "at" part changed to "(?::|\bat)", to account for lines like:
-#     06-22 13:58:02.895  4674  4674 E THREAD_STATE:     bLA.a(PG:173)
-# Normal stack trace lines look like:
-# java.lang.RuntimeException: Intentional Java Crash
-#     at org.chromium.chrome.browser.tab.Tab.handleJavaCrash(Tab.java:682)
-#     at org.chromium.chrome.browser.tab.Tab.loadUrl(Tab.java:644)
-_LINE_PARSE_REGEX = (
-    r'(?:.*?(?::|\bat)\s+%c\.%m\s*\(%s(?::%l)?\)\s*)|'
-    r'(?:(?:.*?[:"]\s+)?%c(?::.*)?)')
-
-
-def main():
-  parser = argparse.ArgumentParser(description=(__doc__))
-  parser.add_argument(
-      'mapping_file',
-      help='ProGuard mapping file from build which the stacktrace is from.')
-  parser.add_argument(
-      '--stacktrace',
-      help='Stacktrace file to be deobfuscated.')
-  args = parser.parse_args()
-
-  retrace_path = os.path.join(
-      _SRC_DIR, 'third_party', 'proguard', 'lib', 'retrace.jar')
-
-  cmd = ['java', '-jar', retrace_path, '-regex', _LINE_PARSE_REGEX,
-         args.mapping_file]
-  if args.stacktrace:
-    cmd.append(args.stacktrace)
-  os.execvp('java', cmd)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index aef8ea4..611fda7 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -2058,7 +2058,11 @@
     }
 
     group(target_name) {
-      forward_variables_from(invoker, [ "data_deps" ])
+      forward_variables_from(invoker,
+                             [
+                               "data",
+                               "data_deps",
+                             ])
       public_deps = [
         ":$_ijar_target_name",
         ":$_process_jar_target_name",
diff --git a/build/env_dump.py b/build/env_dump.py
index 21edfe63..3f82173 100755
--- a/build/env_dump.py
+++ b/build/env_dump.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # Copyright 2013 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/build/ios/clean_env.py b/build/ios/clean_env.py
index 548e2b9..bf56b2f 100755
--- a/build/ios/clean_env.py
+++ b/build/ios/clean_env.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/build/util/java_action.py b/build/util/java_action.py
index abf084c..ed9bb60 100755
--- a/build/util/java_action.py
+++ b/build/util/java_action.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 # Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index ffed54c..30113479 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -478,9 +478,10 @@
     /**
      * Constructs a valid referrer using the given authority.
      * @param authority The authority to use.
-     * @return Referrer with default policy that uses the valid android app scheme.
+     * @return Referrer with default policy that uses the valid android app scheme, or null.
      */
     public static Referrer constructValidReferrerForAuthority(String authority) {
+        if (TextUtils.isEmpty(authority)) return null;
         return new Referrer(new Uri.Builder().scheme(ANDROID_APP_REFERRER_SCHEME)
                 .authority(authority).build().toString(), Referrer.REFERRER_POLICY_DEFAULT);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHelper.java
index 186a039..40274d94 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHelper.java
@@ -40,7 +40,7 @@
     static void sendEmail(
             String email, String subject, String body, String chooserTitle, String fileToAttach) {
         if (TextUtils.isEmpty(email)) {
-            Account[] accounts = AccountManagerHelper.get().getGoogleAccounts();
+            Account[] accounts = AccountManagerHelper.get().tryGetGoogleAccounts();
             if (accounts != null && accounts.length == 1
                     && Patterns.EMAIL_ADDRESS.matcher(accounts[0].name).matches()) {
                 email = accounts[0].name;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java b/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java
index 1a91056..62de119 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java
@@ -42,7 +42,7 @@
     public static void checkHasChildAccount(Context context, final Callback<Boolean> callback) {
         ThreadUtils.assertOnUiThread();
         final AccountManagerHelper helper = AccountManagerHelper.get();
-        helper.getGoogleAccounts(new Callback<Account[]>() {
+        helper.tryGetGoogleAccounts(new Callback<Account[]>() {
             @Override
             public void onResult(Account[] accounts) {
                 if (accounts.length != 1) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
index 1f7eadcc..b0733e29 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -115,7 +115,7 @@
 
     @VisibleForTesting
     protected Account[] getGoogleAccounts() {
-        return AccountManagerHelper.get().getGoogleAccounts();
+        return AccountManagerHelper.get().tryGetGoogleAccounts();
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java
index 3d3a58a..f2ed200 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java
@@ -75,7 +75,7 @@
             Log.d(TAG, "Sign in disallowed");
             return;
         }
-        AccountManagerHelper.get().getGoogleAccounts(new Callback<Account[]>() {
+        AccountManagerHelper.get().tryGetGoogleAccounts(new Callback<Account[]>() {
             @Override
             public void onResult(Account[] accounts) {
                 if (accounts.length != 1) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiver.java
index 248e6cfa..5d93ffa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiver.java
@@ -57,7 +57,7 @@
                         TOS_ACKED_ACCOUNTS, null);
         if (toSAckedAccounts == null || toSAckedAccounts.isEmpty()) return false;
         AccountManagerHelper accountHelper = AccountManagerHelper.get();
-        List<String> accountNames = accountHelper.getGoogleAccountNames();
+        List<String> accountNames = accountHelper.tryGetGoogleAccountNames();
         if (accountNames.isEmpty()) return false;
         for (int k = 0; k < accountNames.size(); k++) {
             if (toSAckedAccounts.contains(accountNames.get(k))) return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncedAccountPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncedAccountPreference.java
index 91deddcc..333893b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncedAccountPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncedAccountPreference.java
@@ -47,7 +47,7 @@
             // signed in account
         }
 
-        Account[] accounts = AccountManagerHelper.get().getGoogleAccounts();
+        Account[] accounts = AccountManagerHelper.get().tryGetGoogleAccounts();
         String[] accountNames = new String[accounts.length];
         String[] accountValues = new String[accounts.length];
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
index 3a9c31b2..44b88cf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
@@ -195,7 +195,7 @@
      * @param profile Profile to use.
      */
     private static void startFetchingAccountsInformation(Context context, Profile profile) {
-        Account[] accounts = AccountManagerHelper.get().getGoogleAccounts();
+        Account[] accounts = AccountManagerHelper.get().tryGetGoogleAccounts();
         for (Account account : accounts) {
             startFetchingAccountInformation(context, profile, account.name);
         }
@@ -381,7 +381,7 @@
         accountsCategory.removeAll();
 
         boolean isChildAccount = mProfile.isChild();
-        Account[] accounts = AccountManagerHelper.get().getGoogleAccounts();
+        Account[] accounts = AccountManagerHelper.get().tryGetGoogleAccounts();
         for (final Account account : accounts) {
             Preference pref = new Preference(getActivity());
             pref.setLayoutResource(R.layout.account_management_account_row);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
index 05d495b..0d87f0ed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
@@ -253,7 +253,7 @@
             updatingGmsDialog = null;
         }
 
-        mAccountManagerHelper.getGoogleAccountNames(new Callback<List<String>>() {
+        mAccountManagerHelper.tryGetGoogleAccountNames(new Callback<List<String>>() {
             @Override
             public void onResult(List<String> result) {
                 if (updatingGmsDialog != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountTrackerService.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountTrackerService.java
index f8f278c..a605db4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountTrackerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountTrackerService.java
@@ -113,7 +113,7 @@
             mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_NOT_STARTED;
             return;
         }
-        AccountManagerHelper.get().getGoogleAccounts(new Callback<Account[]>() {
+        AccountManagerHelper.get().tryGetGoogleAccounts(new Callback<Account[]>() {
             @Override
             public void onResult(final Account[] accounts) {
                 new AsyncTask<Void, Void, String[][]>() {
@@ -199,7 +199,7 @@
         }
 
         mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_VALIDATING;
-        AccountManagerHelper.get().getGoogleAccounts(new Callback<Account[]>() {
+        AccountManagerHelper.get().tryGetGoogleAccounts(new Callback<Account[]>() {
             @Override
             public void onResult(final Account[] accounts) {
                 if (mSystemAccountsChanged
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java
index ce2b8028..b187323 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java
@@ -109,7 +109,7 @@
     @CalledByNative
     public static String[] getSystemAccountNames() {
         AccountManagerHelper accountManagerHelper = AccountManagerHelper.get();
-        java.util.List<String> accountNames = accountManagerHelper.getGoogleAccountNames();
+        java.util.List<String> accountNames = accountManagerHelper.tryGetGoogleAccountNames();
         return accountNames.toArray(new String[accountNames.size()]);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
index a9728e1..f7dc3ed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
@@ -146,7 +146,7 @@
             if (lastSyncAccountName != null && !lastSyncAccountName.isEmpty()) return;
 
             if (!chromePreferenceManager.getSigninPromoShown()
-                    && AccountManagerHelper.get().getGoogleAccountNames().size() > 0) {
+                    && AccountManagerHelper.get().tryGetGoogleAccountNames().size() > 0) {
                 chromePreferenceManager.setShowSigninPromo(true);
             }
 
@@ -257,7 +257,7 @@
     }
 
     private static boolean accountExists(Context context, Account account) {
-        Account[] accounts = AccountManagerHelper.get().getGoogleAccounts();
+        Account[] accounts = AccountManagerHelper.get().tryGetGoogleAccounts();
         for (Account a : accounts) {
             if (a.equals(account)) {
                 return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java
index cafe88e..cc54812 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java
@@ -10,7 +10,6 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.download.ui.ThumbnailProvider;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
@@ -24,7 +23,6 @@
 
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Class responsible for fetching images for the views in the NewTabPage and Chrome Home.
@@ -169,6 +167,10 @@
         mIsDestroyed = true;
     }
 
+    public static String getSnippetDomain(URI snippetUri) {
+        return String.format("%s://%s", snippetUri.getScheme(), snippetUri.getHost());
+    }
+
     private void fetchFaviconFromLocalCache(final URI snippetUri, final boolean fallbackToService,
             final long faviconFetchStartTimeMs, final int faviconSizePx,
             final SnippetArticle suggestion, final Callback<Bitmap> faviconCallback) {
@@ -180,15 +182,15 @@
                             assert faviconCallback != null;
 
                             faviconCallback.onResult(image);
-                            recordFaviconFetchResult(suggestion,
+                            recordFaviconFetchHistograms(suggestion,
                                     fallbackToService ? FaviconFetchResult.SUCCESS_CACHED
                                                       : FaviconFetchResult.SUCCESS_FETCHED,
-                                    faviconFetchStartTimeMs);
+                                    SystemClock.elapsedRealtime() - faviconFetchStartTimeMs);
                         } else if (fallbackToService) {
                             if (!fetchFaviconFromService(suggestion, snippetUri,
                                         faviconFetchStartTimeMs, faviconSizePx, faviconCallback)) {
-                                recordFaviconFetchResult(suggestion, FaviconFetchResult.FAILURE,
-                                        faviconFetchStartTimeMs);
+                                recordFaviconFetchHistograms(suggestion, FaviconFetchResult.FAILURE,
+                                        SystemClock.elapsedRealtime() - faviconFetchStartTimeMs);
                             }
                         }
                     }
@@ -202,7 +204,8 @@
                 /* desiredSizePx */ 0, new Callback<Bitmap>() {
                     @Override
                     public void onResult(Bitmap image) {
-                        recordFaviconFetchTime(faviconFetchStartTimeMs);
+                        SuggestionsMetrics.recordArticleFaviconFetchTime(
+                                SystemClock.elapsedRealtime() - faviconFetchStartTimeMs);
                         if (image == null) return;
                         faviconCallback.onResult(image);
                     }
@@ -227,8 +230,8 @@
                     @Override
                     public void onIconAvailabilityChecked(boolean newlyAvailable) {
                         if (!newlyAvailable) {
-                            recordFaviconFetchResult(suggestion, FaviconFetchResult.FAILURE,
-                                    faviconFetchStartTimeMs);
+                            recordFaviconFetchHistograms(suggestion, FaviconFetchResult.FAILURE,
+                                    SystemClock.elapsedRealtime() - faviconFetchStartTimeMs);
                             return;
                         }
                         // The download succeeded, the favicon is in the cache; fetch it.
@@ -240,22 +243,6 @@
         return true;
     }
 
-    private void recordFaviconFetchTime(long faviconFetchStartTimeMs) {
-        RecordHistogram.recordMediumTimesHistogram(
-                "NewTabPage.ContentSuggestions.ArticleFaviconFetchTime",
-                SystemClock.elapsedRealtime() - faviconFetchStartTimeMs, TimeUnit.MILLISECONDS);
-    }
-
-    private void recordFaviconFetchResult(SnippetArticle suggestion, @FaviconFetchResult int result,
-            long faviconFetchStartTimeMs) {
-        // Record the histogram for articles only to have a fair comparision.
-        if (!suggestion.isArticle()) return;
-        RecordHistogram.recordEnumeratedHistogram(
-                "NewTabPage.ContentSuggestions.ArticleFaviconFetchResult", result,
-                FaviconFetchResult.COUNT);
-        recordFaviconFetchTime(faviconFetchStartTimeMs);
-    }
-
     /**
      * Checks if an icon with the given URL is available. If not,
      * downloads it and stores it as a favicon/large icon for the given {@code pageUrl}.
@@ -285,8 +272,12 @@
         return 0;
     }
 
-    public static String getSnippetDomain(URI snippetUri) {
-        return String.format("%s://%s", snippetUri.getScheme(), snippetUri.getHost());
+    private void recordFaviconFetchHistograms(
+            SnippetArticle suggestion, int result, long fetchTime) {
+        // Record the histogram for articles only to have a fair comparision.
+        if (!suggestion.isArticle()) return;
+        SuggestionsMetrics.recordArticleFaviconFetchResult(result);
+        SuggestionsMetrics.recordArticleFaviconFetchTime(fetchTime);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java
index 61c717a..195549ba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java
@@ -7,13 +7,17 @@
 import android.support.v7.widget.RecyclerView;
 
 import org.chromium.base.Callback;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
+import org.chromium.chrome.browser.ntp.snippets.FaviconFetchResult;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.tab.Tab;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Exposes methods to report suggestions related events, for UMA or Fetch scheduling purposes.
  */
@@ -84,6 +88,30 @@
         });
     }
 
+    // Histogram recordings
+
+    /**
+     * Records the time it took to fetch a favicon for an article.
+     *
+     * @param fetchTime The time it took to fetch the favicon.
+     */
+    public static void recordArticleFaviconFetchTime(long fetchTime) {
+        RecordHistogram.recordMediumTimesHistogram(
+                "NewTabPage.ContentSuggestions.ArticleFaviconFetchTime", fetchTime,
+                TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Records the result from a favicon fetch for an article.
+     *
+     * @param result {@link FaviconFetchResult} The result from the fetch.
+     */
+    public static void recordArticleFaviconFetchResult(@FaviconFetchResult int result) {
+        RecordHistogram.recordEnumeratedHistogram(
+                "NewTabPage.ContentSuggestions.ArticleFaviconFetchResult", result,
+                FaviconFetchResult.COUNT);
+    }
+
     /**
      * One-shot reporter that records the first time the user scrolls a {@link RecyclerView}. If it
      * should be reused, call {@link #reset()} to rearm it.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
index e2de479..ca15dbb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
@@ -335,7 +335,7 @@
         // We remove the the SyncedAccountPreference if there's only 1 account on the device, so
         // it's possible for accountList to be null
         if (accountList != null) {
-            Account[] accounts = AccountManagerHelper.get().getGoogleAccounts();
+            Account[] accounts = AccountManagerHelper.get().tryGetGoogleAccounts();
             if (accounts.length <= 1) {
                 getPreferenceScreen().removePreference(accountList);
             } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 9a70b610..cb9a248c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -681,7 +681,7 @@
         mVrShell.setWebVrModeEnabled(webVrMode, false);
 
         // We're entering VR, but not in WebVr mode.
-        mVrBrowserUsed = !webVrMode;
+        mVrBrowserUsed = !webVrMode && !mAutopresentWebVr;
 
         // onResume needs to be called on GvrLayout after initialization to make sure DON flow works
         // properly.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/util/FeatureUtilitiesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/util/FeatureUtilitiesTest.java
index fdf6d6f4..5a56cc6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/util/FeatureUtilitiesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/util/FeatureUtilitiesTest.java
@@ -26,6 +26,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.components.signin.AccountManagerHelper;
+import org.chromium.components.signin.test.util.AccountHolder;
 import org.chromium.components.signin.test.util.FakeAccountManagerDelegate;
 
 import java.util.ArrayList;
@@ -115,18 +116,6 @@
         }
 
         @Override
-        public Account[] getAccountsByType(String accountType) {
-            if (accountType.equals(mAccountType)) {
-                // Calling function uses length of array to determine if
-                // accounts of the requested type are available, so return
-                // a non-empty array to indicate the account type is correct.
-                return new Account[] { AccountManagerHelper.createAccountFromName("Dummy") };
-            }
-
-            return new Account[0];
-        }
-
-        @Override
         public AuthenticatorDescription[] getAuthenticatorTypes() {
             AuthenticatorDescription googleAuthenticator =
                     new AuthenticatorDescription(mAccountType, "p1", 0, 0, 0, 0);
@@ -149,14 +138,17 @@
             });
     }
 
-    private void setUpAccount(final String accountType) {
-        mAccountManager = new FakeAuthenticationAccountManager(
-                mAccountTestingContext, accountType, mTestAccount);
-
+    private void setUpAccountManager(String accountType) {
+        mAccountManager = new FakeAuthenticationAccountManager(mAccountTestingContext, accountType);
         AccountManagerHelper.overrideAccountManagerHelperForTests(
                 mAccountTestingContext, mAccountManager);
     }
 
+    private void addTestAccount() {
+        mAccountManager.addAccountHolderExplicitly(
+                AccountHolder.builder(mTestAccount).alwaysAccept(true).build());
+    }
+
     @Test
     @SmallTest
     @Feature({"FeatureUtilities", "Speech"})
@@ -220,7 +212,8 @@
     public void testHasGoogleAccountCorrectlyDetected() {
         // Set up an account manager mock that returns Google account types
         // when queried.
-        setUpAccount(AccountManagerHelper.GOOGLE_ACCOUNT_TYPE);
+        setUpAccountManager(AccountManagerHelper.GOOGLE_ACCOUNT_TYPE);
+        addTestAccount();
 
         boolean hasAccounts = FeatureUtilities.hasGoogleAccounts(
                 mAccountTestingContext);
@@ -242,9 +235,9 @@
     @SmallTest
     @Feature({"FeatureUtilities", "GoogleAccounts"})
     public void testHasNoGoogleAccountCorrectlyDetected() {
-        // Set up an account manager mock that doesn't return Google account
-        // types when queried.
-        setUpAccount("Not A Google Account");
+        // Set up an account manager mock that doesn't have any accounts and doesn't have Google
+        // account authenticator.
+        setUpAccountManager("Not A Google Account");
 
         boolean hasAccounts = FeatureUtilities.hasGoogleAccounts(
                 mAccountTestingContext);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java
index 3698d006..1c1c69a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java
@@ -38,6 +38,7 @@
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.superviseduser.SupervisedUserContentProvider.SupervisedUserQueryReply;
 import org.chromium.components.signin.AccountManagerDelegate;
+import org.chromium.components.signin.AccountManagerDelegateException;
 import org.chromium.components.signin.AccountManagerHelper;
 import org.chromium.components.signin.ChromeSigninController;
 import org.chromium.components.webrestrictions.browser.WebRestrictionsContentProvider.WebRestrictionsResult;
@@ -214,7 +215,8 @@
 
     @SuppressWarnings("unchecked")
     @Test
-    public void testShouldProceed_notSignedIn() throws ProcessInitException {
+    public void testShouldProceed_notSignedIn()
+            throws ProcessInitException, AccountManagerDelegateException {
         // Mock things called during startup
         ChromeBrowserInitializer mockBrowserInitializer = mock(ChromeBrowserInitializer.class);
         ChromeBrowserInitializer.setForTesting(mockBrowserInitializer);
@@ -222,7 +224,7 @@
         AccountManagerHelper.overrideAccountManagerHelperForTests(
                 RuntimeEnvironment.application, mockDelegate);
         Account account = new Account("Google", "Dummy");
-        when(mockDelegate.getAccountsByType("Google")).thenReturn(new Account[] {account});
+        when(mockDelegate.getAccountsSync()).thenReturn(new Account[] {account});
 
         WebRestrictionsResult result =
                 mSupervisedUserContentProvider.shouldProceed(DEFAULT_CALLING_PACKAGE, "url");
@@ -242,7 +244,7 @@
     }
 
     @Test
-    public void testShouldProceed_cannotSignIn() {
+    public void testShouldProceed_cannotSignIn() throws AccountManagerDelegateException {
         // Mock things called during startup
         ChromeBrowserInitializer mockBrowserInitializer = mock(ChromeBrowserInitializer.class);
         ChromeBrowserInitializer.setForTesting(mockBrowserInitializer);
@@ -250,7 +252,7 @@
         AccountManagerHelper.overrideAccountManagerHelperForTests(
                 RuntimeEnvironment.application, mockDelegate);
         Account account = new Account("Google", "Dummy");
-        when(mockDelegate.getAccountsByType("Google")).thenReturn(new Account[] {account});
+        when(mockDelegate.getAccountsSync()).thenReturn(new Account[] {account});
 
         // Change the behavior of the forced sign-in processor to not sign in.
         doAnswer(new Answer<Void>() {
diff --git a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
index 4c71856..855d6595 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
@@ -11,12 +11,10 @@
 #include <vector>
 
 #include "base/location.h"
-#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/password_manager/native_backend_gnome_x.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
index 634ecfc0..1de9f288 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
@@ -16,10 +16,8 @@
 #include "base/callback.h"
 #include "base/location.h"
 #include "base/pickle.h"
-#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/password_manager/native_backend_kwallet_x.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/autofill/core/common/password_form.h"
diff --git a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
index 217cc48..031395f9 100644
--- a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
@@ -9,13 +9,11 @@
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
-#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_task_environment.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/password_manager/native_backend_libsecret.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc
index 808fc9f..399a3b2 100644
--- a/chrome/browser/password_manager/password_store_factory.cc
+++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -12,8 +12,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
@@ -106,8 +106,7 @@
 
   password_manager::ToggleAffiliationBasedMatchingBasedOnPasswordSyncedState(
       password_store.get(), sync_service, request_context_getter,
-      profile->GetPath(), content::BrowserThread::GetTaskRunnerForThread(
-                              content::BrowserThread::DB));
+      profile->GetPath());
 }
 
 PasswordStoreFactory::PasswordStoreFactory()
@@ -158,9 +157,9 @@
   std::unique_ptr<password_manager::LoginDatabase> login_db(
       password_manager::CreateLoginDatabase(profile->GetPath()));
 
-  scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner(
-      base::ThreadTaskRunnerHandle::Get());
-  scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner(
+  scoped_refptr<base::SequencedTaskRunner> main_thread_runner(
+      base::SequencedTaskRunnerHandle::Get());
+  scoped_refptr<base::SequencedTaskRunner> db_thread_runner(
       content::BrowserThread::GetTaskRunnerForThread(
           content::BrowserThread::DB));
 
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
index 9a2ce7ec..d84ba77 100644
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ b/chrome/browser/password_manager/password_store_mac.cc
@@ -11,7 +11,7 @@
 using password_manager::MigrationStatus;
 
 PasswordStoreMac::PasswordStoreMac(
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
+    scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
     std::unique_ptr<password_manager::LoginDatabase> login_db,
     PrefService* prefs)
     : PasswordStoreDefault(main_thread_runner, nullptr, std::move(login_db)) {
@@ -49,7 +49,7 @@
   migration_status_.Destroy();
 }
 
-scoped_refptr<base::SingleThreadTaskRunner>
+scoped_refptr<base::SequencedTaskRunner>
 PasswordStoreMac::GetBackgroundTaskRunner() {
   return thread_ ? thread_->task_runner() : nullptr;
 }
@@ -57,7 +57,7 @@
 PasswordStoreMac::~PasswordStoreMac() = default;
 
 void PasswordStoreMac::InitOnBackgroundThread(MigrationStatus status) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
 
   if (login_db() && (status == MigrationStatus::NOT_STARTED ||
                      status == MigrationStatus::FAILED_ONCE ||
diff --git a/chrome/browser/password_manager/password_store_mac.h b/chrome/browser/password_manager/password_store_mac.h
index fa720d5..044a1554 100644
--- a/chrome/browser/password_manager/password_store_mac.h
+++ b/chrome/browser/password_manager/password_store_mac.h
@@ -20,17 +20,15 @@
 // Password store for Mac. It creates a dedicated background thread
 class PasswordStoreMac : public password_manager::PasswordStoreDefault {
  public:
-  PasswordStoreMac(
-      scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-      std::unique_ptr<password_manager::LoginDatabase> login_db,
-      PrefService* prefs);
+  PasswordStoreMac(scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
+                   std::unique_ptr<password_manager::LoginDatabase> login_db,
+                   PrefService* prefs);
 
   // PasswordStore:
   bool Init(const syncer::SyncableService::StartSyncFlare& flare,
             PrefService* prefs) override;
   void ShutdownOnUIThread() override;
-  scoped_refptr<base::SingleThreadTaskRunner> GetBackgroundTaskRunner()
-      override;
+  scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner() override;
 
 #if defined(UNIT_TEST)
   password_manager::LoginDatabase* login_metadata_db() { return login_db(); }
diff --git a/chrome/browser/password_manager/password_store_win.cc b/chrome/browser/password_manager/password_store_win.cc
index 252b2700..5835bf3 100644
--- a/chrome/browser/password_manager/password_store_win.cc
+++ b/chrome/browser/password_manager/password_store_win.cc
@@ -174,8 +174,8 @@
 }
 
 PasswordStoreWin::PasswordStoreWin(
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
+    scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
+    scoped_refptr<base::SequencedTaskRunner> db_thread_runner,
     std::unique_ptr<password_manager::LoginDatabase> login_db,
     const scoped_refptr<PasswordWebDataService>& web_data_service)
     : PasswordStoreDefault(main_thread_runner,
diff --git a/chrome/browser/password_manager/password_store_win.h b/chrome/browser/password_manager/password_store_win.h
index acdaca0..e46344c 100644
--- a/chrome/browser/password_manager/password_store_win.h
+++ b/chrome/browser/password_manager/password_store_win.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequenced_task_runner.h"
 #include "components/password_manager/core/browser/password_store_default.h"
 
 class PasswordWebDataService;
@@ -25,8 +25,8 @@
   // a deferred manner on the DB thread. The |web_data_service| is only used for
   // IE7 password fetching.
   PasswordStoreWin(
-      scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
+      scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
+      scoped_refptr<base::SequencedTaskRunner> db_thread_runner,
       std::unique_ptr<password_manager::LoginDatabase> login_db,
       const scoped_refptr<PasswordWebDataService>& web_data_service);
 
diff --git a/chrome/browser/password_manager/password_store_win_unittest.cc b/chrome/browser/password_manager/password_store_win_unittest.cc
index 62c9c76..1477c8f 100644
--- a/chrome/browser/password_manager/password_store_win_unittest.cc
+++ b/chrome/browser/password_manager/password_store_win_unittest.cc
@@ -18,9 +18,9 @@
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequenced_task_runner.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/os_crypt/ie7_password_win.h"
@@ -171,7 +171,7 @@
 
   PasswordStoreWin* CreatePasswordStore() {
     return new PasswordStoreWin(
-        base::ThreadTaskRunnerHandle::Get(),
+        base::SequencedTaskRunnerHandle::Get(),
         BrowserThread::GetTaskRunnerForThread(BrowserThread::DB),
         base::MakeUnique<LoginDatabase>(test_login_db_file_path()), wds_.get());
   }
diff --git a/chrome/browser/password_manager/password_store_x.cc b/chrome/browser/password_manager/password_store_x.cc
index b802e900..927dc6e 100644
--- a/chrome/browser/password_manager/password_store_x.cc
+++ b/chrome/browser/password_manager/password_store_x.cc
@@ -61,8 +61,8 @@
 }  // namespace
 
 PasswordStoreX::PasswordStoreX(
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
+    scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
+    scoped_refptr<base::SequencedTaskRunner> db_thread_runner,
     std::unique_ptr<password_manager::LoginDatabase> login_db,
     NativeBackend* backend)
     : PasswordStoreDefault(main_thread_runner,
diff --git a/chrome/browser/password_manager/password_store_x.h b/chrome/browser/password_manager/password_store_x.h
index 3d16ecb..5207456e 100644
--- a/chrome/browser/password_manager/password_store_x.h
+++ b/chrome/browser/password_manager/password_store_x.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "components/password_manager/core/browser/password_store_default.h"
 
@@ -88,8 +88,8 @@
 
   // Takes ownership of |login_db| and |backend|. |backend| may be NULL in which
   // case this PasswordStoreX will act the same as PasswordStoreDefault.
-  PasswordStoreX(scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-                 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
+  PasswordStoreX(scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
+                 scoped_refptr<base::SequencedTaskRunner> db_thread_runner,
                  std::unique_ptr<password_manager::LoginDatabase> login_db,
                  NativeBackend* backend);
 
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index a779c0d0..67cd935 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -18,7 +18,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
@@ -333,8 +333,8 @@
 PasswordStoreXTestDelegate::PasswordStoreXTestDelegate(BackendType backend_type)
     : backend_type_(backend_type) {
   SetupTempDir();
-  store_ = new PasswordStoreX(base::ThreadTaskRunnerHandle::Get(),
-                              base::ThreadTaskRunnerHandle::Get(),
+  store_ = new PasswordStoreX(base::SequencedTaskRunnerHandle::Get(),
+                              base::SequencedTaskRunnerHandle::Get(),
                               base::MakeUnique<password_manager::LoginDatabase>(
                                   test_login_db_file_path()),
                               GetBackend(backend_type_));
@@ -402,9 +402,10 @@
 TEST_P(PasswordStoreXTest, Notifications) {
   std::unique_ptr<password_manager::LoginDatabase> login_db(
       new password_manager::LoginDatabase(test_login_db_file_path()));
-  scoped_refptr<PasswordStoreX> store(new PasswordStoreX(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
-      std::move(login_db), GetBackend(GetParam())));
+  scoped_refptr<PasswordStoreX> store(
+      new PasswordStoreX(base::SequencedTaskRunnerHandle::Get(),
+                         base::SequencedTaskRunnerHandle::Get(),
+                         std::move(login_db), GetBackend(GetParam())));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
   password_manager::PasswordFormData form_data = {
@@ -508,9 +509,10 @@
 
   // Initializing the PasswordStore shouldn't trigger a native migration (yet).
   login_db.reset(new password_manager::LoginDatabase(login_db_file));
-  scoped_refptr<PasswordStoreX> store(new PasswordStoreX(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
-      std::move(login_db), GetBackend(GetParam())));
+  scoped_refptr<PasswordStoreX> store(
+      new PasswordStoreX(base::SequencedTaskRunnerHandle::Get(),
+                         base::SequencedTaskRunnerHandle::Get(),
+                         std::move(login_db), GetBackend(GetParam())));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
   MockPasswordStoreConsumer consumer;
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 296ab6d8b..9db21d6 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -224,6 +224,20 @@
     min_time_to_purge_ = kDefaultMinTimeToPurge;
   else
     min_time_to_purge_ = base::TimeDelta::FromSeconds(min_time_to_purge_sec);
+
+  std::string max_purge_and_suspend_time = variations::GetVariationParamValue(
+      "PurgeAndSuspend", "max-purge-and-suspend-time");
+  unsigned int max_time_to_purge_sec = 0;
+  // If max-purge-and-suspend-time is not specified or
+  // max-purge-and-suspend-time is not valid (not number or smaller than
+  // min-purge-and-suspend-time), use default max-time-to-purge, i.e.
+  // min-time-to-purge times kDefaultMinMaxTimeToPurgeRatio.
+  if (max_purge_and_suspend_time.empty() ||
+      !base::StringToUint(max_purge_and_suspend_time, &max_time_to_purge_sec) ||
+      max_time_to_purge_sec < min_time_to_purge_.InSeconds())
+    max_time_to_purge_ = min_time_to_purge_ * kDefaultMinMaxTimeToPurgeRatio;
+  else
+    max_time_to_purge_ = base::TimeDelta::FromSeconds(max_time_to_purge_sec);
 }
 
 void TabManager::Stop() {
@@ -670,10 +684,10 @@
 }
 
 base::TimeDelta TabManager::GetTimeToPurge(
-    base::TimeDelta min_time_to_purge) const {
-  return base::TimeDelta::FromSeconds(
-      base::RandInt(min_time_to_purge.InSeconds(),
-                    min_time_to_purge.InSeconds() * kMinMaxTimeToPurgeRatio));
+    base::TimeDelta min_time_to_purge,
+    base::TimeDelta max_time_to_purge) const {
+  return base::TimeDelta::FromSeconds(base::RandInt(
+      min_time_to_purge.InSeconds(), max_time_to_purge.InSeconds()));
 }
 
 bool TabManager::ShouldPurgeNow(content::WebContents* content) const {
@@ -812,7 +826,8 @@
     GetWebContentsData(old_contents)->SetLastInactiveTime(NowTicks());
     // Re-setting time-to-purge every time a tab becomes inactive.
     GetWebContentsData(old_contents)
-        ->set_time_to_purge(GetTimeToPurge(min_time_to_purge_));
+        ->set_time_to_purge(
+            GetTimeToPurge(min_time_to_purge_, max_time_to_purge_));
     // Only record switch-to-tab metrics when a switch happens, i.e.
     // |old_contents| is set.
     RecordSwitchToTab(new_contents);
@@ -842,7 +857,7 @@
   GetWebContentsData(contents)->SetLastInactiveTime(NowTicks());
   // Re-setting time-to-purge every time a tab becomes inactive.
   GetWebContentsData(contents)->set_time_to_purge(
-      GetTimeToPurge(min_time_to_purge_));
+      GetTimeToPurge(min_time_to_purge_, max_time_to_purge_));
 }
 
 void TabManager::OnBrowserSetLastActive(Browser* browser) {
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 9f3ecddd..83f6a1b 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -203,7 +203,7 @@
 
   // The min/max time to purge ratio. The max time to purge is set to be
   // min time to purge times this value.
-  const int kMinMaxTimeToPurgeRatio = 2;
+  const int kDefaultMinMaxTimeToPurgeRatio = 2;
 
   // This is needed so WebContentsData can call OnDiscardedStateChange, and
   // can use PurgeState.
@@ -259,8 +259,9 @@
   content::WebContents* GetWebContentsById(int64_t tab_contents_id) const;
 
   // Returns a random time-to-purge whose min value is min_time_to_purge and max
-  // value is min_time_to_purge * kMinMaxTimeToPurgeRatio.
-  base::TimeDelta GetTimeToPurge(base::TimeDelta min_time_to_purge) const;
+  // value is max_time_to_purge.
+  base::TimeDelta GetTimeToPurge(base::TimeDelta min_time_to_purge,
+                                 base::TimeDelta max_time_to_purge) const;
 
   // Returns true if the tab specified by |content| is now eligible to have
   // its memory purged.
@@ -373,8 +374,10 @@
   // backgrounded.
   base::TimeDelta minimum_protection_time_;
 
-  // A backgrounded renderer will be purged when this time passes.
+  // A backgrounded renderer will be purged between min_time_to_purge_ and
+  // max_time_to_purge_.
   base::TimeDelta min_time_to_purge_;
+  base::TimeDelta max_time_to_purge_;
 
 #if defined(OS_CHROMEOS)
   std::unique_ptr<TabManagerDelegate> delegate_;
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 6e3f7507..63a8ed33 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -415,7 +415,8 @@
 TEST_F(TabManagerTest, DefaultTimeToPurgeInCorrectRange) {
   TabManager tab_manager;
   base::TimeDelta time_to_purge =
-      tab_manager.GetTimeToPurge(TabManager::kDefaultMinTimeToPurge);
+      tab_manager.GetTimeToPurge(TabManager::kDefaultMinTimeToPurge,
+                                 TabManager::kDefaultMinTimeToPurge * 2);
   EXPECT_GE(time_to_purge, base::TimeDelta::FromMinutes(30));
   EXPECT_LT(time_to_purge, base::TimeDelta::FromMinutes(60));
 }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeSigninUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeSigninUtils.java
index bfd92e5..9945784 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeSigninUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeSigninUtils.java
@@ -84,7 +84,7 @@
      * Removes all fake accounts from the OS.
      */
     public void removeAllFakeAccountsFromOs() {
-        for (Account acct : mFakeAccountManagerDelegate.getAccountsByType(GOOGLE_ACCOUNT_TYPE)) {
+        for (Account acct : mFakeAccountManagerDelegate.getAccountsSyncNoThrow()) {
             mFakeAccountManagerDelegate.removeAccountHolderExplicitly(
                     AccountHolder.builder(acct).build());
         }
@@ -97,11 +97,7 @@
      * @return {@code true} if fake account is on OS, false otherwise.
      */
     public boolean isExistingFakeAccountOnOs(String username) {
-        if (mFakeAccountManagerDelegate.getAccountsByType(GOOGLE_ACCOUNT_TYPE).length == 0) {
-            return false;
-        }
-
-        for (Account acct : mFakeAccountManagerDelegate.getAccountsByType(GOOGLE_ACCOUNT_TYPE)) {
+        for (Account acct : mFakeAccountManagerDelegate.getAccountsSyncNoThrow()) {
             if (username.equals(acct.name)) {
                 return true;
             }
diff --git a/chrome/test/base/mash_browser_tests_main.cc b/chrome/test/base/mash_browser_tests_main.cc
index af58976c..023ca48b 100644
--- a/chrome/test/base/mash_browser_tests_main.cc
+++ b/chrome/test/base/mash_browser_tests_main.cc
@@ -28,6 +28,7 @@
 #include "chrome/test/base/mojo_test_connector.h"
 #include "content/public/app/content_main.h"
 #include "content/public/common/service_manager_connection.h"
+#include "content/public/common/service_names.mojom.h"
 #include "content/public/test/test_launcher.h"
 #include "mash/session/public/interfaces/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -178,6 +179,20 @@
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch("run-in-mash") &&
       !command_line->HasSwitch("run-in-mus")) {
+    // Currently launching content_package_services via the browser_tests binary
+    // will lead to a nested test suite, trying to run all tests again. However
+    // they will be in a strange mixed mode, of a local-Ash, but non-local Aura.
+    //
+    // This leads to continuous crashes in OzonePlatform.
+    //
+    // For now disable this launch until the requesting site can be identified.
+    //
+    // TODO(jonross): find an appropriate way to launch content_package_services
+    // within the mash_browser_tests (crbug.com/738449)
+    if (command_line->GetSwitchValueASCII("service-name") ==
+        content::mojom::kPackagedServicesServiceName) {
+      return true;
+    }
     return false;
   }
 
diff --git a/components/password_manager/content/browser/credential_manager_impl_unittest.cc b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
index d4a7b17..af7f513 100644
--- a/components/password_manager/content/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
@@ -18,10 +18,9 @@
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h"
 #include "components/password_manager/core/browser/credential_manager_password_form_manager.h"
 #include "components/password_manager/core/browser/password_manager.h"
@@ -104,7 +103,7 @@
       const CredentialsCallback& callback) override {
     EXPECT_FALSE(local_forms.empty());
     const autofill::PasswordForm* form = local_forms[0].get();
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(callback, base::Owned(new autofill::PasswordForm(*form))));
     std::vector<autofill::PasswordForm*> raw_forms(local_forms.size());
diff --git a/components/password_manager/content/renderer/credential_manager_client_browsertest.cc b/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
index 1a0342c..8e3c029 100644
--- a/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
+++ b/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
@@ -13,8 +13,6 @@
 #include "base/location.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
 #include "content/public/test/render_view_test.h"
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
index b4c85c64..8f250dbd 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
@@ -9,8 +9,7 @@
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_service.h"
 
@@ -50,7 +49,7 @@
 void AffiliatedMatchHelper::Initialize() {
   DCHECK(password_store_);
   DCHECK(affiliation_service_);
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&AffiliatedMatchHelper::DoDeferredInitialization,
                  weak_ptr_factory_.GetWeakPtr()),
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
index 2266160..45f9606 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
@@ -142,7 +142,6 @@
       std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
 
   PasswordStore* const password_store_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_waiting_;
 
   // Being the sole consumer of AffiliationService, |this| owns the service.
   std::unique_ptr<AffiliationService> affiliation_service_;
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc b/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
index 4221dafe..20b8e0c 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
@@ -12,8 +12,7 @@
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_checker.h"
+#include "base/sequenced_task_runner.h"
 #include "base/time/clock.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
@@ -27,7 +26,7 @@
 
 AffiliationBackend::AffiliationBackend(
     const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
-    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
     std::unique_ptr<base::Clock> time_source,
     std::unique_ptr<base::TickClock> time_tick_source)
     : request_context_getter_(request_context_getter),
@@ -37,14 +36,14 @@
       construction_time_(clock_->Now()),
       weak_ptr_factory_(this) {
   DCHECK_LT(base::Time(), clock_->Now());
+  DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
 AffiliationBackend::~AffiliationBackend() {
 }
 
 void AffiliationBackend::Initialize(const base::FilePath& db_path) {
-  thread_checker_.reset(new base::ThreadChecker);
-
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!throttler_);
   throttler_.reset(
       new AffiliationFetchThrottler(this, task_runner_, tick_clock_.get()));
@@ -62,7 +61,7 @@
     StrategyOnCacheMiss cache_miss_strategy,
     const AffiliationService::ResultCallback& callback,
     const scoped_refptr<base::TaskRunner>& callback_task_runner) {
-  DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   FacetManager* facet_manager = GetOrCreateFacetManager(facet_uri);
   DCHECK(facet_manager);
@@ -75,7 +74,7 @@
 
 void AffiliationBackend::Prefetch(const FacetURI& facet_uri,
                                   const base::Time& keep_fresh_until) {
-  DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   FacetManager* facet_manager = GetOrCreateFacetManager(facet_uri);
   DCHECK(facet_manager);
@@ -87,7 +86,7 @@
 
 void AffiliationBackend::CancelPrefetch(const FacetURI& facet_uri,
                                         const base::Time& keep_fresh_until) {
-  DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   auto facet_manager_it = facet_managers_.find(facet_uri);
   if (facet_manager_it == facet_managers_.end())
@@ -99,7 +98,7 @@
 }
 
 void AffiliationBackend::TrimCacheForFacet(const FacetURI& facet_uri) {
-  DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   AffiliatedFacetsWithUpdateTime affiliation;
   if (cache_->GetAffiliationsForFacet(facet_uri, &affiliation))
@@ -123,7 +122,7 @@
 
 void AffiliationBackend::DiscardCachedDataIfNoLongerNeeded(
     const AffiliatedFacets& affiliated_facets) {
-  DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Discard the equivalence class if there is no facet in the class whose
   // FacetManager claims that it needs to keep the data.
@@ -140,7 +139,7 @@
 }
 
 void AffiliationBackend::OnSendNotification(const FacetURI& facet_uri) {
-  DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   auto facet_manager_it = facet_managers_.find(facet_uri);
   if (facet_manager_it == facet_managers_.end())
@@ -173,7 +172,7 @@
 
 void AffiliationBackend::OnFetchSucceeded(
     std::unique_ptr<AffiliationFetcherDelegate::Result> result) {
-  DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   fetcher_.reset();
   throttler_->InformOfNetworkRequestComplete(true);
@@ -219,7 +218,7 @@
 }
 
 void AffiliationBackend::OnFetchFailed() {
-  DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   fetcher_.reset();
   throttler_->InformOfNetworkRequestComplete(false);
@@ -234,7 +233,7 @@
 }
 
 void AffiliationBackend::OnMalformedResponse() {
-  DCHECK(thread_checker_ && thread_checker_->CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // TODO(engedy): Potentially handle this case differently. crbug.com/437865.
   OnFetchFailed();
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_backend.h b/components/password_manager/core/browser/android_affiliation/affiliation_backend.h
index 467cc650..44f3ec9 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_backend.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_backend.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_delegate.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher_delegate.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_service.h"
@@ -24,9 +25,8 @@
 namespace base {
 class Clock;
 class FilePath;
-class SingleThreadTaskRunner;
+class SequencedTaskRunner;
 class TaskRunner;
-class ThreadChecker;
 class TickClock;
 class Time;
 }  // namespace base
@@ -62,7 +62,7 @@
   // Construction is very cheap, expensive steps are deferred to Initialize().
   AffiliationBackend(
       const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
       std::unique_ptr<base::Clock> time_source,
       std::unique_ptr<base::TickClock> time_tick_source);
   ~AffiliationBackend() override;
@@ -135,12 +135,12 @@
   void SetThrottlerForTesting(
       std::unique_ptr<AffiliationFetchThrottler> throttler);
 
-  // Created in Initialize(), and ensures that all subsequent methods are called
-  // on the same thread.
-  std::unique_ptr<base::ThreadChecker> thread_checker_;
+  // Ensures that all methods, excluding construction, are called on the same
+  // sequence.
+  SEQUENCE_CHECKER(sequence_checker_);
 
   scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
   std::unique_ptr<base::Clock> clock_;
   std::unique_ptr<base::TickClock> tick_clock_;
 
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.cc b/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.cc
index 0ec5f76a..9721b72 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/rand_util.h"
+#include "base/sequenced_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
@@ -50,7 +51,7 @@
 
 AffiliationFetchThrottler::AffiliationFetchThrottler(
     AffiliationFetchThrottlerDelegate* delegate,
-    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
     base::TickClock* tick_clock)
     : delegate_(delegate),
       task_runner_(task_runner),
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.h b/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.h
index 770cd65..d9a3cba 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.h
@@ -18,7 +18,7 @@
 
 namespace base {
 class TickClock;
-class SingleThreadTaskRunner;
+class SequencedTaskRunner;
 }  // namespace base
 
 namespace password_manager {
@@ -57,7 +57,7 @@
   // |delegate| and |tick_clock| should outlive the throttler.
   AffiliationFetchThrottler(
       AffiliationFetchThrottlerDelegate* delegate,
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
       base::TickClock* tick_clock);
   ~AffiliationFetchThrottler() override;
 
@@ -118,7 +118,7 @@
   void OnConnectionTypeChanged(
       net::NetworkChangeNotifier::ConnectionType type) override;
 
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
   base::TickClock* tick_clock_;
   State state_;
   bool has_network_connectivity_;
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_service.cc b/components/password_manager/core/browser/android_affiliation/affiliation_service.cc
index 71463423..98eb5f56 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_service.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_service.cc
@@ -9,8 +9,8 @@
 #include "base/files/file_path.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/default_clock.h"
 #include "base/time/default_tick_clock.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_backend.h"
@@ -19,14 +19,13 @@
 namespace password_manager {
 
 AffiliationService::AffiliationService(
-    scoped_refptr<base::SingleThreadTaskRunner> backend_task_runner)
+    scoped_refptr<base::SequencedTaskRunner> backend_task_runner)
     : backend_(nullptr),
       backend_task_runner_(backend_task_runner),
-      weak_ptr_factory_(this) {
-}
+      weak_ptr_factory_(this) {}
 
 AffiliationService::~AffiliationService() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (backend_) {
     backend_task_runner_->DeleteSoon(FROM_HERE, backend_);
     backend_ = nullptr;
@@ -36,7 +35,7 @@
 void AffiliationService::Initialize(
     net::URLRequestContextGetter* request_context_getter,
     const base::FilePath& db_path) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!backend_);
   backend_ =
       new AffiliationBackend(request_context_getter, backend_task_runner_,
@@ -53,18 +52,18 @@
     const FacetURI& facet_uri,
     StrategyOnCacheMiss cache_miss_strategy,
     const ResultCallback& result_callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(backend_);
   backend_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&AffiliationBackend::GetAffiliations,
                  base::Unretained(backend_), facet_uri, cache_miss_strategy,
-                 result_callback, base::ThreadTaskRunnerHandle::Get()));
+                 result_callback, base::SequencedTaskRunnerHandle::Get()));
 }
 
 void AffiliationService::Prefetch(const FacetURI& facet_uri,
                                   const base::Time& keep_fresh_until) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(backend_);
   backend_task_runner_->PostTask(
       FROM_HERE,
@@ -74,7 +73,7 @@
 
 void AffiliationService::CancelPrefetch(const FacetURI& facet_uri,
                                         const base::Time& keep_fresh_until) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(backend_);
   backend_task_runner_->PostTask(
       FROM_HERE,
@@ -83,7 +82,7 @@
 }
 
 void AffiliationService::TrimCacheForFacet(const FacetURI& facet_uri) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(backend_);
   backend_task_runner_->PostTask(
       FROM_HERE, base::Bind(&AffiliationBackend::TrimCacheForFacet,
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_service.h b/components/password_manager/core/browser/android_affiliation/affiliation_service.h
index 5e94a3a..168cae9 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_service.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_service.h
@@ -11,13 +11,13 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
+#include "base/sequence_checker.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
 
 namespace base {
 class FilePath;
-class SingleThreadTaskRunner;
+class SequencedTaskRunner;
 }  // namespace base
 
 namespace net {
@@ -98,8 +98,8 @@
 
   // The |backend_task_runner| should be a task runner corresponding to a thread
   // that can take blocking I/O, and is normally Chrome's DB thread.
-  AffiliationService(
-      scoped_refptr<base::SingleThreadTaskRunner> backend_task_runner);
+  explicit AffiliationService(
+      scoped_refptr<base::SequencedTaskRunner> backend_task_runner);
   ~AffiliationService() override;
 
   // Initializes the service by creating its backend and transferring it to the
@@ -150,10 +150,10 @@
   // thread, so it will outlive |this| along with all its in-flight tasks.
   AffiliationBackend* backend_;
 
-  // TaskRunner to be used to run the |backend_| (usually the DB thread).
-  scoped_refptr<base::SingleThreadTaskRunner> backend_task_runner_;
+  // TaskRunner to be used to run the |backend_|.
+  scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
 
-  base::ThreadChecker thread_checker_;
+  SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<AffiliationService> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AffiliationService);
diff --git a/components/password_manager/core/browser/hash_password_manager.cc b/components/password_manager/core/browser/hash_password_manager.cc
index a12d7bd7..8d6bb63c 100644
--- a/components/password_manager/core/browser/hash_password_manager.cc
+++ b/components/password_manager/core/browser/hash_password_manager.cc
@@ -8,6 +8,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/os_crypt/os_crypt.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "crypto/random.h"
@@ -24,8 +25,9 @@
     return false;
 
   std::string salt = CreateRandomSalt();
-  // TODO(crbug.com/657041) Implement hash calculation.
-  prefs_->SetString(prefs::kSyncPasswordHash, std::string());
+  std::string hash = base::Uint64ToString(
+      password_manager_util::CalculateSyncPasswordHash(password, salt));
+  EncryptAndSaveToPrefs(prefs::kSyncPasswordHash, hash);
 
   // Password length and salt are stored together.
   std::string length_salt = LengthAndSaltToString(salt, password.size());
@@ -40,15 +42,13 @@
 
 base::Optional<SyncPasswordData> HashPasswordManager::RetrievePasswordHash() {
   if (!prefs_ || !prefs_->HasPrefPath(prefs::kSyncPasswordHash))
-    return base::Optional<SyncPasswordData>();
+    return base::nullopt;
 
   SyncPasswordData result;
   std::string hash_str =
       RetrivedDecryptedStringFromPrefs(prefs::kSyncPasswordHash);
-  // TODO(crbug.com/657041) Add checking of hash correctness retrieving when
-  // hash calculation is implemented.
   if (!base::StringToUint64(hash_str, &result.hash))
-    result.hash = 0;
+    return base::nullopt;
 
   StringToLengthAndSalt(
       RetrivedDecryptedStringFromPrefs(prefs::kSyncPasswordLengthAndHashSalt),
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 06ef4c445..ebbf616 100644
--- a/components/password_manager/core/browser/hash_password_manager_unittest.cc
+++ b/components/password_manager/core/browser/hash_password_manager_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "components/os_crypt/os_crypt_mocker.h"
+#include "components/password_manager/core/browser/password_manager_util.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"
@@ -58,13 +59,14 @@
   hash_password_manager.SavePasswordHash(base::ASCIIToUTF16("sync_password"));
   EXPECT_TRUE(prefs_.HasPrefPath(prefs::kSyncPasswordLengthAndHashSalt));
 
-  base::Optional<SyncPasswordData> sync_password_date =
+  base::Optional<SyncPasswordData> sync_password_data =
       hash_password_manager.RetrievePasswordHash();
-  ASSERT_TRUE(sync_password_date);
-  EXPECT_EQ(13u, sync_password_date->length);
-  EXPECT_EQ(16u, sync_password_date->salt.size());
-  // TODO(crbug.com/657041) Add proper checking of hash when hash calculation is
-  // implemented.
+  ASSERT_TRUE(sync_password_data);
+  EXPECT_EQ(13u, sync_password_data->length);
+  EXPECT_EQ(16u, sync_password_data->salt.size());
+  uint64_t expected_hash = password_manager_util::CalculateSyncPasswordHash(
+      base::ASCIIToUTF16("sync_password"), sync_password_data->salt);
+  EXPECT_EQ(expected_hash, sync_password_data->hash);
 }
 
 }  // namespace
diff --git a/components/password_manager/core/browser/http_data_cleaner.cc b/components/password_manager/core/browser/http_data_cleaner.cc
index 0df47eab..9b29a50 100644
--- a/components/password_manager/core/browser/http_data_cleaner.cc
+++ b/components/password_manager/core/browser/http_data_cleaner.cc
@@ -203,11 +203,11 @@
   // round trip of tasks will be scheduled. Finally, when no weak ptrs remain,
   // this method sets a boolean preference flag and returns.
   if (cleaner->HasWeakPtrs()) {
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner =
-        base::ThreadTaskRunnerHandle::Get();
+    scoped_refptr<base::SequencedTaskRunner> main_thread_runner =
+        base::SequencedTaskRunnerHandle::Get();
     const auto post_to_thread =
         [](std::unique_ptr<ObsoleteHttpCleaner> cleaner, PrefService* prefs,
-           scoped_refptr<base::SingleThreadTaskRunner> thread_runner) {
+           scoped_refptr<base::SequencedTaskRunner> thread_runner) {
           thread_runner->PostTask(
               FROM_HERE, base::Bind(&WaitUntilCleaningIsDone,
                                     base::Passed(std::move(cleaner)), prefs));
@@ -243,7 +243,7 @@
     int delay_in_seconds) {
   if (!prefs->GetBoolean(
           password_manager::prefs::kWasObsoleteHttpDataCleaned)) {
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&InitiateCleaning, make_scoped_refptr(store), prefs,
                    request_context),
diff --git a/components/password_manager/core/browser/http_password_store_migrator.cc b/components/password_manager/core/browser/http_password_store_migrator.cc
index 46114572..859b04af 100644
--- a/components/password_manager/core/browser/http_password_store_migrator.cc
+++ b/components/password_manager/core/browser/http_password_store_migrator.cc
@@ -53,7 +53,7 @@
 
 void HttpPasswordStoreMigrator::OnGetPasswordStoreResults(
     std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   results_ = std::move(results);
   got_password_store_results_ = true;
 
@@ -62,7 +62,7 @@
 }
 
 void HttpPasswordStoreMigrator::OnHSTSQueryResult(bool is_hsts) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   mode_ = is_hsts ? MigrationMode::MOVE : MigrationMode::COPY;
   got_hsts_query_result_ = true;
 
diff --git a/components/password_manager/core/browser/http_password_store_migrator.h b/components/password_manager/core/browser/http_password_store_migrator.h
index 47a378c..a3075ce 100644
--- a/components/password_manager/core/browser/http_password_store_migrator.h
+++ b/components/password_manager/core/browser/http_password_store_migrator.h
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/threading/thread_checker.h"
+#include "base/sequence_checker.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "url/gurl.h"
 
@@ -76,7 +76,7 @@
   MigrationMode mode_;
   std::vector<std::unique_ptr<autofill::PasswordForm>> results_;
   GURL http_origin_domain_;
-  base::ThreadChecker thread_checker_;
+  SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(HttpPasswordStoreMigrator);
 };
diff --git a/components/password_manager/core/browser/mock_password_store.cc b/components/password_manager/core/browser/mock_password_store.cc
index b0e2c3a..7992d2b 100644
--- a/components/password_manager/core/browser/mock_password_store.cc
+++ b/components/password_manager/core/browser/mock_password_store.cc
@@ -5,14 +5,13 @@
 #include "components/password_manager/core/browser/mock_password_store.h"
 
 #include "base/memory/ptr_util.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 
 namespace password_manager {
 
 MockPasswordStore::MockPasswordStore()
-    : PasswordStore(base::ThreadTaskRunnerHandle::Get(),
-                    base::ThreadTaskRunnerHandle::Get()) {
-}
+    : PasswordStore(base::SequencedTaskRunnerHandle::Get(),
+                    base::SequencedTaskRunnerHandle::Get()) {}
 
 MockPasswordStore::~MockPasswordStore() {
 }
diff --git a/components/password_manager/core/browser/password_reuse_detector.cc b/components/password_manager/core/browser/password_reuse_detector.cc
index 51eb81d..7d6e1ca 100644
--- a/components/password_manager/core/browser/password_reuse_detector.cc
+++ b/components/password_manager/core/browser/password_reuse_detector.cc
@@ -89,9 +89,18 @@
   if (Origin(GURL(domain)).IsSameOriginWith(gaia_origin))
     return false;
 
-  // TODO(crbug.com/657041): Implement checking a hash of |input| with
-  // |sync_password_data_|.
+  if (input.size() < sync_password_data_->length)
+    return false;
 
+  size_t offset = input.size() - sync_password_data_->length;
+  base::string16 reuse_candidate = input.substr(offset);
+
+  if (password_manager_util::CalculateSyncPasswordHash(
+          reuse_candidate, sync_password_data_->salt) ==
+      sync_password_data_->hash) {
+    consumer->OnReuseFound(reuse_candidate, kSyncPasswordDomain, 1, 0);
+    return true;
+  }
   return false;
 }
 
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 6266693..8b510f85 100644
--- a/components/password_manager/core/browser/password_reuse_detector_unittest.cc
+++ b/components/password_manager/core/browser/password_reuse_detector_unittest.cc
@@ -12,6 +12,7 @@
 #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/browser/password_manager_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -60,6 +61,15 @@
   return changes;
 }
 
+SyncPasswordData GetSyncPasswordData(const std::string& sync_password) {
+  SyncPasswordData sync_password_data;
+  sync_password_data.salt = "1234567890123456";
+  sync_password_data.length = sync_password.size();
+  sync_password_data.hash = password_manager_util::CalculateSyncPasswordHash(
+      base::ASCIIToUTF16(sync_password), sync_password_data.salt);
+  return sync_password_data;
+}
+
 TEST(PasswordReuseDetectorTest, TypingPasswordOnDifferentSite) {
   PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
@@ -185,33 +195,30 @@
                             &mockConsumer);
 }
 
-// TODO(crbug.com/657041): Enable when hash calculation is implemented.
-TEST(PasswordReuseDetectorTest, DISABLED_SyncPasswordNoReuse) {
+TEST(PasswordReuseDetectorTest, SyncPasswordNoReuse) {
   PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
-  // TODO(crbug.com/657041): Pass a password hash when hash calculation is
-  // implemented.
-  reuse_detector.UseSyncPasswordHash(base::Optional<SyncPasswordData>());
+  std::string sync_password = "sync_password";
+  reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
 
   EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
-  reuse_detector.CheckReuse(ASCIIToUTF16("sync_password"),
+  // Typing sync password on https://accounts.google.com is OK.
+  reuse_detector.CheckReuse(ASCIIToUTF16("123sync_password"),
                             "https://accounts.google.com", &mockConsumer);
   // Only suffixes are verifed.
   reuse_detector.CheckReuse(ASCIIToUTF16("sync_password123"),
                             "https://evil.com", &mockConsumer);
 }
 
-// TODO(crbug.com/657041): Enable when hash calculation is implemented.
-TEST(PasswordReuseDetectorTest, DISABLED_SyncPasswordReuseFound) {
+TEST(PasswordReuseDetectorTest, SyncPasswordReuseFound) {
   PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
-  // TODO(crbug.com/657041): Pass a password hash when hash calculation is
-  // implemented.
-  reuse_detector.UseSyncPasswordHash(base::Optional<SyncPasswordData>());
+  std::string sync_password = "sync_password";
+  reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
 
   EXPECT_CALL(mockConsumer,
               OnReuseFound(ASCIIToUTF16("sync_password"),
@@ -220,18 +227,15 @@
                             &mockConsumer);
 }
 
-// TODO(crbug.com/657041): Enable when hash calculation is implemented.
-TEST(PasswordReuseDetectorTest,
-     DISABLED_SavedPasswordsReuseSyncPasswordAvailable) {
+TEST(PasswordReuseDetectorTest, SavedPasswordsReuseSyncPasswordAvailable) {
   // Check that reuse of saved passwords is detected also if the sync password
   // hash is saved.
   PasswordReuseDetector reuse_detector;
   reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
   MockPasswordReuseDetectorConsumer mockConsumer;
 
-  // TODO(crbug.com/657041): Pass a password hash when hash calculation is
-  // implemented.
-  reuse_detector.UseSyncPasswordHash(base::Optional<SyncPasswordData>());
+  std::string sync_password = "sync_password";
+  reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
 
   EXPECT_CALL(mockConsumer,
               OnReuseFound(ASCIIToUTF16("password"), "google.com", 5, 1));
@@ -239,6 +243,20 @@
                             &mockConsumer);
 }
 
+TEST(PasswordReuseDetectorTest, ClearSyncPasswordHash) {
+  PasswordReuseDetector reuse_detector;
+  reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
+  MockPasswordReuseDetectorConsumer mockConsumer;
+
+  std::string sync_password = "sync_password";
+  reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
+  reuse_detector.ClearSyncPasswordHash();
+
+  // Check that no reuse is found, since hash is cleared.
+  reuse_detector.CheckReuse(ASCIIToUTF16("sync_password"), "https://evil.com",
+                            &mockConsumer);
+}
+
 }  // 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 46b25fb..6b243b99b 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -14,7 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
@@ -33,7 +33,7 @@
 PasswordStore::GetLoginsRequest::GetLoginsRequest(
     PasswordStoreConsumer* consumer)
     : consumer_weak_(consumer->GetWeakPtr()) {
-  origin_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+  origin_task_runner_ = base::SequencedTaskRunnerHandle::Get();
 }
 
 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
@@ -64,7 +64,7 @@
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
 PasswordStore::CheckReuseRequest::CheckReuseRequest(
     PasswordReuseDetectorConsumer* consumer)
-    : origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+    : origin_task_runner_(base::SequencedTaskRunnerHandle::Get()),
       consumer_weak_(consumer->AsWeakPtr()) {}
 
 PasswordStore::CheckReuseRequest::~CheckReuseRequest() {}
@@ -107,8 +107,8 @@
 }
 
 PasswordStore::PasswordStore(
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner)
+    scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
+    scoped_refptr<base::SequencedTaskRunner> db_thread_runner)
     : main_thread_runner_(main_thread_runner),
       db_thread_runner_(db_thread_runner),
       observers_(new base::ObserverListThreadSafe<Observer>()),
@@ -259,7 +259,7 @@
 
 void PasswordStore::ReportMetrics(const std::string& sync_username,
                                   bool custom_passphrase_sync_enabled) {
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner(
+  scoped_refptr<base::SequencedTaskRunner> task_runner(
       GetBackgroundTaskRunner());
   if (task_runner) {
     base::Closure task =
@@ -301,7 +301,7 @@
 }
 
 bool PasswordStore::ScheduleTask(const base::Closure& task) {
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner(
+  scoped_refptr<base::SequencedTaskRunner> task_runner(
       GetBackgroundTaskRunner());
   if (task_runner.get())
     return task_runner->PostTask(FROM_HERE, task);
@@ -321,7 +321,7 @@
 
 base::WeakPtr<syncer::SyncableService>
 PasswordStore::GetPasswordSyncableService() {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   DCHECK(syncable_service_);
   return syncable_service_->AsWeakPtr();
 }
@@ -365,7 +365,7 @@
   DCHECK(shutdown_called_);
 }
 
-scoped_refptr<base::SingleThreadTaskRunner>
+scoped_refptr<base::SequencedTaskRunner>
 PasswordStore::GetBackgroundTaskRunner() {
   return db_thread_runner_;
 }
@@ -420,7 +420,7 @@
 
 void PasswordStore::NotifyLoginsChanged(
     const PasswordStoreChangeList& changes) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   if (!changes.empty()) {
     observers_->Notify(FROM_HERE, &Observer::OnLoginsChanged, changes);
     if (syncable_service_)
@@ -609,7 +609,7 @@
     const FormDigest& form,
     std::unique_ptr<GetLoginsRequest> request,
     const std::vector<std::string>& additional_android_realms) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   std::vector<std::unique_ptr<PasswordForm>> results(FillMatchingLogins(form));
   for (const std::string& realm : additional_android_realms) {
     std::vector<std::unique_ptr<PasswordForm>> more_results(
@@ -649,7 +649,7 @@
 
 std::unique_ptr<PasswordForm> PasswordStore::GetLoginImpl(
     const PasswordForm& primary_key) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   std::vector<std::unique_ptr<PasswordForm>> candidates(
       FillMatchingLogins(FormDigest(primary_key)));
   for (auto& candidate : candidates) {
@@ -683,7 +683,7 @@
 void PasswordStore::UpdateAffiliatedWebLoginsImpl(
     const PasswordForm& updated_android_form,
     const std::vector<std::string>& affiliated_web_realms) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   PasswordStoreChangeList all_changes;
   for (const std::string& affiliated_web_realm : affiliated_web_realms) {
     std::vector<std::unique_ptr<PasswordForm>> web_logins(FillMatchingLogins(
@@ -769,7 +769,7 @@
 
 void PasswordStore::InitOnBackgroundThread(
     const syncer::SyncableService::StartSyncFlare& flare) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   DCHECK(!syncable_service_);
   syncable_service_.reset(new PasswordSyncableService(this));
   syncable_service_->InjectStartSyncFlare(flare);
@@ -782,7 +782,7 @@
 }
 
 void PasswordStore::DestroyOnBackgroundThread() {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   syncable_service_.reset();
 // TODO(crbug.com/706392): Fix password reuse detection for Android.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 3d94d90..11fe83f 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -14,7 +14,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/observer_list_threadsafe.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "components/keyed_service/core/refcounted_keyed_service.h"
 #include "components/password_manager/core/browser/password_store_change.h"
@@ -90,8 +90,8 @@
     GURL origin;
   };
 
-  PasswordStore(scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-                scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner);
+  PasswordStore(scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
+                scoped_refptr<base::SequencedTaskRunner> db_thread_runner);
 
   // Reimplement this to add custom initialization. Always call this too.
   virtual bool Init(const syncer::SyncableService::StartSyncFlare& flare,
@@ -298,7 +298,7 @@
     // See GetLogins(). Logins older than this will be removed from the reply.
     base::Time ignore_logins_cutoff_;
 
-    scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
+    scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
     base::WeakPtr<PasswordStoreConsumer> consumer_weak_;
 
     DISALLOW_COPY_AND_ASSIGN(GetLoginsRequest);
@@ -322,7 +322,7 @@
                       int number_matches) override;
 
    private:
-    const scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
+    const scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
     const base::WeakPtr<PasswordReuseDetectorConsumer> consumer_weak_;
 
     DISALLOW_COPY_AND_ASSIGN(CheckReuseRequest);
@@ -332,9 +332,9 @@
   ~PasswordStore() override;
 
   // Get the TaskRunner to use for PasswordStore background tasks.
-  // By default, a SingleThreadTaskRunner on the DB thread is used, but
+  // By default, a SequencedTaskRunner on the DB thread is used, but
   // subclasses can override.
-  virtual scoped_refptr<base::SingleThreadTaskRunner> GetBackgroundTaskRunner();
+  virtual scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner();
 
   // Methods below will be run in PasswordStore's own thread.
   // Synchronous implementation that reports usage metrics.
@@ -443,11 +443,11 @@
 #endif
 
   // TaskRunner for tasks that run on the main thread (usually the UI thread).
-  scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner_;
+  scoped_refptr<base::SequencedTaskRunner> main_thread_runner_;
 
   // TaskRunner for the DB thread. By default, this is the task runner used for
   // background tasks -- see |GetBackgroundTaskRunner|.
-  scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner_;
+  scoped_refptr<base::SequencedTaskRunner> db_thread_runner_;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(PasswordStoreTest, GetLoginImpl);
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc
index 2e05c0a..64261d99 100644
--- a/components/password_manager/core/browser/password_store_default.cc
+++ b/components/password_manager/core/browser/password_store_default.cc
@@ -17,8 +17,8 @@
 namespace password_manager {
 
 PasswordStoreDefault::PasswordStoreDefault(
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
+    scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
+    scoped_refptr<base::SequencedTaskRunner> db_thread_runner,
     std::unique_ptr<LoginDatabase> login_db)
     : PasswordStore(main_thread_runner, db_thread_runner),
       login_db_(std::move(login_db)) {}
@@ -39,7 +39,7 @@
 }
 
 void PasswordStoreDefault::InitOnDBThread() {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   DCHECK(login_db_);
   if (!login_db_->Init()) {
     login_db_.reset();
@@ -52,13 +52,13 @@
     bool custom_passphrase_sync_enabled) {
   if (!login_db_)
     return;
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   login_db_->ReportMetrics(sync_username, custom_passphrase_sync_enabled);
 }
 
 PasswordStoreChangeList PasswordStoreDefault::AddLoginImpl(
     const PasswordForm& form) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   if (!login_db_)
     return PasswordStoreChangeList();
   return login_db_->AddLogin(form);
@@ -66,7 +66,7 @@
 
 PasswordStoreChangeList PasswordStoreDefault::UpdateLoginImpl(
     const PasswordForm& form) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   if (!login_db_)
     return PasswordStoreChangeList();
   return login_db_->UpdateLogin(form);
@@ -74,7 +74,7 @@
 
 PasswordStoreChangeList PasswordStoreDefault::RemoveLoginImpl(
     const PasswordForm& form) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   PasswordStoreChangeList changes;
   if (login_db_ && login_db_->RemoveLogin(form))
     changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
@@ -194,43 +194,43 @@
 
 bool PasswordStoreDefault::FillAutofillableLogins(
     std::vector<std::unique_ptr<PasswordForm>>* forms) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   return login_db_ && login_db_->GetAutofillableLogins(forms);
 }
 
 bool PasswordStoreDefault::FillBlacklistLogins(
     std::vector<std::unique_ptr<PasswordForm>>* forms) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   return login_db_ && login_db_->GetBlacklistLogins(forms);
 }
 
 void PasswordStoreDefault::AddSiteStatsImpl(const InteractionsStats& stats) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   if (login_db_)
     login_db_->stats_table().AddRow(stats);
 }
 
 void PasswordStoreDefault::RemoveSiteStatsImpl(const GURL& origin_domain) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   if (login_db_)
     login_db_->stats_table().RemoveRow(origin_domain);
 }
 
 std::vector<InteractionsStats> PasswordStoreDefault::GetAllSiteStatsImpl() {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   return login_db_ ? login_db_->stats_table().GetAllRows()
                    : std::vector<InteractionsStats>();
 }
 
 std::vector<InteractionsStats> PasswordStoreDefault::GetSiteStatsImpl(
     const GURL& origin_domain) {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   return login_db_ ? login_db_->stats_table().GetRows(origin_domain)
                    : std::vector<InteractionsStats>();
 }
 
 void PasswordStoreDefault::ResetLoginDB() {
-  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+  DCHECK(GetBackgroundTaskRunner()->RunsTasksInCurrentSequence());
   login_db_.reset();
 }
 
diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h
index be550455..4fd5570 100644
--- a/components/password_manager/core/browser/password_store_default.h
+++ b/components/password_manager/core/browser/password_store_default.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequenced_task_runner.h"
 #include "components/password_manager/core/browser/login_database.h"
 #include "components/password_manager/core/browser/password_store.h"
 
@@ -25,8 +25,8 @@
   // The |login_db| must not have been Init()-ed yet. It will be initialized in
   // a deferred manner on the DB thread.
   PasswordStoreDefault(
-      scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
+      scoped_refptr<base::SequencedTaskRunner> main_thread_runner,
+      scoped_refptr<base::SequencedTaskRunner> db_thread_runner,
       std::unique_ptr<LoginDatabase> login_db);
 
   bool Init(const syncer::SyncableService::StartSyncFlare& flare,
diff --git a/components/password_manager/core/browser/password_store_default_unittest.cc b/components/password_manager/core/browser/password_store_default_unittest.cc
index cc2e8afd..8a7374a 100644
--- a/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -16,7 +16,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_task_environment.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "components/password_manager/core/browser/login_database.h"
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
@@ -143,8 +143,8 @@
 PasswordStoreDefaultTestDelegate::CreateInitializedStore(
     std::unique_ptr<LoginDatabase> database) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
-      std::move(database)));
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(), std::move(database)));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
   return store;
diff --git a/components/password_manager/core/browser/password_store_factory_util.cc b/components/password_manager/core/browser/password_store_factory_util.cc
index 28b7724..6f19620 100644
--- a/components/password_manager/core/browser/password_store_factory_util.cc
+++ b/components/password_manager/core/browser/password_store_factory_util.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "base/task_scheduler/post_task.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_service.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
@@ -28,13 +29,17 @@
 void ActivateAffiliationBasedMatching(
     PasswordStore* password_store,
     net::URLRequestContextGetter* request_context_getter,
-    const base::FilePath& db_path,
-    scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner) {
+    const base::FilePath& db_path) {
   // The PasswordStore is so far the only consumer of the AffiliationService,
   // therefore the service is owned by the AffiliatedMatchHelper, which in
   // turn is owned by the PasswordStore.
+  // Task priority is USER_VISIBLE, because AffiliationService-related tasks
+  // block obtaining credentials from PasswordStore, which matches the
+  // USER_VISIBLE example: "Loading data that might be shown in the UI after a
+  // future user interaction."
   std::unique_ptr<AffiliationService> affiliation_service(
-      new AffiliationService(db_thread_runner));
+      new AffiliationService(base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::USER_VISIBLE})));
   affiliation_service->Initialize(request_context_getter, db_path);
   std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper(
       new AffiliatedMatchHelper(password_store,
@@ -56,8 +61,7 @@
     PasswordStore* password_store,
     syncer::SyncService* sync_service,
     net::URLRequestContextGetter* request_context_getter,
-    const base::FilePath& profile_path,
-    scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner) {
+    const base::FilePath& profile_path) {
   DCHECK(password_store);
 
   const bool matching_should_be_active =
@@ -67,8 +71,7 @@
 
   if (matching_should_be_active && !matching_is_active) {
     ActivateAffiliationBasedMatching(password_store, request_context_getter,
-                                     GetAffiliationDatabasePath(profile_path),
-                                     db_thread_runner);
+                                     GetAffiliationDatabasePath(profile_path));
   } else if (!matching_should_be_active && matching_is_active) {
     password_store->SetAffiliatedMatchHelper(
         base::WrapUnique<AffiliatedMatchHelper>(nullptr));
diff --git a/components/password_manager/core/browser/password_store_factory_util.h b/components/password_manager/core/browser/password_store_factory_util.h
index 6f3a707..b3f7a1c4 100644
--- a/components/password_manager/core/browser/password_store_factory_util.h
+++ b/components/password_manager/core/browser/password_store_factory_util.h
@@ -9,7 +9,6 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/password_manager/core/browser/login_database.h"
@@ -22,16 +21,14 @@
 
 // Activates or deactivates affiliation-based matching for |password_store|,
 // depending on whether or not the |sync_service| is syncing passwords stored
-// therein. The AffiliationService will use |db_thread_runner| as its backend
-// thread, and |request_context_getter| to fetch affiliation information. This
-// function should be called whenever there is a possibility that syncing
-// passwords has just started or ended.
+// therein. The AffiliationService will use |request_context_getter| to fetch
+// affiliation information. This function should be called whenever there is a
+// possibility that syncing passwords has just started or ended.
 void ToggleAffiliationBasedMatchingBasedOnPasswordSyncedState(
     PasswordStore* password_store,
     syncer::SyncService* sync_service,
     net::URLRequestContextGetter* request_context_getter,
-    const base::FilePath& profile_path,
-    scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner);
+    const base::FilePath& profile_path);
 
 // Creates a LoginDatabase. Looks in |profile_path| for the database file.
 // Does not call LoginDatabase::Init() -- to avoid UI jank, that needs to be
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index e95ed71..f536b89c 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -21,7 +21,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/scoped_task_environment.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
@@ -140,7 +140,8 @@
 
 TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
@@ -234,7 +235,8 @@
 
 TEST_F(PasswordStoreTest, StartSyncFlare) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
   StartSyncFlareMock mock;
   store->Init(
@@ -264,7 +266,8 @@
   /* clang-format on */
 
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
@@ -327,7 +330,8 @@
   /* clang-format on */
 
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
@@ -380,7 +384,8 @@
   /* clang-format on */
 
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
@@ -433,7 +438,8 @@
   /* clang-format on */
 
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
@@ -538,7 +544,8 @@
   /* clang-format on */
 
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
@@ -721,8 +728,8 @@
                    << test_remove_and_add_login);
 
       scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-          base::ThreadTaskRunnerHandle::Get(),
-          base::ThreadTaskRunnerHandle::Get(),
+          base::SequencedTaskRunnerHandle::Get(),
+          base::SequencedTaskRunnerHandle::Get(),
           base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
       store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
       store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
@@ -830,8 +837,8 @@
   for (bool blacklisted : kFalseTrue) {
     SCOPED_TRACE(testing::Message("use blacklisted logins: ") << blacklisted);
     scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-        base::ThreadTaskRunnerHandle::Get(),
-        base::ThreadTaskRunnerHandle::Get(),
+        base::SequencedTaskRunnerHandle::Get(),
+        base::SequencedTaskRunnerHandle::Get(),
         base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
     store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
     store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
@@ -912,7 +919,8 @@
        L"username_value_6", L"", true, 1}};
 
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
@@ -947,7 +955,8 @@
        "https://facebook.com", "", L"", L"", L"", L"", L"topsecret", true, 1}};
 
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
@@ -990,7 +999,8 @@
 #if !defined(OS_CHROMEOS)
 TEST_F(PasswordStoreTest, SavingClearingSyncPassword) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
 
   TestingPrefServiceSimple prefs;
@@ -1008,15 +1018,22 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
 
-  // TODO(crbug.com/657041): Check that password reuse works when sync hash
-  // calculation is implemented.
+  // 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);
 
   // Check that no sync password reuse is found after clearing the saved sync
   // password hash.
   store->ClearSyncPasswordHash();
   EXPECT_FALSE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
-  // TODO(crbug.com/657041): Check that no password reuse happens here when sync
-  // hash calculation is implemented.
+  EXPECT_CALL(mock_consumer, OnReuseFound(_, _, _, _)).Times(0);
+  store->CheckReuse(input, "https://facebook.com", &mock_consumer);
+  base::RunLoop().RunUntilIdle();
 
   store->ShutdownOnUIThread();
   base::RunLoop().RunUntilIdle();
@@ -1024,7 +1041,8 @@
 
 TEST_F(PasswordStoreTest, SubscriptionAndUnsubscriptionFromSignInEvents) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
+      base::SequencedTaskRunnerHandle::Get(),
       base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
 
   std::unique_ptr<MockPasswordStoreSigninNotifier> notifier =
diff --git a/components/password_manager/core/browser/sql_table_builder.cc b/components/password_manager/core/browser/sql_table_builder.cc
index f49caa65..caa654be 100644
--- a/components/password_manager/core/browser/sql_table_builder.cc
+++ b/components/password_manager/core/browser/sql_table_builder.cc
@@ -35,6 +35,9 @@
 struct SQLTableBuilder::Column {
   std::string name;
   std::string type;
+  // Whether this column is part of the table's PRIMARY KEY constraint.
+  bool part_of_primary_key;
+  // Whether this column is part of the table's UNIQUE constraint.
   bool part_of_unique_key;
   // The first version this column is part of.
   unsigned min_version;
@@ -69,10 +72,16 @@
 
 void SQLTableBuilder::AddColumn(std::string name, std::string type) {
   DCHECK(FindLastColumnByName(name) == columns_.rend());
-  columns_.push_back({std::move(name), std::move(type), false,
+  columns_.push_back({std::move(name), std::move(type), false, false,
                       sealed_version_ + 1, kInvalidVersion, false});
 }
 
+void SQLTableBuilder::AddColumnToPrimaryKey(std::string name,
+                                            std::string type) {
+  AddColumn(std::move(name), std::move(type));
+  columns_.back().part_of_primary_key = true;
+}
+
 void SQLTableBuilder::AddColumnToUniqueKey(std::string name, std::string type) {
   AddColumn(std::move(name), std::move(type));
   columns_.back().part_of_unique_key = true;
@@ -99,6 +108,7 @@
     // just replaced, it needs to be kept for generating the migration code.
     Column new_column = {new_name,
                          old_column->type,
+                         old_column->part_of_primary_key,
                          old_column->part_of_unique_key,
                          sealed_version_ + 1,
                          kInvalidVersion,
@@ -205,17 +215,23 @@
 
 unsigned SQLTableBuilder::SealVersion() {
   if (sealed_version_ == kInvalidVersion) {
-    DCHECK_EQ(std::string(), unique_constraint_);
-    // First sealed version, time to compute the UNIQUE string.
+    DCHECK_EQ(std::string(), constraints_);
+    // First sealed version, time to compute the PRIMARY KEY and UNIQUE string.
+    std::string primary_key;
     std::string unique_key;
     for (const Column& column : columns_) {
+      if (column.part_of_primary_key)
+        Append(column.name, &primary_key);
       if (column.part_of_unique_key)
         Append(column.name, &unique_key);
     }
-    DCHECK(!unique_key.empty());
-    unique_constraint_ = "UNIQUE (" + unique_key + ")";
+    DCHECK(!primary_key.empty() || !unique_key.empty());
+    if (!primary_key.empty())
+      Append("PRIMARY KEY (" + primary_key + ")", &constraints_);
+    if (!unique_key.empty())
+      Append("UNIQUE (" + unique_key + ")", &constraints_);
   }
-  DCHECK(!unique_constraint_.empty());
+  DCHECK(!constraints_.empty());
   return ++sealed_version_;
 }
 
@@ -230,7 +246,7 @@
 
 bool SQLTableBuilder::CreateTable(sql::Connection* db) {
   DCHECK(IsVersionLastAndSealed(sealed_version_));
-  DCHECK(!unique_constraint_.empty());
+  DCHECK(!constraints_.empty());
 
   if (db->DoesTableExist(table_name_.c_str()))
     return true;
@@ -255,7 +271,7 @@
   return transaction.Begin() &&
          db->Execute(base::StringPrintf("CREATE TABLE %s (%s, %s)",
                                         table_name_.c_str(), names.c_str(),
-                                        unique_constraint_.c_str())
+                                        constraints_.c_str())
                          .c_str()) &&
          std::all_of(create_index_sqls.begin(), create_index_sqls.end(),
                      [&db](const std::string& sql) {
@@ -278,7 +294,8 @@
   DCHECK(IsVersionLastAndSealed(sealed_version_));
   std::string result;
   for (const Column& column : columns_) {
-    if (IsColumnInLastVersion(column) && !column.part_of_unique_key)
+    if (IsColumnInLastVersion(column) &&
+        !(column.part_of_primary_key || column.part_of_unique_key))
       Append(column.name + "=?", &result);
   }
   return result;
@@ -288,7 +305,8 @@
   DCHECK(IsVersionLastAndSealed(sealed_version_));
   std::string result;
   for (const Column& column : columns_) {
-    if (IsColumnInLastVersion(column) && column.part_of_unique_key) {
+    if (IsColumnInLastVersion(column) &&
+        (column.part_of_primary_key || column.part_of_unique_key)) {
       if (!result.empty())
         result += " AND ";
       result += column.name + "=?";
@@ -297,12 +315,26 @@
   return result;
 }
 
-std::string SQLTableBuilder::ListAllIndexNames() const {
+std::vector<base::StringPiece> SQLTableBuilder::AllPrimaryKeyNames() const {
   DCHECK(IsVersionLastAndSealed(sealed_version_));
-  std::string result;
+  std::vector<base::StringPiece> result;
+  result.reserve(columns_.size());
+  for (const Column& column : columns_) {
+    if (IsColumnInLastVersion(column) && column.part_of_primary_key) {
+      result.emplace_back(column.name);
+    }
+  }
+  return result;
+}
+
+std::vector<base::StringPiece> SQLTableBuilder::AllIndexNames() const {
+  DCHECK(IsVersionLastAndSealed(sealed_version_));
+  std::vector<base::StringPiece> result;
+  result.reserve(indices_.size());
   for (const Index& index : indices_) {
-    if (IsIndexInLastVersion(index))
-      Append(index.name, &result);
+    if (IsIndexInLastVersion(index)) {
+      result.emplace_back(index.name);
+    }
   }
   return result;
 }
@@ -326,7 +358,7 @@
   DCHECK_LT(old_version, sealed_version_);
   DCHECK_GE(old_version, 0u);
   DCHECK(IsVersionLastAndSealed(sealed_version_));
-  DCHECK(!unique_constraint_.empty());
+  DCHECK(!constraints_.empty());
 
   // Names of columns from old version, values of which are copied.
   std::string old_names;
@@ -340,6 +372,7 @@
 
   for (auto column = columns_.begin(); column != columns_.end(); ++column) {
     if (column->max_version == old_version) {
+      DCHECK(!column->part_of_primary_key);
       DCHECK(!column->part_of_unique_key);
       // This column was deleted after |old_version|. It can have two reasons:
       needs_temp_table = true;
@@ -356,6 +389,7 @@
       }
     } else if (column->min_version == old_version + 1) {
       // This column was added after old_version.
+      DCHECK(!column->part_of_primary_key);
       DCHECK(!column->part_of_unique_key);
       added_names.push_back(column->name + " " + column->type);
     } else if (column->min_version <= old_version &&
@@ -384,7 +418,7 @@
     if (!(transaction.Begin() &&
           db->Execute(base::StringPrintf(
                           "CREATE TABLE %s (%s, %s)", temp_table_name.c_str(),
-                          new_names.c_str(), unique_constraint_.c_str())
+                          new_names.c_str(), constraints_.c_str())
                           .c_str()) &&
           db->Execute(
               base::StringPrintf("INSERT OR REPLACE INTO %s SELECT %s FROM %s",
diff --git a/components/password_manager/core/browser/sql_table_builder.h b/components/password_manager/core/browser/sql_table_builder.h
index 8407186d..6cf78cca 100644
--- a/components/password_manager/core/browser/sql_table_builder.h
+++ b/components/password_manager/core/browser/sql_table_builder.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/strings/string_piece.h"
 
 namespace sql {
 class Connection;
@@ -25,6 +26,7 @@
 // SQLTableBuilder builder("logins");
 //
 // // First describe a couple of versions:
+// builder.AddColumnToPrimaryKey("id", "INTEGER");
 // builder.AddColumn("name", "VARCHAR");
 // builder.AddColumn("icon", "VARCHAR");
 // builder.AddColumn("password", "VARCHAR NOT NULL");
@@ -53,6 +55,11 @@
   // must not have been added to the table in this version before.
   void AddColumn(std::string name, std::string type);
 
+  // As AddColumn but also adds column |name| to the primary key of the table.
+  // SealVersion must not have been called yet (the builder does not currently
+  // support migration code for changing the primary key between versions).
+  void AddColumnToPrimaryKey(std::string name, std::string type);
+
   // As AddColumn but also adds column |name| to the unique key of the table.
   // SealVersion must not have been called yet (the builder does not currently
   // support migration code for changing the unique key between versions).
@@ -105,17 +112,22 @@
   // version. The last version must be sealed.
   std::string ListAllColumnNames() const;
 
-  // Same as ListAllColumnNames, but for non-unique key names only, and with
-  // names followed by " = ?".
+  // Same as ListAllColumnNames, but for non-unique key names only (i.e. keys
+  // that are part of neither the PRIMARY KEY nor the UNIQUE constraint), and
+  // with names followed by " = ?".
   std::string ListAllNonuniqueKeyNames() const;
 
   // Same as ListAllNonuniqueKeyNames, but for unique key names and separated by
   // " AND ".
   std::string ListAllUniqueKeyNames() const;
 
-  // Returns the comma-separated list of all index names present in the last
+  // Returns a vector of all PRIMARY KEY names that are present in the last
   // version. The last version must be sealed.
-  std::string ListAllIndexNames() const;
+  std::vector<base::StringPiece> AllPrimaryKeyNames() const;
+
+  // Returns a vector of all index names that are present in the last
+  // version. The last version must be sealed.
+  std::vector<base::StringPiece> AllIndexNames() const;
 
   // Returns the number of all columns present in the last version. The last
   // version must be sealed.
@@ -177,9 +189,9 @@
 
   std::vector<Index> indices_;  // Indices of the table, across all versions.
 
-  // The "UNIQUE" part of an SQL CREATE TABLE constraint. This value is
-  // computed dring sealing the first version (0).
-  std::string unique_constraint_;
+  // The SQL CREATE TABLE constraints. This value is computed during sealing the
+  // first version (0).
+  std::string constraints_;
 
   // The name of the table.
   const std::string table_name_;
diff --git a/components/password_manager/core/browser/sql_table_builder_unittest.cc b/components/password_manager/core/browser/sql_table_builder_unittest.cc
index 3fbe38a8..b1c1393c 100644
--- a/components/password_manager/core/browser/sql_table_builder_unittest.cc
+++ b/components/password_manager/core/browser/sql_table_builder_unittest.cc
@@ -9,8 +9,11 @@
 #include "base/macros.h"
 #include "sql/connection.h"
 #include "sql/statement.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::UnorderedElementsAre;
+
 namespace password_manager {
 
 class SQLTableBuilderTest : public testing::Test {
@@ -266,6 +269,7 @@
 }
 
 TEST_F(SQLTableBuilderTest, MigrateFrom_RenameAndAddColumns) {
+  builder()->AddColumnToPrimaryKey("id", "INTEGER");
   builder()->AddColumn("old_name", "INTEGER");
   EXPECT_EQ(0u, builder()->SealVersion());
 
@@ -279,14 +283,18 @@
 
   EXPECT_TRUE(builder()->MigrateFrom(0, db()));
   EXPECT_FALSE(db()->DoesColumnExist("my_logins_table", "old_name"));
+  EXPECT_TRUE(db()->DoesColumnExist("my_logins_table", "id"));
   EXPECT_TRUE(db()->DoesColumnExist("my_logins_table", "added"));
   EXPECT_TRUE(db()->DoesColumnExist("my_logins_table", "new_name"));
+  EXPECT_TRUE(IsColumnOfType("id", "INTEGER"));
   EXPECT_TRUE(IsColumnOfType("added", "VARCHAR"));
   EXPECT_TRUE(IsColumnOfType("new_name", "INTEGER"));
-  EXPECT_EQ(3u, builder()->NumberOfColumns());
-  EXPECT_EQ("signon_realm, new_name, added", builder()->ListAllColumnNames());
+  EXPECT_EQ(4u, builder()->NumberOfColumns());
+  EXPECT_EQ("signon_realm, id, new_name, added",
+            builder()->ListAllColumnNames());
   EXPECT_EQ("new_name=?, added=?", builder()->ListAllNonuniqueKeyNames());
-  EXPECT_EQ("signon_realm=?", builder()->ListAllUniqueKeyNames());
+  EXPECT_EQ("signon_realm=? AND id=?", builder()->ListAllUniqueKeyNames());
+  EXPECT_THAT(builder()->AllPrimaryKeyNames(), UnorderedElementsAre("id"));
 }
 
 TEST_F(SQLTableBuilderTest, MigrateFrom_RenameAndAddIndices) {
@@ -306,10 +314,13 @@
   EXPECT_TRUE(db()->DoesIndexExist("added"));
   EXPECT_TRUE(db()->DoesIndexExist("new_name"));
   EXPECT_EQ(2u, builder()->NumberOfIndices());
-  EXPECT_EQ("new_name, added", builder()->ListAllIndexNames());
+  EXPECT_THAT(builder()->AllIndexNames(),
+              UnorderedElementsAre("new_name", "added"));
 }
 
 TEST_F(SQLTableBuilderTest, MigrateFrom_RenameAndAddAndDropColumns) {
+  builder()->AddColumnToPrimaryKey("pk_1", "VARCHAR NOT NULL");
+  builder()->AddColumnToPrimaryKey("pk_2", "VARCHAR NOT NULL");
   builder()->AddColumnToUniqueKey("uni", "VARCHAR NOT NULL");
   builder()->AddColumn("old_name", "INTEGER");
   EXPECT_EQ(0u, builder()->SealVersion());
@@ -328,13 +339,19 @@
   EXPECT_TRUE(builder()->MigrateFrom(0, db()));
   EXPECT_FALSE(db()->DoesColumnExist("my_logins_table", "old_name"));
   EXPECT_FALSE(db()->DoesColumnExist("my_logins_table", "added"));
+  EXPECT_TRUE(db()->DoesColumnExist("my_logins_table", "pk_1"));
+  EXPECT_TRUE(db()->DoesColumnExist("my_logins_table", "pk_2"));
   EXPECT_TRUE(db()->DoesColumnExist("my_logins_table", "uni"));
   EXPECT_TRUE(db()->DoesColumnExist("my_logins_table", "new_name"));
   EXPECT_TRUE(IsColumnOfType("new_name", "INTEGER"));
-  EXPECT_EQ(3u, builder()->NumberOfColumns());
-  EXPECT_EQ("signon_realm, uni, new_name", builder()->ListAllColumnNames());
+  EXPECT_EQ(5u, builder()->NumberOfColumns());
+  EXPECT_EQ("signon_realm, pk_1, pk_2, uni, new_name",
+            builder()->ListAllColumnNames());
   EXPECT_EQ("new_name=?", builder()->ListAllNonuniqueKeyNames());
-  EXPECT_EQ("signon_realm=? AND uni=?", builder()->ListAllUniqueKeyNames());
+  EXPECT_EQ("signon_realm=? AND pk_1=? AND pk_2=? AND uni=?",
+            builder()->ListAllUniqueKeyNames());
+  EXPECT_THAT(builder()->AllPrimaryKeyNames(),
+              UnorderedElementsAre("pk_1", "pk_2"));
 }
 
 TEST_F(SQLTableBuilderTest, MigrateFrom_RenameAndAddAndDropIndices) {
@@ -357,7 +374,7 @@
   EXPECT_FALSE(db()->DoesIndexExist("added"));
   EXPECT_TRUE(db()->DoesIndexExist("new_name"));
   EXPECT_EQ(1u, builder()->NumberOfColumns());
-  EXPECT_EQ("new_name", builder()->ListAllIndexNames());
+  EXPECT_THAT(builder()->AllIndexNames(), UnorderedElementsAre("new_name"));
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index 1e11a32..5c4c585e 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -7,7 +7,7 @@
 #include <stddef.h>
 
 #include "base/memory/ptr_util.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/psl_matching_helper.h"
 #include "components/password_manager/core/browser/statistics_table.h"
@@ -15,9 +15,8 @@
 namespace password_manager {
 
 TestPasswordStore::TestPasswordStore()
-    : PasswordStore(base::ThreadTaskRunnerHandle::Get(),
-                    base::ThreadTaskRunnerHandle::Get()) {
-}
+    : PasswordStore(base::SequencedTaskRunnerHandle::Get(),
+                    base::SequencedTaskRunnerHandle::Get()) {}
 
 TestPasswordStore::~TestPasswordStore() {
 }
diff --git a/components/signin/core/browser/android/BUILD.gn b/components/signin/core/browser/android/BUILD.gn
index 760282f..d9dda3e 100644
--- a/components/signin/core/browser/android/BUILD.gn
+++ b/components/signin/core/browser/android/BUILD.gn
@@ -25,6 +25,7 @@
     "java/src/org/chromium/components/signin/AuthException.java",
     "java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java",
     "java/src/org/chromium/components/signin/ChromeSigninController.java",
+    "java/src/org/chromium/components/signin/AccountManagerDelegateException.java",
     "java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java",
   ]
 }
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java
index 2e52e58..004d68c 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java
@@ -20,10 +20,18 @@
 public interface AccountManagerDelegate {
     /**
      * Get all the accounts for a given {@code type}.
+     * This is deprecated an will be removed soon.
+     */
+    @Deprecated
+    @WorkerThread
+    Account[] getAccountsByType(String type);
+
+    /**
+     * Get all the accounts.
      * This method shouldn't be called on the UI thread (violated due to crbug.com/517697).
      */
     @WorkerThread
-    Account[] getAccountsByType(String type);
+    Account[] getAccountsSync() throws AccountManagerDelegateException;
 
     /**
      * Get an auth token.
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegateException.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegateException.java
new file mode 100644
index 0000000..ed32737
--- /dev/null
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegateException.java
@@ -0,0 +1,13 @@
+// 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.components.signin;
+
+/**
+ * AccountManagerDelegateException encapsulates errors that can happen while getting list of
+ * accounts.
+ *
+ * Currently, this exception is a stub. Support for different errors will be added soon.
+ */
+public class AccountManagerDelegateException extends Exception {}
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerHelper.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerHelper.java
index 9b3b9fe..2b08786c 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerHelper.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerHelper.java
@@ -140,12 +140,13 @@
     }
 
     /**
-     * This method is deprecated; please use the asynchronous version below instead.
+     * Retrieves a list of the Google account names on the device.
      *
-     * See http://crbug.com/517697 for details.
+     * @throws AccountManagerDelegateException if Google Play Services are out of date,
+     *         Chrome lacks necessary permissions, etc.
      */
     @WorkerThread
-    public List<String> getGoogleAccountNames() {
+    public List<String> getGoogleAccountNames() throws AccountManagerDelegateException {
         List<String> accountNames = new ArrayList<>();
         for (Account account : getGoogleAccounts()) {
             accountNames.add(account.name);
@@ -154,11 +155,24 @@
     }
 
     /**
-     * Retrieves a list of the Google account names on the device asynchronously.
+     * Retrieves a list of the Google account names on the device.
+     * Returns an empty list if Google Play Services aren't available or out of date.
+     */
+    @WorkerThread
+    public List<String> tryGetGoogleAccountNames() {
+        List<String> accountNames = new ArrayList<>();
+        for (Account account : tryGetGoogleAccounts()) {
+            accountNames.add(account.name);
+        }
+        return accountNames;
+    }
+
+    /**
+     * Asynchronous version of {@link #tryGetGoogleAccountNames()}.
      */
     @MainThread
-    public void getGoogleAccountNames(final Callback<List<String>> callback) {
-        getGoogleAccounts(new Callback<Account[]>() {
+    public void tryGetGoogleAccountNames(final Callback<List<String>> callback) {
+        tryGetGoogleAccounts(new Callback<Account[]>() {
             @Override
             public void onResult(Account[] accounts) {
                 List<String> accountNames = new ArrayList<>();
@@ -171,25 +185,39 @@
     }
 
     /**
-     * This method is deprecated; please use the asynchronous version below instead.
+     * Retrieves all Google accounts on the device.
      *
-     * See http://crbug.com/517697 for details.
+     * @throws AccountManagerDelegateException if Google Play Services are out of date,
+     *         Chrome lacks necessary permissions, etc.
      */
     @WorkerThread
-    public Account[] getGoogleAccounts() {
-        return mDelegate.getAccountsByType(GOOGLE_ACCOUNT_TYPE);
+    public Account[] getGoogleAccounts() throws AccountManagerDelegateException {
+        return mDelegate.getAccountsSync();
     }
 
     /**
-     * Retrieves all Google accounts on the device asynchronously.
+     * Retrieves all Google accounts on the device.
+     * Returns an empty array if an error occurs while getting account list.
+     */
+    @WorkerThread
+    public Account[] tryGetGoogleAccounts() {
+        try {
+            return getGoogleAccounts();
+        } catch (AccountManagerDelegateException e) {
+            return new Account[0];
+        }
+    }
+
+    /**
+     * Asynchronous version of {@link #tryGetGoogleAccounts()}.
      */
     @MainThread
-    public void getGoogleAccounts(final Callback<Account[]> callback) {
+    public void tryGetGoogleAccounts(final Callback<Account[]> callback) {
         ThreadUtils.assertOnUiThread();
         new AsyncTask<Void, Void, Account[]>() {
             @Override
             protected Account[] doInBackground(Void... params) {
-                return getGoogleAccounts();
+                return tryGetGoogleAccounts();
             }
 
             @Override
@@ -200,21 +228,29 @@
     }
 
     /**
-     * This method is deprecated; please use the asynchronous version below instead.
-     *
-     * See http://crbug.com/517697 for details.
+     * This method is deprecated and will be removed soon.
      */
-    @WorkerThread
-    public boolean hasGoogleAccounts() {
-        return getGoogleAccounts().length > 0;
+    // TODO(bsazonov) remove this method after fixing internal usages.
+    @MainThread
+    public void getGoogleAccounts(final Callback<Account[]> callback) {
+        tryGetGoogleAccounts(callback);
     }
 
     /**
-     * Asynchronously determine whether any Google accounts have been added.
+     * Determine whether there are any Google accounts on the device.
+     * Returns false if an error occurs while getting account list.
+     */
+    @WorkerThread
+    public boolean hasGoogleAccounts() {
+        return tryGetGoogleAccounts().length > 0;
+    }
+
+    /**
+     * Asynchronous version of {@link #hasGoogleAccounts()}.
      */
     @MainThread
     public void hasGoogleAccounts(final Callback<Boolean> callback) {
-        getGoogleAccounts(new Callback<Account[]>() {
+        tryGetGoogleAccounts(new Callback<Account[]>() {
             @Override
             public void onResult(Account[] accounts) {
                 callback.onResult(accounts.length > 0);
@@ -236,14 +272,13 @@
     }
 
     /**
-     * This method is deprecated; please use the asynchronous version below instead.
-     *
-     * See http://crbug.com/517697 for details.
+     * Returns the account if it exists; null if account doesn't exists or an error occurs
+     * while getting account list.
      */
     @WorkerThread
     public Account getAccountFromName(String accountName) {
         String canonicalName = canonicalizeName(accountName);
-        Account[] accounts = getGoogleAccounts();
+        Account[] accounts = tryGetGoogleAccounts();
         for (Account account : accounts) {
             if (canonicalizeName(account.name).equals(canonicalName)) {
                 return account;
@@ -253,12 +288,12 @@
     }
 
     /**
-     * Asynchronously returns the account if it exists; null otherwise.
+     * Asynchronous version of {@link #getAccountFromName(String)}.
      */
     @MainThread
     public void getAccountFromName(String accountName, final Callback<Account> callback) {
         final String canonicalName = canonicalizeName(accountName);
-        getGoogleAccounts(new Callback<Account[]>() {
+        tryGetGoogleAccounts(new Callback<Account[]>() {
             @Override
             public void onResult(Account[] accounts) {
                 Account accountForName = null;
@@ -274,9 +309,8 @@
     }
 
     /**
-     * This method is deprecated; please use the asynchronous version below instead.
-     *
-     * See http://crbug.com/517697 for details.
+     * Returns whether an account exists with the given name.
+     * Returns false if an error occurs while getting account list.
      */
     @WorkerThread
     public boolean hasAccountForName(String accountName) {
@@ -284,7 +318,7 @@
     }
 
     /**
-     * Asynchronously returns whether an account exists with the given name.
+     * Asynchronous version of {@link #hasAccountForName(String)}.
      */
     // TODO(maxbogue): Remove once this function is used outside of tests.
     @VisibleForTesting
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
index ba1b73d..f1231936 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
@@ -61,6 +61,11 @@
     }
 
     @Override
+    public Account[] getAccountsSync() throws AccountManagerDelegateException {
+        return getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
+    }
+
+    @Override
     public String getAuthToken(Account account, String authTokenScope) throws AuthException {
         assert !ThreadUtils.runningOnUiThread();
         assert AccountManagerHelper.GOOGLE_ACCOUNT_TYPE.equals(account.type);
diff --git a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
index 64eaf04..d61073e84 100644
--- a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
+++ b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
@@ -16,6 +16,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.components.signin.AccountManagerDelegate;
+import org.chromium.components.signin.AccountManagerDelegateException;
 import org.chromium.components.signin.AccountManagerHelper;
 
 import java.util.ArrayList;
@@ -68,6 +69,19 @@
         return validAccounts.toArray(new Account[0]);
     }
 
+    @Override
+    public Account[] getAccountsSync() throws AccountManagerDelegateException {
+        return getAccountsSyncNoThrow();
+    }
+
+    public Account[] getAccountsSyncNoThrow() {
+        ArrayList<Account> result = new ArrayList<>();
+        for (AccountHolder ah : mAccounts) {
+            result.add(ah.getAccount());
+        }
+        return result.toArray(new Account[0]);
+    }
+
     /**
      * Add an AccountHolder directly.
      *
diff --git a/components/sync/android/java/src/org/chromium/components/sync/AndroidSyncSettings.java b/components/sync/android/java/src/org/chromium/components/sync/AndroidSyncSettings.java
index e131335f..5207bb6 100644
--- a/components/sync/android/java/src/org/chromium/components/sync/AndroidSyncSettings.java
+++ b/components/sync/android/java/src/org/chromium/components/sync/AndroidSyncSettings.java
@@ -252,7 +252,7 @@
         ThreadUtils.postOnUiThread(new Runnable() {
             @Override
             public void run() {
-                AccountManagerHelper.get().getGoogleAccounts(new Callback<Account[]>() {
+                AccountManagerHelper.get().tryGetGoogleAccounts(new Callback<Account[]>() {
                     @Override
                     public void onResult(Account[] accounts) {
                         synchronized (mLock) {
diff --git a/content/browser/blob_storage/blob_url_loader_factory.cc b/content/browser/blob_storage/blob_url_loader_factory.cc
index 5b79e7c..dbb2883 100644
--- a/content/browser/blob_storage/blob_url_loader_factory.cc
+++ b/content/browser/blob_storage/blob_url_loader_factory.cc
@@ -351,15 +351,18 @@
 
 }  // namespace
 
-BlobURLLoaderFactory::BlobURLLoaderFactory(
+// static
+scoped_refptr<BlobURLLoaderFactory> BlobURLLoaderFactory::Create(
     BlobContextGetter blob_storage_context_getter,
-    scoped_refptr<storage::FileSystemContext> file_system_context)
-    : file_system_context_(file_system_context) {
+    scoped_refptr<storage::FileSystemContext> file_system_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  auto factory = base::MakeRefCounted<BlobURLLoaderFactory>(
+      std::move(file_system_context));
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&BlobURLLoaderFactory::InitializeOnIO, this,
+      base::BindOnce(&BlobURLLoaderFactory::InitializeOnIO, factory,
                      std::move(blob_storage_context_getter)));
+  return factory;
 }
 
 void BlobURLLoaderFactory::HandleRequest(
@@ -370,6 +373,10 @@
                                          std::move(request)));
 }
 
+BlobURLLoaderFactory::BlobURLLoaderFactory(
+    scoped_refptr<storage::FileSystemContext> file_system_context)
+    : file_system_context_(std::move(file_system_context)) {}
+
 BlobURLLoaderFactory::~BlobURLLoaderFactory() {}
 
 void BlobURLLoaderFactory::InitializeOnIO(
diff --git a/content/browser/blob_storage/blob_url_loader_factory.h b/content/browser/blob_storage/blob_url_loader_factory.h
index 35df893..9f01143 100644
--- a/content/browser/blob_storage/blob_url_loader_factory.h
+++ b/content/browser/blob_storage/blob_url_loader_factory.h
@@ -30,7 +30,8 @@
  public:
   using BlobContextGetter =
       base::OnceCallback<base::WeakPtr<storage::BlobStorageContext>()>;
-  CONTENT_EXPORT BlobURLLoaderFactory(
+
+  static CONTENT_EXPORT scoped_refptr<BlobURLLoaderFactory> Create(
       BlobContextGetter blob_storage_context_getter,
       scoped_refptr<storage::FileSystemContext> file_system_context);
 
@@ -66,7 +67,11 @@
  private:
   friend class base::DeleteHelper<BlobURLLoaderFactory>;
   friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
+  template <typename T, typename... Args>
+  friend scoped_refptr<T> base::MakeRefCounted(Args&&... args);
 
+  BlobURLLoaderFactory(
+      scoped_refptr<storage::FileSystemContext> file_system_context);
   ~BlobURLLoaderFactory() override;
 
   void InitializeOnIO(BlobContextGetter blob_storage_context_getter);
diff --git a/content/browser/blob_storage/blob_url_unittest.cc b/content/browser/blob_storage/blob_url_unittest.cc
index 93d7cc9..32b4837 100644
--- a/content/browser/blob_storage/blob_url_unittest.cc
+++ b/content/browser/blob_storage/blob_url_unittest.cc
@@ -283,10 +283,11 @@
 
       mojom::URLLoaderAssociatedPtr url_loader;
       TestURLLoaderClient url_loader_client;
-      scoped_refptr<BlobURLLoaderFactory> factory = new BlobURLLoaderFactory(
-          base::Bind(&BlobURLRequestJobTest::GetStorageContext,
-                     base::Unretained(this)),
-          file_system_context_);
+      scoped_refptr<BlobURLLoaderFactory> factory =
+          BlobURLLoaderFactory::Create(
+              base::Bind(&BlobURLRequestJobTest::GetStorageContext,
+                         base::Unretained(this)),
+              file_system_context_);
       base::RunLoop().RunUntilIdle();
       factory->CreateLoaderAndStart(mojo::MakeRequest(&url_loader), 0, 0,
                                     mojom::kURLLoadOptionNone, request,
diff --git a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
index e9f5acc..cfb976b 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
+++ b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
@@ -20,9 +20,9 @@
 #include "build/build_config.h"
 #include "content/public/common/media_stream_request.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "media/audio/audio_manager_base.h"
 #include "media/audio/audio_system_impl.h"
 #include "media/audio/audio_thread_impl.h"
+#include "media/audio/mock_audio_manager.h"
 #include "media/base/media_switches.h"
 #include "media/base/test_helpers.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -64,7 +64,7 @@
   MAYBE_AudioInputDeviceManagerTest() {}
 
  protected:
-  void SetUp() override {
+  virtual void Initialize() {
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kUseFakeDeviceForMediaStream);
     // AudioInputDeviceManager accesses AudioSystem from IO thread, so it never
@@ -74,16 +74,20 @@
     // Flush the message loop to ensure proper initialization of AudioManager.
     base::RunLoop().RunUntilIdle();
 
-    audio_system_ = media::AudioSystemImpl::Create(audio_manager_.get());
-    manager_ = new AudioInputDeviceManager(audio_system_.get());
-    audio_input_listener_.reset(new MockAudioInputDeviceManagerListener());
-    manager_->RegisterListener(audio_input_listener_.get());
-
     // Use fake devices.
     devices_.emplace_back(MEDIA_DEVICE_AUDIO_CAPTURE, "Fake Device 1",
                           "fake_device_1");
     devices_.emplace_back(MEDIA_DEVICE_AUDIO_CAPTURE, "Fake Device 2",
                           "fake_device_2");
+  }
+
+  void SetUp() override {
+    Initialize();
+
+    audio_system_ = media::AudioSystemImpl::Create(audio_manager_.get());
+    manager_ = new AudioInputDeviceManager(audio_system_.get());
+    audio_input_listener_.reset(new MockAudioInputDeviceManagerListener());
+    manager_->RegisterListener(audio_input_listener_.get());
 
     // Wait until we get the list.
     base::RunLoop().RunUntilIdle();
@@ -296,4 +300,62 @@
   base::RunLoop().RunUntilIdle();
 }
 
+class AudioInputDeviceManagerNoDevicesTest
+    : public MAYBE_AudioInputDeviceManagerTest {
+ public:
+  AudioInputDeviceManagerNoDevicesTest(){};
+
+ protected:
+  void Initialize() override {
+    // MockAudioManager has no input and no output audio devices.
+    audio_manager_ = base::MakeUnique<media::MockAudioManager>(
+        base::MakeUnique<media::AudioThreadImpl>());
+
+    // Devices to request from AudioInputDeviceManager.
+    devices_.emplace_back(MEDIA_TAB_AUDIO_CAPTURE, "Tab capture",
+                          "tab_capture");
+    devices_.emplace_back(MEDIA_DESKTOP_AUDIO_CAPTURE, "Desktop capture",
+                          "desktop_capture");
+    devices_.emplace_back(MEDIA_DEVICE_AUDIO_CAPTURE, "Fake Device",
+                          "fake_device");
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AudioInputDeviceManagerNoDevicesTest);
+};
+
+TEST_F(AudioInputDeviceManagerNoDevicesTest,
+       ParametersValidWithoutAudioDevices) {
+  ASSERT_FALSE(devices_.empty());
+
+  InSequence s;
+
+  for (const auto& device_request : devices_) {
+    int session_id = manager_->Open(device_request.device);
+
+    EXPECT_CALL(*audio_input_listener_,
+                Opened(device_request.device.type, session_id))
+        .Times(1);
+    WaitForOpenCompletion();
+
+    // Expects that device parameters stored by the manager are valid.
+    const StreamDeviceInfo* device_info =
+        manager_->GetOpenedDeviceInfoById(session_id);
+    EXPECT_TRUE(
+        media::AudioParameters(media::AudioParameters::AUDIO_FAKE,
+                               static_cast<media::ChannelLayout>(
+                                   device_info->device.input.channel_layout),
+                               device_info->device.input.sample_rate, 16,
+                               device_info->device.input.frames_per_buffer)
+            .IsValid());
+
+    manager_->Close(session_id);
+    EXPECT_CALL(*audio_input_listener_,
+                Closed(device_request.device.type, session_id))
+        .Times(1);
+
+    base::RunLoop().RunUntilIdle();
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
index 5052626..ed267bc 100644
--- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc
+++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -313,9 +313,10 @@
   // As the overscroll is handled during scroll events from the trackpad, the
   // RWHVA window is transformed by the overscroll controller. This transform
   // triggers a synthetic mouse-move event to be generated (by the aura
-  // RootWindow). But this event interferes with the overscroll gesture. So,
-  // ignore such synthetic mouse-move events if an overscroll gesture is in
-  // progress.
+  // RootWindow). Also, with a touchscreen, we may get a synthetic mouse-move
+  // caused by a pointer grab. But these events interfere with the overscroll
+  // gesture. So, ignore such synthetic mouse-move events if an overscroll
+  // gesture is in progress.
   OverscrollController* overscroll_controller =
       delegate_->overscroll_controller();
   if (overscroll_controller &&
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 7e6db81..8369ba8 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -550,7 +550,7 @@
         ChromeBlobStorageContext::GetFor(context);
     BlobURLLoaderFactory::BlobContextGetter blob_getter =
         base::BindOnce(&BlobStorageContextGetter, blob_context);
-    partition->blob_url_loader_factory_ = new BlobURLLoaderFactory(
+    partition->blob_url_loader_factory_ = BlobURLLoaderFactory::Create(
         std::move(blob_getter), partition->filesystem_context_);
 
     partition->url_loader_factory_getter_ = new URLLoaderFactoryGetter();
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index c8009fe5..9cd07123 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -28,6 +28,7 @@
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_message_filter.h"
+#include "content/public/browser/overscroll_configuration.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents_delegate.h"
@@ -429,6 +430,108 @@
   TestOverscrollNavigation(true);
 }
 
+namespace {
+// This fails the test if it sees any mouse move events.
+class SpuriousMouseMoveEventObserver
+    : public RenderWidgetHost::InputEventObserver {
+ public:
+  explicit SpuriousMouseMoveEventObserver(RenderWidgetHost* host)
+      : host_(host) {
+    host_->AddInputEventObserver(this);
+  }
+
+  ~SpuriousMouseMoveEventObserver() override {
+    host_->RemoveInputEventObserver(this);
+  }
+
+  void OnInputEvent(const blink::WebInputEvent& event) override {
+    EXPECT_NE(blink::WebInputEvent::kMouseMove, event.GetType())
+        << "Unexpected mouse move event.";
+  }
+
+ private:
+  RenderWidgetHost* host_;
+
+  DISALLOW_COPY_AND_ASSIGN(SpuriousMouseMoveEventObserver);
+};
+}  // namespace
+
+// Start an overscroll gesture and then check if the gesture is interrupted by
+// a spurious mouse event. Overscrolling may trigger mouse-move events, but
+// these should all be marked as synthesized and get dropped while the
+// overscroll gesture is in progress.
+// See crbug.com/731914
+IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
+                       OverscrollNotInterruptedBySpuriousMouseEvents) {
+  ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/overscroll_navigation.html"));
+  WebContentsImpl* web_contents =
+      static_cast<WebContentsImpl*>(shell()->web_contents());
+  NavigationController& controller = web_contents->GetController();
+  RenderFrameHost* main_frame = web_contents->GetMainFrame();
+
+  EXPECT_FALSE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+  int index = -1;
+  std::unique_ptr<base::Value> value =
+      content::ExecuteScriptAndGetValue(main_frame, "get_current()");
+  ASSERT_TRUE(value->GetAsInteger(&index));
+  EXPECT_EQ(0, index);
+
+  ExecuteSyncJSFunction(main_frame, "navigate_next()");
+  value = content::ExecuteScriptAndGetValue(main_frame, "get_current()");
+  ASSERT_TRUE(value->GetAsInteger(&index));
+  EXPECT_EQ(1, index);
+  EXPECT_TRUE(controller.CanGoBack());
+  EXPECT_FALSE(controller.CanGoForward());
+
+  // We start an overscroll gesture, but pause mid-gesture.
+
+  // Fail the test if the following gesture produces mouse-moves that don't get
+  // dropped.
+  SpuriousMouseMoveEventObserver mouse_observer(GetRenderWidgetHost());
+
+  blink::WebGestureEvent gesture_scroll_begin(
+      blink::WebGestureEvent::kGestureScrollBegin,
+      blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::kTimeStampForTesting);
+  gesture_scroll_begin.source_device = blink::kWebGestureDeviceTouchscreen;
+  gesture_scroll_begin.data.scroll_begin.delta_hint_units =
+      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
+  gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
+  gesture_scroll_begin.data.scroll_begin.delta_y_hint = 0.f;
+  GetRenderWidgetHost()->ForwardGestureEvent(gesture_scroll_begin);
+
+  blink::WebGestureEvent gesture_scroll_update(
+      blink::WebGestureEvent::kGestureScrollUpdate,
+      blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::kTimeStampForTesting);
+  gesture_scroll_update.source_device = blink::kWebGestureDeviceTouchscreen;
+  gesture_scroll_update.data.scroll_update.delta_units =
+      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
+  gesture_scroll_update.data.scroll_update.delta_y = 0.f;
+  float horiz_threshold =
+      GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN);
+  gesture_scroll_update.data.scroll_update.delta_x = horiz_threshold + 1;
+  GetRenderWidgetHost()->ForwardGestureEvent(gesture_scroll_update);
+
+  // Wait for the overscroll gesture to start and then allow some time for the
+  // spurious mouse event. Since we're testing that an event does not happen,
+  // we just have a timeout. This could potentially result in the event
+  // happening after the timeout, which would cause the test to succeed
+  // incorrectly. That said, the event we're worried about happens almost
+  // instantly after the start of the overscroll gesture.
+  base::RunLoop run_loop;
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
+  run_loop.Run();
+
+  // Check that the overscroll gesture was not reset.
+  OverscrollController* overscroll_controller =
+      static_cast<RenderWidgetHostViewAura*>(GetRenderWidgetHostView())
+          ->overscroll_controller();
+  EXPECT_NE(OVERSCROLL_NONE, overscroll_controller->overscroll_mode());
+}
+
 // Disabled because the test always fails the first time it runs on the Win Aura
 // bots, and usually but not always passes second-try (See crbug.com/179532).
 // On Linux, the test frequently times out. (See crbug.com/440043).
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index 2f5f3cf..4cfc06a 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -1119,11 +1119,14 @@
             'gpu': '10de:104a',
             'os': 'Windows-2008ServerR2-SP1'
           },
+          # Temporarily disable AMD deqp ES3 tests due to issues with the log
+          # size causing out-of-memory errors in the recipe engine.
+          # crbug.com/713196
           # AMD Win 7
-          {
-            'gpu': '1002:6613',
-            'os': 'Windows-2008ServerR2-SP1'
-          }
+          #{
+          #  'gpu': '1002:6613',
+          #  'os': 'Windows-2008ServerR2-SP1'
+          #}
         ],
       }
     ],
diff --git a/docs/android_debugging_instructions.md b/docs/android_debugging_instructions.md
index fbb4f98..3c4eba2a 100644
--- a/docs/android_debugging_instructions.md
+++ b/docs/android_debugging_instructions.md
@@ -203,19 +203,23 @@
 
 ```shell
 out/Default/apks/ChromePublic.apk.mapping
-out/Default/apks/Chrome.apk.mapping
+out/Default/apks/ChromeModernPublic.apk.mapping
+etc.
 ```
 
-To deobfuscate a stack trace from a file, run
+Build the `java_deobfuscate` tool:
 
 ```shell
-build/android/stacktrace/java_deobfuscate.py PROGUARD_MAPPING_FILE.mapping --stacktrace STACKTRACE_FILE
+ninja -C out/Default java_deobfuscate
 ```
 
-Deobfuscation also works from `stdin`:
+Then run it via:
 
 ```shell
-adb logcat -d | build/android/stacktrace/java_deobfuscate.py PROGUARD_MAPPING_FILE.mapping
+# For a file:
+out/Default/bin/java_deobfuscate PROGUARD_MAPPING_FILE.mapping < FILE
+# For logcat:
+adb logcat | out/Default/bin/java_deobfuscate PROGUARD_MAPPING_FILE.mapping
 ```
 
 ## Get WebKit code to output to the adb log
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc b/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc
index d5d74614..d6ac1a2 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc
+++ b/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc
@@ -9,8 +9,8 @@
 
 #include "base/command_line.h"
 #include "base/memory/singleton.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
@@ -60,8 +60,7 @@
       browser_state->GetRequestContext();
   password_manager::ToggleAffiliationBasedMatchingBasedOnPasswordSyncedState(
       password_store.get(), sync_service, request_context_getter,
-      browser_state->GetStatePath(),
-      web::WebThread::GetTaskRunnerForThread(web::WebThread::DB));
+      browser_state->GetStatePath());
 }
 
 IOSChromePasswordStoreFactory::IOSChromePasswordStoreFactory()
@@ -79,9 +78,9 @@
   std::unique_ptr<password_manager::LoginDatabase> login_db(
       password_manager::CreateLoginDatabase(context->GetStatePath()));
 
-  scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner(
-      base::ThreadTaskRunnerHandle::Get());
-  scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner(
+  scoped_refptr<base::SequencedTaskRunner> main_thread_runner(
+      base::SequencedTaskRunnerHandle::Get());
+  scoped_refptr<base::SequencedTaskRunner> db_thread_runner(
       web::WebThread::GetTaskRunnerForThread(web::WebThread::DB));
 
   scoped_refptr<password_manager::PasswordStore> store =
diff --git a/ios/chrome/browser/web/progress_indicator_egtest.mm b/ios/chrome/browser/web/progress_indicator_egtest.mm
index 93beaf4e..5f5daf7 100644
--- a/ios/chrome/browser/web/progress_indicator_egtest.mm
+++ b/ios/chrome/browser/web/progress_indicator_egtest.mm
@@ -13,7 +13,6 @@
 #include "ios/chrome/test/app/web_view_interaction_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
-#import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/third_party/material_components_ios/src/components/ProgressView/src/MaterialProgressView.h"
 #include "ios/web/public/test/http_server/html_response_provider.h"
@@ -25,8 +24,6 @@
 #error "This file requires ARC support."
 #endif
 
-using chrome_test_util::WebViewContainingText;
-
 namespace {
 
 // Text to display in form page.
@@ -184,20 +181,12 @@
 
   // Load form first.
   [ChromeEarlGrey loadURL:formURL];
-
-  // TODO(crbug.com/707009): Replace this matcher with
-  // [ChromeEarlGrey waitForWebViewContainingText]. It fails to synchronize with
-  // the progress bar.
-  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kFormPageText)]
-      assertWithMatcher:grey_notNil()];
+  [ChromeEarlGrey waitForWebViewContainingText:kFormPageText];
 
   chrome_test_util::SubmitWebViewFormWithId(kFormID);
 
   // Wait until the page is half loaded.
-  // TODO(crbug.com/707009): Replace this matcher with
-  // [ChromeEarlGrey waitForWebViewContainingText].
-  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kPageText)]
-      assertWithMatcher:grey_notNil()];
+  [ChromeEarlGrey waitForWebViewContainingText:kPageText];
 
   // Verify progress view visible and halfway progress.
   [[EarlGrey selectElementWithMatcher:ProgressViewWithProgress(0.5)]
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 4201f5b..69809871 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1315,6 +1315,9 @@
       "quic/core/quic_spdy_stream.h",
       "quic/core/quic_stream.cc",
       "quic/core/quic_stream.h",
+      "quic/core/quic_stream_frame_data_producer.h",
+      "quic/core/quic_stream_send_buffer.cc",
+      "quic/core/quic_stream_send_buffer.h",
       "quic/core/quic_stream_sequencer.cc",
       "quic/core/quic_stream_sequencer.h",
       "quic/core/quic_stream_sequencer_buffer.cc",
@@ -3104,6 +3107,8 @@
     "quic/test_tools/quic_time_wait_list_manager_peer.h",
     "quic/test_tools/rtt_stats_peer.cc",
     "quic/test_tools/rtt_stats_peer.h",
+    "quic/test_tools/simple_data_producer.cc",
+    "quic/test_tools/simple_data_producer.h",
     "quic/test_tools/simple_quic_framer.cc",
     "quic/test_tools/simple_quic_framer.h",
     "quic/test_tools/simulator/actor.cc",
@@ -4921,6 +4926,7 @@
     "quic/core/quic_simple_buffer_allocator_test.cc",
     "quic/core/quic_socket_address_coder_test.cc",
     "quic/core/quic_spdy_stream_test.cc",
+    "quic/core/quic_stream_send_buffer_test.cc",
     "quic/core/quic_stream_sequencer_buffer_test.cc",
     "quic/core/quic_stream_sequencer_test.cc",
     "quic/core/quic_stream_test.cc",
diff --git a/net/quic/core/frames/quic_stream_frame.cc b/net/quic/core/frames/quic_stream_frame.cc
index ba346396..ccae486 100644
--- a/net/quic/core/frames/quic_stream_frame.cc
+++ b/net/quic/core/frames/quic_stream_frame.cc
@@ -52,6 +52,12 @@
 QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
                                  bool fin,
                                  QuicStreamOffset offset,
+                                 QuicPacketLength data_length)
+    : QuicStreamFrame(stream_id, fin, offset, nullptr, data_length, nullptr) {}
+
+QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
+                                 bool fin,
+                                 QuicStreamOffset offset,
                                  const char* data_buffer,
                                  QuicPacketLength data_length,
                                  UniqueStreamBuffer buffer)
diff --git a/net/quic/core/frames/quic_stream_frame.h b/net/quic/core/frames/quic_stream_frame.h
index 138cc48..90cfbfe 100644
--- a/net/quic/core/frames/quic_stream_frame.h
+++ b/net/quic/core/frames/quic_stream_frame.h
@@ -50,6 +50,10 @@
                   QuicStreamOffset offset,
                   QuicPacketLength data_length,
                   UniqueStreamBuffer buffer);
+  QuicStreamFrame(QuicStreamId stream_id,
+                  bool fin,
+                  QuicStreamOffset offset,
+                  QuicPacketLength data_length);
   ~QuicStreamFrame();
 
   friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
@@ -60,6 +64,10 @@
   QuicPacketLength data_length;
   const char* data_buffer;
   QuicStreamOffset offset;  // Location of this data in the stream.
+  // TODO(fayang): When deprecating
+  // FLAGS_quic_reloadable_flag_quic_stream_owns_data: (1) Remove buffer from
+  // QuicStreamFrame; (2) remove the constructor uses UniqueStreamBuffer and (3)
+  // Move definition of UniqueStreamBuffer to QuicStreamSendBuffer.
   // nullptr when the QuicStreamFrame is received, and non-null when sent.
   UniqueStreamBuffer buffer;
 
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc
index 26f097d..4f6c889 100644
--- a/net/quic/core/quic_connection.cc
+++ b/net/quic/core/quic_connection.cc
@@ -2441,4 +2441,23 @@
   sent_packet_manager_.SetStreamNotifier(stream_notifier);
 }
 
+void QuicConnection::SetDelegateSavesData(bool delegate_saves_data) {
+  packet_generator_.SetDelegateSavesData(delegate_saves_data);
+}
+
+void QuicConnection::SaveStreamData(QuicStreamId id,
+                                    QuicIOVector iov,
+                                    size_t iov_offset,
+                                    QuicStreamOffset offset,
+                                    QuicByteCount data_length) {
+  visitor_->SaveStreamData(id, iov, iov_offset, offset, data_length);
+}
+
+bool QuicConnection::WriteStreamData(QuicStreamId id,
+                                     QuicStreamOffset offset,
+                                     QuicByteCount data_length,
+                                     QuicDataWriter* writer) {
+  return visitor_->WriteStreamData(id, offset, data_length, writer);
+}
+
 }  // namespace net
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h
index 4503c6c..4d081cc 100644
--- a/net/quic/core/quic_connection.h
+++ b/net/quic/core/quic_connection.h
@@ -160,6 +160,19 @@
   // Called to ask if any streams are open in this visitor, excluding the
   // reserved crypto and headers stream.
   virtual bool HasOpenDynamicStreams() const = 0;
+
+  // Save |data_length| data starts at |iov_offset| in |iov|.
+  virtual void SaveStreamData(QuicStreamId id,
+                              QuicIOVector iov,
+                              size_t iov_offset,
+                              QuicStreamOffset offset,
+                              QuicByteCount data_length) = 0;
+
+  // Write |data_length| data with |offset| of stream |id| to |writer|.
+  virtual bool WriteStreamData(QuicStreamId id,
+                               QuicStreamOffset offset,
+                               QuicByteCount data_length,
+                               QuicDataWriter* writer) = 0;
 };
 
 // Interface which gets callbacks from the QuicConnection at interesting
@@ -464,6 +477,17 @@
   // QuicPacketCreator::DelegateInterface
   void OnSerializedPacket(SerializedPacket* packet) override;
 
+  // QuicStreamFrameDataProducer methods:
+  void SaveStreamData(QuicStreamId id,
+                      QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length) override;
+  bool WriteStreamData(QuicStreamId id,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override;
+
   // QuicSentPacketManager::NetworkChangeVisitor
   void OnCongestionChange() override;
   void OnPathDegrading() override;
@@ -662,6 +686,11 @@
   // Sets the stream notifer on the SentPacketManager.
   void SetStreamNotifier(StreamNotifierInterface* stream_notifier);
 
+  // Enable/disable delegate saves data in PacketCreator.
+  // TODO(fayang): Remove this method when deprecating
+  // quic_reloadable_flag_quic_stream_owns_data.
+  void SetDelegateSavesData(bool delegate_saves_data);
+
   // Return the name of the cipher of the primary decrypter of the framer.
   const char* cipher_name() const { return framer_.decrypter()->cipher_name(); }
   // Return the id of the cipher of the primary decrypter of the framer.
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc
index c2eb3023..554675ec 100644
--- a/net/quic/core/quic_connection_test.cc
+++ b/net/quic/core/quic_connection_test.cc
@@ -826,8 +826,9 @@
     QuicPacketHeader header;
     QuicPacketCreatorPeer::FillPacketHeader(&peer_creator_, &header);
     char encrypted_buffer[kMaxPacketSize];
+    // TODO(fayang): Use data producer to produce data.
     size_t length = peer_framer_.BuildDataPacket(
-        header, frames, encrypted_buffer, kMaxPacketSize);
+        header, frames, encrypted_buffer, kMaxPacketSize, nullptr);
     DCHECK_GT(length, 0u);
 
     const size_t encrypted_length = peer_framer_.EncryptInPlace(
@@ -1907,13 +1908,13 @@
   // using writev.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
 
-  char data[] = "ABCD";
+  char data[] = "ABCDEF";
   struct iovec iov[2];
   iov[0].iov_base = data;
-  iov[0].iov_len = 2;
-  iov[1].iov_base = data + 2;
+  iov[0].iov_len = 4;
+  iov[1].iov_base = data + 4;
   iov[1].iov_len = 2;
-  connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, NO_FIN, nullptr);
+  connection_.SendStreamData(1, QuicIOVector(iov, 2, 6), 0, NO_FIN, nullptr);
 
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
   EXPECT_FALSE(connection_.HasQueuedData());
@@ -1925,7 +1926,7 @@
   EXPECT_EQ(1u, writer_->padding_frames().size());
   QuicStreamFrame* frame = writer_->stream_frames()[0].get();
   EXPECT_EQ(1u, frame->stream_id);
-  EXPECT_EQ("ABCD", QuicStringPiece(frame->data_buffer, frame->data_length));
+  EXPECT_EQ("ABCDEF", QuicStringPiece(frame->data_buffer, frame->data_length));
 }
 
 TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
@@ -1933,13 +1934,13 @@
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
 
   BlockOnNextWrite();
-  char data[] = "ABCD";
+  char data[] = "ABCDEF";
   struct iovec iov[2];
   iov[0].iov_base = data;
-  iov[0].iov_len = 2;
-  iov[1].iov_base = data + 2;
+  iov[0].iov_len = 4;
+  iov[1].iov_base = data + 4;
   iov[1].iov_len = 2;
-  connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, NO_FIN, nullptr);
+  connection_.SendStreamData(1, QuicIOVector(iov, 2, 6), 0, NO_FIN, nullptr);
 
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
   EXPECT_TRUE(connection_.HasQueuedData());
@@ -3099,7 +3100,8 @@
 
   // Send more packets, and ensure that none of them sets the alarm.
   for (QuicPacketCount i = 0; i < 4 * kPacketsBetweenMtuProbesBase; i++) {
-    SendStreamDataToPeer(3, ".", i, NO_FIN, nullptr);
+    SendStreamDataToPeer(3, ".", kPacketsBetweenMtuProbesBase + 1 + i, NO_FIN,
+                         nullptr);
     ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
   }
 
@@ -3228,7 +3230,8 @@
 
   // Send more packets, and ensure that none of them sets the alarm.
   for (QuicPacketCount i = 0; i < 4 * kPacketsBetweenMtuProbesBase; i++) {
-    SendStreamDataToPeer(3, ".", i, NO_FIN, nullptr);
+    SendStreamDataToPeer(3, ".", kPacketsBetweenMtuProbesBase + 1 + i, NO_FIN,
+                         nullptr);
     ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
   }
 
@@ -3327,7 +3330,7 @@
   // Now send more data. This will not move the timeout becase
   // no data has been recieved since the previous write.
   clock_.AdvanceTime(five_ms);
-  SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, FIN, nullptr);
+  SendStreamDataToPeer(kClientDataStreamId1, "foo", 3, FIN, nullptr);
   EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
 
   // The original alarm will fire.  We should not time out because we had a
@@ -3466,7 +3469,7 @@
   // Now send more data. This will not move the timeout becase
   // no data has been recieved since the previous write.
   clock_.AdvanceTime(five_ms);
-  SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, FIN, nullptr);
+  SendStreamDataToPeer(kClientDataStreamId1, "foo", 3, FIN, nullptr);
   EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
 
   // The original alarm will fire.  We should not time out because we had a
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h
index 324093b..add549a 100644
--- a/net/quic/core/quic_flags_list.h
+++ b/net/quic/core/quic_flags_list.h
@@ -177,6 +177,9 @@
 // When true, defaults to BBR congestion control instead of Cubic.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_default_to_bbr, false)
 
+// If true, stream sent data is saved in streams rather than stream frames.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_stream_owns_data, false)
+
 // Allow a new rate based recovery in QUIC BBR to be enabled via connection
 // option.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_rate_recovery, false)
diff --git a/net/quic/core/quic_framer.cc b/net/quic/core/quic_framer.cc
index f5d771c..590f1aec 100644
--- a/net/quic/core/quic_framer.cc
+++ b/net/quic/core/quic_framer.cc
@@ -18,6 +18,7 @@
 #include "net/quic/core/quic_data_reader.h"
 #include "net/quic/core/quic_data_writer.h"
 #include "net/quic/core/quic_socket_address_coder.h"
+#include "net/quic/core/quic_stream_frame_data_producer.h"
 #include "net/quic/core/quic_utils.h"
 #include "net/quic/platform/api/quic_aligned.h"
 #include "net/quic/platform/api/quic_bug_tracker.h"
@@ -312,7 +313,8 @@
 size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header,
                                    const QuicFrames& frames,
                                    char* buffer,
-                                   size_t packet_length) {
+                                   size_t packet_length,
+                                   QuicStreamFrameDataProducer* data_producer) {
   QuicDataWriter writer(packet_length, buffer, perspective_, endianness());
   if (!AppendPacketHeader(header, &writer)) {
     QUIC_BUG << "AppendPacketHeader failed";
@@ -338,7 +340,7 @@
         break;
       case STREAM_FRAME:
         if (!AppendStreamFrame(*frame.stream_frame, no_stream_frame_length,
-                               &writer)) {
+                               &writer, data_producer)) {
           QUIC_BUG << "AppendStreamFrame failed";
           return 0;
         }
@@ -1791,7 +1793,8 @@
 
 bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame,
                                    bool no_stream_frame_length,
-                                   QuicDataWriter* writer) {
+                                   QuicDataWriter* writer,
+                                   QuicStreamFrameDataProducer* data_producer) {
   if (!AppendStreamId(GetStreamIdSize(frame.stream_id), frame.stream_id,
                       writer)) {
     QUIC_BUG << "Writing stream id size failed.";
@@ -1810,6 +1813,19 @@
     }
   }
 
+  if (data_producer != nullptr) {
+    DCHECK_EQ(nullptr, frame.data_buffer);
+    if (frame.data_length == 0) {
+      return true;
+    }
+    if (!data_producer->WriteStreamData(frame.stream_id, frame.offset,
+                                        frame.data_length, writer)) {
+      QUIC_BUG << "Writing frame data failed.";
+      return false;
+    }
+    return true;
+  }
+
   if (!writer->WriteBytes(frame.data_buffer, frame.data_length)) {
     QUIC_BUG << "Writing frame data failed.";
     return false;
diff --git a/net/quic/core/quic_framer.h b/net/quic/core/quic_framer.h
index f244191f..5131bab 100644
--- a/net/quic/core/quic_framer.h
+++ b/net/quic/core/quic_framer.h
@@ -27,6 +27,7 @@
 class QuicDecrypter;
 class QuicEncrypter;
 class QuicFramer;
+class QuicStreamFrameDataProducer;
 
 // Number of bytes reserved for the frame type preceding each frame.
 const size_t kQuicFrameTypeSize = 1;
@@ -241,7 +242,8 @@
   size_t BuildDataPacket(const QuicPacketHeader& header,
                          const QuicFrames& frames,
                          char* buffer,
-                         size_t packet_length);
+                         size_t packet_length,
+                         QuicStreamFrameDataProducer* data_producer);
 
   // Returns a new public reset packet.
   static std::unique_ptr<QuicEncryptedPacket> BuildPublicResetPacket(
@@ -262,7 +264,8 @@
                       QuicDataWriter* writer);
   bool AppendStreamFrame(const QuicStreamFrame& frame,
                          bool last_frame_in_packet,
-                         QuicDataWriter* builder);
+                         QuicDataWriter* writer,
+                         QuicStreamFrameDataProducer* data_producer);
 
   // SetDecrypter sets the primary decrypter, replacing any that already exists,
   // and takes ownership. If an alternative decrypter is in place then the
diff --git a/net/quic/core/quic_headers_stream_test.cc b/net/quic/core/quic_headers_stream_test.cc
index 14401ee6..4f3b9d4 100644
--- a/net/quic/core/quic_headers_stream_test.cc
+++ b/net/quic/core/quic_headers_stream_test.cc
@@ -1048,7 +1048,7 @@
   EXPECT_CALL(session_,
               WritevData(headers_stream_, kHeadersStreamId, _, _, NO_FIN, _))
       .WillRepeatedly(
-          WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
+          Invoke(&session_, &MockQuicSpdySession::ConsumeAndSaveAllData));
   InSequence s;
   QuicReferenceCountedPointer<MockAckListener> ack_listener1(
       new MockAckListener());
diff --git a/net/quic/core/quic_packet_creator.cc b/net/quic/core/quic_packet_creator.cc
index 05508cb..84413a9 100644
--- a/net/quic/core/quic_packet_creator.cc
+++ b/net/quic/core/quic_packet_creator.cc
@@ -16,6 +16,7 @@
 #include "net/quic/platform/api/quic_flag_utils.h"
 #include "net/quic/platform/api/quic_flags.h"
 #include "net/quic/platform/api/quic_logging.h"
+#include "net/quic/platform/api/quic_ptr_util.h"
 #include "net/quic/platform/api/quic_string_piece.h"
 
 using std::string;
@@ -47,7 +48,8 @@
       latched_flag_no_stop_waiting_frames_(
           FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames),
       pending_padding_bytes_(0),
-      needs_full_padding_(false) {
+      needs_full_padding_(false),
+      delegate_saves_data_(false) {
   SetMaxPacketLength(kDefaultMaxPacketSize);
 }
 
@@ -130,22 +132,17 @@
   }
   CreateStreamFrame(id, iov, iov_offset, offset, fin, frame);
   // Explicitly disallow multi-packet CHLOs.
-  if (id == kCryptoStreamId &&
-      frame->stream_frame->data_length >= sizeof(kCHLO) &&
-      strncmp(frame->stream_frame->data_buffer,
-              reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) == 0) {
-    DCHECK_EQ(0u, iov_offset);
-    if (FLAGS_quic_enforce_single_packet_chlo &&
-        frame->stream_frame->data_length < iov.iov->iov_len) {
-      const string error_details = "Client hello won't fit in a single packet.";
-      QUIC_BUG << error_details << " Constructed stream frame length: "
-               << frame->stream_frame->data_length
-               << " CHLO length: " << iov.iov->iov_len;
-      delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details,
-                                      ConnectionCloseSource::FROM_SELF);
-      delete frame->stream_frame;
-      return false;
-    }
+  if (StreamFrameStartsWithChlo(iov, iov_offset, *frame->stream_frame) &&
+      FLAGS_quic_enforce_single_packet_chlo &&
+      frame->stream_frame->data_length < iov.iov->iov_len) {
+    const string error_details = "Client hello won't fit in a single packet.";
+    QUIC_BUG << error_details << " Constructed stream frame length: "
+             << frame->stream_frame->data_length
+             << " CHLO length: " << iov.iov->iov_len;
+    delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details,
+                                    ConnectionCloseSource::FROM_SELF);
+    delete frame->stream_frame;
+    return false;
   }
   if (!AddFrame(*frame, /*save_retransmittable_frames=*/true)) {
     // Fails if we try to write unencrypted stream data.
@@ -211,6 +208,14 @@
       std::min<size_t>(BytesFree() - min_frame_size, data_size);
 
   bool set_fin = fin && bytes_consumed == data_size;  // Last frame.
+  if (delegate_saves_data_) {
+    *frame =
+        QuicFrame(new QuicStreamFrame(id, set_fin, offset, bytes_consumed));
+    if (bytes_consumed > 0) {
+      delegate_->SaveStreamData(id, iov, iov_offset, offset, bytes_consumed);
+    }
+    return;
+  }
   UniqueStreamBuffer buffer =
       NewStreamBuffer(buffer_allocator_, bytes_consumed);
   QuicUtils::CopyToBuffer(iov, iov_offset, bytes_consumed, buffer.get());
@@ -332,11 +337,22 @@
       std::min<size_t>(available_size, remaining_data_size);
 
   const bool set_fin = fin && (bytes_consumed == remaining_data_size);
-  UniqueStreamBuffer stream_buffer =
-      NewStreamBuffer(buffer_allocator_, bytes_consumed);
-  QuicUtils::CopyToBuffer(iov, iov_offset, bytes_consumed, stream_buffer.get());
-  std::unique_ptr<QuicStreamFrame> frame(new QuicStreamFrame(
-      id, set_fin, stream_offset, bytes_consumed, std::move(stream_buffer)));
+  std::unique_ptr<QuicStreamFrame> frame;
+  if (delegate_saves_data_) {
+    frame = QuicMakeUnique<QuicStreamFrame>(id, set_fin, stream_offset,
+                                            bytes_consumed);
+    if (bytes_consumed > 0) {
+      delegate_->SaveStreamData(id, iov, iov_offset, stream_offset,
+                                bytes_consumed);
+    }
+  } else {
+    UniqueStreamBuffer stream_buffer =
+        NewStreamBuffer(buffer_allocator_, bytes_consumed);
+    QuicUtils::CopyToBuffer(iov, iov_offset, bytes_consumed,
+                            stream_buffer.get());
+    frame = QuicMakeUnique<QuicStreamFrame>(
+        id, set_fin, stream_offset, bytes_consumed, std::move(stream_buffer));
+  }
   QUIC_DVLOG(1) << ENDPOINT << "Adding frame: " << *frame;
 
   // TODO(ianswett): AppendTypeByte and AppendStreamFrame could be optimized
@@ -347,7 +363,8 @@
     return;
   }
   if (!framer_->AppendStreamFrame(*frame, /* no stream frame length */ true,
-                                  &writer)) {
+                                  &writer,
+                                  delegate_saves_data_ ? delegate_ : nullptr)) {
     QUIC_BUG << "AppendStreamFrame failed";
     return;
   }
@@ -438,8 +455,9 @@
   DCHECK_GE(max_plaintext_size_, packet_size_);
   // Use the packet_size_ instead of the buffer size to ensure smaller
   // packet sizes are properly used.
-  size_t length = framer_->BuildDataPacket(header, queued_frames_,
-                                           encrypted_buffer, packet_size_);
+  size_t length = framer_->BuildDataPacket(
+      header, queued_frames_, encrypted_buffer, packet_size_,
+      delegate_saves_data_ ? delegate_ : nullptr);
   if (length == 0) {
     QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames.";
     return;
@@ -609,4 +627,30 @@
   pending_padding_bytes_ += size;
 }
 
+bool QuicPacketCreator::StreamFrameStartsWithChlo(
+    QuicIOVector iov,
+    size_t iov_offset,
+    const QuicStreamFrame& frame) const {
+  if (!delegate_saves_data_) {
+    return frame.stream_id == kCryptoStreamId &&
+           frame.data_length >= sizeof(kCHLO) &&
+           strncmp(frame.data_buffer, reinterpret_cast<const char*>(&kCHLO),
+                   sizeof(kCHLO)) == 0;
+  }
+
+  if (framer_->perspective() == Perspective::IS_SERVER ||
+      frame.stream_id != kCryptoStreamId || iov_offset != 0 ||
+      frame.data_length < sizeof(kCHLO)) {
+    return false;
+  }
+
+  if (iov.iov[0].iov_len < sizeof(kCHLO)) {
+    QUIC_BUG << "iov length " << iov.iov[0].iov_len << " is less than "
+             << sizeof(kCHLO);
+    return false;
+  }
+  return strncmp(reinterpret_cast<const char*>(iov.iov[0].iov_base),
+                 reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) == 0;
+}
+
 }  // namespace net
diff --git a/net/quic/core/quic_packet_creator.h b/net/quic/core/quic_packet_creator.h
index 57c1615..667c659d 100644
--- a/net/quic/core/quic_packet_creator.h
+++ b/net/quic/core/quic_packet_creator.h
@@ -21,6 +21,7 @@
 #include "net/quic/core/quic_iovector.h"
 #include "net/quic/core/quic_packets.h"
 #include "net/quic/core/quic_pending_retransmission.h"
+#include "net/quic/core/quic_stream_frame_data_producer.h"
 #include "net/quic/platform/api/quic_export.h"
 
 namespace net {
@@ -32,7 +33,8 @@
  public:
   // A delegate interface for further processing serialized packet.
   class QUIC_EXPORT_PRIVATE DelegateInterface
-      : public QuicConnectionCloseDelegateInterface {
+      : public QuicConnectionCloseDelegateInterface,
+        public QuicStreamFrameDataProducer {
    public:
     ~DelegateInterface() override {}
     // Called when a packet is serialized. Delegate does not take the ownership
@@ -216,6 +218,10 @@
 
   QuicByteCount pending_padding_bytes() const { return pending_padding_bytes_; }
 
+  void set_delegate_saves_data(bool delegate_saves_data) {
+    delegate_saves_data_ = delegate_saves_data;
+  }
+
  private:
   friend class test::QuicPacketCreatorPeer;
 
@@ -261,6 +267,11 @@
   // packet's public header.
   bool IncludeNonceInPublicHeader();
 
+  // Returns true if |frame| starts with CHLO.
+  bool StreamFrameStartsWithChlo(QuicIOVector iov,
+                                 size_t iov_offset,
+                                 const QuicStreamFrame& frame) const;
+
   // Does not own these delegates or the framer.
   DelegateInterface* delegate_;
   DebugDelegate* debug_delegate_;
@@ -310,6 +321,10 @@
   // bytes.
   bool needs_full_padding_;
 
+  // Indicates whether frame data is saved by delegate_. TODO(fayang): Remove
+  // this boolean when deprecating quic_reloadable_flag_quic_stream_owns_data.
+  bool delegate_saves_data_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicPacketCreator);
 };
 
diff --git a/net/quic/core/quic_packet_creator_test.cc b/net/quic/core/quic_packet_creator_test.cc
index ae31766..0499ba71 100644
--- a/net/quic/core/quic_packet_creator_test.cc
+++ b/net/quic/core/quic_packet_creator_test.cc
@@ -13,6 +13,7 @@
 #include "net/quic/core/crypto/null_encrypter.h"
 #include "net/quic/core/crypto/quic_decrypter.h"
 #include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_data_writer.h"
 #include "net/quic/core/quic_pending_retransmission.h"
 #include "net/quic/core/quic_simple_buffer_allocator.h"
 #include "net/quic/core/quic_utils.h"
@@ -41,21 +42,25 @@
 struct TestParams {
   TestParams(QuicVersion version,
              bool version_serialization,
-             QuicConnectionIdLength length)
+             QuicConnectionIdLength length,
+             bool delegate_saves_data)
       : version(version),
         connection_id_length(length),
-        version_serialization(version_serialization) {}
+        version_serialization(version_serialization),
+        delegate_saves_data(delegate_saves_data) {}
 
   friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
     os << "{ client_version: " << QuicVersionToString(p.version)
        << " connection id length: " << p.connection_id_length
-       << " include version: " << p.version_serialization << " }";
+       << " include version: " << p.version_serialization
+       << " delegate_saves_data: " << p.delegate_saves_data << " }";
     return os;
   }
 
   QuicVersion version;
   QuicConnectionIdLength connection_id_length;
   bool version_serialization;
+  bool delegate_saves_data;
 };
 
 // Constructs various test permutations.
@@ -63,31 +68,22 @@
   std::vector<TestParams> params;
   constexpr QuicConnectionIdLength kMax = PACKET_8BYTE_CONNECTION_ID;
   QuicVersionVector all_supported_versions = AllSupportedVersions();
-  for (size_t i = 0; i < all_supported_versions.size(); ++i) {
-    params.push_back(TestParams(all_supported_versions[i], true, kMax));
-    params.push_back(TestParams(all_supported_versions[i], false, kMax));
+  for (bool delegate_saves_data : {true, false}) {
+    for (size_t i = 0; i < all_supported_versions.size(); ++i) {
+      params.push_back(TestParams(all_supported_versions[i], true, kMax,
+                                  delegate_saves_data));
+      params.push_back(TestParams(all_supported_versions[i], false, kMax,
+                                  delegate_saves_data));
+    }
+    params.push_back(TestParams(all_supported_versions[0], true,
+                                PACKET_0BYTE_CONNECTION_ID,
+                                delegate_saves_data));
+    params.push_back(
+        TestParams(all_supported_versions[0], true, kMax, delegate_saves_data));
   }
-  params.push_back(
-      TestParams(all_supported_versions[0], true, PACKET_0BYTE_CONNECTION_ID));
-  params.push_back(TestParams(all_supported_versions[0], true, kMax));
   return params;
 }
 
-class MockDelegate : public QuicPacketCreator::DelegateInterface {
- public:
-  MockDelegate() {}
-  ~MockDelegate() override {}
-
-  MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet));
-  MOCK_METHOD3(OnUnrecoverableError,
-               void(QuicErrorCode,
-                    const string&,
-                    ConnectionCloseSource source));
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockDelegate);
-};
-
 class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> {
  public:
   void ClearSerializedPacketForTests(SerializedPacket* serialized_packet) {
@@ -136,6 +132,9 @@
                           new NullEncrypter(Perspective::IS_CLIENT));
     client_framer_.set_visitor(&framer_visitor_);
     server_framer_.set_visitor(&framer_visitor_);
+    if (GetParam().delegate_saves_data) {
+      creator_.set_delegate_saves_data(true);
+    }
   }
 
   ~QuicPacketCreatorTest() override {
@@ -165,8 +164,19 @@
     EXPECT_EQ(STREAM_FRAME, frame.type);
     ASSERT_TRUE(frame.stream_frame);
     EXPECT_EQ(stream_id, frame.stream_frame->stream_id);
-    EXPECT_EQ(data, QuicStringPiece(frame.stream_frame->data_buffer,
-                                    frame.stream_frame->data_length));
+    if (GetParam().delegate_saves_data) {
+      char buf[kMaxPacketSize];
+      QuicDataWriter writer(kMaxPacketSize, buf, Perspective::IS_CLIENT,
+                            HOST_BYTE_ORDER);
+      if (frame.stream_frame->data_length > 0) {
+        delegate_.WriteStreamData(stream_id, frame.stream_frame->offset,
+                                  frame.stream_frame->data_length, &writer);
+      }
+      EXPECT_EQ(data, QuicStringPiece(buf, frame.stream_frame->data_length));
+    } else {
+      EXPECT_EQ(data, QuicStringPiece(frame.stream_frame->data_buffer,
+                                      frame.stream_frame->data_length));
+    }
     EXPECT_EQ(offset, frame.stream_frame->offset);
     EXPECT_EQ(fin, frame.stream_frame->fin);
   }
@@ -216,7 +226,7 @@
   QuicFramer server_framer_;
   QuicFramer client_framer_;
   StrictMock<MockFramerVisitor> framer_visitor_;
-  StrictMock<MockDelegate> delegate_;
+  StrictMock<MockPacketCreatorDelegate> delegate_;
   QuicConnectionId connection_id_;
   string data_;
   struct iovec iov_;
diff --git a/net/quic/core/quic_packet_generator.cc b/net/quic/core/quic_packet_generator.cc
index 7487cde..be882ce 100644
--- a/net/quic/core/quic_packet_generator.cc
+++ b/net/quic/core/quic_packet_generator.cc
@@ -353,4 +353,8 @@
          packet_creator_.HasPendingRetransmittableFrames();
 }
 
+void QuicPacketGenerator::SetDelegateSavesData(bool delegate_saves_data) {
+  packet_creator_.set_delegate_saves_data(delegate_saves_data);
+}
+
 }  // namespace net
diff --git a/net/quic/core/quic_packet_generator.h b/net/quic/core/quic_packet_generator.h
index 43bffc1..1b04881 100644
--- a/net/quic/core/quic_packet_generator.h
+++ b/net/quic/core/quic_packet_generator.h
@@ -180,6 +180,9 @@
   // when there are frames queued in the creator.
   void SetMaxPacketLength(QuicByteCount length);
 
+  // Let delegate save stream data in creator.
+  void SetDelegateSavesData(bool delegate_saves_data);
+
   void set_debug_delegate(QuicPacketCreator::DebugDelegate* debug_delegate) {
     packet_creator_.set_debug_delegate(debug_delegate);
   }
diff --git a/net/quic/core/quic_packet_generator_test.cc b/net/quic/core/quic_packet_generator_test.cc
index d72e191c..254098c 100644
--- a/net/quic/core/quic_packet_generator_test.cc
+++ b/net/quic/core/quic_packet_generator_test.cc
@@ -22,6 +22,7 @@
 #include "net/quic/test_tools/quic_packet_creator_peer.h"
 #include "net/quic/test_tools/quic_packet_generator_peer.h"
 #include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simple_data_producer.h"
 #include "net/quic/test_tools/simple_quic_framer.h"
 
 using std::string;
@@ -69,7 +70,23 @@
         .WillRepeatedly(Return(true));
   }
 
+  void SaveStreamData(QuicStreamId id,
+                      QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length) override {
+    producer_.SaveStreamData(id, iov, iov_offset, offset, data_length);
+  }
+  bool WriteStreamData(QuicStreamId id,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override {
+    return producer_.WriteStreamData(id, offset, data_length, writer);
+  }
+
  private:
+  SimpleDataProducer producer_;
+
   DISALLOW_COPY_AND_ASSIGN(MockDelegate);
 };
 
@@ -116,6 +133,8 @@
     creator_->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
                            new NullEncrypter(Perspective::IS_CLIENT));
     creator_->set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+    generator_.SetDelegateSavesData(
+        FLAGS_quic_reloadable_flag_quic_stream_owns_data);
   }
 
   ~QuicPacketGeneratorTest() override {
@@ -228,6 +247,7 @@
  private:
   std::unique_ptr<char[]> data_array_;
   struct iovec iov_;
+  SimpleDataProducer producer_;
 };
 
 class MockDebugDelegate : public QuicPacketCreator::DebugDelegate {
diff --git a/net/quic/core/quic_session.cc b/net/quic/core/quic_session.cc
index 5aa0de73..aaae090 100644
--- a/net/quic/core/quic_session.cc
+++ b/net/quic/core/quic_session.cc
@@ -47,13 +47,18 @@
       currently_writing_stream_id_(0),
       respect_goaway_(true),
       use_stream_notifier_(
-          FLAGS_quic_reloadable_flag_quic_use_stream_notifier2) {}
+          FLAGS_quic_reloadable_flag_quic_use_stream_notifier2),
+      streams_own_data_(use_stream_notifier_ &&
+                        FLAGS_quic_reloadable_flag_quic_stream_owns_data) {}
 
 void QuicSession::Initialize() {
   connection_->set_visitor(this);
   if (use_stream_notifier_) {
     connection_->SetStreamNotifier(this);
   }
+  if (streams_own_data_) {
+    connection_->SetDelegateSavesData(true);
+  }
   connection_->SetFromConfig(config_);
 
   DCHECK_EQ(kCryptoStreamId, GetMutableCryptoStream()->id());
@@ -1022,4 +1027,34 @@
   stream->OnStreamFrameDiscarded(frame);
 }
 
+void QuicSession::SaveStreamData(QuicStreamId id,
+                                 QuicIOVector iov,
+                                 size_t iov_offset,
+                                 QuicStreamOffset offset,
+                                 QuicByteCount data_length) {
+  QuicStream* stream = GetStream(id);
+  if (stream == nullptr) {
+    QUIC_BUG << "Stream " << id << " does not exist when trying to save data.";
+    connection()->CloseConnection(
+        QUIC_INTERNAL_ERROR, "Attempt to save data of a closed stream",
+        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    return;
+  }
+  stream->SaveStreamData(iov, iov_offset, offset, data_length);
+}
+
+bool QuicSession::WriteStreamData(QuicStreamId id,
+                                  QuicStreamOffset offset,
+                                  QuicByteCount data_length,
+                                  QuicDataWriter* writer) {
+  QuicStream* stream = GetStream(id);
+  if (stream == nullptr) {
+    // This causes the connection to be closed because of failed to serialize
+    // packet.
+    QUIC_BUG << "Stream " << id << " does not exist when trying to write data.";
+    return false;
+  }
+  return stream->WriteStreamData(offset, data_length, writer);
+}
+
 }  // namespace net
diff --git a/net/quic/core/quic_session.h b/net/quic/core/quic_session.h
index bad3a73..9310f9a 100644
--- a/net/quic/core/quic_session.h
+++ b/net/quic/core/quic_session.h
@@ -108,6 +108,15 @@
   bool HasPendingHandshake() const override;
   bool HasOpenDynamicStreams() const override;
   void OnPathDegrading() override;
+  void SaveStreamData(QuicStreamId id,
+                      QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length) override;
+  bool WriteStreamData(QuicStreamId id,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override;
 
   // StreamNotifierInterface methods:
   void OnStreamFrameAcked(const QuicStreamFrame& frame,
@@ -269,6 +278,8 @@
 
   bool use_stream_notifier() const { return use_stream_notifier_; }
 
+  bool streams_own_data() const { return streams_own_data_; }
+
  protected:
   using StaticStreamMap = QuicSmallMap<QuicStreamId, QuicStream*, 2>;
 
@@ -516,6 +527,10 @@
   // This session is notified on every ack or loss.
   const bool use_stream_notifier_;
 
+  // Streams of this session own their outstanding data. Outstanding data here
+  // means sent data waiting to be acked.
+  const bool streams_own_data_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicSession);
 };
 
diff --git a/net/quic/core/quic_spdy_stream_test.cc b/net/quic/core/quic_spdy_stream_test.cc
index 2ebc374..eb29525 100644
--- a/net/quic/core/quic_spdy_stream_test.cc
+++ b/net/quic/core/quic_spdy_stream_test.cc
@@ -973,7 +973,8 @@
   }
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .Times(AnyNumber())
-      .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+      .WillRepeatedly(
+          Invoke(session_.get(), &MockQuicSpdySession::ConsumeAndSaveAllData));
   testing::InSequence s;
   QuicReferenceCountedPointer<MockAckListener> ack_listener1(
       new MockAckListener());
diff --git a/net/quic/core/quic_stream.cc b/net/quic/core/quic_stream.cc
index 4e8d7a6..e8583b6 100644
--- a/net/quic/core/quic_stream.cc
+++ b/net/quic/core/quic_stream.cc
@@ -77,7 +77,8 @@
       stream_contributes_to_connection_flow_control_(true),
       busy_counter_(0),
       add_random_padding_after_fin_(false),
-      ack_listener_(nullptr) {
+      ack_listener_(nullptr),
+      send_buffer_(session->connection()->helper()->GetBufferAllocator()) {
   SetFromConfig();
 }
 
@@ -532,6 +533,9 @@
   if (frame.fin) {
     fin_outstanding_ = false;
   }
+  if (session_->streams_own_data() && frame.data_length > 0) {
+    send_buffer_.RemoveStreamFrame(frame.offset, frame.data_length);
+  }
   if (!IsWaitingForAcks()) {
     session_->OnStreamDoneWaitingForAcks(id_);
   }
@@ -541,4 +545,19 @@
   return stream_bytes_outstanding_ || fin_outstanding_;
 }
 
+void QuicStream::SaveStreamData(QuicIOVector iov,
+                                size_t iov_offset,
+                                QuicStreamOffset offset,
+                                QuicByteCount data_length) {
+  DCHECK_LT(0u, data_length);
+  send_buffer_.SaveStreamData(iov, iov_offset, offset, data_length);
+}
+
+bool QuicStream::WriteStreamData(QuicStreamOffset offset,
+                                 QuicByteCount data_length,
+                                 QuicDataWriter* writer) {
+  DCHECK_LT(0u, data_length);
+  return send_buffer_.WriteStreamData(offset, data_length, writer);
+}
+
 }  // namespace net
diff --git a/net/quic/core/quic_stream.h b/net/quic/core/quic_stream.h
index 6c4d831..a8bff46 100644
--- a/net/quic/core/quic_stream.h
+++ b/net/quic/core/quic_stream.h
@@ -27,6 +27,7 @@
 #include "net/quic/core/quic_flow_controller.h"
 #include "net/quic/core/quic_iovector.h"
 #include "net/quic/core/quic_packets.h"
+#include "net/quic/core/quic_stream_send_buffer.h"
 #include "net/quic/core/quic_stream_sequencer.h"
 #include "net/quic/core/quic_types.h"
 #include "net/quic/core/stream_notifier_interface.h"
@@ -196,6 +197,17 @@
   // Adds random padding after the fin is consumed for this stream.
   void AddRandomPaddingAfterFin();
 
+  // Save |data_length| of data starts at |iov_offset| in |iov| to send buffer.
+  void SaveStreamData(QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length);
+
+  // Write |data_length| of data starts at |offset| from send buffer.
+  bool WriteStreamData(QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer);
+
   // StreamNotifierInterface methods:
   void OnStreamFrameAcked(const QuicStreamFrame& frame,
                           QuicTime::Delta ack_delay_time) override;
@@ -350,6 +362,10 @@
   // are acked.
   QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener_;
 
+  // Send buffer of this stream. Send buffer is cleaned up when data gets acked
+  // or discarded.
+  QuicStreamSendBuffer send_buffer_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicStream);
 };
 
diff --git a/net/quic/core/quic_stream_frame_data_producer.h b/net/quic/core/quic_stream_frame_data_producer.h
new file mode 100644
index 0000000..abe8af1f
--- /dev/null
+++ b/net/quic/core/quic_stream_frame_data_producer.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CORE_QUIC_STREAM_FRAME_DATA_PRODUCER_H_
+#define NET_QUIC_CORE_QUIC_STREAM_FRAME_DATA_PRODUCER_H_
+
+#include "net/quic/core/quic_iovector.h"
+#include "net/quic/core/quic_types.h"
+
+namespace net {
+
+class QuicDataWriter;
+
+// Pure virtual class to save and retrieve stream data.
+class QUIC_EXPORT_PRIVATE QuicStreamFrameDataProducer {
+ public:
+  virtual ~QuicStreamFrameDataProducer() {}
+
+  // Save |data_length| data starts at |iov_offset| in |iov|.
+  virtual void SaveStreamData(QuicStreamId id,
+                              QuicIOVector iov,
+                              size_t iov_offset,
+                              QuicStreamOffset offset,
+                              QuicByteCount data_length) = 0;
+
+  // Let |writer| write |data_length| data with |offset| of stream |id|. Returns
+  // false when the writing fails either because stream is closed or
+  // corresponding data is failed to be retrieved. This method allows writing a
+  // single stream frame from data that spans multiple buffers.
+  virtual bool WriteStreamData(QuicStreamId id,
+                               QuicStreamOffset offset,
+                               QuicByteCount data_length,
+                               QuicDataWriter* writer) = 0;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CORE_QUIC_STREAM_FRAME_DATA_PRODUCER_H_
diff --git a/net/quic/core/quic_stream_send_buffer.cc b/net/quic/core/quic_stream_send_buffer.cc
new file mode 100644
index 0000000..e38d100
--- /dev/null
+++ b/net/quic/core/quic_stream_send_buffer.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_data_writer.h"
+#include "net/quic/core/quic_stream_send_buffer.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/platform/api/quic_bug_tracker.h"
+
+namespace net {
+
+QuicStreamDataSlice::QuicStreamDataSlice(UniqueStreamBuffer data,
+                                         QuicStreamOffset offset,
+                                         QuicByteCount data_length)
+    : data(std::move(data)),
+      offset(offset),
+      data_length(data_length),
+      data_length_waiting_for_acks(data_length) {}
+
+QuicStreamDataSlice::~QuicStreamDataSlice() {}
+
+QuicStreamSendBuffer::QuicStreamSendBuffer(QuicBufferAllocator* allocator)
+    : allocator_(allocator) {}
+
+QuicStreamSendBuffer::~QuicStreamSendBuffer() {}
+
+void QuicStreamSendBuffer::SaveStreamData(QuicIOVector iov,
+                                          size_t iov_offset,
+                                          QuicStreamOffset offset,
+                                          QuicByteCount data_length) {
+  DCHECK_LE(iov_offset + data_length, iov.total_length);
+  UniqueStreamBuffer buffer = NewStreamBuffer(allocator_, data_length);
+  QuicUtils::CopyToBuffer(iov, iov_offset, data_length, buffer.get());
+  send_buffer_.emplace_back(std::move(buffer), offset, data_length);
+}
+
+bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset,
+                                           QuicByteCount data_length,
+                                           QuicDataWriter* writer) {
+  for (const QuicStreamDataSlice& slice : send_buffer_) {
+    if (offset < slice.offset) {
+      break;
+    }
+    if (offset >= slice.offset + slice.data_length) {
+      continue;
+    }
+    QuicByteCount slice_offset = offset - slice.offset;
+    QuicByteCount copy_length =
+        std::min(data_length, slice.data_length - slice_offset);
+    if (!writer->WriteBytes(slice.data.get() + slice_offset, copy_length)) {
+      return false;
+    }
+    offset += copy_length;
+    data_length -= copy_length;
+  }
+
+  return data_length == 0;
+}
+
+void QuicStreamSendBuffer::RemoveStreamFrame(QuicStreamOffset offset,
+                                             QuicByteCount data_length) {
+  DCHECK_LT(0u, data_length);
+  for (QuicStreamDataSlice& slice : send_buffer_) {
+    if (offset < slice.offset) {
+      break;
+    }
+    if (offset >= slice.offset + slice.data_length) {
+      continue;
+    }
+    QuicByteCount slice_offset = offset - slice.offset;
+    QuicByteCount removing_length =
+        std::min(data_length, slice.data_length - slice_offset);
+    slice.data_length_waiting_for_acks -= removing_length;
+    offset += removing_length;
+    data_length -= removing_length;
+  }
+  DCHECK_EQ(0u, data_length);
+
+  // Remove data which stops waiting for acks. Please note, data can be
+  // acked out of order, but send buffer is cleaned up in order.
+  while (!send_buffer_.empty() &&
+         send_buffer_.front().data_length_waiting_for_acks == 0) {
+    send_buffer_.pop_front();
+  }
+}
+
+size_t QuicStreamSendBuffer::size() const {
+  return send_buffer_.size();
+}
+
+}  // namespace net
diff --git a/net/quic/core/quic_stream_send_buffer.h b/net/quic/core/quic_stream_send_buffer.h
new file mode 100644
index 0000000..1534521
--- /dev/null
+++ b/net/quic/core/quic_stream_send_buffer.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_
+#define NET_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_
+
+#include <deque>
+
+#include "net/quic/core/frames/quic_stream_frame.h"
+#include "net/quic/core/quic_iovector.h"
+
+namespace net {
+
+class QuicDataWriter;
+
+// QuicStreamDataSlice comprises information of a piece of stream data.
+struct QuicStreamDataSlice {
+  QuicStreamDataSlice(UniqueStreamBuffer data,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length);
+  QuicStreamDataSlice(const QuicStreamDataSlice& other) = delete;
+  QuicStreamDataSlice(QuicStreamDataSlice&& other) = delete;
+  ~QuicStreamDataSlice();
+
+  // Stream data of this data slice.
+  UniqueStreamBuffer data;
+  // Location of this data slice in the stream.
+  QuicStreamOffset offset;
+  // Length of this data slice in bytes.
+  QuicByteCount data_length;
+  // Length of payload which is waiting for acks.
+  QuicByteCount data_length_waiting_for_acks;
+};
+
+// QuicStreamSendBuffer contains a list of QuicStreamDataSlices. New data slices
+// are added to the tail of the list. Data slices are removed from the head of
+// the list when they get fully acked. Stream data can be retrieved and acked
+// across slice boundaries.
+class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer {
+ public:
+  explicit QuicStreamSendBuffer(QuicBufferAllocator* allocator);
+  QuicStreamSendBuffer(const QuicStreamSendBuffer& other) = delete;
+  QuicStreamSendBuffer(QuicStreamSendBuffer&& other) = delete;
+  ~QuicStreamSendBuffer();
+
+  // Save |data_length| of data starts at |iov_offset| in |iov| to send buffer.
+  void SaveStreamData(QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length);
+
+  // Write |data_length| of data starts at |offset|.
+  bool WriteStreamData(QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer);
+
+  // Called when data [offset, offset + data_length) is acked or removed as
+  // stream is canceled. Removes fully acked data slice from send buffer.
+  void RemoveStreamFrame(QuicStreamOffset offset, QuicByteCount data_length);
+
+  // Number of data slices in send buffer.
+  size_t size() const;
+
+ private:
+  std::deque<QuicStreamDataSlice> send_buffer_;
+
+  QuicBufferAllocator* allocator_;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_
diff --git a/net/quic/core/quic_stream_send_buffer_test.cc b/net/quic/core/quic_stream_send_buffer_test.cc
new file mode 100644
index 0000000..d3520a8
--- /dev/null
+++ b/net/quic/core/quic_stream_send_buffer_test.cc
@@ -0,0 +1,112 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_stream_send_buffer.h"
+
+#include "net/quic/core/quic_data_writer.h"
+#include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/platform/api/quic_test.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+struct iovec MakeIovec(QuicStringPiece data) {
+  struct iovec iov = {const_cast<char*>(data.data()),
+                      static_cast<size_t>(data.size())};
+  return iov;
+}
+
+class QuicStreamSendBufferTest : public QuicTest {
+ public:
+  QuicStreamSendBufferTest() : send_buffer_(&allocator_) {
+    EXPECT_EQ(0u, send_buffer_.size());
+    string data1(1536, 'a');
+    string data2(256, 'b');
+    string data3(2048, 'c');
+    struct iovec iov[3];
+    iov[0] = MakeIovec(QuicStringPiece(data1));
+    iov[1] = MakeIovec(QuicStringPiece(data2));
+    iov[2] = MakeIovec(QuicStringPiece(data3));
+    QuicIOVector quic_iov(iov, 3, 3840);
+
+    // Add all data.
+    send_buffer_.SaveStreamData(quic_iov, /*iov_offset=*/0, /*offset=*/0, 1024);
+    send_buffer_.SaveStreamData(quic_iov, /*iov_offset=*/1024,
+                                /*offset=*/1024, 1024);
+    send_buffer_.SaveStreamData(quic_iov, /*iov_offset=*/2048,
+                                /*offset=*/2048, 1024);
+    send_buffer_.SaveStreamData(quic_iov, /*iov_offset=*/3072,
+                                /*offset=*/3072, 768);
+    EXPECT_EQ(4u, send_buffer_.size());
+  }
+
+  SimpleBufferAllocator allocator_;
+  QuicStreamSendBuffer send_buffer_;
+};
+
+TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) {
+  char buf[4000];
+  QuicDataWriter writer(4000, buf, Perspective::IS_CLIENT, HOST_BYTE_ORDER);
+  string copy1(1024, 'a');
+  string copy2 = string(512, 'a') + string(256, 'b') + string(256, 'c');
+  string copy3(1024, 'c');
+  string copy4(768, 'c');
+
+  ASSERT_TRUE(send_buffer_.WriteStreamData(0, 1024, &writer));
+  EXPECT_EQ(copy1, QuicStringPiece(buf, 1024));
+  ASSERT_TRUE(send_buffer_.WriteStreamData(1024, 1024, &writer));
+  EXPECT_EQ(copy2, QuicStringPiece(buf + 1024, 1024));
+  ASSERT_TRUE(send_buffer_.WriteStreamData(2048, 1024, &writer));
+  EXPECT_EQ(copy3, QuicStringPiece(buf + 2048, 1024));
+  ASSERT_TRUE(send_buffer_.WriteStreamData(2048, 768, &writer));
+  EXPECT_EQ(copy4, QuicStringPiece(buf + 3072, 768));
+
+  // Test data piece across boundries.
+  QuicDataWriter writer2(4000, buf, Perspective::IS_CLIENT, HOST_BYTE_ORDER);
+  string copy5 = string(536, 'a') + string(256, 'b') + string(232, 'c');
+  ASSERT_TRUE(send_buffer_.WriteStreamData(1000, 1024, &writer2));
+  EXPECT_EQ(copy5, QuicStringPiece(buf, 1024));
+  ASSERT_TRUE(send_buffer_.WriteStreamData(2500, 1024, &writer2));
+  EXPECT_EQ(copy3, QuicStringPiece(buf + 1024, 1024));
+
+  // Invalid data copy.
+  QuicDataWriter writer3(4000, buf, Perspective::IS_CLIENT, HOST_BYTE_ORDER);
+  EXPECT_FALSE(send_buffer_.WriteStreamData(3000, 1024, &writer3));
+  EXPECT_FALSE(send_buffer_.WriteStreamData(0, 4000, &writer3));
+}
+
+TEST_F(QuicStreamSendBufferTest, RemoveStreamFrame) {
+  send_buffer_.RemoveStreamFrame(1024, 1024);
+  EXPECT_EQ(4u, send_buffer_.size());
+  send_buffer_.RemoveStreamFrame(2048, 1024);
+  EXPECT_EQ(4u, send_buffer_.size());
+  send_buffer_.RemoveStreamFrame(0, 1024);
+  // Send buffer is cleaned up in order.
+  EXPECT_EQ(1u, send_buffer_.size());
+  send_buffer_.RemoveStreamFrame(3072, 768);
+  EXPECT_EQ(0u, send_buffer_.size());
+}
+
+TEST_F(QuicStreamSendBufferTest, RemoveStreamFrameAcrossBoundries) {
+  send_buffer_.RemoveStreamFrame(2024, 576);
+  EXPECT_EQ(4u, send_buffer_.size());
+  send_buffer_.RemoveStreamFrame(0, 1000);
+  EXPECT_EQ(4u, send_buffer_.size());
+  send_buffer_.RemoveStreamFrame(1000, 1024);
+  // Send buffer is cleaned up in order.
+  EXPECT_EQ(2u, send_buffer_.size());
+  send_buffer_.RemoveStreamFrame(2600, 1024);
+  EXPECT_EQ(1u, send_buffer_.size());
+  send_buffer_.RemoveStreamFrame(3624, 216);
+  EXPECT_EQ(0u, send_buffer_.size());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/core/quic_stream_test.cc b/net/quic/core/quic_stream_test.cc
index c08eba40..e9e04a92 100644
--- a/net/quic/core/quic_stream_test.cc
+++ b/net/quic/core/quic_stream_test.cc
@@ -717,45 +717,110 @@
 TEST_F(QuicStreamTest, StreamWaitsForAcks) {
   Initialize(kShouldProcessData);
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
-      .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+      .WillRepeatedly(
+          Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
   // Stream is not waiting for acks initially.
   EXPECT_FALSE(stream_->IsWaitingForAcks());
+  EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
 
   // Send kData1.
   stream_->WriteOrBufferData(kData1, false, nullptr);
+  if (session_->streams_own_data()) {
+    EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+  } else {
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+  }
   EXPECT_TRUE(stream_->IsWaitingForAcks());
   QuicStreamFrame frame1(stream_->id(), false, 0, kData1);
   stream_->OnStreamFrameAcked(frame1, QuicTime::Delta::Zero());
   // Stream is not waiting for acks as all sent data is acked.
   EXPECT_FALSE(stream_->IsWaitingForAcks());
+  EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
 
   // Send kData2.
   stream_->WriteOrBufferData(kData2, false, nullptr);
   EXPECT_TRUE(stream_->IsWaitingForAcks());
+  if (session_->streams_own_data()) {
+    EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+  } else {
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+  }
   // Send FIN.
   stream_->WriteOrBufferData("", true, nullptr);
+  if (session_->streams_own_data()) {
+    // Fin only frame is not stored in send buffer.
+    EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+  } else {
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+  }
 
   // kData2 is acked.
   QuicStreamFrame frame2(stream_->id(), false, 9, kData2);
   stream_->OnStreamFrameAcked(frame2, QuicTime::Delta::Zero());
   // Stream is waiting for acks as FIN is not acked.
   EXPECT_TRUE(stream_->IsWaitingForAcks());
+  EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
 
   // FIN is acked.
   QuicStreamFrame frame3(stream_->id(), true, 18, "");
   stream_->OnStreamFrameAcked(frame3, QuicTime::Delta::Zero());
   EXPECT_FALSE(stream_->IsWaitingForAcks());
+  EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+}
+
+TEST_F(QuicStreamTest, StreamDataGetAckedOutOfOrder) {
+  Initialize(kShouldProcessData);
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+      .WillRepeatedly(
+          Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
+  // Send data.
+  stream_->WriteOrBufferData(kData1, false, nullptr);
+  stream_->WriteOrBufferData(kData1, false, nullptr);
+  stream_->WriteOrBufferData(kData1, false, nullptr);
+  stream_->WriteOrBufferData("", true, nullptr);
+  if (session_->streams_own_data()) {
+    EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size());
+  } else {
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+  }
+  EXPECT_TRUE(stream_->IsWaitingForAcks());
+
+  QuicStreamFrame frame1(stream_->id(), false, 0, kData1);
+  QuicStreamFrame frame2(stream_->id(), false, 9, kData1);
+  QuicStreamFrame frame3(stream_->id(), false, 18, kData1);
+  QuicStreamFrame frame4(stream_->id(), true, 27, "");
+  stream_->OnStreamFrameAcked(frame2, QuicTime::Delta::Zero());
+  if (session_->streams_own_data()) {
+    EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size());
+  }
+  stream_->OnStreamFrameAcked(frame3, QuicTime::Delta::Zero());
+  if (session_->streams_own_data()) {
+    EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size());
+  }
+  stream_->OnStreamFrameDiscarded(frame1);
+  EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+  // FIN is not acked yet.
+  EXPECT_TRUE(stream_->IsWaitingForAcks());
+  stream_->OnStreamFrameAcked(frame4, QuicTime::Delta::Zero());
+  EXPECT_FALSE(stream_->IsWaitingForAcks());
 }
 
 TEST_F(QuicStreamTest, CancelStream) {
   Initialize(kShouldProcessData);
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
-      .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+      .WillRepeatedly(
+          Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
   EXPECT_FALSE(stream_->IsWaitingForAcks());
+  EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
 
   stream_->WriteOrBufferData(kData1, false, nullptr);
   QuicStreamFrame frame(stream_->id(), 0, false, kData1);
   EXPECT_TRUE(stream_->IsWaitingForAcks());
+  if (session_->streams_own_data()) {
+    EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+  } else {
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+  }
   // Cancel stream.
   stream_->Reset(QUIC_STREAM_NO_ERROR);
   // stream still waits for acks as the error code is QUIC_STREAM_NO_ERROR, and
@@ -768,18 +833,26 @@
     stream_->OnStreamFrameDiscarded(frame);
     // Stream stops waiting for acks as data is not going to be retransmitted.
     EXPECT_FALSE(stream_->IsWaitingForAcks());
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
   }
 }
 
 TEST_F(QuicStreamTest, RstFrameReceivedStreamNotFinishSending) {
   Initialize(kShouldProcessData);
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
-      .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+      .WillRepeatedly(
+          Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
   EXPECT_FALSE(stream_->IsWaitingForAcks());
+  EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
 
   stream_->WriteOrBufferData(kData1, false, nullptr);
   QuicStreamFrame frame(stream_->id(), 0, false, kData1);
   EXPECT_TRUE(stream_->IsWaitingForAcks());
+  if (session_->streams_own_data()) {
+    EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+  } else {
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+  }
 
   // RST_STREAM received.
   QuicRstStreamFrame rst_frame(stream_->id(), QUIC_STREAM_CANCELLED, 9);
@@ -791,14 +864,17 @@
     // Stream stops waiting for acks as it does not finish sending and rst is
     // sent.
     EXPECT_FALSE(stream_->IsWaitingForAcks());
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
   }
 }
 
 TEST_F(QuicStreamTest, RstFrameReceivedStreamFinishSending) {
   Initialize(kShouldProcessData);
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
-      .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+      .WillRepeatedly(
+          Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
   EXPECT_FALSE(stream_->IsWaitingForAcks());
+  EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
 
   stream_->WriteOrBufferData(kData1, true, nullptr);
   EXPECT_TRUE(stream_->IsWaitingForAcks());
@@ -809,13 +885,20 @@
   stream_->OnStreamReset(rst_frame);
   // Stream stops waiting for acks as it has unacked data.
   EXPECT_TRUE(stream_->IsWaitingForAcks());
+  if (session_->streams_own_data()) {
+    EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size());
+  } else {
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
+  }
 }
 
 TEST_F(QuicStreamTest, ConnectionClosed) {
   Initialize(kShouldProcessData);
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
-      .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+      .WillRepeatedly(
+          Invoke(session_.get(), &MockQuicSession::ConsumeAndSaveAllData));
   EXPECT_FALSE(stream_->IsWaitingForAcks());
+  EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
 
   stream_->WriteOrBufferData(kData1, false, nullptr);
   QuicStreamFrame frame(stream_->id(), 0, false, kData1);
@@ -829,6 +912,7 @@
     stream_->OnStreamFrameDiscarded(frame);
     // Stream stops waiting for acks as connection is going to close.
     EXPECT_FALSE(stream_->IsWaitingForAcks());
+    EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size());
   }
 }
 
diff --git a/net/quic/test_tools/quic_stream_peer.cc b/net/quic/test_tools/quic_stream_peer.cc
index 4dfbea7e..213be66 100644
--- a/net/quic/test_tools/quic_stream_peer.cc
+++ b/net/quic/test_tools/quic_stream_peer.cc
@@ -81,5 +81,10 @@
   return stream->session();
 }
 
+// static
+QuicStreamSendBuffer& QuicStreamPeer::SendBuffer(QuicStream* stream) {
+  return stream->send_buffer_;
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/test_tools/quic_stream_peer.h b/net/quic/test_tools/quic_stream_peer.h
index b7c3356..3f1ce44 100644
--- a/net/quic/test_tools/quic_stream_peer.h
+++ b/net/quic/test_tools/quic_stream_peer.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "net/quic/core/quic_packets.h"
+#include "net/quic/core/quic_stream_send_buffer.h"
 #include "net/quic/core/quic_stream_sequencer.h"
 #include "net/quic/platform/api/quic_string_piece.h"
 
@@ -43,6 +44,8 @@
   static QuicStreamSequencer* sequencer(QuicStream* stream);
   static QuicSession* session(QuicStream* stream);
 
+  static QuicStreamSendBuffer& SendBuffer(QuicStream* stream);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicStreamPeer);
 };
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 51136c56..8edd8c7 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -72,7 +72,8 @@
                                    const QuicFrames& frames,
                                    size_t packet_size) {
   char* buffer = new char[packet_size];
-  size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size);
+  size_t length =
+      framer->BuildDataPacket(header, frames, buffer, packet_size, nullptr);
   DCHECK_NE(0u, length);
   // Re-construct the data packet with data ownership.
   return new QuicPacket(buffer, length, /* owns_buffer */ true,
@@ -211,6 +212,20 @@
 
 MockQuicConnectionVisitor::~MockQuicConnectionVisitor() {}
 
+void MockQuicConnectionVisitor::SaveStreamData(QuicStreamId id,
+                                               QuicIOVector iov,
+                                               size_t iov_offset,
+                                               QuicStreamOffset offset,
+                                               QuicByteCount data_length) {
+  producer_.SaveStreamData(id, iov, iov_offset, offset, data_length);
+}
+bool MockQuicConnectionVisitor::WriteStreamData(QuicStreamId id,
+                                                QuicStreamOffset offset,
+                                                QuicByteCount data_length,
+                                                QuicDataWriter* writer) {
+  return producer_.WriteStreamData(id, offset, data_length, writer);
+}
+
 MockQuicConnectionHelper::MockQuicConnectionHelper() {}
 
 MockQuicConnectionHelper::~MockQuicConnectionHelper() {}
@@ -379,6 +394,21 @@
   return QuicConsumedData(data.total_length, state != NO_FIN);
 }
 
+QuicConsumedData MockQuicSession::ConsumeAndSaveAllData(
+    QuicStream* stream,
+    QuicStreamId id,
+    const QuicIOVector& data,
+    QuicStreamOffset offset,
+    StreamSendingState state,
+    const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) {
+  QuicConsumedData consumed =
+      QuicConsumedData(data.total_length, state != NO_FIN);
+  if (streams_own_data() && data.total_length > 0) {
+    SaveStreamData(id, data, 0, offset, data.total_length);
+  }
+  return consumed;
+}
+
 MockQuicCryptoStream::MockQuicCryptoStream(QuicSession* session)
     : QuicCryptoStream(session), params_(new QuicCryptoNegotiatedParameters) {}
 
@@ -427,6 +457,21 @@
   return WriteHeadersMock(id, write_headers_, fin, priority, ack_listener);
 }
 
+QuicConsumedData MockQuicSpdySession::ConsumeAndSaveAllData(
+    QuicStream* stream,
+    QuicStreamId id,
+    const QuicIOVector& data,
+    QuicStreamOffset offset,
+    StreamSendingState state,
+    const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) {
+  QuicConsumedData consumed =
+      QuicConsumedData(data.total_length, state != NO_FIN);
+  if (streams_own_data() && data.total_length > 0) {
+    SaveStreamData(id, data, 0, offset, data.total_length);
+  }
+  return consumed;
+}
+
 TestQuicSpdyServerSession::TestQuicSpdyServerSession(
     QuicConnection* connection,
     const QuicConfig& config,
@@ -811,6 +856,24 @@
 
 MockConnectionCloseDelegate::~MockConnectionCloseDelegate() {}
 
+MockPacketCreatorDelegate::MockPacketCreatorDelegate() {}
+MockPacketCreatorDelegate::~MockPacketCreatorDelegate() {}
+
+void MockPacketCreatorDelegate::SaveStreamData(QuicStreamId id,
+                                               QuicIOVector iov,
+                                               size_t iov_offset,
+                                               QuicStreamOffset offset,
+                                               QuicByteCount data_length) {
+  producer_.SaveStreamData(id, iov, iov_offset, offset, data_length);
+}
+
+bool MockPacketCreatorDelegate::WriteStreamData(QuicStreamId id,
+                                                QuicStreamOffset offset,
+                                                QuicByteCount data_length,
+                                                QuicDataWriter* writer) {
+  return producer_.WriteStreamData(id, offset, data_length, writer);
+}
+
 void CreateClientSessionForTest(QuicServerId server_id,
                                 bool supports_stateless_rejects,
                                 QuicTime::Delta connection_start_time,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 1781752..d74a8dc 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -28,6 +28,7 @@
 #include "net/quic/platform/api/quic_string_piece.h"
 #include "net/quic/test_tools/mock_clock.h"
 #include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/simple_data_producer.h"
 #include "net/test/gtest_util.h"
 #include "net/tools/quic/quic_per_connection_packet_writer.h"
 #include "net/tools/quic/test_tools/mock_quic_session_visitor.h"
@@ -295,8 +296,19 @@
   MOCK_METHOD0(OnConfigNegotiated, void());
   MOCK_METHOD0(PostProcessAfterData, void());
   MOCK_METHOD0(OnAckNeedsRetransmittableFrame, void());
+  void SaveStreamData(QuicStreamId id,
+                      QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length) override;
+  bool WriteStreamData(QuicStreamId id,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override;
 
  private:
+  SimpleDataProducer producer_;
+
   DISALLOW_COPY_AND_ASSIGN(MockQuicConnectionVisitor);
 };
 
@@ -511,6 +523,15 @@
       const QuicReferenceCountedPointer<QuicAckListenerInterface>&
           ack_listener);
 
+  QuicConsumedData ConsumeAndSaveAllData(
+      QuicStream* stream,
+      QuicStreamId id,
+      const QuicIOVector& data,
+      QuicStreamOffset offset,
+      StreamSendingState state,
+      const QuicReferenceCountedPointer<QuicAckListenerInterface>&
+          ack_listener);
+
  private:
   std::unique_ptr<QuicCryptoStream> crypto_stream_;
 
@@ -630,6 +651,15 @@
     return QuicSpdySession::ShouldCreateOutgoingDynamicStream2();
   }
 
+  QuicConsumedData ConsumeAndSaveAllData(
+      QuicStream* stream,
+      QuicStreamId id,
+      const QuicIOVector& data,
+      QuicStreamOffset offset,
+      StreamSendingState state,
+      const QuicReferenceCountedPointer<QuicAckListenerInterface>&
+          ack_listener);
+
   using QuicSession::ActivateStream;
 
  private:
@@ -917,6 +947,33 @@
                     ConnectionCloseSource source));
 };
 
+class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface {
+ public:
+  MockPacketCreatorDelegate();
+  ~MockPacketCreatorDelegate() override;
+
+  MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet));
+  MOCK_METHOD3(OnUnrecoverableError,
+               void(QuicErrorCode,
+                    const std::string&,
+                    ConnectionCloseSource source));
+
+  void SaveStreamData(QuicStreamId id,
+                      QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length) override;
+  bool WriteStreamData(QuicStreamId id,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override;
+
+ private:
+  SimpleDataProducer producer_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockPacketCreatorDelegate);
+};
+
 // Creates a client session for testing.
 //
 // server_id: The server id associated with this stream.
diff --git a/net/quic/test_tools/simple_data_producer.cc b/net/quic/test_tools/simple_data_producer.cc
new file mode 100644
index 0000000..65eb3e61
--- /dev/null
+++ b/net/quic/test_tools/simple_data_producer.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/test_tools/simple_data_producer.h"
+
+#include "net/quic/platform/api/quic_map_util.h"
+
+namespace net {
+
+namespace test {
+
+SimpleDataProducer::SimpleDataProducer() {}
+SimpleDataProducer::~SimpleDataProducer() {}
+
+void SimpleDataProducer::SaveStreamData(QuicStreamId id,
+                                        QuicIOVector iov,
+                                        size_t iov_offset,
+                                        QuicStreamOffset offset,
+                                        QuicByteCount data_length) {
+  if (!QuicContainsKey(send_buffer_map_, id)) {
+    send_buffer_map_[id].reset(new QuicStreamSendBuffer(&allocator_));
+  }
+  send_buffer_map_[id]->SaveStreamData(iov, iov_offset, offset, data_length);
+}
+
+bool SimpleDataProducer::WriteStreamData(QuicStreamId id,
+                                         QuicStreamOffset offset,
+                                         QuicByteCount data_length,
+                                         QuicDataWriter* writer) {
+  return send_buffer_map_[id]->WriteStreamData(offset, data_length, writer);
+}
+
+}  // namespace test
+
+}  // namespace net
diff --git a/net/quic/test_tools/simple_data_producer.h b/net/quic/test_tools/simple_data_producer.h
new file mode 100644
index 0000000..73d7eb0
--- /dev/null
+++ b/net/quic/test_tools/simple_data_producer.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_TEST_TOOLS_SIMPLE_DATA_PRODUCER_H_
+#define NET_QUIC_TEST_TOOLS_SIMPLE_DATA_PRODUCER_H_
+
+#include <unordered_map>
+
+#include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/core/quic_stream_frame_data_producer.h"
+#include "net/quic/core/quic_stream_send_buffer.h"
+
+namespace net {
+
+namespace test {
+
+// A simple data producer which copies stream data into a map from stream
+// id to send buffer.
+class SimpleDataProducer : public QuicStreamFrameDataProducer {
+ public:
+  SimpleDataProducer();
+  ~SimpleDataProducer() override;
+
+  // QuicStreamFrameDataProducer methods:
+  void SaveStreamData(QuicStreamId id,
+                      QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length) override;
+  bool WriteStreamData(QuicStreamId id,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override;
+
+ private:
+  using SendBufferMap =
+      std::unordered_map<QuicStreamId, std::unique_ptr<QuicStreamSendBuffer>>;
+
+  SimpleBufferAllocator allocator_;
+
+  SendBufferMap send_buffer_map_;
+};
+
+}  // namespace test
+
+}  // namespace net
+
+#endif  // NET_QUIC_TEST_TOOLS_SIMPLE_DATA_PRODUCER_H_
diff --git a/net/quic/test_tools/simulator/quic_endpoint.cc b/net/quic/test_tools/simulator/quic_endpoint.cc
index 6e810d43..f936be8 100644
--- a/net/quic/test_tools/simulator/quic_endpoint.cc
+++ b/net/quic/test_tools/simulator/quic_endpoint.cc
@@ -244,6 +244,21 @@
   }
 }
 
+void QuicEndpoint::SaveStreamData(QuicStreamId id,
+                                  QuicIOVector iov,
+                                  size_t iov_offset,
+                                  QuicStreamOffset offset,
+                                  QuicByteCount data_length) {
+  producer_.SaveStreamData(id, iov, iov_offset, offset, data_length);
+}
+
+bool QuicEndpoint::WriteStreamData(QuicStreamId id,
+                                   QuicStreamOffset offset,
+                                   QuicByteCount data_length,
+                                   QuicDataWriter* writer) {
+  return producer_.WriteStreamData(id, offset, data_length, writer);
+}
+
 QuicEndpointMultiplexer::QuicEndpointMultiplexer(
     string name,
     std::initializer_list<QuicEndpoint*> endpoints)
diff --git a/net/quic/test_tools/simulator/quic_endpoint.h b/net/quic/test_tools/simulator/quic_endpoint.h
index 3199994..8d76b55 100644
--- a/net/quic/test_tools/simulator/quic_endpoint.h
+++ b/net/quic/test_tools/simulator/quic_endpoint.h
@@ -9,6 +9,7 @@
 #include "net/quic/core/crypto/null_encrypter.h"
 #include "net/quic/core/quic_connection.h"
 #include "net/quic/core/quic_packets.h"
+#include "net/quic/test_tools/simple_data_producer.h"
 #include "net/quic/test_tools/simulator/link.h"
 #include "net/quic/test_tools/simulator/queue.h"
 #include "net/tools/quic/quic_default_packet_writer.h"
@@ -90,6 +91,15 @@
   void OnPathDegrading() override {}
   void PostProcessAfterData() override {}
   void OnAckNeedsRetransmittableFrame() override {}
+  void SaveStreamData(QuicStreamId id,
+                      QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length) override;
+  bool WriteStreamData(QuicStreamId id,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override;
   // End QuicConnectionVisitorInterface implementation.
 
  private:
@@ -140,6 +150,8 @@
   bool wrong_data_received_;
 
   std::unique_ptr<char[]> transmission_buffer_;
+
+  test::SimpleDataProducer producer_;
 };
 
 // Multiplexes multiple connections at the same host on the network.
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index a5cb9a7..cc17c80 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -52,6 +52,8 @@
 // to be handed off to the time wait list manager.
 class PacketCollector : public QuicPacketCreator::DelegateInterface {
  public:
+  explicit PacketCollector(QuicBufferAllocator* allocator)
+      : send_buffer_(allocator) {}
   ~PacketCollector() override {}
 
   void OnSerializedPacket(SerializedPacket* serialized_packet) override {
@@ -68,12 +70,32 @@
                             const string& error_details,
                             ConnectionCloseSource source) override {}
 
+  void SaveStreamData(QuicStreamId id,
+                      QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length) override {
+    DCHECK_EQ(kCryptoStreamId, id);
+    send_buffer_.SaveStreamData(iov, iov_offset, offset, data_length);
+  }
+
+  bool WriteStreamData(QuicStreamId id,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override {
+    DCHECK_EQ(kCryptoStreamId, id);
+    return send_buffer_.WriteStreamData(offset, data_length, writer);
+  }
+
   std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() {
     return &packets_;
   }
 
  private:
   std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_;
+  // This is only needed until the packets are encrypted. Once packets are
+  // encrypted, the stream data is no longer required.
+  QuicStreamSendBuffer send_buffer_;
 };
 
 // Helper for statelessly closing connections by generating the
@@ -87,6 +109,7 @@
                                 QuicTimeWaitListManager* time_wait_list_manager)
       : connection_id_(connection_id),
         framer_(framer),
+        collector_(helper->GetBufferAllocator()),
         creator_(connection_id,
                  framer,
                  helper->GetBufferAllocator(),
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index e6beca6..87107b1 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -16773,25 +16773,6 @@
       },
       {
         "args": [
-          "--test-launcher-batch-limit=400",
-          "--deqp-egl-display-type=angle-d3d11"
-        ],
-        "name": "angle_deqp_gles3_d3d11_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": false,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6613",
-              "os": "Windows-2008ServerR2-SP1"
-            }
-          ],
-          "shards": 12
-        },
-        "test": "angle_deqp_gles3_tests",
-        "use_xvfb": false
-      },
-      {
-        "args": [
           "--use-gpu-in-tests",
           "--test-launcher-retry-limit=0"
         ],
@@ -17391,25 +17372,6 @@
       },
       {
         "args": [
-          "--test-launcher-batch-limit=400",
-          "--deqp-egl-display-type=angle-d3d11"
-        ],
-        "name": "angle_deqp_gles3_d3d11_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6613",
-              "os": "Windows-2008ServerR2-SP1"
-            }
-          ],
-          "shards": 12
-        },
-        "test": "angle_deqp_gles3_tests",
-        "use_xvfb": false
-      },
-      {
-        "args": [
           "--use-gpu-in-tests",
           "--test-launcher-retry-limit=0"
         ],
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContent.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContent.cpp
index 15d9d08e..c7ad5a8e 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContent.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContent.cpp
@@ -15,8 +15,6 @@
 class CSSParserLocalContext;
 namespace blink {
 
-using CSSCounterValue = cssvalue::CSSCounterValue;
-
 namespace {
 
 CSSValue* ConsumeAttr(CSSParserTokenRange args,
@@ -67,7 +65,7 @@
 
   if (!args.AtEnd())
     return nullptr;
-  return blink::CSSCounterValue::Create(identifier, list_style, separator);
+  return cssvalue::CSSCounterValue::Create(identifier, list_style, separator);
 }
 
 }  // namespace
diff --git a/third_party/proguard/BUILD.gn b/third_party/proguard/BUILD.gn
new file mode 100644
index 0000000..e43a60d9
--- /dev/null
+++ b/third_party/proguard/BUILD.gn
@@ -0,0 +1,22 @@
+# 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("//build/config/android/rules.gni")
+
+java_prebuilt("proguard_java") {
+  jar_path = "lib/proguard.jar"
+  data = [
+    "$root_build_dir/lib.java/third_party/proguard/proguard.jar",
+  ]
+}
+
+java_prebuilt("retrace_java") {
+  jar_path = "lib/retrace.jar"
+  deps = [
+    ":proguard_java",
+  ]
+  data = [
+    "$root_build_dir/lib.java/third_party/proguard/retrace.jar",
+  ]
+}
diff --git a/third_party/proguard/OWNERS b/third_party/proguard/OWNERS
index 4f349f6a..3a28457 100644
--- a/third_party/proguard/OWNERS
+++ b/third_party/proguard/OWNERS
@@ -1,2 +1,3 @@
+agrieve@chromium.org
 torne@chromium.org
 yfriedman@chromium.org
diff --git a/tools/perf/benchmarks/system_health_smoke_test.py b/tools/perf/benchmarks/system_health_smoke_test.py
index 3d95293a..61acdd8 100644
--- a/tools/perf/benchmarks/system_health_smoke_test.py
+++ b/tools/perf/benchmarks/system_health_smoke_test.py
@@ -36,8 +36,6 @@
   'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_mobile.browse:news:cnn',  # pylint: disable=line-too-long
   # cburg.com/721549
   'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_mobile.browse:news:toi',  # pylint: disable=line-too-long
-  # crbug.com/702455
-  'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.browse:media:youtube',  # pylint: disable=line-too-long
   # crbug.com/637230
   'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.browse:news:cnn',  # pylint: disable=line-too-long
   # Permenently disabled from smoke test for being long-running.
diff --git a/ui/aura/env_input_state_controller.cc b/ui/aura/env_input_state_controller.cc
index 7e3b291..6807055 100644
--- a/ui/aura/env_input_state_controller.cc
+++ b/ui/aura/env_input_state_controller.cc
@@ -26,8 +26,11 @@
       break;
   }
 
+  // If a synthesized event is created from a native event (e.g. EnterNotify
+  // XEvents), then we should take the location as we would for a
+  // non-synthesized event.
   if (event.type() != ui::ET_MOUSE_CAPTURE_CHANGED &&
-      !(event.flags() & ui::EF_IS_SYNTHESIZED)) {
+      (!(event.flags() & ui::EF_IS_SYNTHESIZED) || event.HasNativeEvent())) {
     SetLastMouseLocation(window, event.root_location());
   }
 }
diff --git a/ui/aura/window_tree_host_x11.cc b/ui/aura/window_tree_host_x11.cc
index 0635b7a..d57358c 100644
--- a/ui/aura/window_tree_host_x11.cc
+++ b/ui/aura/window_tree_host_x11.cc
@@ -252,9 +252,6 @@
                     root_window);
             cursor_client->SetDisplay(display);
           }
-          // EnterNotify creates ET_MOUSE_MOVE. Mark as synthesized as this is
-          // not a real mouse move event.
-          mouse_event.set_flags(mouse_event.flags() | ui::EF_IS_SYNTHESIZED);
         }
 
         TranslateAndDispatchLocatedEvent(&mouse_event);
diff --git a/ui/events/platform/x11/x11_event_source_libevent.cc b/ui/events/platform/x11/x11_event_source_libevent.cc
index 7edd46c8..85bdb73 100644
--- a/ui/events/platform/x11/x11_event_source_libevent.cc
+++ b/ui/events/platform/x11/x11_event_source_libevent.cc
@@ -87,10 +87,6 @@
   switch (xev.type) {
     case LeaveNotify:
     case EnterNotify:
-      // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is
-      // not real mouse move event.
-      if (xev.type == EnterNotify)
-        flags |= EF_IS_SYNTHESIZED;
       return base::MakeUnique<MouseEvent>(ET_MOUSE_MOVED,
                                           EventLocationFromXEvent(xev),
                                           EventSystemLocationFromXEvent(xev),
diff --git a/ui/events/x/events_x_unittest.cc b/ui/events/x/events_x_unittest.cc
index cf62b2b..a7082e6 100644
--- a/ui/events/x/events_x_unittest.cc
+++ b/ui/events/x/events_x_unittest.cc
@@ -189,6 +189,7 @@
   // the way views handle mouse enter. See comments for EnterNotify case in
   // ui::EventTypeFromNative for more details.
   EXPECT_EQ(ui::ET_MOUSE_MOVED, ui::EventTypeFromNative(&event));
+  EXPECT_TRUE(ui::EventFlagsFromNative(&event) & ui::EF_IS_SYNTHESIZED);
   EXPECT_EQ(
       "10,20",
       gfx::ToFlooredPoint(ui::EventLocationFromNative(&event)).ToString());
diff --git a/ui/events/x/events_x_utils.cc b/ui/events/x/events_x_utils.cc
index fa37616..af656b4 100644
--- a/ui/events/x/events_x_utils.cc
+++ b/ui/events/x/events_x_utils.cc
@@ -474,6 +474,9 @@
       return flags;
     }
     case EnterNotify:
+      // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is not
+      // a real mouse move event.
+      return GetEventFlagsFromXState(xev.xcrossing.state) | EF_IS_SYNTHESIZED;
     case LeaveNotify:
       return GetEventFlagsFromXState(xev.xcrossing.state);
     case MotionNotify:
diff --git a/ui/gl/test/gl_image_test_template.h b/ui/gl/test/gl_image_test_template.h
index fdd9983..d4a250f 100644
--- a/ui/gl/test/gl_image_test_template.h
+++ b/ui/gl/test/gl_image_test_template.h
@@ -186,7 +186,9 @@
 TYPED_TEST_CASE_P(GLImageTest);
 
 TYPED_TEST_P(GLImageTest, Create) {
-  const gfx::Size small_image_size(4, 4);
+  // NOTE: On some drm devices (mediatek) the mininum width/height to add an fb
+  // for a bo must be 64.
+  const gfx::Size small_image_size(64, 64);
   const gfx::Size large_image_size(512, 512);
   const uint8_t* image_color = this->delegate_.GetImageColor();
 
diff --git a/ui/message_center/notification.cc b/ui/message_center/notification.cc
index 2b7a312..4f49cf7 100644
--- a/ui/message_center/notification.cc
+++ b/ui/message_center/notification.cc
@@ -32,19 +32,7 @@
 
 ButtonInfo& ButtonInfo::operator=(const ButtonInfo& other) = default;
 
-RichNotificationData::RichNotificationData()
-    : priority(DEFAULT_PRIORITY),
-      never_timeout(false),
-      timestamp(base::Time::Now()),
-      context_message(base::string16()),
-      progress(0),
-      should_make_spoken_feedback_for_popup_updates(true),
-      clickable(true),
-#if defined(OS_CHROMEOS)
-      pinned(false),
-#endif  // defined(OS_CHROMEOS)
-      renotify(false),
-      silent(false) {}
+RichNotificationData::RichNotificationData() : timestamp(base::Time::Now()) {}
 
 RichNotificationData::RichNotificationData(const RichNotificationData& other)
     : priority(other.priority),
@@ -67,9 +55,9 @@
       silent(other.silent),
       accessible_name(other.accessible_name) {}
 
-RichNotificationData::~RichNotificationData() {}
+RichNotificationData::~RichNotificationData() = default;
 
-Notification::Notification() {}
+Notification::Notification() = default;
 
 Notification::Notification(NotificationType type,
                            const std::string& id,
@@ -143,7 +131,7 @@
   return *this;
 }
 
-Notification::~Notification() {}
+Notification::~Notification() = default;
 
 bool Notification::IsRead() const {
   return is_read_ || optional_fields_.priority == MIN_PRIORITY;
diff --git a/ui/message_center/notification.h b/ui/message_center/notification.h
index 6aff50c..3e9a1a8 100644
--- a/ui/message_center/notification.h
+++ b/ui/message_center/notification.h
@@ -32,52 +32,114 @@
 }
 #endif
 
+// Represents an individual item in NOTIFICATION_TYPE_MULTIPLE notifications.
 struct MESSAGE_CENTER_EXPORT NotificationItem {
+  NotificationItem(const base::string16& title, const base::string16& message);
+
   base::string16 title;
   base::string16 message;
-
-  NotificationItem(const base::string16& title, const base::string16& message);
 };
 
-enum class ButtonType { BUTTON, TEXT };
+enum class ButtonType {
+  // A simple button having an icon and a title that the user can click on.
+  BUTTON,
 
+  // A button having an icon and a title that should also enable the user to
+  // input text, enabling them to quickly respond from the notification.
+  TEXT
+};
+
+// Represents a button to be shown as part of a notification.
 struct MESSAGE_CENTER_EXPORT ButtonInfo {
-  base::string16 title;
-  gfx::Image icon;
-  ButtonType type = ButtonType::BUTTON;
-  base::string16 placeholder;
-
   explicit ButtonInfo(const base::string16& title);
   ButtonInfo(const ButtonInfo& other);
   ~ButtonInfo();
   ButtonInfo& operator=(const ButtonInfo& other);
+
+  // Title that should be displayed on the notification button.
+  base::string16 title;
+
+  // Icon that should be displayed on the notification button. Optional. On some
+  // platforms, a mask will be applied to the icon, to match the visual
+  // requirements of the notification.
+  gfx::Image icon;
+
+  // Type of this button.
+  ButtonType type = ButtonType::BUTTON;
+
+  // The placeholder string that should be displayed in the input field for TEXT
+  // type buttons until the user has entered a response themselves.
+  base::string16 placeholder;
 };
 
+// Represents rich features available for notifications.
 class MESSAGE_CENTER_EXPORT RichNotificationData {
  public:
   RichNotificationData();
   RichNotificationData(const RichNotificationData& other);
   ~RichNotificationData();
 
-  int priority;
-  bool never_timeout;
+  // Priority of the notification. This must be one of the NotificationPriority
+  // values defined in notification_types.h.
+  int priority = DEFAULT_PRIORITY;
+
+  // Whether the notification should remain on screen indefinitely.
+  bool never_timeout = false;
+
+  // Time indicating when the notification was shown. Defaults to the time at
+  // which the RichNotificationData instance is constructed.
   base::Time timestamp;
+
+  // Context message to display below the notification's content. Optional. May
+  // not be used for notifications that have an explicit origin URL set.
   base::string16 context_message;
+
+  // Large image to display on the notification. Optional.
   gfx::Image image;
+
+  // Small badge to display on the notification to illustrate the source of the
+  // notification. Optional.
   gfx::Image small_image;
+
+  // Items to display on the notification. Only applicable for notifications
+  // that have type NOTIFICATION_TYPE_MULTIPLE.
   std::vector<NotificationItem> items;
-  int progress;
+
+  // Progress, in range of [0-100], of NOTIFICATION_TYPE_PROGRESS notifications.
+  int progress = 0;
+
+  // Buttons that should show up on the notification. A maximum of 16 buttons
+  // is supported by the current implementation, but this may differ between
+  // platforms.
   std::vector<ButtonInfo> buttons;
-  bool should_make_spoken_feedback_for_popup_updates;
-  bool clickable;
+
+  // Whether updates to the visible notification should be announced to users
+  // depending on visual assistance systems.
+  bool should_make_spoken_feedback_for_popup_updates = true;
+
+  // Whether it should be possible for the user to click on the notification.
+  bool clickable = true;
+
 #if defined(OS_CHROMEOS)
   // Flag if the notification is pinned. If true, the notification is pinned
-  // and user can't remove it.
-  bool pinned;
+  // and the user can't remove it.
+  bool pinned = false;
 #endif  // defined(OS_CHROMEOS)
+
+  // Vibration pattern to play when displaying the notification. There must be
+  // an odd number of entries in this pattern when it's set: numbers of
+  // milliseconds to vibrate separated by numbers of milliseconds to pause.
   std::vector<int> vibration_pattern;
-  bool renotify;
-  bool silent;
+
+  // Whether the vibration pattern and other applicable announcement mechanisms
+  // should be considered when updating the notification.
+  bool renotify = false;
+
+  // Whether all announcement mechansims should be suppressed when displaying
+  // the notification.
+  bool silent = false;
+
+  // An accessible description of the notification's contents.
   base::string16 accessible_name;
 };
 
@@ -86,6 +148,24 @@
   // Default constructor needed for generated mojom files
   Notification();
 
+  // Creates a new notification.
+  //
+  // |type|: Type of the notification that dictates the layout.
+  // |id|: Identifier of the notification. Showing a notification that shares
+  //       its profile and identifier with an already visible notification will
+  //       replace the former one
+  // |title|: Title of the notification.
+  // |message|: Body text of the notification. May not be used for certain
+  //            values of |type|, for example list-style notifications.
+  // |icon|: Icon to show alongside of the notification.
+  // |display_source|: Textual representation of who's shown the notification.
+  // |origin_url|: URL of the website responsible for showing the notification.
+  // |notifier_id|: NotifierId instance representing the system responsible for
+  //                showing the notification.
+  // |optional_fields|: Rich data that can be used to assign more elaborate
+  //                    features to notifications.
+  // |delegate|: Delegate that will influence the behaviour of this notification
+  //             and receives events on its behalf.
   Notification(NotificationType type,
                const std::string& id,
                const base::string16& title,
@@ -97,8 +177,13 @@
                const RichNotificationData& optional_fields,
                NotificationDelegate* delegate);
 
+  // Creates a copy of the |other| notification. The delegate, if any, will be
+  // identical for both the Notification instances. The |id| of the notification
+  // will be replaced by the given value.
   Notification(const std::string& id, const Notification& other);
 
+  // Creates a copy of the |other| notification. The delegate, if any, will be
+  // identical for both the Notification instances.
   Notification(const Notification& other);
 
   Notification& operator=(const Notification& other);
diff --git a/ui/message_center/views/notification_control_buttons_view.cc b/ui/message_center/views/notification_control_buttons_view.cc
index 2db5a2d..322734a 100644
--- a/ui/message_center/views/notification_control_buttons_view.cc
+++ b/ui/message_center/views/notification_control_buttons_view.cc
@@ -46,7 +46,8 @@
 
 void NotificationControlButtonsView::ShowCloseButton(bool show) {
   if (show && !close_button_) {
-    close_button_ = new message_center::PaddedButton(this);
+    close_button_ = base::MakeUnique<message_center::PaddedButton>(this);
+    close_button_->set_owned_by_client();
     close_button_->SetImage(views::CustomButton::STATE_NORMAL,
                             message_center::GetCloseIcon());
     close_button_->SetAccessibleName(l10n_util::GetStringUTF16(
@@ -58,16 +59,17 @@
 
     // Add the button at the last.
     DCHECK_LE(child_count(), 1);
-    AddChildView(close_button_);
+    AddChildView(close_button_.get());
   } else if (!show && close_button_) {
-    RemoveChildView(close_button_);
-    close_button_ = nullptr;
+    DCHECK(Contains(close_button_.get()));
+    close_button_.reset();
   }
 }
 
 void NotificationControlButtonsView::ShowSettingsButton(bool show) {
   if (show && !settings_button_) {
-    settings_button_ = new message_center::PaddedButton(this);
+    settings_button_ = base::MakeUnique<message_center::PaddedButton>(this);
+    settings_button_->set_owned_by_client();
     settings_button_->SetImage(views::CustomButton::STATE_NORMAL,
                                message_center::GetSettingsIcon());
     settings_button_->SetAccessibleName(l10n_util::GetStringUTF16(
@@ -79,10 +81,10 @@
 
     // Add the button at the first.
     DCHECK_LE(child_count(), 1);
-    AddChildViewAt(settings_button_, 0);
+    AddChildViewAt(settings_button_.get(), 0);
   } else if (!show && settings_button_) {
-    RemoveChildView(settings_button_);
-    settings_button_ = nullptr;
+    DCHECK(Contains(settings_button_.get()));
+    settings_button_.reset();
   }
 }
 
@@ -113,15 +115,25 @@
   return settings_button_ && settings_button_->HasFocus();
 }
 
+message_center::PaddedButton*
+NotificationControlButtonsView::close_button_for_testing() const {
+  return close_button_.get();
+}
+
+message_center::PaddedButton*
+NotificationControlButtonsView::settings_button_for_testing() const {
+  return settings_button_.get();
+}
+
 const char* NotificationControlButtonsView::GetClassName() const {
   return kViewClassName;
 }
 
 void NotificationControlButtonsView::ButtonPressed(views::Button* sender,
                                                    const ui::Event& event) {
-  if (close_button_ && sender == close_button_) {
+  if (close_button_ && sender == close_button_.get()) {
     message_view_->OnCloseButtonPressed();
-  } else if (settings_button_ && sender == settings_button_) {
+  } else if (settings_button_ && sender == settings_button_.get()) {
     message_view_->OnSettingsButtonPressed();
   }
 }
diff --git a/ui/message_center/views/notification_control_buttons_view.h b/ui/message_center/views/notification_control_buttons_view.h
index ee9faab..2dcf1d20 100644
--- a/ui/message_center/views/notification_control_buttons_view.h
+++ b/ui/message_center/views/notification_control_buttons_view.h
@@ -51,12 +51,9 @@
   // close button, false otherwise.
   bool IsSettingsButtonFocused() const;
 
-  message_center::PaddedButton* close_button_for_testing() const {
-    return close_button_;
-  }
-  message_center::PaddedButton* settings_button_for_testing() const {
-    return settings_button_;
-  }
+  // Methods for testing.
+  message_center::PaddedButton* close_button_for_testing() const;
+  message_center::PaddedButton* settings_button_for_testing() const;
 
   // views::View
   const char* GetClassName() const override;
@@ -72,8 +69,8 @@
  private:
   MessageView* message_view_;
 
-  message_center::PaddedButton* close_button_ = nullptr;
-  message_center::PaddedButton* settings_button_ = nullptr;
+  std::unique_ptr<message_center::PaddedButton> close_button_;
+  std::unique_ptr<message_center::PaddedButton> settings_button_;
 
   std::unique_ptr<gfx::LinearAnimation> bgcolor_animation_;
   SkColor bgcolor_origin_;
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.cc b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
index 7081e84..dd9bfe7 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
@@ -66,14 +66,18 @@
     // DRM_MODE_FB_MODIFIERS set. We only set that when we've created
     // a bo with modifiers, otherwise, we rely on the "no modifiers"
     // behavior doing the right thing.
-    drm_->AddFramebuffer2(gbm_bo_get_width(bo), gbm_bo_get_height(bo),
-                          framebuffer_pixel_format_, handles, strides, offsets,
-                          modifiers, &framebuffer_, addfb_flags);
+    bool ret = drm_->AddFramebuffer2(
+        gbm_bo_get_width(bo), gbm_bo_get_height(bo), framebuffer_pixel_format_,
+        handles, strides, offsets, modifiers, &framebuffer_, addfb_flags);
+    PLOG_IF(ERROR, !ret) << "AddFramebuffer2 failed";
+    DCHECK(ret);
     if (opaque_framebuffer_pixel_format_ != framebuffer_pixel_format_) {
-      drm_->AddFramebuffer2(gbm_bo_get_width(bo), gbm_bo_get_height(bo),
-                            opaque_framebuffer_pixel_format_, handles, strides,
-                            offsets, modifiers, &opaque_framebuffer_,
-                            addfb_flags);
+      ret = drm_->AddFramebuffer2(gbm_bo_get_width(bo), gbm_bo_get_height(bo),
+                                  opaque_framebuffer_pixel_format_, handles,
+                                  strides, offsets, modifiers,
+                                  &opaque_framebuffer_, addfb_flags);
+      PLOG_IF(ERROR, !ret) << "AddFramebuffer2 failed";
+      DCHECK(ret);
     }
   }
 }
diff --git a/ui/platform_window/x11/x11_window.cc b/ui/platform_window/x11/x11_window.cc
index 64bd7a8..9630d3f7 100644
--- a/ui/platform_window/x11/x11_window.cc
+++ b/ui/platform_window/x11/x11_window.cc
@@ -87,11 +87,8 @@
   XEvent* xev = event;
   switch (xev->type) {
     case EnterNotify: {
-      // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is
-      // not real mouse move event.
       MouseEvent mouse_event(xev);
       CHECK_EQ(ET_MOUSE_MOVED, mouse_event.type());
-      mouse_event.set_flags(mouse_event.flags() | EF_IS_SYNTHESIZED);
       delegate()->DispatchEvent(&mouse_event);
       break;
     }