diff --git a/AUTHORS b/AUTHORS
index 2694366..7085b7b7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -835,6 +835,7 @@
 Yong Wang <ccyongwang@tencent.com>
 Charles Vaughn <cvaughn@gmail.com>
 
+ACCESS CO., LTD. <*@access-company.com>
 BlackBerry Limited <*@blackberry.com>
 Code Aurora Forum <*@codeaurora.org>
 Comodo CA Limited
diff --git a/DEPS b/DEPS
index 53a75fd..be08e7a4 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'c7be00366bb0171e2d247ea71e291a64e3d10254',
+  'skia_revision': '459c9679a221bbe66a735080728afb9599fa5ed7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '2bbb55162f0c9490a2085ed6eaa38038a7605609',
+  'pdfium_revision': '2e2a4fcd43677c5882dcf00cb4b99635cb2cfcd3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -72,7 +72,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '777fdd6443d5f01420b67137118febdf56a1c8e4',
+  'boringssl_revision': 'afd88c27f2fe9f8f1a6d5b287cc16b1bc8f06198',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '380124f4ad9d972449c81462ec99a4c916fcd2d8',
+  'catapult_revision': 'abff3b4929c74e4eb90a877520b82570853ac5c5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -208,7 +208,7 @@
     Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '28a5cdde5c32bcf66715343c10f74e85713f7aaf',
 
   'src/third_party/usrsctp/usrsctplib':
-    Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '8679f2b0bf063ac894dc473debefd61dbbebf622',
+    Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '2f6478eb8d40f1766a96b5b033ed26c0c2244589',
 
   'src/third_party/libsrtp':
     Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + 'ccf84786f8ef803cb9c75e919e5a3976b9f5a672',
@@ -409,7 +409,7 @@
 
     # For Linux and Chromium OS.
     'src/third_party/cros_system_api':
-      Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'f425c1c372b0077a67937855f03f1089d0df7970',
+      Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'c6eab9e4d0b4f56176df23d30b815dc94b774a3d',
 
     'src/third_party/freetype/src':
       Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + Var('freetype_revision'),
@@ -466,7 +466,7 @@
       Var('chromium_git') + '/external/android_protobuf.git' + '@' + '999188d0dc72e97f7fe08bb756958a2cf090f4e7',
 
     'src/third_party/android_tools':
-      Var('chromium_git') + '/android_tools.git' + '@' + 'b65c4776dac2cf1b80e969b3b2d4e081b9c84f29',
+      Var('chromium_git') + '/android_tools.git' + '@' + 'cb6bc21107001e2f2eeee2707b482b2b755baf51',
 
     'src/third_party/apache-portable-runtime/src':
       Var('chromium_git') + '/external/apache-portable-runtime.git' + '@' + 'c76a8c4277e09a82eaa229e35246edea1ee0a6a1',
@@ -957,6 +957,17 @@
                 '-s', 'src/third_party/gvr-android-sdk/common_library.aar.sha1',
     ],
   },
+  {
+    'name': 'vr_controller_test_api',
+    'pattern': '\\.sha1',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--platform=linux*',
+                '--no_auth',
+                '--bucket', 'chromium-gvr-static-shim/controller_test_api',
+                '-s', 'src/third_party/gvr-android-sdk/test-libraries/controller_test_api.aar.sha1',
+    ],
+  },
   # Pull luci-go binaries (isolate, swarming) using checked-in hashes.
   {
     'name': 'luci-go_win',
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
index 5c824d2..2b2e0a4 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsTest.java
@@ -598,7 +598,7 @@
         }
 
         @Override
-        public void determinedVisibility(int pid) {}
+        public void onDeterminedVisibility(int pid) {}
 
         @Override
         public void onSentToBackground() {}
diff --git a/apps/app_restore_service_browsertest.cc b/apps/app_restore_service_browsertest.cc
index acdea78..9946a8a87 100644
--- a/apps/app_restore_service_browsertest.cc
+++ b/apps/app_restore_service_browsertest.cc
@@ -5,6 +5,7 @@
 #include "apps/app_restore_service.h"
 #include "apps/app_restore_service_factory.h"
 #include "apps/saved_files_service.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "content/public/browser/browser_context.h"
@@ -114,6 +115,7 @@
       extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
       content::NotificationService::AllSources());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   base::FilePath temp_file;
@@ -154,6 +156,7 @@
       extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
       content::NotificationService::AllSources());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   base::FilePath temp_file;
diff --git a/base/BUILD.gn b/base/BUILD.gn
index b284bec..43897be 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2585,6 +2585,7 @@
       "//testing/android/reporter:reporter_java",
       "//third_party/android_support_test_runner:exposed_instrumentation_api_publish_java",
       "//third_party/android_support_test_runner:runner_java",
+      "//third_party/android_tools:android_support_chromium_java",
       "//third_party/hamcrest:hamcrest_core_java",
       "//third_party/junit",
     ]
@@ -2594,6 +2595,7 @@
       "test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java",
       "test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java",
       "test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java",
+      "test/android/javatests/src/org/chromium/base/test/BaseChromiumRunnerCommon.java",
       "test/android/javatests/src/org/chromium/base/test/BaseTestResult.java",
       "test/android/javatests/src/org/chromium/base/test/SetUpTestRule.java",
       "test/android/javatests/src/org/chromium/base/test/SetUpStatement.java",
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
index 6b97bdd..61109f1 100644
--- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
+++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
@@ -44,7 +44,9 @@
         super.attachBaseContext(base);
         assert getBaseContext() != null;
         checkAppBeingReplaced();
-        ChromiumMultiDexInstaller.install(this);
+        if (BuildConfig.isMultidexEnabled()) {
+            ChromiumMultiDexInstaller.install(this);
+        }
     }
 
     /**
diff --git a/base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java b/base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java
index 3d036c2..9049cb0 100644
--- a/base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java
+++ b/base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java
@@ -12,7 +12,6 @@
 import android.os.Build;
 import android.support.multidex.MultiDex;
 
-import org.chromium.base.BuildConfig;
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
 
@@ -48,8 +47,6 @@
      */
     @VisibleForTesting
     public static void install(Context context) {
-        if (!BuildConfig.isMultidexEnabled()) return;
-
         // TODO(jbudorick): Back out this version check once support for K & below works.
         // http://crbug.com/512357
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 3e4cebe4..2643793 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -388,13 +388,31 @@
     *bucket_count = kBucketCount_MAX - 1;
   }
 
-  if (*minimum >= *maximum)
-    return false;
-  if (*bucket_count < 3)
-    return false;
-  if (*bucket_count > static_cast<uint32_t>(*maximum - *minimum + 2))
-    return false;
-  return true;
+  bool check_okay = true;
+
+  if (*minimum > *maximum) {
+    check_okay = false;
+    std::swap(*minimum, *maximum);
+  }
+  if (*maximum == *minimum) {
+    check_okay = false;
+    *maximum = *minimum + 1;
+  }
+  if (*bucket_count < 3) {
+    check_okay = false;
+    *bucket_count = 3;
+  }
+  if (*bucket_count > static_cast<uint32_t>(*maximum - *minimum + 2)) {
+    check_okay = false;
+    *bucket_count = static_cast<uint32_t>(*maximum - *minimum + 2);
+  }
+
+  if (!check_okay) {
+    UMA_HISTOGRAM_SPARSE_SLOWLY("Histogram.BadConstructionArguments",
+                                static_cast<Sample>(HashMetricName(name)));
+  }
+
+  return check_okay;
 }
 
 uint64_t Histogram::name_hash() const {
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index a76dd632..20d5104 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -179,11 +179,12 @@
   const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
 
   // This function validates histogram construction arguments. It returns false
-  // if some of the arguments are totally bad.
+  // if some of the arguments are bad but also corrects them so they should
+  // function on non-dcheck builds without crashing.
   // Note. Currently it allow some bad input, e.g. 0 as minimum, but silently
   // converts it to good input: 1.
-  // TODO(kaiwang): Be more restrict and return false for any bad input, and
-  // make this a readonly validating function.
+  // TODO(bcwhite): Use false returns to create "sink" histograms so that bad
+  // data doesn't create confusion on the servers.
   static bool InspectConstructionArguments(const std::string& name,
                                            Sample* minimum,
                                            Sample* maximum,
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
index fcd60869..a48c4ab 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
@@ -4,7 +4,8 @@
 
 package org.chromium.base.test;
 
-import android.os.Bundle;
+import android.app.Application;
+import android.content.Context;
 import android.support.test.runner.AndroidJUnitRunner;
 
 import org.chromium.base.multidex.ChromiumMultiDexInstaller;
@@ -18,8 +19,11 @@
  */
 public class BaseChromiumAndroidJUnitRunner extends AndroidJUnitRunner {
     @Override
-    public void onCreate(Bundle arguments) {
-        ChromiumMultiDexInstaller.install(getTargetContext());
-        super.onCreate(arguments);
+    public Application newApplication(ClassLoader cl, String className, Context context)
+            throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        ChromiumMultiDexInstaller.install(new BaseChromiumRunnerCommon.MultiDexContextWrapper(
+                getContext(), getTargetContext()));
+        BaseChromiumRunnerCommon.reorderDexPathElements(cl, getContext(), getTargetContext());
+        return super.newApplication(cl, className, context);
     }
 }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumInstrumentationTestRunner.java
index d44c9dd..693bb62 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumInstrumentationTestRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumInstrumentationTestRunner.java
@@ -4,7 +4,8 @@
 
 package org.chromium.base.test;
 
-import android.os.Bundle;
+import android.app.Application;
+import android.content.Context;
 
 import org.chromium.base.multidex.ChromiumMultiDexInstaller;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -16,9 +17,12 @@
  */
 public class BaseChromiumInstrumentationTestRunner extends BaseInstrumentationTestRunner {
     @Override
-    public void onCreate(Bundle arguments) {
-        ChromiumMultiDexInstaller.install(getTargetContext());
-        super.onCreate(arguments);
+    public Application newApplication(ClassLoader cl, String className, Context context)
+            throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        ChromiumMultiDexInstaller.install(new BaseChromiumRunnerCommon.MultiDexContextWrapper(
+                getContext(), getTargetContext()));
+        BaseChromiumRunnerCommon.reorderDexPathElements(cl, getContext(), getTargetContext());
+        return super.newApplication(cl, className, context);
     }
 
     /**
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumRunnerCommon.java b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumRunnerCommon.java
new file mode 100644
index 0000000..fcda9103
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumRunnerCommon.java
@@ -0,0 +1,162 @@
+// 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.base.test;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+
+import org.chromium.android.support.PackageManagerWrapper;
+import org.chromium.base.Log;
+import org.chromium.base.annotations.MainDex;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ *  Functionality common to the JUnit3 and JUnit4 runners.
+ */
+@MainDex
+class BaseChromiumRunnerCommon {
+    private static final String TAG = "base_test";
+
+    /**
+     *  A ContextWrapper that allows multidex test APKs to extract secondary dexes into
+     *  the APK under test's data directory.
+     */
+    @MainDex
+    static class MultiDexContextWrapper extends ContextWrapper {
+        private Context mAppContext;
+
+        MultiDexContextWrapper(Context instrContext, Context appContext) {
+            super(instrContext);
+            mAppContext = appContext;
+        }
+
+        @Override
+        public File getFilesDir() {
+            return mAppContext.getFilesDir();
+        }
+
+        @Override
+        public SharedPreferences getSharedPreferences(String name, int mode) {
+            return mAppContext.getSharedPreferences(name, mode);
+        }
+
+        @Override
+        public PackageManager getPackageManager() {
+            return new PackageManagerWrapper(super.getPackageManager()) {
+                @Override
+                public ApplicationInfo getApplicationInfo(String packageName, int flags) {
+                    try {
+                        ApplicationInfo ai = super.getApplicationInfo(packageName, flags);
+                        if (packageName.equals(getPackageName())) {
+                            ApplicationInfo appAi =
+                                    super.getApplicationInfo(mAppContext.getPackageName(), flags);
+                            File dataDir = new File(appAi.dataDir, "test-multidex");
+                            if (!dataDir.exists() && !dataDir.mkdirs()) {
+                                throw new IOException(String.format(
+                                        "Unable to create test multidex directory \"%s\"",
+                                        dataDir.getPath()));
+                            }
+                            ai.dataDir = dataDir.getPath();
+                        }
+                        return ai;
+                    } catch (Exception e) {
+                        Log.e(TAG, "Failed to get application info for %s", packageName, e);
+                    }
+                    return null;
+                }
+            };
+        }
+    }
+
+    /**
+     * Ensure all test dex entries precede app dex entries.
+     *
+     * @param cl ClassLoader to modify. Assumed to be a derivative of
+     *        {@link dalvik.system.BaseDexClassLoader}. If this isn't
+     *        the case, reordering will fail.
+     */
+    static void reorderDexPathElements(ClassLoader cl, Context context, Context targetContext) {
+        try {
+            Log.i(TAG,
+                    "Reordering dex files. If you're building a multidex test APK and see a "
+                            + "class resolving to an unexpected implementation, this may be why.");
+            Field pathListField = findField(cl, "pathList");
+            Object dexPathList = pathListField.get(cl);
+            Field dexElementsField = findField(dexPathList, "dexElements");
+            Object[] dexElementsList = (Object[]) dexElementsField.get(dexPathList);
+            Arrays.sort(dexElementsList,
+                    new DexListReorderingComparator(
+                            context.getPackageName(), targetContext.getPackageName()));
+            dexElementsField.set(dexPathList, dexElementsList);
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to reorder dex elements for testing.", e);
+        }
+    }
+
+    /**
+     *  Comparator for sorting dex list entries.
+     *
+     *  Using this to sort a list of dex list entries will result in the following order:
+     *   - Strings that contain neither the test package nor the app package in lexicographical
+     *     order.
+     *   - Strings that contain the test package in lexicographical order.
+     *   - Strings that contain the app package but not the test package in lexicographical order.
+     */
+    private static class DexListReorderingComparator implements Comparator<Object>, Serializable {
+        private String mTestPackage;
+        private String mAppPackage;
+
+        public DexListReorderingComparator(String testPackage, String appPackage) {
+            mTestPackage = testPackage;
+            mAppPackage = appPackage;
+        }
+
+        @Override
+        public int compare(Object o1, Object o2) {
+            String s1 = o1.toString();
+            String s2 = o2.toString();
+            if (s1.contains(mTestPackage)) {
+                if (!s2.contains(mTestPackage)) {
+                    if (s2.contains(mAppPackage)) {
+                        return -1;
+                    } else {
+                        return 1;
+                    }
+                }
+            } else if (s1.contains(mAppPackage)) {
+                if (s2.contains(mTestPackage)) {
+                    return 1;
+                } else if (!s2.contains(mAppPackage)) {
+                    return 1;
+                }
+            } else if (s2.contains(mTestPackage) || s2.contains(mAppPackage)) {
+                return -1;
+            }
+            return s1.compareTo(s2);
+        }
+    }
+
+    private static Field findField(Object instance, String name) throws NoSuchFieldException {
+        for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
+            try {
+                Field f = clazz.getDeclaredField(name);
+                f.setAccessible(true);
+                return f;
+            } catch (NoSuchFieldException e) {
+            }
+        }
+        throw new NoSuchFieldException(
+                "Unable to find field " + name + " in " + instance.getClass());
+    }
+}
diff --git a/base/test/multiprocess_test.cc b/base/test/multiprocess_test.cc
index 9da243347..d45e3a8 100644
--- a/base/test/multiprocess_test.cc
+++ b/base/test/multiprocess_test.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 
 namespace base {
@@ -44,6 +45,7 @@
 #endif  // !defined(OS_ANDROID)
 
 CommandLine GetMultiProcessTestChildBaseCommandLine() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   CommandLine cmd_line = *CommandLine::ForCurrentProcess();
   cmd_line.SetProgram(MakeAbsoluteFilePath(cmd_line.GetProgram()));
   return cmd_line;
diff --git a/base/test/scoped_task_environment.cc b/base/test/scoped_task_environment.cc
index b18bf6a..1e8782e 100644
--- a/base/test/scoped_task_environment.cc
+++ b/base/test/scoped_task_environment.cc
@@ -12,7 +12,12 @@
 namespace base {
 namespace test {
 
-ScopedTaskEnvironment::ScopedTaskEnvironment() {
+ScopedTaskEnvironment::ScopedTaskEnvironment(MainThreadType main_thread_type)
+    : message_loop_(main_thread_type == MainThreadType::DEFAULT
+                        ? MessageLoop::TYPE_DEFAULT
+                        : (main_thread_type == MainThreadType::UI
+                               ? MessageLoop::TYPE_UI
+                               : MessageLoop::TYPE_IO)) {
   DCHECK(!TaskScheduler::GetInstance());
 
   // Instantiate a TaskScheduler with 1 thread in each of its 4 pools. Threads
diff --git a/base/test/scoped_task_environment.h b/base/test/scoped_task_environment.h
index 2887d07..b0a6db3 100644
--- a/base/test/scoped_task_environment.h
+++ b/base/test/scoped_task_environment.h
@@ -32,7 +32,17 @@
 // https://docs.google.com/document/d/1QabRo8c7D9LsYY3cEcaPQbOCLo8Tu-6VLykYXyl3Pkk/edit
 class ScopedTaskEnvironment {
  public:
-  ScopedTaskEnvironment();
+  enum class MainThreadType {
+    // The main thread doesn't pump messages.
+    DEFAULT,
+    // The main thread pumps UI messages.
+    UI,
+    // The main thread pumps asynchronous IO messages.
+    IO,
+  };
+
+  ScopedTaskEnvironment(
+      MainThreadType main_thread_type = MainThreadType::DEFAULT);
 
   // Runs pending (Thread|Sequenced)TaskRunnerHandle tasks and pending
   // BLOCK_SHUTDOWN TaskScheduler tasks. Then, unregisters the TaskScheduler and
diff --git a/build/android/main_dex_classes.flags b/build/android/main_dex_classes.flags
index 81152dc..9bb7977a 100644
--- a/build/android/main_dex_classes.flags
+++ b/build/android/main_dex_classes.flags
@@ -1,3 +1,10 @@
+# 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.
+
+# Proguard flags for what should be kept in the main dex. Only used
+# during main dex list determination, not during actual proguarding.
+
 -keep @**.MainDex class * {
   *;
 }
diff --git a/build/android/multidex.flags b/build/android/multidex.flags
new file mode 100644
index 0000000..59e7e85
--- /dev/null
+++ b/build/android/multidex.flags
@@ -0,0 +1,12 @@
+# 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.
+
+# Proguard flags for what to keep through proguarding when multidex is
+# enabled. Not used during main dex list determination.
+
+-keepattributes *Annotations*
+-keep @interface org.chromium.base.annotations.MainDex
+-keep @**.MainDex class * {
+  *;
+}
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 4455732..eddbbf3 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1935,6 +1935,9 @@
       if (defined(invoker.proguard_configs)) {
         _proguard_configs += invoker.proguard_configs
       }
+      if (enable_multidex) {
+        _proguard_configs += [ "//build/android/multidex.flags" ]
+      }
       assert(_proguard_configs != [])  # Mark as used.
       _proguard_target = "${_template_name}__proguard"
       proguard(_proguard_target) {
diff --git a/build/linux/unbundle/opus.gn b/build/linux/unbundle/opus.gn
new file mode 100644
index 0000000..e779a97d
--- /dev/null
+++ b/build/linux/unbundle/opus.gn
@@ -0,0 +1,45 @@
+# 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/linux/pkg_config.gni")
+import("//build/shim_headers.gni")
+
+pkg_config("system_opus") {
+  packages = [ "opus" ]
+}
+
+shim_headers("opus_shim") {
+  root_path = "src/include"
+  headers = [
+    "opus.h",
+    "opus_defines.h",
+    "opus_multistream.h",
+    "opus_types.h",
+  ]
+}
+
+source_set("opus") {
+  deps = [
+    ":opus_shim",
+  ]
+  public_configs = [ ":system_opus" ]
+}
+
+source_set("opus_compare") {
+}
+
+source_set("opus_demo") {
+}
+
+source_set("test_opus_api") {
+}
+
+source_set("test_opus_decode") {
+}
+
+source_set("test_opus_encode") {
+}
+
+source_set("test_opus_padding") {
+}
diff --git a/build/linux/unbundle/replace_gn_files.py b/build/linux/unbundle/replace_gn_files.py
index 7570a8b..3b457146 100755
--- a/build/linux/unbundle/replace_gn_files.py
+++ b/build/linux/unbundle/replace_gn_files.py
@@ -29,6 +29,7 @@
   'libwebp': 'third_party/libwebp/BUILD.gn',
   'libxml': 'third_party/libxml/BUILD.gn',
   'libxslt': 'third_party/libxslt/BUILD.gn',
+  'opus': 'third_party/opus/BUILD.gn',
   're2': 'third_party/re2/BUILD.gn',
   'snappy': 'third_party/snappy/BUILD.gn',
   'yasm': 'third_party/yasm/yasm_assemble.gni',
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn
index 853b040..3161db12 100644
--- a/build/secondary/third_party/android_tools/BUILD.gn
+++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -193,6 +193,11 @@
   aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
 }
 
+android_library("android_support_chromium_java") {
+  testonly = true
+  java_files = [ "$android_sdk_root/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java" ]
+}
+
 # TODO(dgn): Remove this once no other target has a dependency on it
 java_group("google_play_services_default_resources") {
   deps = []
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 0f3ba5c0..1fa9929 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -641,15 +641,11 @@
     bool synchronous_composite =
         !HasImplThread() &&
         !layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
-    // Allow relaim resources for this test so that mailboxes in the display
-    // will be returned inside the commit that replaces them.
-    bool force_disable_reclaim_resources = false;
     return base::MakeUnique<TestCompositorFrameSink>(
         compositor_context_provider, std::move(worker_context_provider),
         shared_bitmap_manager(), gpu_memory_buffer_manager(),
         layer_tree_host()->GetSettings().renderer_settings,
-        ImplThreadTaskRunner(), synchronous_composite,
-        force_disable_reclaim_resources);
+        ImplThreadTaskRunner(), synchronous_composite);
   }
 
   void AdvanceTestCase() {
diff --git a/cc/output/compositor_frame_sink.h b/cc/output/compositor_frame_sink.h
index 650f7191..f8b7a47 100644
--- a/cc/output/compositor_frame_sink.h
+++ b/cc/output/compositor_frame_sink.h
@@ -41,9 +41,13 @@
   struct Capabilities {
     Capabilities() = default;
 
-    // Whether ForceReclaimResources can be called to reclaim all resources
-    // from the CompositorFrameSink.
-    bool can_force_reclaim_resources = false;
+    // True if we must always swap, even if there is no damage to the frame.
+    // Needed for both the browser compositor as well as layout tests.
+    // TODO(ericrk): This should be test-only for layout tests, but tab
+    // capture has issues capturing offscreen tabs whithout this. We should
+    // remove this dependency. crbug.com/680196
+    bool must_always_swap = false;
+
     // True if sync points for resources are needed when swapping delegated
     // frames.
     bool delegated_sync_points_required = true;
@@ -102,10 +106,6 @@
     return shared_bitmap_manager_;
   }
 
-  // If supported, this causes a ReclaimResources for all resources that are
-  // currently in use.
-  virtual void ForceReclaimResources() {}
-
   // If supported, this sets the LocalSurfaceId the CompositorFrameSink will use
   // to submit a CompositorFrame.
   virtual void SetLocalSurfaceId(const LocalSurfaceId& local_surface_id) {}
diff --git a/cc/surfaces/compositor_frame_sink_support.cc b/cc/surfaces/compositor_frame_sink_support.cc
index 39b7fbd..09bfdbc7 100644
--- a/cc/surfaces/compositor_frame_sink_support.cc
+++ b/cc/surfaces/compositor_frame_sink_support.cc
@@ -206,11 +206,6 @@
     client_->WillDrawSurface(local_surface_id, damage_rect);
 }
 
-void CompositorFrameSinkSupport::ForceReclaimResources() {
-  DCHECK(surface_factory_);
-  surface_factory_->ClearSurface();
-}
-
 void CompositorFrameSinkSupport::ClaimTemporaryReference(
     const SurfaceId& surface_id) {
   surface_manager_->AssignTemporaryReference(surface_id, frame_sink_id_);
diff --git a/cc/surfaces/compositor_frame_sink_support.h b/cc/surfaces/compositor_frame_sink_support.h
index 75f5605d..33e44f9 100644
--- a/cc/surfaces/compositor_frame_sink_support.h
+++ b/cc/surfaces/compositor_frame_sink_support.h
@@ -69,7 +69,6 @@
   void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
                              CompositorFrame frame);
   void RequestCopyOfSurface(std::unique_ptr<CopyOutputRequest> request);
-  void ForceReclaimResources();
   void ClaimTemporaryReference(const SurfaceId& surface_id);
 
  protected:
diff --git a/cc/surfaces/direct_compositor_frame_sink.cc b/cc/surfaces/direct_compositor_frame_sink.cc
index 13b6c62..505d38a 100644
--- a/cc/surfaces/direct_compositor_frame_sink.cc
+++ b/cc/surfaces/direct_compositor_frame_sink.cc
@@ -31,7 +31,7 @@
       surface_manager_(surface_manager),
       display_(display) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  capabilities_.can_force_reclaim_resources = true;
+  capabilities_.must_always_swap = true;
   // Display and DirectCompositorFrameSink share a GL context, so sync
   // points aren't needed when passing resources between them.
   capabilities_.delegated_sync_points_required = false;
@@ -47,7 +47,7 @@
       surface_manager_(surface_manager),
       display_(display) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  capabilities_.can_force_reclaim_resources = true;
+  capabilities_.must_always_swap = true;
 }
 
 DirectCompositorFrameSink::~DirectCompositorFrameSink() {
@@ -110,10 +110,6 @@
                                   std::move(frame));
 }
 
-void DirectCompositorFrameSink::ForceReclaimResources() {
-  support_->ForceReclaimResources();
-}
-
 void DirectCompositorFrameSink::DisplayOutputSurfaceLost() {
   is_lost_ = true;
   client_->DidLoseCompositorFrameSink();
diff --git a/cc/surfaces/direct_compositor_frame_sink.h b/cc/surfaces/direct_compositor_frame_sink.h
index 5aa021b4..98d4cecd 100644
--- a/cc/surfaces/direct_compositor_frame_sink.h
+++ b/cc/surfaces/direct_compositor_frame_sink.h
@@ -51,7 +51,6 @@
   bool BindToClient(CompositorFrameSinkClient* client) override;
   void DetachFromClient() override;
   void SubmitCompositorFrame(CompositorFrame frame) override;
-  void ForceReclaimResources() override;
 
   // DisplayClient implementation.
   void DisplayOutputSurfaceLost() override;
diff --git a/cc/surfaces/direct_compositor_frame_sink_unittest.cc b/cc/surfaces/direct_compositor_frame_sink_unittest.cc
index 5f1b8b8..bfb3875 100644
--- a/cc/surfaces/direct_compositor_frame_sink_unittest.cc
+++ b/cc/surfaces/direct_compositor_frame_sink_unittest.cc
@@ -171,19 +171,6 @@
   EXPECT_EQ(2u, display_output_surface_->num_sent_frames());
 }
 
-TEST_F(DirectCompositorFrameSinkTest,
-       LockingResourcesDoesNotIndirectlyCauseDamage) {
-  compositor_frame_sink_->ForceReclaimResources();
-  EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
-  task_runner_->RunPendingTasks();
-  EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
-
-  SwapBuffersWithDamage(gfx::Rect());
-  EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
-}
-
 class TestBeginFrameObserver : public BeginFrameObserverBase {
  public:
   const BeginFrameAck& ack() const { return ack_; }
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index be2332b..2ceae593 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -82,11 +82,6 @@
   UnrefFrameResourcesAndRunDrawCallback(std::move(previous_pending_frame_data));
 }
 
-void Surface::EvictFrame() {
-  QueueFrame(CompositorFrame(), DrawCallback(), WillDrawCallback());
-  active_frame_data_.reset();
-}
-
 void Surface::RequestCopyOfOutput(
     std::unique_ptr<CopyOutputRequest> copy_request) {
   if (!active_frame_data_ ||
diff --git a/cc/surfaces/surface.h b/cc/surfaces/surface.h
index 5aefd5e..603036f 100644
--- a/cc/surfaces/surface.h
+++ b/cc/surfaces/surface.h
@@ -60,7 +60,6 @@
   void QueueFrame(CompositorFrame frame,
                   const DrawCallback& draw_callback,
                   const WillDrawCallback& will_draw_callback);
-  void EvictFrame();
   void RequestCopyOfOutput(std::unique_ptr<CopyOutputRequest> copy_request);
 
   // Notifies the Surface that a blocking SurfaceId now has an active frame.
diff --git a/cc/surfaces/surface_factory.cc b/cc/surfaces/surface_factory.cc
index 76167c9f..7d65ec2 100644
--- a/cc/surfaces/surface_factory.cc
+++ b/cc/surfaces/surface_factory.cc
@@ -87,13 +87,6 @@
   manager_->SurfaceModified(current_surface_->surface_id());
 }
 
-void SurfaceFactory::ClearSurface() {
-  if (!current_surface_)
-    return;
-  current_surface_->EvictFrame();
-  manager_->SurfaceModified(current_surface_->surface_id());
-}
-
 void SurfaceFactory::ReceiveFromChild(
     const TransferableResourceArray& resources) {
   holder_.ReceiveFromChild(resources);
diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h
index 0a206e6f..55782e4 100644
--- a/cc/surfaces/surface_factory.h
+++ b/cc/surfaces/surface_factory.h
@@ -65,10 +65,6 @@
                              const WillDrawCallback& will_draw_callback);
   void RequestCopyOfSurface(std::unique_ptr<CopyOutputRequest> copy_request);
 
-  // Evicts the current frame on the surface. All the resources
-  // will be released and Surface::HasFrame will return false.
-  void ClearSurface();
-
   SurfaceFactoryClient* client() { return client_; }
 
   void ReceiveFromChild(const TransferableResourceArray& resources);
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index 6298b78..7935b39 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -52,14 +52,10 @@
   bool synchronous_composite =
       !HasImplThread() &&
       !layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
-  // Allow resource reclaiming for partial raster tests to get back
-  // resources from the Display.
-  bool force_disable_reclaim_resources = false;
   auto delegating_output_surface = base::MakeUnique<TestCompositorFrameSink>(
       compositor_context_provider, std::move(worker_context_provider),
       shared_bitmap_manager(), gpu_memory_buffer_manager(), RendererSettings(),
-      ImplThreadTaskRunner(), synchronous_composite,
-      force_disable_reclaim_resources);
+      ImplThreadTaskRunner(), synchronous_composite);
   delegating_output_surface->SetEnlargePassTextureAmount(
       enlarge_texture_amount_);
   return delegating_output_surface;
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index db7a93c..45d898a57 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -863,14 +863,11 @@
   bool synchronous_composite =
       !HasImplThread() &&
       !layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
-  // Disable reclaim resources by default to act like the Display lives
-  // out-of-process.
-  bool force_disable_reclaim_resources = true;
   return base::MakeUnique<TestCompositorFrameSink>(
       compositor_context_provider, std::move(worker_context_provider),
       shared_bitmap_manager(), gpu_memory_buffer_manager(),
       layer_tree_host()->GetSettings().renderer_settings, impl_task_runner_,
-      synchronous_composite, force_disable_reclaim_resources);
+      synchronous_composite);
 }
 
 std::unique_ptr<OutputSurface>
diff --git a/cc/test/test_compositor_frame_sink.cc b/cc/test/test_compositor_frame_sink.cc
index 75ace29..8a856ed 100644
--- a/cc/test/test_compositor_frame_sink.cc
+++ b/cc/test/test_compositor_frame_sink.cc
@@ -27,8 +27,7 @@
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     const RendererSettings& renderer_settings,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    bool synchronous_composite,
-    bool force_disable_reclaim_resources)
+    bool synchronous_composite)
     : CompositorFrameSink(std::move(compositor_context_provider),
                           std::move(worker_context_provider),
                           gpu_memory_buffer_manager,
@@ -41,11 +40,6 @@
       local_surface_id_allocator_(new LocalSurfaceIdAllocator()),
       external_begin_frame_source_(this),
       weak_ptr_factory_(this) {
-  // Since this CompositorFrameSink and the Display are tightly coupled and in
-  // the same process/thread, the LayerTreeHostImpl can reclaim resources from
-  // the Display. But we allow tests to disable this to mimic an out-of-process
-  // Display.
-  capabilities_.can_force_reclaim_resources = !force_disable_reclaim_resources;
   // Always use sync tokens so that code paths in resource provider that deal
   // with sync tokens are tested.
   capabilities_.delegated_sync_points_required = true;
@@ -160,13 +154,6 @@
   }
 }
 
-void TestCompositorFrameSink::ForceReclaimResources() {
-  if (capabilities_.can_force_reclaim_resources &&
-      delegated_local_surface_id_.is_valid()) {
-    support_->ForceReclaimResources();
-  }
-}
-
 void TestCompositorFrameSink::DidReceiveCompositorFrameAck(
     const ReturnedResourceArray& resources) {
   ReclaimResources(resources);
diff --git a/cc/test/test_compositor_frame_sink.h b/cc/test/test_compositor_frame_sink.h
index 3b00ae0..dad6c04 100644
--- a/cc/test/test_compositor_frame_sink.h
+++ b/cc/test/test_compositor_frame_sink.h
@@ -57,8 +57,7 @@
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       const RendererSettings& renderer_settings,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-      bool synchronous_composite,
-      bool force_disable_reclaim_resources);
+      bool synchronous_composite);
   ~TestCompositorFrameSink() override;
 
   // This client must be set before BindToClient() happens.
@@ -79,7 +78,6 @@
   void DetachFromClient() override;
   void SetLocalSurfaceId(const LocalSurfaceId& local_surface_id) override;
   void SubmitCompositorFrame(CompositorFrame frame) override;
-  void ForceReclaimResources() override;
 
   // CompositorFrameSinkSupportClient implementation.
   void DidReceiveCompositorFrameAck(
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 89c7ab70..5d38bf5 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -324,15 +324,6 @@
 void LayerTreeHostImpl::BeginCommit() {
   TRACE_EVENT0("cc", "LayerTreeHostImpl::BeginCommit");
 
-  // Ensure all textures are returned so partial texture updates can happen
-  // during the commit.
-  // TODO(ericrk): We should not need to ForceReclaimResources when using
-  // Impl-side-painting as it doesn't upload during commits. However,
-  // Display::Draw currently relies on resource being reclaimed to block drawing
-  // between BeginCommit / Swap. See crbug.com/489515.
-  if (compositor_frame_sink_)
-    compositor_frame_sink_->ForceReclaimResources();
-
   if (!CommitToActiveTree())
     CreatePendingTree();
 }
@@ -800,8 +791,8 @@
       !root_surface->layer_list().empty();
   bool hud_wants_to_draw_ = active_tree_->hud_layer() &&
                             active_tree_->hud_layer()->IsAnimatingHUDContents();
-  bool resources_must_be_resent =
-      compositor_frame_sink_->capabilities().can_force_reclaim_resources;
+  bool must_always_swap =
+      compositor_frame_sink_->capabilities().must_always_swap;
   // When touch handle visibility changes there is no visible damage
   // because touch handles are composited in the browser. However we
   // still want the browser to be notified that the handles changed
@@ -812,8 +803,7 @@
   if (root_surface_has_contributing_layers &&
       root_surface_has_no_visible_damage &&
       !active_tree_->property_trees()->effect_tree.HasCopyRequests() &&
-      !resources_must_be_resent && !hud_wants_to_draw_ &&
-      !handle_visibility_changed) {
+      !must_always_swap && !hud_wants_to_draw_ && !handle_visibility_changed) {
     TRACE_EVENT0("cc",
                  "LayerTreeHostImpl::CalculateRenderPasses::EmptyDamageRect");
     frame->has_no_damage = true;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 74f2ab2..34d269f 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -8805,8 +8805,7 @@
   auto compositor_frame_sink = base::MakeUnique<TestCompositorFrameSink>(
       context_provider, TestContextProvider::CreateWorker(), nullptr, nullptr,
       RendererSettings(), base::ThreadTaskRunnerHandle::Get().get(),
-      true /* synchronous_composite */,
-      false /* force_disable_reclaim_resources */);
+      true /* synchronous_composite */);
   compositor_frame_sink->SetClient(&test_client_);
 
   CreateHostImpl(DefaultSettings(), std::move(compositor_frame_sink));
@@ -11912,32 +11911,6 @@
   EXPECT_FALSE(host_impl_->use_msaa());
 }
 
-// A mock output surface which lets us detect calls to ForceReclaimResources.
-class MockReclaimResourcesCompositorFrameSink : public FakeCompositorFrameSink {
- public:
-  MockReclaimResourcesCompositorFrameSink()
-      : FakeCompositorFrameSink(TestContextProvider::Create(),
-                                TestContextProvider::CreateWorker()) {}
-
-  MOCK_METHOD0(ForceReclaimResources, void());
-};
-
-// Display::Draw (and the planned Display Scheduler) currently rely on resources
-// being reclaimed to block drawing between BeginCommit / Swap. This test
-// ensures that BeginCommit triggers ForceReclaimResources. See
-// crbug.com/489515.
-TEST_F(LayerTreeHostImplTest, BeginCommitReclaimsResources) {
-  auto compositor_frame_sink =
-      base::MakeUnique<MockReclaimResourcesCompositorFrameSink>();
-  // Hold an unowned pointer to the output surface to use for mock expectations.
-  MockReclaimResourcesCompositorFrameSink* mock_compositor_frame_sink =
-      compositor_frame_sink.get();
-
-  CreateHostImpl(DefaultSettings(), std::move(compositor_frame_sink));
-  EXPECT_CALL(*mock_compositor_frame_sink, ForceReclaimResources()).Times(1);
-  host_impl_->BeginCommit();
-}
-
 TEST_F(LayerTreeHostImplTest, UpdatePageScaleFactorOnActiveTree) {
   // Check page scale factor update in property trees when an update is made
   // on the active tree.
diff --git a/cc/trees/layer_tree_host_pixeltest_tiles.cc b/cc/trees/layer_tree_host_pixeltest_tiles.cc
index d6145d57..a5c02acf 100644
--- a/cc/trees/layer_tree_host_pixeltest_tiles.cc
+++ b/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -157,11 +157,17 @@
   void DidCommitAndDrawFrame() override {
     switch (layer_tree_host()->SourceFrameNumber()) {
       case 1:
-        // We have done one frame, so the layer's content has been rastered.
-        // Now we change the picture behind it to record something completely
-        // different, but we give a smaller invalidation rect. The layer should
-        // only re-raster the stuff in the rect. If it doesn't do partial raster
-        // it would re-raster the whole thing instead.
+        // We have done one frame, but the resource may not be available for
+        // partial raster yet. Force a second frame.
+        picture_layer_->SetNeedsDisplayRect(gfx::Rect(50, 50, 100, 100));
+        break;
+      case 2:
+        // We have done two frames, so the layer's content has been rastered
+        // twice and the first frame's resource is available for partial
+        // raster. Now we change the picture behind it to record something
+        // completely different, but we give a smaller invalidation rect. The
+        // layer should only re-raster the stuff in the rect. If it doesn't do
+        // partial raster it would re-raster the whole thing instead.
         client_.set_blue_top(false);
         Finish();
         picture_layer_->SetNeedsDisplayRect(gfx::Rect(50, 50, 100, 100));
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 850a28f..b31b02d 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -3085,7 +3085,6 @@
       const RendererSettings& renderer_settings,
       base::SingleThreadTaskRunner* task_runner,
       bool synchronous_composite,
-      bool force_disable_reclaim_resources,
       base::Closure invalidate_callback)
       : TestCompositorFrameSink(std::move(compositor_context_provider),
                                 std::move(worker_context_provider),
@@ -3093,8 +3092,7 @@
                                 gpu_memory_buffer_manager,
                                 renderer_settings,
                                 task_runner,
-                                synchronous_composite,
-                                force_disable_reclaim_resources),
+                                synchronous_composite),
         invalidate_callback_(std::move(invalidate_callback)) {}
 
   // TestCompositorFrameSink overrides.
@@ -3130,7 +3128,6 @@
         shared_bitmap_manager(), gpu_memory_buffer_manager(),
         layer_tree_host()->GetSettings().renderer_settings,
         ImplThreadTaskRunner(), false /* synchronous_composite */,
-        false /* force_disable_reclaim_resources */,
         std::move(on_draw_callback));
     compositor_frame_sink_ = frame_sink.get();
     return std::move(frame_sink);
@@ -5747,14 +5744,11 @@
     bool synchronous_composite =
         !HasImplThread() &&
         !layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
-    // Relaiming resources is parameterized for this test.
-    bool force_disable_reclaim_resources = !reclaim_resources_;
     return base::MakeUnique<TestCompositorFrameSink>(
         compositor_context_provider, std::move(worker_context_provider),
         shared_bitmap_manager(), gpu_memory_buffer_manager(),
         layer_tree_host()->GetSettings().renderer_settings,
-        ImplThreadTaskRunner(), synchronous_composite,
-        force_disable_reclaim_resources);
+        ImplThreadTaskRunner(), synchronous_composite);
   }
 
   void BeginTest() override {
@@ -5801,19 +5795,13 @@
       EXPECT_TRUE(swap_promise_result_[0].dtor_called);
     }
 
-    // Second swap promise fails to swap if not reclaiming resources from the
-    // Display.
+    // Second swap promise fails to swap.
     {
       base::AutoLock lock(swap_promise_result_[1].lock);
       EXPECT_TRUE(swap_promise_result_[1].did_activate_called);
-      if (!reclaim_resources_) {
-        EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
-        EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
-        EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
-      } else {
-        EXPECT_TRUE(swap_promise_result_[1].did_swap_called);
-        EXPECT_FALSE(swap_promise_result_[1].did_not_swap_called);
-      }
+      EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
+      EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
+      EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
       EXPECT_TRUE(swap_promise_result_[1].dtor_called);
     }
 
@@ -5828,20 +5816,12 @@
     }
   }
 
-  bool reclaim_resources_;
   int commit_count_ = 0;
   TestSwapPromiseResult swap_promise_result_[3];
 };
 
-TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, NoReclaim) {
-  reclaim_resources_ = false;
-  RunTest(CompositorMode::SINGLE_THREADED);
-}
-
-TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, Reclaim) {
-  reclaim_resources_ = true;
-  RunTest(CompositorMode::SINGLE_THREADED);
-}
+// Synchronous composite is a single-threaded only feature.
+SINGLE_THREAD_TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise);
 
 // Make sure page scale and top control deltas are applied to the client even
 // when the LayerTreeHost doesn't have a root layer.
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index f7be83ed..2ba30af 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -512,9 +512,11 @@
 
     java_files = [
       "javatests/src/org/chromium/chrome/browser/media/RouterTestUtils.java",
+      "javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/MockVrCoreVersionCheckerImpl.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/MockVrDaydreamApi.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTest.java",
+      "javatests/src/org/chromium/chrome/browser/vr_shell/VrTestBase.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/VrUtils.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java",
     ]
@@ -531,6 +533,7 @@
       "//third_party/android_protobuf:protobuf_nano_javalib",
       "//third_party/android_support_test_runner:runner_java",
       "//third_party/android_tools:android_support_v7_appcompat_java",
+      "//third_party/gvr-android-sdk:controller_test_api_java",
       "//third_party/gvr-android-sdk:gvr_common_java",
       "//ui/android:ui_java",
     ]
@@ -882,6 +885,11 @@
     "//net/android:net_test_support_apk",
   ]
   proguard_enabled = !is_java_debug
+
+  # The test APK contains code from both the APK under test and the
+  # test APK when proguard is enabled. That causes this APK to exceed
+  # the dex limit.
+  enable_multidex = proguard_enabled
 }
 
 if (enable_vr) {
diff --git a/chrome/android/java/res/layout/button_preference_button.xml b/chrome/android/java/res/layout/button_preference_button.xml
index 47ad44b..76e950d 100644
--- a/chrome/android/java/res/layout/button_preference_button.xml
+++ b/chrome/android/java/res/layout/button_preference_button.xml
@@ -3,7 +3,9 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<!-- Layout used by ButtonPreference for the button widget style. -->
+<!-- Layout used by ButtonPreference for the button widget style.
+     android:focusable="false" makes it possible to trigger an event with the 'ENTER' key.
+     See crbug.com/674736 -->
 <org.chromium.ui.widget.ButtonCompat
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:chrome="http://schemas.android.com/apk/res-auto"
@@ -11,5 +13,6 @@
     android:layout_height="wrap_content"
     android:layout_width="wrap_content"
     android:minHeight="40dp"
+    android:focusable="false"
     android:textColor="@android:color/white"
     chrome:buttonColor="@color/pref_accent_color" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/TabularContextMenuUi.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/TabularContextMenuUi.java
index 5440368..64096dc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/TabularContextMenuUi.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/TabularContextMenuUi.java
@@ -91,6 +91,47 @@
     }
 
     /**
+     * Creates a ViewPageAdapter based off the given list of views.
+     * @param activity Used to inflate the new ViewPager
+     * @param params Used to get the header text.
+     * @param itemGroups The list of views to put into the ViewPager. The string is the title of the
+     *                   tab
+     * @return Returns a complete tabular context menu view.
+     */
+    @VisibleForTesting
+    View createPagerView(Activity activity, ContextMenuParams params,
+            List<Pair<Integer, List<ContextMenuItem>>> itemGroups) {
+        View view = LayoutInflater.from(activity).inflate(R.layout.tabular_context_menu, null);
+
+        List<Pair<String, ViewGroup>> viewGroups = new ArrayList<>();
+        int maxCount = 0;
+        for (int i = 0; i < itemGroups.size(); i++) {
+            Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i);
+            maxCount = Math.max(maxCount, itemGroup.second.size());
+        }
+        for (int i = 0; i < itemGroups.size(); i++) {
+            Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i);
+            // TODO(tedchoc): Pass the ContextMenuGroup identifier to determine if it's an image.
+            boolean isImageTab = itemGroup.first == R.string.contextmenu_image_title;
+            viewGroups.add(new Pair<>(activity.getString(itemGroup.first),
+                    createContextMenuPageUi(
+                            activity, params, itemGroup.second, isImageTab, maxCount)));
+        }
+        TabularContextMenuViewPager pager =
+                (TabularContextMenuViewPager) view.findViewById(R.id.custom_pager);
+        pager.setAdapter(new TabularContextMenuPagerAdapter(viewGroups));
+
+        TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout);
+        if (itemGroups.size() <= 1) {
+            tabLayout.setVisibility(View.GONE);
+        } else {
+            tabLayout.setupWithViewPager((ViewPager) view.findViewById(R.id.custom_pager));
+        }
+
+        return view;
+    }
+
+    /**
      * Creates the view of a context menu. Based off the Context Type, it'll adjust the list of
      * items and display only the ones that'll be on that specific group.
      * @param activity Used to get the resources of an item.
@@ -109,10 +150,13 @@
                 R.layout.tabular_context_menu_page, null);
         ListView listView = (ListView) baseLayout.findViewById(R.id.selectable_items);
 
+        displayHeaderIfVisibleItems(params, baseLayout);
         if (isImage) {
+            // #displayHeaderIfVisibleItems() sets these two views to GONE if the header text is
+            // empty but they should still be visible because we have an image to display.
+            baseLayout.findViewById(R.id.context_header_layout).setVisibility(View.VISIBLE);
+            baseLayout.findViewById(R.id.context_divider).setVisibility(View.VISIBLE);
             displayImageHeader(baseLayout, params, activity.getResources());
-        } else {
-            displayHeaderIfVisibleItems(params, baseLayout);
         }
 
         // Set the list adapter and get the height to display it appropriately in a dialog.
@@ -155,12 +199,6 @@
 
     private void displayImageHeader(
             ViewGroup baseLayout, ContextMenuParams params, Resources resources) {
-        displayHeaderIfVisibleItems(params, baseLayout);
-        // #displayHeaderIfVisibleItems() sets these two views to GONE if the header text is
-        // empty but they should still be visible because we have an image to display.
-        baseLayout.findViewById(R.id.context_header_layout).setVisibility(View.VISIBLE);
-        baseLayout.findViewById(R.id.context_divider).setVisibility(View.VISIBLE);
-
         mHeaderImageView = (ImageView) baseLayout.findViewById(R.id.context_header_image);
         TextView headerTextView = (TextView) baseLayout.findViewById(R.id.context_header_text);
         // We'd prefer the header text is the title text instead of the link text for images.
@@ -210,46 +248,6 @@
     }
 
     /**
-     * Creates a ViewPageAdapter based off the given list of views.
-     * @param activity Used to inflate the new ViewPager
-     * @param params Used to get the header text.
-     * @param itemGroups The list of views to put into the ViewPager. The string is the title of the
-     *                   tab
-     * @return Returns a complete tabular context menu view.
-     */
-    @VisibleForTesting
-    View createPagerView(Activity activity, ContextMenuParams params,
-            List<Pair<Integer, List<ContextMenuItem>>> itemGroups) {
-        View view = LayoutInflater.from(activity).inflate(R.layout.tabular_context_menu, null);
-
-        List<Pair<String, ViewGroup>> viewGroups = new ArrayList<>();
-        int maxCount = 0;
-        for (int i = 0; i < itemGroups.size(); i++) {
-            Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i);
-            maxCount = Math.max(maxCount, itemGroup.second.size());
-        }
-        for (int i = 0; i < itemGroups.size(); i++) {
-            Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i);
-            // TODO(tedchoc): Pass the ContextMenuGroup identifier to determine if it's an image.
-            boolean isImageTab = itemGroup.first == R.string.contextmenu_image_title;
-            viewGroups.add(new Pair<>(activity.getString(itemGroup.first),
-                    createContextMenuPageUi(
-                            activity, params, itemGroup.second, isImageTab, maxCount)));
-        }
-        TabularContextMenuViewPager pager =
-                (TabularContextMenuViewPager) view.findViewById(R.id.custom_pager);
-        pager.setAdapter(new TabularContextMenuPagerAdapter(viewGroups));
-
-        TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout);
-        if (itemGroups.size() <= 1) {
-            tabLayout.setVisibility(View.GONE);
-        }
-        tabLayout.setupWithViewPager((ViewPager) view.findViewById(R.id.custom_pager));
-
-        return view;
-    }
-
-    /**
      * When an thumbnail is retrieved for the header of an image, this will set the header to
      * that particular bitmap.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index 9fac8503..740ebb1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -1123,9 +1123,9 @@
 
             @Override
             protected void onPostExecute(Intent intent) {
-                if (intent == null
-                        || !ExternalNavigationDelegateImpl.resolveIntent(intent, true)
-                        || !DownloadUtils.fireOpenIntentForDownload(context, intent)) {
+                if (intent == null || !ExternalNavigationDelegateImpl.resolveIntent(intent, true)
+                        || !DownloadUtils.fireOpenIntentForDownload(context, intent)
+                        || !hasDownloadManagerService()) {
                     openDownloadsPage(context);
                 } else {
                     DownloadManagerService service =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java
index 93f08a5..67fadc1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java
@@ -27,7 +27,7 @@
         super(context, attrs);
         setLayoutResource(R.layout.button_preference_layout);
         setWidgetLayoutResource(R.layout.button_preference_button);
-        setSelectable(false);
+        setSelectable(true);
     }
 
     @Override
@@ -43,5 +43,14 @@
                 }
             }
         });
+
+        View viewFrame = view.findViewById(android.R.id.widget_frame);
+        viewFrame.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // This is intentionally left blank to prevent triggering an event after tapping
+                // any part of the view that is not the button.
+            }
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
index 0441146..241589f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
@@ -119,7 +119,7 @@
         }
 
         @Override
-        public void determinedVisibility(int pid) {
+        public void onDeterminedVisibility(int pid) {
             synchronized (mVisibilityCallsMap) {
                 mVisibilityCallsMap.put(pid, mVisibilityCallsMap.get(pid) + "DETERMINED;");
             }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 324d7fd..476fc94 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -41,6 +41,7 @@
 import android.view.ViewGroup;
 import android.widget.EditText;
 import android.widget.ImageButton;
+import android.widget.TextView;
 
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
@@ -138,6 +139,20 @@
             + "        }"
             + "   </script>"
             + "</body></html>";
+    private static final String ONLOAD_TITLE_CHANGE = "<!DOCTYPE html><html><body>"
+            + "    <script>"
+            + "        window.onload = function () {"
+            + "            document.title = \"nytimes.com\";"
+            + "        }"
+            + "   </script>"
+            + "</body></html>";
+    private static final String DELAYED_TITLE_CHANGE = "<!DOCTYPE html><html><body>"
+            + "    <script>"
+            + "        window.onload = function () {"
+            + "           setTimeout(function (){ document.title = \"nytimes.com\"}, 200);"
+            + "        }"
+            + "   </script>"
+            + "</body></html>";
 
     private static int sIdToIncrement = 1;
 
@@ -1058,6 +1073,84 @@
     }
 
     /**
+     * Tests that TITLE_ONLY state works as expected with a title getting set onload.
+     */
+    @SmallTest
+    public void testToolbarTitleOnlyStateWithProperTitle() throws InterruptedException {
+        final String url = mWebServer.setResponse("/test.html", ONLOAD_TITLE_CHANGE, null);
+        hideDomainAndEnsureTitleIsSet(
+                url, CustomTabsConnection.SpeculationParams.NO_SPECULATION, "nytimes.com");
+    }
+
+    /**
+     * Tests that TITLE_ONLY state works as expected with a title getting set during prerendering.
+
+     */
+    @SmallTest
+    public void testToolbarTitleOnlyStateWithProperTitlePrerendered() throws InterruptedException {
+        final String url = mWebServer.setResponse("/test.html", ONLOAD_TITLE_CHANGE, null);
+        hideDomainAndEnsureTitleIsSet(
+                url, CustomTabsConnection.SpeculationParams.PRERENDER, "nytimes.com");
+    }
+
+    /**
+     * Tests that TITLE_ONLY state works as expected with a title getting set delayed after load.
+
+     */
+    @SmallTest
+    public void testToolbarTitleOnlyStateWithDelayedTitle() throws InterruptedException {
+        final String url = mWebServer.setResponse("/test.html", DELAYED_TITLE_CHANGE, null);
+        hideDomainAndEnsureTitleIsSet(
+                url, CustomTabsConnection.SpeculationParams.NO_SPECULATION, "nytimes.com");
+    }
+
+    private void hideDomainAndEnsureTitleIsSet(
+            final String url, int speculation, final String expectedTitle) {
+        final CustomTabsConnection connection = warmUpAndWait();
+        Context context = getInstrumentation().getTargetContext();
+        Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, url);
+        intent.putExtra(
+                CustomTabsIntent.EXTRA_TITLE_VISIBILITY_STATE, CustomTabsIntent.SHOW_PAGE_TITLE);
+        final CustomTabsSessionToken token =
+                CustomTabsSessionToken.getSessionTokenFromIntent(intent);
+        assertTrue(connection.newSession(token));
+        connection.mClientManager.setHideDomainForSession(token, true);
+
+        if (speculation != CustomTabsConnection.SpeculationParams.NO_SPECULATION) {
+            connection.setSpeculationModeForSession(token, speculation);
+            assertTrue(connection.mayLaunchUrl(token, Uri.parse(url), null, null));
+            try {
+                ensureCompletedSpeculationForUrl(connection, url, speculation);
+            } catch (Exception e1) {
+                fail();
+            }
+        }
+
+        try {
+            startCustomTabActivityWithIntent(intent);
+        } catch (InterruptedException e) {
+            fail();
+        }
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                final Tab currentTab = getActivity().getActivityTab();
+                return url.equals(currentTab.getUrl());
+            }
+        });
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                CustomTabToolbar toolbar =
+                        (CustomTabToolbar) getActivity().findViewById(R.id.toolbar);
+                TextView titleBar = (TextView) toolbar.findViewById(R.id.title_bar);
+                return titleBar != null && titleBar.isShown()
+                        && (titleBar.getText()).toString().equals(expectedTitle);
+            }
+        });
+    }
+
+    /**
      * Tests that basic postMessage functionality works through sending a single postMessage
      * request.
      */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java
new file mode 100644
index 0000000..304169a
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.vr_shell;
+
+import android.content.Context;
+
+import com.google.vr.testframework.controller.ControllerTestApi;
+
+/**
+ * Wrapper for the ControllerTestApi class to handle more complex actions such
+ * as clicking and dragging.
+ *
+ * Requires that VrCore's settings file is modified to use the test API:
+ *   - UseAutomatedController: true
+ *   - PairedControllerDriver: "DRIVER_AUTOMATED"
+ *   - PairedControllerAddress: "FOO"
+ */
+public class EmulatedVrController {
+    private final ControllerTestApi mApi;
+
+    public EmulatedVrController(Context context) {
+        mApi = new ControllerTestApi(context);
+    }
+
+    public ControllerTestApi getApi() {
+        return mApi;
+    }
+
+    /**
+     * Presses and quickly releases the Daydream controller's touchpad button.
+     * Or, if the button is already pressed, releases and quickly presses again.
+     */
+    public void pressReleaseTouchpadButton() {
+        mApi.buttonEvent.sendClickButtonEvent();
+    }
+
+    // TODO(bsheedy): Add support for more complex actions, e.g. click/drag/release
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTest.java
index 7452083b..db02139 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTest.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
 import org.chromium.chrome.test.util.RenderUtils.ViewRenderer;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.browser.test.util.Criteria;
@@ -34,10 +33,12 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
- * Instrumentation tests for VR Shell (Chrome VR)
+ * End-to-end tests for VR browsing, aka "VR Shell". This may require
+ * interacting with WebVR in addition to the VR browser, so inherit from
+ * VrTestBase for the WebVR test framework.
  */
 @CommandLineFlags.Add("enable-features=VrShell")
-public class VrShellTest extends ChromeTabbedActivityTestBase {
+public class VrShellTest extends VrTestBase {
     private static final String GOLDEN_DIR =
             "chrome/test/data/android/render_tests";
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrTestBase.java
new file mode 100644
index 0000000..d0bc080
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrTestBase.java
@@ -0,0 +1,212 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.vr_shell;
+
+import static org.chromium.chrome.browser.vr_shell.VrUtils.POLL_CHECK_INTERVAL_LONG_MS;
+import static org.chromium.chrome.browser.vr_shell.VrUtils.POLL_CHECK_INTERVAL_SHORT_MS;
+import static org.chromium.chrome.browser.vr_shell.VrUtils.POLL_TIMEOUT_LONG_MS;
+import static org.chromium.chrome.browser.vr_shell.VrUtils.POLL_TIMEOUT_SHORT_MS;
+
+import org.chromium.base.Log;
+import org.chromium.base.test.util.UrlUtils;
+import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
+import org.chromium.content.browser.test.util.ClickUtils;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.JavaScriptUtils;
+import org.chromium.content_public.browser.WebContents;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This is a workaround for testing aspects of WebVR that aren't testable with
+ * WebVR's mocked layout tests, such as E2E tests.
+ *
+ * The general test flow is:
+ * - Load the HTML file containing the test, which:
+ *   - Loads the WebVR boilerplate code and some test functions
+ *   - Sets up common elements like the canvas and synchronization variable
+ *   - Sets up any steps that need to be triggered by the Java code
+ * - Check if any VRDisplay objects were found and fail the test if it doesn't
+ *       match what we expect for that test
+ * - Repeat:
+ *   - Run any necessary Java-side code, e.g. trigger a user action
+ *   - Trigger the next JavaScript test step and wait for it to finish
+ *
+ * The JavaScript code will automatically process test results once all
+ * testharness.js tests are done, just like in layout tests. Once the results
+ * are processed, the JavaScript code will automatically signal the Java code,
+ * which can then grab the results and pass/fail the instrumentation test.
+ */
+public class VrTestBase extends ChromeTabbedActivityTestBase {
+    private static final String TAG = "VrTestBase";
+    protected static final String TEST_DIR = "chrome/test/data/android/webvr_instrumentation";
+    protected static final int PAGE_LOAD_TIMEOUT_S = 10;
+
+    protected WebContents mWebContents;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mWebContents = getActivity().getActivityTab().getWebContents();
+    }
+
+    @Override
+    public void startMainActivity() throws InterruptedException {
+        startMainActivityOnBlankPage();
+    }
+
+    /**
+     * Gets the file:// URL to the test file
+     * @param testName The name of the test whose file will be retrieved
+     * @return The file:// URL to the specified test file
+     */
+    protected String getHtmlTestFile(String testName) {
+        return "file://" + UrlUtils.getIsolatedTestFilePath(TEST_DIR) + "/html/" + testName
+                + ".html";
+    }
+
+    /**
+     * Blocks until the promise returned by nagivator.getVRDisplays() resolves,
+     * then checks whether a VRDisplay was actually found.
+     * @param webContents The WebContents to run the JavaScript through
+     * @return Whether a VRDisplay was found
+     */
+    protected boolean vrDisplayFound(WebContents webContents) {
+        pollJavaScriptBoolean("vrDisplayPromiseDone", POLL_TIMEOUT_SHORT_MS, webContents);
+        return !runJavaScriptOrFail("vrDisplay", POLL_TIMEOUT_SHORT_MS, webContents).equals("null");
+    }
+
+    /**
+     * Use to tap in the middle of the screen, triggering the canvas' onclick
+     * to fulfil WebVR's gesture requirement for presenting.
+     */
+    protected void enterVrTap() {
+        ClickUtils.mouseSingleClickView(
+                getInstrumentation(), getActivity().getWindow().getDecorView().getRootView());
+    }
+
+    /**
+     * Taps in the middle of the screen then waits for the JavaScript step to finish.
+     * @param webContents The WebContents for the tab the JavaScript step is in
+     */
+    protected void enterVrTapAndWait(WebContents webContents) {
+        enterVrTap();
+        waitOnJavaScriptStep(webContents);
+    }
+
+    /**
+     * Use to simulate a Daydream View NFC scan without blocking afterwards
+     */
+    protected void simNfcScan() {
+        VrUtils.simNfc(getActivity());
+    }
+
+    /**
+     * Simulate an NFC scan and wait for the JavaScript code in the given
+     * WebContents to signal that it is done with the step.
+     * @param webContents The WebContents for the JavaScript that will be polled
+     */
+    protected void simNfcScanAndWait(WebContents webContents) {
+        simNfcScan();
+        waitOnJavaScriptStep(webContents);
+    }
+
+    /**
+     * Helper function to run the given JavaScript, return the return value,
+     * and fail if a timeout/interrupt occurs so we don't have to catch or
+     * declare exceptions all the time.
+     * @param js The JavaScript to run
+     * @param timeout The timeout in milliseconds before a failure
+     * @param webContents The WebContents object to run the JavaScript in
+     * @return The return value of the JavaScript
+     */
+    protected String runJavaScriptOrFail(String js, int timeout, WebContents webContents) {
+        try {
+            return JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                    webContents, js, timeout, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException | TimeoutException e) {
+            fail("Fatal interruption or timeout running JavaScript: " + js);
+        }
+        return "Not reached";
+    }
+
+    /**
+     * Ends the test harness test and checks whether there it passed
+     * @param webContents The WebContents for the tab to check results in
+     * @return "Passed" if test passed, String with failure reason otherwise
+     */
+    protected String checkResults(WebContents webContents) {
+        if (runJavaScriptOrFail("testPassed", POLL_TIMEOUT_SHORT_MS, webContents).equals("true")) {
+            return "Passed";
+        }
+        return runJavaScriptOrFail("resultString", POLL_TIMEOUT_SHORT_MS, webContents);
+    }
+
+    /**
+     * Helper function to end the test harness test and assert that it passed,
+     * setting the failure reason as the description if it didn't.
+     * @param webContents The WebContents for the tab to check test results in
+     */
+    protected void endTest(WebContents webContents) {
+        assertEquals("Passed", checkResults(webContents));
+    }
+
+    /**
+     * Polls the provided JavaScript boolean until the timeout is reached or
+     * the boolean is true.
+     * @param boolName The name of the JavaScript boolean or expression to poll
+     * @param timeoutMs The polling timeout in milliseconds
+     * @param webContents The WebContents to run the JavaScript through
+     * @return True if the boolean evaluated to true, false if timed out
+     */
+    protected boolean pollJavaScriptBoolean(
+            final String boolName, int timeoutMs, final WebContents webContents) {
+        try {
+            CriteriaHelper.pollInstrumentationThread(Criteria.equals(true, new Callable<Boolean>() {
+                @Override
+                public Boolean call() {
+                    String result = "false";
+                    try {
+                        result = JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents,
+                                boolName, POLL_CHECK_INTERVAL_SHORT_MS, TimeUnit.MILLISECONDS);
+                    } catch (InterruptedException | TimeoutException e) {
+                        // Expected to happen regularly, do nothing
+                    }
+                    return Boolean.parseBoolean(result);
+                }
+            }), timeoutMs, POLL_CHECK_INTERVAL_LONG_MS);
+        } catch (AssertionError e) {
+            Log.d(TAG, "pollJavaScriptBoolean() timed out");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Waits for a JavaScript step to finish, asserting that the step finished
+     * instead of timing out.
+     * @param webContents The WebContents for the tab the JavaScript step is in
+     */
+    protected void waitOnJavaScriptStep(WebContents webContents) {
+        assertTrue("Polling JavaScript boolean javascriptDone succeeded",
+                pollJavaScriptBoolean("javascriptDone", POLL_TIMEOUT_LONG_MS, webContents));
+        // Reset the synchronization boolean
+        runJavaScriptOrFail("javascriptDone = false", POLL_TIMEOUT_SHORT_MS, webContents);
+    }
+
+    /**
+     * Executes a JavaScript step function using the given WebContents.
+     * @param stepFunction The JavaScript step function to call
+     * @param webContents The WebContents for the tab the JavaScript is in
+     */
+    protected void executeStepAndWait(String stepFunction, WebContents webContents) {
+        // Run the step and block
+        JavaScriptUtils.executeJavaScript(webContents, stepFunction);
+        waitOnJavaScriptStep(webContents);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java
index 7ef17e1..248d64f1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java
@@ -4,9 +4,6 @@
 
 package org.chromium.chrome.browser.vr_shell;
 
-import static org.chromium.chrome.browser.vr_shell.VrUtils.POLL_CHECK_INTERVAL_LONG_MS;
-import static org.chromium.chrome.browser.vr_shell.VrUtils.POLL_CHECK_INTERVAL_SHORT_MS;
-import static org.chromium.chrome.browser.vr_shell.VrUtils.POLL_TIMEOUT_LONG_MS;
 import static org.chromium.chrome.browser.vr_shell.VrUtils.POLL_TIMEOUT_SHORT_MS;
 import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VIEWER_DAYDREAM;
 import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_WEBVR_SUPPORTED;
@@ -17,213 +14,22 @@
 import android.support.test.filters.SmallTest;
 import android.widget.TextView;
 
-import org.chromium.base.Log;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Restriction;
-import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
-import org.chromium.content.browser.test.util.ClickUtils;
-import org.chromium.content.browser.test.util.Criteria;
-import org.chromium.content.browser.test.util.CriteriaHelper;
-import org.chromium.content.browser.test.util.JavaScriptUtils;
-import org.chromium.content_public.browser.WebContents;
 
-import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
 /**
- * This is a workaround for testing aspects of WebVR that aren't testable with
- * WebVR's mocked layout tests, such as E2E tests.
- *
- * The general test flow is:
- * - Load the HTML file containing the test, which:
- *   - Loads the WebVR boilerplate code and some test functions
- *   - Sets up common elements like the canvas and synchronization variable
- *   - Sets up any steps that need to be triggered by the Java code
- * - Check if any VRDisplay objects were found and fail the test if it doesn't
- *       match what we expect for that test
- * - Repeat:
- *   - Run any necessary Java-side code, e.g. trigger a user action
- *   - Trigger the next JavaScript test step and wait for it to finish
- *
- * The JavaScript code will automatically process test results once all
- * testharness.js tests are done, just like in layout tests. Once the results
- * are processed, the JavaScript code will automatically signal the Java code,
- * which can then grab the results and pass/fail the instrumentation test.
+ * End-to-end tests for WebVR using the WebVR test framework from
+ * VrTestBase.
  */
 @CommandLineFlags.Add("enable-webvr")
 @Restriction(RESTRICTION_TYPE_WEBVR_SUPPORTED)
-public class WebVrTest extends ChromeTabbedActivityTestBase {
+public class WebVrTest extends VrTestBase {
     private static final String TAG = "WebVrTest";
-    private static final String TEST_DIR = "chrome/test/data/android/webvr_instrumentation";
-    private static final int PAGE_LOAD_TIMEOUT_S = 10;
-
-    private WebContents mWebContents;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mWebContents = getActivity().getActivityTab().getWebContents();
-    }
-
-    @Override
-    public void startMainActivity() throws InterruptedException {
-        startMainActivityOnBlankPage();
-    }
-
-    /**
-     * Gets the file:// URL to the test file
-     * @param testName The name of the test whose file will be retrieved
-     * @return The file:// URL to the specified test file
-     */
-    private String getHtmlTestFile(String testName) {
-        return "file://" + UrlUtils.getIsolatedTestFilePath(TEST_DIR) + "/html/" + testName
-                + ".html";
-    }
-
-    /**
-     * Blocks until the promise returned by nagivator.getVRDisplays() resolves,
-     * then checks whether a VRDisplay was actually found.
-     * @param webContents The WebContents to run the JavaScript through
-     * @return Whether a VRDisplay was found
-     */
-    private boolean vrDisplayFound(WebContents webContents) {
-        pollJavaScriptBoolean("vrDisplayPromiseDone", POLL_TIMEOUT_SHORT_MS, webContents);
-        return !runJavaScriptOrFail("vrDisplay", POLL_TIMEOUT_SHORT_MS, webContents).equals("null");
-    }
-
-    /**
-     * Use to tap in the middle of the screen, triggering the canvas' onclick
-     * to fulfil WebVR's gesture requirement for presenting.
-     */
-    private void enterVrTap() {
-        ClickUtils.mouseSingleClickView(
-                getInstrumentation(), getActivity().getWindow().getDecorView().getRootView());
-    }
-
-    /**
-     * Taps in the middle of the screen then waits for the JavaScript step to finish.
-     * @param webContents The WebContents for the tab the JavaScript step is in
-     */
-    private void enterVrTapAndWait(WebContents webContents) {
-        enterVrTap();
-        waitOnJavaScriptStep(webContents);
-    }
-
-    /**
-     * Use to simulate a Daydream View NFC scan without blocking afterwards
-     */
-    private void simNfcScan() {
-        VrUtils.simNfc(getActivity());
-    }
-
-    /**
-     * Simulate an NFC scan and wait for the JavaScript code in the given
-     * WebContents to signal that it is done with the step.
-     * @param webContents The WebContents for the JavaScript that will be polled
-     */
-    private void simNfcScanAndWait(WebContents webContents) {
-        simNfcScan();
-        waitOnJavaScriptStep(webContents);
-    }
-
-    /**
-     * Helper function to run the given JavaScript, return the return value,
-     * and fail if a timeout/interrupt occurs so we don't have to catch or
-     * declare exceptions all the time.
-     * @param js The JavaScript to run
-     * @param timeout The timeout in milliseconds before a failure
-     * @param webContents The WebContents object to run the JavaScript in
-     * @return The return value of the JavaScript
-     */
-    private String runJavaScriptOrFail(String js, int timeout, WebContents webContents) {
-        try {
-            return JavaScriptUtils.executeJavaScriptAndWaitForResult(
-                    webContents, js, timeout, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException | TimeoutException e) {
-            fail("Fatal interruption or timeout running JavaScript: " + js);
-        }
-        return "Not reached";
-    }
-
-    /**
-     * Ends the test harness test and checks whether there it passed
-     * @param webContents The WebContents for the tab to check results in
-     * @return "Passed" if test passed, String with failure reason otherwise
-     */
-    private String checkResults(WebContents webContents) {
-        if (runJavaScriptOrFail("testPassed", POLL_TIMEOUT_SHORT_MS, webContents).equals("true")) {
-            return "Passed";
-        }
-        return runJavaScriptOrFail("resultString", POLL_TIMEOUT_SHORT_MS, webContents);
-    }
-
-    /**
-     * Helper function to end the test harness test and assert that it passed,
-     * setting the failure reason as the description if it didn't.
-     * @param webContents The WebContents for the tab to check test results in
-     */
-    private void endTest(WebContents webContents) {
-        assertEquals("Passed", checkResults(webContents));
-    }
-
-    /**
-     * Polls the provided JavaScript boolean until the timeout is reached or
-     * the boolean is true.
-     * @param boolName The name of the JavaScript boolean or expression to poll
-     * @param timeoutMs The polling timeout in milliseconds
-     * @param webContents The WebContents to run the JavaScript through
-     * @return True if the boolean evaluated to true, false if timed out
-     */
-    private boolean pollJavaScriptBoolean(
-            final String boolName, int timeoutMs, final WebContents webContents) {
-        try {
-            CriteriaHelper.pollInstrumentationThread(Criteria.equals(true, new Callable<Boolean>() {
-                @Override
-                public Boolean call() {
-                    String result = "false";
-                    try {
-                        result = JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents,
-                                boolName, POLL_CHECK_INTERVAL_SHORT_MS, TimeUnit.MILLISECONDS);
-                    } catch (InterruptedException | TimeoutException e) {
-                        // Expected to happen regularly, do nothing
-                    }
-                    return Boolean.parseBoolean(result);
-                }
-            }), timeoutMs, POLL_CHECK_INTERVAL_LONG_MS);
-        } catch (AssertionError e) {
-            Log.d(TAG, "pollJavaScriptBoolean() timed out");
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Waits for a JavaScript step to finish, asserting that the step finished
-     * instead of timing out.
-     * @param webContents The WebContents for the tab the JavaScript step is in
-     */
-    private void waitOnJavaScriptStep(WebContents webContents) {
-        assertTrue("Polling JavaScript boolean javascriptDone succeeded",
-                pollJavaScriptBoolean("javascriptDone", POLL_TIMEOUT_LONG_MS, webContents));
-        // Reset the synchronization boolean
-        runJavaScriptOrFail("javascriptDone = false", POLL_TIMEOUT_SHORT_MS, webContents);
-    }
-
-    /**
-     * Executes a JavaScript step function using the given WebContents.
-     * @param stepFunction The JavaScript step function to call
-     * @param webContents The WebContents for the tab the JavaScript is in
-     */
-    private void executeStepAndWait(String stepFunction, WebContents webContents) {
-        // Run the step and block
-        JavaScriptUtils.executeJavaScript(webContents, stepFunction);
-        waitOnJavaScriptStep(webContents);
-    }
 
     /**
      * Tests that a successful requestPresent call actually enters VR
@@ -284,6 +90,26 @@
     }
 
     /**
+     * Tests that Daydream controller clicks are registered as screen taps when
+     * the viewer is a Daydream View.
+     */
+    @LargeTest
+    @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM)
+    public void testControllerClicksRegisteredAsTapsOnDaydream() throws InterruptedException {
+        EmulatedVrController controller = new EmulatedVrController(getActivity());
+        String testName = "test_screen_taps_registered";
+        loadUrl(getHtmlTestFile(testName), PAGE_LOAD_TIMEOUT_S);
+        assertTrue("VRDisplay found", vrDisplayFound(mWebContents));
+        executeStepAndWait("stepVerifyNoInitialTaps()", mWebContents);
+        // Tap and wait to enter VR
+        enterVrTapAndWait(mWebContents);
+        // Send a controller click and wait for JavaScript to receive it
+        controller.pressReleaseTouchpadButton();
+        waitOnJavaScriptStep(mWebContents);
+        endTest(mWebContents);
+    }
+
+    /**
      * Tests that screen touches are still registered when the viewer is
      * Cardboard.
      */
@@ -293,7 +119,7 @@
     */
     @DisabledTest(message = "crbug.com/713781")
     public void testScreenTapsRegisteredOnCardboard() throws InterruptedException {
-        String testName = "test_screen_taps_registered_on_cardboard";
+        String testName = "test_screen_taps_registered";
         loadUrl(getHtmlTestFile(testName), PAGE_LOAD_TIMEOUT_S);
         assertTrue("VRDisplay found", vrDisplayFound(mWebContents));
         executeStepAndWait("stepVerifyNoInitialTaps()", mWebContents);
diff --git a/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json b/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json
index a34bfb3..6b7d0f2e 100644
--- a/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json
+++ b/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json
@@ -5,7 +5,10 @@
     "set": {
       "VrSkipDon": true,
       "DaydreamSetupComplete": true,
-      "VrDeviceParams": "CgxHb29nbGUsIEluYy4SDURheWRyZWFtIFZpZXcdCfkgPSUB3oI9KhAAAFxCAABcQgAAXEIAAFxCNd9PDT06CLgexT7Zzhc_WABgAJqRYBoIARIKDQAAAAAV9P3UPBIKDQAAAAAV9P3UvA"
+      "VrDeviceParams": "CgxHb29nbGUsIEluYy4SDURheWRyZWFtIFZpZXcdCfkgPSUB3oI9KhAAAFxCAABcQgAAXEIAAFxCNd9PDT06CLgexT7Zzhc_WABgAJqRYBoIARIKDQAAAAAV9P3UPBIKDQAAAAAV9P3UvA",
+      "UseAutomatedController": true,
+      "PairedControllerDriver": "DRIVER_AUTOMATED",
+      "PairedControllerAddress": "FOO"
     }
   }
 ]
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 84b5bee..f929816 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2984,6 +2984,7 @@
       "android/tab_state.h",
       "android/tab_web_contents_delegate_android.cc",
       "android/tab_web_contents_delegate_android.h",
+      "android/thumbnail/scoped_ptr_expiring_cache.h",
       "android/thumbnail/thumbnail.cc",
       "android/thumbnail/thumbnail.h",
       "android/thumbnail/thumbnail_cache.cc",
diff --git a/chrome/browser/android/offline_pages/offline_page_model_factory.cc b/chrome/browser/android/offline_pages/offline_page_model_factory.cc
index 089b558..75f965b 100644
--- a/chrome/browser/android/offline_pages/offline_page_model_factory.cc
+++ b/chrome/browser/android/offline_pages/offline_page_model_factory.cc
@@ -9,14 +9,13 @@
 #include "base/files/file_path.h"
 #include "base/memory/singleton.h"
 #include "base/sequenced_task_runner.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/post_task.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/offline_pages/core/offline_page_metadata_store_sql.h"
 #include "components/offline_pages/core/offline_page_model_impl.h"
-#include "content/public/browser/browser_thread.h"
 
 namespace offline_pages {
 
@@ -42,8 +41,7 @@
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
   scoped_refptr<base::SequencedTaskRunner> background_task_runner =
-      content::BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(
-          content::BrowserThread::GetBlockingPool()->GetSequenceToken());
+      base::CreateSequencedTaskRunnerWithTraits(base::TaskTraits().MayBlock());
 
   base::FilePath store_path =
       profile->GetPath().Append(chrome::kOfflinePageMetadataDirname);
diff --git a/chrome/browser/android/vr_shell/BUILD.gn b/chrome/browser/android/vr_shell/BUILD.gn
index dc166f9..fc8cb2e 100644
--- a/chrome/browser/android/vr_shell/BUILD.gn
+++ b/chrome/browser/android/vr_shell/BUILD.gn
@@ -20,6 +20,8 @@
       "animation.h",
       "easing.cc",
       "easing.h",
+      "elbow_model.cc",
+      "elbow_model.h",
       "fps_meter.cc",
       "fps_meter.h",
       "gltf_asset.cc",
diff --git a/chrome/browser/android/vr_shell/elbow_model.cc b/chrome/browser/android/vr_shell/elbow_model.cc
new file mode 100644
index 0000000..f71ece0
--- /dev/null
+++ b/chrome/browser/android/vr_shell/elbow_model.cc
@@ -0,0 +1,142 @@
+// 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.
+
+// Adapted from:
+// https://github.com/googlevr/gvr-unity-sdk/blob/master/Samples/DaydreamLabsControllerPlayground/Assets/GoogleVR/Scripts/Controller/GvrArmModel.cs
+
+#include "chrome/browser/android/vr_shell/elbow_model.h"
+
+#include <cmath>
+
+#include "device/vr/vr_math.h"
+
+namespace vr_shell {
+
+namespace {
+
+constexpr vr::Quatf kNoRotation = {0.0f, 0.0f, 0.0f, 1.0f};
+constexpr gfx::Point3F kDefaultShoulderRight = {0.19f, -0.19f, 0.03f};
+constexpr float kFadeDistanceFromFace = 0.34f;
+constexpr gfx::Point3F kDefaultRelativeElbow = {0.195f, -0.5f, 0.075f};
+constexpr gfx::Point3F kDefaultRelativeWrist = {0.0f, 0.0f, -0.25f};
+constexpr gfx::Vector3dF kForward = {0.0f, 0.0f, -1.0f};
+constexpr gfx::Vector3dF kUp = {0.0f, 1.0f, 0.0f};
+constexpr gfx::Vector3dF kDefaultArmExtensionOffset = {-0.13f, 0.14f, -0.08f};
+constexpr float kMinExtensionAngle = 7.0f;
+constexpr float kMaxExtenstionAngle = 60.0f;
+constexpr float kExtensionWeight = 0.4f;
+constexpr float kDeltaAlpha = 3.0f;
+constexpr float kDefaultElbowRotationRatio = 0.4f;
+
+}  // namespace
+
+ElbowModel::ElbowModel(gvr::ControllerHandedness handedness)
+    : handedness_(handedness),
+      alpha_value_(1.0f),
+      torso_direction_{0.0f, 0.0f, 0.0f} {}
+
+ElbowModel::~ElbowModel() = default;
+
+void ElbowModel::UpdateHandedness() {
+  handed_multiplier_ = {
+      handedness_ == GVR_CONTROLLER_RIGHT_HANDED ? 1.0f : -1.0f, 1.0f, 1.0f};
+  shoulder_rotation_ = kNoRotation;
+  shoulder_position_ =
+      vr::ScalePoint(kDefaultShoulderRight, handed_multiplier_);
+}
+
+void ElbowModel::Update(const UpdateData& update) {
+  UpdateHandedness();
+  UpdateTorsoDirection(update);
+  ApplyArmModel(update);
+  UpdateTransparency(update);
+}
+
+void ElbowModel::UpdateTorsoDirection(const UpdateData& update) {
+  auto head_direction = update.head_direction;
+  head_direction.set_y(0);
+  vr::NormalizeVector(&head_direction);
+
+  // Determine the gaze direction horizontally.
+  float angular_velocity = update.gyro.Length();
+  float gaze_filter_strength =
+      vr::Clampf((angular_velocity - 0.2f) / 45.0f, 0.0f, 0.1f);
+  torso_direction_ =
+      vr::QuatSlerp(torso_direction_, head_direction, gaze_filter_strength);
+
+  // Rotate the fixed joints.
+  auto gaze_rotation = vr::GetVectorRotation(kForward, torso_direction_);
+  shoulder_rotation_ = gaze_rotation;
+  vr::Mat4f gaze_rotation_mat;
+  vr::QuatToMatrix(gaze_rotation, &gaze_rotation_mat);
+  shoulder_position_ = vr::ToPoint(vr::MatrixVectorRotate(
+      gaze_rotation_mat, vr::ToVector(shoulder_position_)));
+}
+
+void ElbowModel::ApplyArmModel(const UpdateData& update) {
+  // Controller's orientation relative to the user.
+  auto controller_orientation = update.orientation;
+  controller_orientation = vr::QuatProduct(vr::InvertQuat(shoulder_rotation_),
+                                           controller_orientation);
+
+  // Relative positions of the joints.
+  elbow_position_ = vr::ScalePoint(kDefaultRelativeElbow, handed_multiplier_);
+  wrist_position_ = vr::ScalePoint(kDefaultRelativeWrist, handed_multiplier_);
+  auto arm_extension_offset =
+      vr::ScaleVector(kDefaultArmExtensionOffset, handed_multiplier_);
+
+  // Extract just the x rotation angle.
+  vr::Mat4f controller_orientation_mat;
+  QuatToMatrix(controller_orientation, &controller_orientation_mat);
+  auto controller_forward =
+      vr::MatrixVectorRotate(controller_orientation_mat, kForward);
+  float x_angle =
+      90.0f - gfx::AngleBetweenVectorsInDegrees(controller_forward, kUp);
+
+  // Remove the z rotation from the controller
+  auto x_y_rotation = vr::GetVectorRotation(kForward, controller_forward);
+
+  // Offset the elbow by the extension.
+  float normalized_angle = (x_angle - kMinExtensionAngle) /
+                           (kMaxExtenstionAngle - kMinExtensionAngle);
+  float extension_ratio = vr::Clampf(normalized_angle, 0.0f, 1.0f);
+  elbow_position_ = elbow_position_ +
+                    gfx::ScaleVector3d(arm_extension_offset, extension_ratio);
+
+  // Calculate the lerp interpolation factor.
+  float total_angle = vr::QuatAngleDegrees(x_y_rotation, kNoRotation);
+  float lerp_suppresion = 1.0f - pow(total_angle / 180.0f, 6);
+  float lerp_value = lerp_suppresion * (kDefaultElbowRotationRatio +
+                                        (1.0f - kDefaultElbowRotationRatio) *
+                                            extension_ratio * kExtensionWeight);
+
+  // Apply the absolute rotations to the joints.
+  auto lerp_rotation = vr::QuatLerp(kNoRotation, x_y_rotation, lerp_value);
+  elbow_rotation_ = vr::QuatProduct(
+      vr::QuatProduct(shoulder_rotation_, vr::InvertQuat(lerp_rotation)),
+      controller_orientation);
+  wrist_rotation_ = vr::QuatProduct(shoulder_rotation_, controller_orientation);
+
+  // Determine the relative positions.
+  vr::Mat4f shoulder_rotation_mat;
+  QuatToMatrix(shoulder_rotation_, &shoulder_rotation_mat);
+  elbow_position_ = vr::ToPoint(vr::MatrixVectorRotate(
+      shoulder_rotation_mat, vr::ToVector(elbow_position_)));
+  vr::Mat4f elbow_rotation_mat;
+  QuatToMatrix(elbow_rotation_, &elbow_rotation_mat);
+  wrist_position_ =
+      elbow_position_ +
+      vr::MatrixVectorRotate(elbow_rotation_mat, vr::ToVector(wrist_position_));
+}
+
+void ElbowModel::UpdateTransparency(const UpdateData& update) {
+  float distance_to_face = vr::ToVector(wrist_position_).Length();
+  float alpha_change = kDeltaAlpha * update.delta_time_seconds;
+  alpha_value_ = vr::Clampf(distance_to_face < kFadeDistanceFromFace
+                                ? alpha_value_ - alpha_change
+                                : alpha_value_ + alpha_change,
+                            0.0f, 1.0f);
+}
+
+}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/elbow_model.h b/chrome/browser/android/vr_shell/elbow_model.h
new file mode 100644
index 0000000..afb990ba4
--- /dev/null
+++ b/chrome/browser/android/vr_shell/elbow_model.h
@@ -0,0 +1,57 @@
+// 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.
+
+// Adapted from:
+// https://github.com/googlevr/gvr-unity-sdk/blob/master/Samples/DaydreamLabsControllerPlayground/Assets/GoogleVR/Scripts/Controller/GvrArmModel.cs
+
+#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_ELBOW_MODEL_H_
+#define CHROME_BROWSER_ANDROID_VR_SHELL_ELBOW_MODEL_H_
+
+#include "device/vr/vr_types.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
+
+namespace vr_shell {
+
+class ElbowModel {
+ public:
+  struct UpdateData {
+    bool connected;
+    vr::Quatf orientation;
+    gfx::Vector3dF gyro;
+    gfx::Vector3dF head_direction;
+    float delta_time_seconds;
+  };
+
+  explicit ElbowModel(gvr::ControllerHandedness handedness);
+  ~ElbowModel();
+
+  const gfx::Point3F& GetControllerPosition() const { return wrist_position_; }
+  const vr::Quatf& GetControllerRotation() const { return wrist_rotation_; }
+  float GetAlphaValue() const { return alpha_value_; }
+
+  void Update(const UpdateData& update);
+
+ private:
+  void UpdateHandedness();
+  void UpdateTorsoDirection(const UpdateData& update);
+  void ApplyArmModel(const UpdateData& update);
+  void UpdateTransparency(const UpdateData& update);
+
+  gvr::ControllerHandedness handedness_;
+
+  gfx::Point3F wrist_position_;
+  vr::Quatf wrist_rotation_;
+  float alpha_value_;
+
+  gfx::Point3F elbow_position_;
+  vr::Quatf elbow_rotation_;
+  gfx::Point3F shoulder_position_;
+  vr::Quatf shoulder_rotation_;
+  gfx::Vector3dF torso_direction_;
+  gfx::Vector3dF handed_multiplier_;
+};
+
+}  // namespace vr_shell
+
+#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_ELBOW_MODEL_H_
diff --git a/chrome/browser/android/vr_shell/vr_controller.cc b/chrome/browser/android/vr_shell/vr_controller.cc
index 177b3b6..89584100 100644
--- a/chrome/browser/android/vr_shell/vr_controller.cc
+++ b/chrome/browser/android/vr_shell/vr_controller.cc
@@ -9,7 +9,9 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/time/time.h"
+#include "chrome/browser/android/vr_shell/elbow_model.h"
 #include "device/vr/vr_math.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_controller.h"
@@ -41,11 +43,18 @@
 
 constexpr int kMaxNumOfExtrapolations = 2;
 
-static constexpr gfx::Point3F kControllerPosition = {0.2f, -0.5f, -0.15f};
+// Distance from the center of the controller to start rendering the laser.
+constexpr float kLaserStartDisplacement = 0.045;
 
 void ClampTouchpadPosition(gfx::Vector2dF* position) {
-  position->set_x(std::min(std::max(0.0f, position->x()), 1.0f));
-  position->set_y(std::min(std::max(0.0f, position->y()), 1.0f));
+  position->set_x(vr::Clampf(position->x(), 0.0f, 1.0f));
+  position->set_y(vr::Clampf(position->y(), 0.0f, 1.0f));
+}
+
+float DeltaTimeSeconds(int64_t last_timestamp_nanos) {
+  return (gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos -
+          last_timestamp_nanos) /
+         kNanoSecondsPerSecond;
 }
 
 }  // namespace
@@ -53,7 +62,10 @@
 VrController::VrController(gvr_context* vr_context) {
   DVLOG(1) << __FUNCTION__ << "=" << this;
   Initialize(vr_context);
+  elbow_model_ = base::MakeUnique<ElbowModel>(handedness_);
   Reset();
+  last_timestamp_nanos_ =
+      gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos;
 }
 
 VrController::~VrController() {
@@ -114,18 +126,24 @@
 }
 
 void VrController::GetTransform(vr::Mat4f* out) const {
-  // TODO(acondor): Position and orientation needs to be obtained
-  // from an elbow model.
-  // Placing the controller in a fixed position for now.
-  vr::SetIdentityM(out);
-  // Changing rotation point.
-  vr::TranslateM(*out, gfx::Vector3dF(0, 0, 0.05), out);
-  vr::Mat4f quat_to_matrix;
-  vr::QuatToMatrix(Orientation(), &quat_to_matrix);
-  vr::MatrixMul(quat_to_matrix, *out, out);
-  gfx::Vector3dF translation(kControllerPosition.x(), kControllerPosition.y(),
-                             kControllerPosition.z() - 0.05);
-  vr::TranslateM(*out, translation, out);
+  QuatToMatrix(elbow_model_->GetControllerRotation(), out);
+  auto position = elbow_model_->GetControllerPosition();
+  vr::TranslateM(*out, vr::ToVector(position), out);
+}
+
+float VrController::GetOpacity() const {
+  return elbow_model_->GetAlphaValue();
+}
+
+gfx::Point3F VrController::GetPointerStart() const {
+  auto controller_position = elbow_model_->GetControllerPosition();
+  gfx::Vector3dF pointer_direction{0.0f, -sin(kErgoAngleOffset),
+                                   -cos(kErgoAngleOffset)};
+  vr::Mat4f rotation_mat;
+  vr::QuatToMatrix(Orientation(), &rotation_mat);
+  pointer_direction = vr::MatrixVectorRotate(rotation_mat, pointer_direction);
+  return controller_position +
+         gfx::ScaleVector3d(pointer_direction, kLaserStartDisplacement);
 }
 
 VrControllerModel::State VrController::GetModelState() const {
@@ -162,7 +180,7 @@
   return controller_state_->GetConnectionState() == gvr::kControllerConnected;
 }
 
-void VrController::UpdateState() {
+void VrController::UpdateState(const gfx::Vector3dF& head_direction) {
   const int32_t old_status = controller_state_->GetApiStatus();
   const int32_t old_connection_state = controller_state_->GetConnectionState();
   // Read current controller state.
@@ -174,6 +192,12 @@
             << gvr_controller_connection_state_to_string(
                    controller_state_->GetConnectionState());
   }
+
+  const gvr::Vec3f& gvr_gyro = controller_state_->GetGyro();
+  elbow_model_->Update({IsConnected(), Orientation(),
+                        gfx::Vector3dF(gvr_gyro.x, gvr_gyro.y, gvr_gyro.z),
+                        head_direction,
+                        DeltaTimeSeconds(last_timestamp_nanos_)});
 }
 
 void VrController::UpdateTouchInfo() {
@@ -185,10 +209,7 @@
     extrapolated_touch_++;
     touch_position_changed_ = true;
     // Fill the touch_info
-    float duration =
-        (gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos -
-         last_timestamp_nanos_) /
-        kNanoSecondsPerSecond;
+    float duration = DeltaTimeSeconds(last_timestamp_nanos_);
     touch_info_->touch_point.position.set_x(cur_touch_point_->position.x() +
                                             overall_velocity_.x() * duration);
     touch_info_->touch_point.position.set_y(cur_touch_point_->position.y() +
diff --git a/chrome/browser/android/vr_shell/vr_controller.h b/chrome/browser/android/vr_shell/vr_controller.h
index 9cc0b3d..d3afda8 100644
--- a/chrome/browser/android/vr_shell/vr_controller.h
+++ b/chrome/browser/android/vr_shell/vr_controller.h
@@ -25,6 +25,11 @@
 
 namespace vr_shell {
 
+class ElbowModel;
+
+// Angle (radians) the beam down from the controller axis, for wrist comfort.
+constexpr float kErgoAngleOffset = 0.26f;
+
 class VrController {
  public:
   // Controller API entry point.
@@ -43,7 +48,7 @@
   device::GvrGamepadData GetGamepadData();
 
   // Must be called when the GL renderer gets OnDrawFrame().
-  void UpdateState();
+  void UpdateState(const gfx::Vector3dF& head_direction);
 
   std::vector<std::unique_ptr<WebGestureEvent>> DetectGestures();
 
@@ -54,8 +59,9 @@
   float TouchPosY();
 
   vr::Quatf Orientation() const;
-
   void GetTransform(vr::Mat4f* out) const;
+  float GetOpacity() const;
+  gfx::Point3F GetPointerStart() const;
 
   VrControllerModel::State GetModelState() const;
 
@@ -170,6 +176,8 @@
   // Number of consecutively extrapolated touch points
   int extrapolated_touch_ = 0;
 
+  std::unique_ptr<ElbowModel> elbow_model_;
+
   DISALLOW_COPY_AND_ASSIGN(VrController);
 };
 
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index 27e62da0..6eaa0dd9 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -47,15 +47,8 @@
 
 static constexpr float kLaserWidth = 0.01f;
 
-// Angle (radians) the beam down from the controller axis, for wrist comfort.
-static constexpr float kErgoAngleOffset = 0.26f;
-
 static constexpr gfx::Point3F kOrigin = {0.0f, 0.0f, 0.0f};
 
-// In lieu of an elbow model, we assume a position for the user's hand.
-// TODO(mthiesse): Handedness options.
-static constexpr gfx::Point3F kHandPosition = {0.2f, -0.5f, -0.2f};
-
 // Fraction of the distance to the object the cursor is drawn at to avoid
 // rounding errors drawing the cursor behind the object.
 static constexpr float kReticleOffset = 0.99f;
@@ -514,15 +507,16 @@
       FROM_HERE, base::Bind(&VrShell::GvrDelegateReady, weak_vr_shell_));
 }
 
-void VrShellGl::UpdateController() {
-  controller_->UpdateState();
+void VrShellGl::UpdateController(const gfx::Vector3dF& head_direction) {
+  controller_->UpdateState(head_direction);
+  pointer_start_ = controller_->GetPointerStart();
 
   device::GvrGamepadData pad = controller_->GetGamepadData();
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&VrShell::UpdateGamepadData, weak_vr_shell_, pad));
 }
 
-void VrShellGl::HandleControllerInput(const gfx::Vector3dF& forward_vector) {
+void VrShellGl::HandleControllerInput(const gfx::Vector3dF& head_direction) {
   if (ShouldDrawWebVr()) {
     // Process screen touch events for Cardboard button compatibility.
     // Also send tap events for controller "touchpad click" events.
@@ -546,7 +540,7 @@
     // No controller detected, set up a gaze cursor that tracks the
     // forward direction.
     ergo_neutral_pose = {0.0f, 0.0f, -1.0f};
-    controller_quat_ = GetRotationFromZAxis(forward_vector);
+    controller_quat_ = GetRotationFromZAxis(head_direction);
   } else {
     ergo_neutral_pose = {0.0f, -sin(kErgoAngleOffset), -cos(kErgoAngleOffset)};
     controller_quat_ = controller_->Orientation();
@@ -579,7 +573,7 @@
   // simplicity.
   float distance = scene_->GetBackgroundDistance();
   target_point_ =
-      vr::GetRayPoint(kHandPosition, controller_direction, distance);
+      vr::GetRayPoint(pointer_start_, controller_direction, distance);
   gfx::Vector3dF eye_to_target = target_point_ - kOrigin;
   vr::NormalizeVector(&eye_to_target);
 
@@ -866,8 +860,9 @@
     // TODO(crbug.com/704690): Acquire controller state in a way that's timely
     // for both the gamepad API and UI input handling.
     TRACE_EVENT0("gpu", "VrShellGl::UpdateController");
-    UpdateController();
-    HandleControllerInput(vr::GetForwardVector(head_pose));
+    auto head_direction = vr::GetForwardVector(head_pose);
+    UpdateController(head_direction);
+    HandleControllerInput(head_direction);
   }
 
   DrawWorldElements(head_pose);
@@ -983,8 +978,8 @@
 
     DrawElements(render_matrix, elementsInDrawOrder);
     if (draw_cursor) {
-      DrawCursor(render_matrix);
       DrawController(render_matrix);
+      DrawCursor(render_matrix);
     }
   }
 }
@@ -1100,7 +1095,7 @@
 
   // Find the length of the beam (from hand to target).
   const float laser_length =
-      std::sqrt(kHandPosition.SquaredDistanceTo(target_point));
+      std::sqrt(pointer_start_.SquaredDistanceTo(target_point));
 
   // Build a beam, originating from the origin.
   vr::SetIdentityM(&mat);
@@ -1114,11 +1109,12 @@
   vr::QuatToMatrix(quat, &rotation_mat);
   vr::MatrixMul(rotation_mat, mat, &mat);
 
-  const gfx::Vector3dF beam_direction = target_point_ - kHandPosition;
+  const gfx::Vector3dF beam_direction = target_point_ - pointer_start_;
 
   vr::Mat4f beam_direction_mat;
   vr::QuatToMatrix(GetRotationFromZAxis(beam_direction), &beam_direction_mat);
 
+  float opacity = controller_->GetOpacity();
   // Render multiple faces to make the laser appear cylindrical.
   const int faces = 4;
   for (int i = 0; i < faces; i++) {
@@ -1132,22 +1128,23 @@
     vr::MatrixMul(beam_direction_mat, face_transform, &face_transform);
 
     // Move the beam origin to the hand.
-    vr::TranslateM(face_transform, kHandPosition - kOrigin, &face_transform);
+    vr::TranslateM(face_transform, pointer_start_ - kOrigin, &face_transform);
 
     vr::MatrixMul(render_matrix, face_transform, &transform);
-    vr_shell_renderer_->GetLaserRenderer()->Draw(transform);
+    vr_shell_renderer_->GetLaserRenderer()->Draw(opacity, transform);
   }
 }
 
 void VrShellGl::DrawController(const vr::Mat4f& view_proj_matrix) {
   if (!vr_shell_renderer_->GetControllerRenderer()->IsSetUp())
     return;
+  auto state = controller_->GetModelState();
+  auto opacity = controller_->GetOpacity();
   vr::Mat4f controller_transform;
   controller_->GetTransform(&controller_transform);
   vr::Mat4f transform;
   vr::MatrixMul(view_proj_matrix, controller_transform, &transform);
-  auto state = controller_->GetModelState();
-  vr_shell_renderer_->GetControllerRenderer()->Draw(state, transform);
+  vr_shell_renderer_->GetControllerRenderer()->Draw(state, opacity, transform);
 }
 
 bool VrShellGl::ShouldDrawWebVr() {
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.h b/chrome/browser/android/vr_shell/vr_shell_gl.h
index 8aa1406..f01c3b3b 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.h
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.h
@@ -130,8 +130,8 @@
   void DrawWebVr();
   bool WebVrPoseByteIsValid(int pose_index_byte);
 
-  void UpdateController();
-  void HandleControllerInput(const gfx::Vector3dF& forward_vector);
+  void UpdateController(const gfx::Vector3dF& head_direction);
+  void HandleControllerInput(const gfx::Vector3dF& head_direction);
   void HandleControllerAppButtonActivity(
       const gfx::Vector3dF& controller_direction);
   void SendEventsToTarget(InputTarget input_target, int pixel_x, int pixel_y);
@@ -232,6 +232,8 @@
 
   std::unique_ptr<FPSMeter> fps_meter_;
 
+  gfx::Point3F pointer_start_;
+
   base::WeakPtrFactory<VrShellGl> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(VrShellGl);
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.cc b/chrome/browser/android/vr_shell/vr_shell_renderer.cc
index 61a5f0d..b037a0b0 100644
--- a/chrome/browser/android/vr_shell/vr_shell_renderer.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_renderer.cc
@@ -208,6 +208,7 @@
           uniform lowp vec4 color;
           uniform mediump float fade_point;
           uniform mediump float fade_end;
+          uniform mediump float u_Opacity;
 
           void main() {
             mediump vec2 uv = v_TexCoordinate;
@@ -218,7 +219,8 @@
             mediump float total_fade = front_fade_factor * back_fade_factor;
             lowp vec4 texture_color = texture2D(texture_unit, uv);
             lowp vec4 final_color = color * texture_color;
-            gl_FragColor = vec4(final_color.xyz, final_color.w * total_fade);
+            gl_FragColor = vec4(final_color.xyz,
+                                final_color.w * total_fade * u_Opacity);
           }
           /* clang-format on */);
     case vr_shell::ShaderID::GRADIENT_QUAD_FRAGMENT_SHADER:
@@ -244,9 +246,11 @@
           precision mediump float;
           uniform sampler2D u_texture;
           varying vec2 v_TexCoordinate;
+          uniform mediump float u_Opacity;
 
           void main() {
-            gl_FragColor = texture2D(u_texture, v_TexCoordinate);
+            lowp vec4 texture_color = texture2D(u_texture, v_TexCoordinate);
+            gl_FragColor = vec4(texture_color.xyz, texture_color.w * u_Opacity);
           }
           /* clang-format on */);
     default:
@@ -544,6 +548,7 @@
   color_handle_ = glGetUniformLocation(program_handle_, "color");
   fade_point_handle_ = glGetUniformLocation(program_handle_, "fade_point");
   fade_end_handle_ = glGetUniformLocation(program_handle_, "fade_end");
+  opacity_handle_ = glGetUniformLocation(program_handle_, "u_Opacity");
 
   glGenTextures(1, &texture_data_handle_);
   glBindTexture(GL_TEXTURE_2D, texture_data_handle_);
@@ -557,7 +562,7 @@
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 }
 
-void LaserRenderer::Draw(const vr::Mat4f& view_proj_matrix) {
+void LaserRenderer::Draw(float opacity, const vr::Mat4f& view_proj_matrix) {
   PrepareToDraw(model_view_proj_matrix_handle_, view_proj_matrix);
 
   // Link texture data with texture unit.
@@ -569,6 +574,7 @@
               kLaserColor[3]);
   glUniform1f(fade_point_handle_, kFadePoint);
   glUniform1f(fade_end_handle_, kFadeEnd);
+  glUniform1f(opacity_handle_, opacity);
 
   glDrawArrays(GL_TRIANGLES, 0, kVerticesNumber);
 
@@ -584,6 +590,7 @@
   model_view_proj_matrix_handle_ =
       glGetUniformLocation(program_handle_, "u_ModelViewProjMatrix");
   tex_uniform_handle_ = glGetUniformLocation(program_handle_, "u_Texture");
+  opacity_handle_ = glGetUniformLocation(program_handle_, "u_Opacity");
 }
 
 ControllerRenderer::~ControllerRenderer() = default;
@@ -632,9 +639,12 @@
 }
 
 void ControllerRenderer::Draw(VrControllerModel::State state,
+                              float opacity,
                               const vr::Mat4f& view_proj_matrix) {
   glUseProgram(program_handle_);
 
+  glUniform1f(opacity_handle_, opacity);
+
   glUniformMatrix4fv(model_view_proj_matrix_handle_, 1, false,
                      MatrixToGLArray(view_proj_matrix).data());
 
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.h b/chrome/browser/android/vr_shell/vr_shell_renderer.h
index 0b1c5aa..7a046ab 100644
--- a/chrome/browser/android/vr_shell/vr_shell_renderer.h
+++ b/chrome/browser/android/vr_shell/vr_shell_renderer.h
@@ -178,7 +178,7 @@
   LaserRenderer();
   ~LaserRenderer() override;
 
-  void Draw(const vr::Mat4f& view_proj_matrix);
+  void Draw(float opacity, const vr::Mat4f& view_proj_matrix);
 
  private:
   GLuint model_view_proj_matrix_handle_;
@@ -187,6 +187,7 @@
   GLuint color_handle_;
   GLuint fade_point_handle_;
   GLuint fade_end_handle_;
+  GLuint opacity_handle_;
 
   DISALLOW_COPY_AND_ASSIGN(LaserRenderer);
 };
@@ -197,12 +198,15 @@
   ~ControllerRenderer() override;
 
   void SetUp(std::unique_ptr<VrControllerModel> model);
-  void Draw(VrControllerModel::State state, const vr::Mat4f& view_proj_matrix);
+  void Draw(VrControllerModel::State state,
+            float opacity,
+            const vr::Mat4f& view_proj_matrix);
   bool IsSetUp() const { return setup_; }
 
  private:
   GLuint model_view_proj_matrix_handle_;
   GLuint tex_uniform_handle_;
+  GLuint opacity_handle_;
   GLuint indices_buffer_ = 0;
   GLuint vertex_buffer_ = 0;
   GLint position_components_ = 0;
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index c0b4161b..1d46c37 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -16,6 +16,7 @@
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/app_controller_mac.h"
 #include "chrome/browser/apps/app_browsertest_util.h"
@@ -257,6 +258,7 @@
   base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
 
   // Lock the active profile.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   Profile* profile = [ac lastProfile];
   ProfileAttributesEntry* entry;
   ASSERT_TRUE(g_browser_process->profile_manager()->
@@ -292,6 +294,7 @@
 
   base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   Profile* profile = [ac lastProfile];
   EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath());
   EXPECT_TRUE(profile->IsGuestSession());
@@ -326,6 +329,7 @@
   // Prohibiting guest mode forces the user manager flow for About Chrome.
   local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   Profile* guest_profile = [ac lastProfile];
   EXPECT_EQ(ProfileManager::GetGuestProfilePath(), guest_profile->GetPath());
   EXPECT_TRUE(guest_profile->IsGuestSession());
@@ -538,6 +542,7 @@
       BookmarkModelFactory::GetForBrowserContext(profile1));
 
   // Create profile 2.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath path2 = profile_manager->GenerateNextProfileDirectoryPath();
   Profile* profile2 =
       Profile::CreateProfile(path2, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
diff --git a/chrome/browser/apps/app_browsertest.cc b/chrome/browser/apps/app_browsertest.cc
index 2fdf6f8..e258bdd 100644
--- a/chrome/browser/apps/app_browsertest.cc
+++ b/chrome/browser/apps/app_browsertest.cc
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/apps/app_browsertest_util.h"
@@ -601,6 +602,7 @@
 // a handler accepts "".
 IN_PROC_BROWSER_TEST_F(PlatformAppWithFileBrowserTest,
                        LaunchWithFileEmptyExtension) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath test_file;
@@ -615,6 +617,7 @@
 // a handler accepts *.
 IN_PROC_BROWSER_TEST_F(PlatformAppWithFileBrowserTest,
                        LaunchWithFileEmptyExtensionAcceptAny) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath test_file;
@@ -723,6 +726,7 @@
 // Tests that the file is created if the file does not exist and the app has the
 // fileSystem.write permission.
 IN_PROC_BROWSER_TEST_F(PlatformAppWithFileBrowserTest, LaunchNewFile) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   ASSERT_TRUE(RunPlatformAppTestWithFile(
diff --git a/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm b/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
index 33f94c5..919877c 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
 #include "chrome/browser/apps/app_shim/test/app_shim_host_manager_test_api_mac.h"
 #include "chrome/browser/browser_process.h"
@@ -65,6 +66,7 @@
       user_data_dir.Append(app_mode::kAppShimSocketSymlinkName);
 
   base::FilePath socket_path;
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   CHECK(base::ReadSymbolicLink(symlink_path, &socket_path));
   app_mode::VerifySocketPermissions(socket_path);
 
@@ -76,7 +78,10 @@
       this, io_thread_.task_runner().get());
 }
 
-TestShimClient::~TestShimClient() {}
+TestShimClient::~TestShimClient() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  io_thread_.Stop();
+}
 
 bool TestShimClient::OnMessageReceived(const IPC::Message& message) {
   return true;
@@ -276,6 +281,7 @@
   directory_in_tmp_ = test_api.directory_in_tmp();
 
   // Check that socket files have been created.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(directory_in_tmp_));
   EXPECT_TRUE(base::PathExists(symlink_path_));
 
diff --git a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
index ea990bd..238e0e1 100644
--- a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
@@ -18,6 +18,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_timeouts.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
@@ -261,6 +262,7 @@
   // (always) in tests. If it wasn't the case, the following test would fail
   // (but flakily since the creation happens on the FILE thread).
   shim_path_ = GetAppShimPath(profile(), app);
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_FALSE(base::PathExists(shim_path_));
 
   // To create a shim in a test, instead call UpdateAllShortcuts, which has been
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index bf978ee..32c2fe9 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
@@ -2558,6 +2559,7 @@
                 "web_view/download");
   ASSERT_TRUE(guest_web_contents);
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temporary_download_dir;
   ASSERT_TRUE(temporary_download_dir.CreateUniqueTempDir());
   DownloadPrefs::FromBrowserContext(guest_web_contents->GetBrowserContext())
@@ -2715,6 +2717,7 @@
   content::WebContents* web_contents = GetFirstAppWindowWebContents();
   ASSERT_TRUE(web_contents);
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temporary_download_dir;
   ASSERT_TRUE(temporary_download_dir.CreateUniqueTempDir());
   DownloadPrefs::FromBrowserContext(web_contents->GetBrowserContext())
@@ -2800,6 +2803,7 @@
   content::WebContents* web_contents = GetFirstAppWindowWebContents();
   ASSERT_TRUE(web_contents);
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temporary_download_dir;
   ASSERT_TRUE(temporary_download_dir.CreateUniqueTempDir());
   DownloadPrefs::FromBrowserContext(web_contents->GetBrowserContext())
@@ -2858,6 +2862,7 @@
   DownloadHistoryWaiter history_waiter(browser_context);
   history_waiter.WaitForHistoryLoad();
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temporary_download_dir;
   ASSERT_TRUE(temporary_download_dir.Set(
       DownloadPrefs::FromBrowserContext(browser_context)->DownloadPath()));
diff --git a/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc
index 0851507..8524ba33 100644
--- a/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/thread_test_helper.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/browsing_data/browsing_data_helper_browsertest.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -54,6 +55,7 @@
 class BrowsingDataLocalStorageHelperTest : public InProcessBrowserTest {
  protected:
   void CreateLocalStorageFilesForTest() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     // Note: This helper depends on details of how the dom_storage library
     // stores data in the host file system.
     base::FilePath storage_path = GetLocalStoragePathForTestingProfile();
@@ -128,6 +130,7 @@
   content::RunAllBlockingPoolTasksUntilIdle();
 
   // Ensure the file has been deleted.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FileEnumerator file_enumerator(
       GetLocalStoragePathForTestingProfile(),
       false,
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
index 70250bc..5700047 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 
 #include "chrome/browser/browsing_data/cache_counter.h"
@@ -77,6 +78,7 @@
   }
 
   void DownloadAnItem() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::ScopedTempDir downloads_directory;
     ASSERT_TRUE(downloads_directory.CreateUniqueTempDir());
     browser()->profile()->GetPrefs()->SetFilePath(
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index bfeee854..1d22706 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -47,6 +48,7 @@
 
   void WriteFile(const base::FilePath::StringType& filename,
                  base::StringPiece contents) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     EXPECT_EQ(base::checked_cast<int>(contents.size()),
               base::WriteFile(service_worker_dir_.GetPath().Append(filename),
                               contents.data(), contents.size()));
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 06ee059..a641111 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -364,6 +364,7 @@
     "camera_presence_notifier.h",
     "certificate_provider/certificate_info.cc",
     "certificate_provider/certificate_info.h",
+    "certificate_provider/certificate_provider.h",
     "certificate_provider/certificate_provider_service.cc",
     "certificate_provider/certificate_provider_service.h",
     "certificate_provider/certificate_provider_service_factory.cc",
@@ -811,6 +812,8 @@
     "login/saml/saml_offline_signin_limiter_factory.h",
     "login/screen_manager.cc",
     "login/screen_manager.h",
+    "login/screens/app_launch_splash_screen_view.h",
+    "login/screens/arc_kiosk_splash_screen_view.h",
     "login/screens/arc_terms_of_service_screen.cc",
     "login/screens/arc_terms_of_service_screen.h",
     "login/screens/arc_terms_of_service_screen_view.h",
@@ -877,6 +880,7 @@
     "login/screens/update_view.h",
     "login/screens/user_image_screen.cc",
     "login/screens/user_image_screen.h",
+    "login/screens/user_image_view.h",
     "login/screens/user_selection_screen.cc",
     "login/screens/user_selection_screen.h",
     "login/screens/wrong_hwid_screen.cc",
@@ -1077,6 +1081,7 @@
     "platform_keys/platform_keys_service.h",
     "platform_keys/platform_keys_service_factory.cc",
     "platform_keys/platform_keys_service_factory.h",
+    "policy/active_directory_join_delegate.h",
     "policy/active_directory_policy_manager.cc",
     "policy/active_directory_policy_manager.h",
     "policy/affiliated_cloud_policy_invalidator.cc",
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 0e9d7764..06ecc1d9 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -631,6 +632,7 @@
 
   // Adds a new user for testing to the current session.
   void AddUser(const TestAccountInfo& info, bool log_in) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     const AccountId account_id(AccountId::FromUserEmail(info.email));
     if (log_in) {
       session_manager::SessionManager::Get()->CreateSession(account_id,
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index e1769d3f..e5ffef3 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -14,6 +14,7 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/string_piece.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
@@ -624,6 +625,7 @@
 void FileManagerBrowserTestBase::OnMessage(const std::string& name,
                                            const base::DictionaryValue& value,
                                            std::string* output) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (name == "getTestName") {
     // Pass the test case name.
     *output = GetTestCaseNameParam();
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
index d5d975c..26c0c7c7 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.h"
@@ -102,6 +103,7 @@
       const char* sub_dir,
       const wallpaper::WallpaperFilesId& wallpaper_files_id,
       const std::string& id) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath wallpaper_path =
         WallpaperManager::Get()->GetCustomWallpaperPath(sub_dir,
                                                         wallpaper_files_id, id);
@@ -113,6 +115,7 @@
 
   // Logs in |account_id|.
   void LogIn(const AccountId& account_id, const std::string& user_id_hash) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     SessionManager::Get()->CreateSession(account_id, user_id_hash);
     SessionManager::Get()->SessionStarted();
     // Flush to ensure the created session and ACTIVE state reaches ash.
@@ -152,6 +155,7 @@
   // Only needs to be called (once) by tests that want to test loading of
   // default wallpapers.
   void CreateCmdlineWallpapers() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     wallpaper_dir_.reset(new base::ScopedTempDir);
     ASSERT_TRUE(wallpaper_dir_->CreateUniqueTempDir());
     wallpaper_manager_test_utils::CreateCmdlineWallpapers(
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.cc
index 83d0e09..028da45f 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.cc
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
 #include "chromeos/chromeos_switches.h"
@@ -111,6 +112,7 @@
                    int width,
                    int height,
                    SkColor color) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   std::vector<unsigned char> output;
   if (!CreateJPEGImage(width, height, color, &output))
     return false;
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.cc b/chrome/browser/component_updater/sw_reporter_installer_win.cc
index 385bf12..ea42ade 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.cc
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.cc
@@ -498,13 +498,4 @@
   registry->RegisterStringPref(prefs::kSwReporterPromptSeed, "");
 }
 
-void RegisterUserInitiatedSwReporterScan(base::Closure callback) {
-  // Fetch the latest version of the Cleanup component and run it,
-  // bypassing the usual scheduling logic. Once the scan is done, report
-  // whether the scan was successful and the names of the Unwanted Software that
-  // can be removed by the Cleanup tool.
-  // TODO(proberge): Implement me.
-  callback.Run();
-}
-
 }  // namespace component_updater
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.h b/chrome/browser/component_updater/sw_reporter_installer_win.h
index 79064eb..dc3f19c 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.h
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.h
@@ -93,10 +93,6 @@
 void RegisterProfilePrefsForSwReporter(
     user_prefs::PrefRegistrySyncable* registry);
 
-// Called by chrome://cleanup/ to manually trigger a reporter run.
-// TODO(proberge): Replace the Closure with a typed callback.
-void RegisterUserInitiatedSwReporterScan(base::Closure callback);
-
 }  // namespace component_updater
 
 #endif  // CHROME_BROWSER_COMPONENT_UPDATER_SW_REPORTER_INSTALLER_WIN_H_
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 700ebf86..1bca197 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -23,6 +23,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/test/test_timeouts.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -597,6 +598,7 @@
   const Extension* GetExtensionByPath(
       const extensions::ExtensionSet& extensions,
       const base::FilePath& path) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath extension_path = base::MakeAbsoluteFilePath(path);
     EXPECT_TRUE(!extension_path.empty());
     for (const scoped_refptr<const Extension>& extension : extensions) {
diff --git a/chrome/browser/downgrade/user_data_downgrade_browsertest.cc b/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
index a395463..dbab5a47 100644
--- a/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
+++ b/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/version.h"
 #include "base/win/registry.h"
 #include "chrome/common/chrome_constants.h"
@@ -115,6 +116,7 @@
 // Verify the user data directory has been renamed and created again after
 // downgrade.
 IN_PROC_BROWSER_TEST_F(UserDataDowngradeBrowserCopyAndCleanTest, Test) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   content::BrowserThread::GetBlockingPool()->FlushForTesting();
   EXPECT_EQ(chrome::kChromeVersion, GetLastVersion(user_data_dir_).GetString());
   ASSERT_FALSE(base::PathExists(other_file_));
@@ -122,12 +124,14 @@
 
 // Verify the user data directory will not be reset without downgrade.
 IN_PROC_BROWSER_TEST_F(UserDataDowngradeBrowserNoResetTest, Test) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_EQ(chrome::kChromeVersion, GetLastVersion(user_data_dir_).GetString());
   ASSERT_TRUE(base::PathExists(other_file_));
 }
 
 // Verify the "Last Version" file won't be created for non-msi install.
 IN_PROC_BROWSER_TEST_F(UserDataDowngradeBrowserNoMSITest, Test) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_FALSE(base::PathExists(last_version_file_path_));
   ASSERT_TRUE(base::PathExists(other_file_));
 }
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index a6dab6d9..d5168de2 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -31,6 +31,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
 #include "base/test/test_file_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
@@ -503,6 +504,7 @@
     if (!browser)
       return false;
 
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     if (!downloads_directory_.CreateUniqueTempDir())
       return false;
 
@@ -631,6 +633,7 @@
   bool CheckDownloadFullPaths(Browser* browser,
                               const base::FilePath& downloaded_file,
                               const base::FilePath& origin_file) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     bool origin_file_exists = base::PathExists(origin_file);
     EXPECT_TRUE(origin_file_exists) << origin_file.value();
     if (!origin_file_exists)
@@ -697,6 +700,7 @@
                    SizeTestType type,
                    const std::string& partial_indication,
                    const std::string& total_indication) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     EXPECT_TRUE(type == SIZE_TEST_TYPE_UNKNOWN || type == SIZE_TEST_TYPE_KNOWN);
     if (type != SIZE_TEST_TYPE_KNOWN && type != SIZE_TEST_TYPE_UNKNOWN)
       return false;
@@ -792,6 +796,7 @@
                   const int64_t file_size) {
     std::string file_contents;
 
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     bool read = base::ReadFileToString(path, &file_contents);
     EXPECT_TRUE(read) << "Failed reading file: " << path.value() << std::endl;
     if (!read)
@@ -927,6 +932,7 @@
 
       if (item->GetState() == content::DownloadItem::COMPLETE) {
         // Clean up the file, in case it ended up in the My Documents folder.
+        base::ThreadRestrictions::ScopedAllowIO allow_io;
         base::FilePath destination_folder = GetDownloadDirectory(browser());
         base::FilePath my_downloaded_file = item->GetTargetFilePath();
         EXPECT_TRUE(base::PathExists(my_downloaded_file));
@@ -1200,6 +1206,7 @@
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
   base::FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
   base::FilePath downloaded_file(DestinationFile(browser(), file));
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(content::IsFileQuarantined(downloaded_file, url, GURL()));
   CheckDownload(browser(), file, file);
 }
@@ -1281,6 +1288,7 @@
   ui_test_utils::NavigateToURL(browser(), url);
 
   // Check that we did not download the web page.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_FALSE(base::PathExists(file_path));
 
   // Check state.
@@ -1380,6 +1388,7 @@
   // Check that we did not download the file.
   base::FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
   base::FilePath file_path(DestinationFile(browser(), file));
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_FALSE(base::PathExists(file_path));
 
   // Check state.
@@ -1478,6 +1487,7 @@
   // later.
   base::FilePath origin(OriginFile(base::FilePath(FILE_PATH_LITERAL(
       "downloads/a_zip_file.zip"))));
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::PathExists(origin));
   int64_t origin_file_size = 0;
   EXPECT_TRUE(base::GetFileSize(origin, &origin_file_size));
@@ -1982,6 +1992,7 @@
   // Confirm the downloaded data exists.
   base::FilePath downloaded_file = GetDownloadDirectory(browser());
   downloaded_file = downloaded_file.Append(FILE_PATH_LITERAL("a_red_dot.png"));
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(downloaded_file));
 }
 
@@ -2204,6 +2215,7 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents);
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
   base::ScopedTempDir other_directory;
   ASSERT_TRUE(other_directory.CreateUniqueTempDir());
@@ -2240,6 +2252,7 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents);
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
   base::ScopedTempDir other_directory;
   ASSERT_TRUE(other_directory.CreateUniqueTempDir());
@@ -2931,6 +2944,7 @@
   content::DownloadManager* manager = DownloadManagerForBrowser(browser());
   base::FilePath origin_file(OriginFile(base::FilePath(FILE_PATH_LITERAL(
       "downloads/a_zip_file.zip"))));
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::PathExists(origin_file));
   std::string origin_contents;
   ASSERT_TRUE(base::ReadFileToString(origin_file, &origin_contents));
@@ -2948,6 +2962,7 @@
         (index == 0 ? std::string(".zip") :
                       base::StringPrintf(" (%d).zip", index)),
               target_path.BaseName().AsUTF8Unsafe());
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     ASSERT_TRUE(base::PathExists(target_path));
     ASSERT_TRUE(VerifyFile(target_path, origin_contents,
                            origin_contents.size()));
@@ -2987,6 +3002,7 @@
   };
 
   std::vector<DownloadItem*> download_items;
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath origin_directory =
       GetDownloadDirectory(browser()).Append(FILE_PATH_LITERAL("origin"));
   ASSERT_TRUE(base::CreateDirectory(origin_directory));
@@ -3084,23 +3100,27 @@
   base::FilePath file_path(
       GetDownloadDirectory(browser()).AppendASCII("source").AppendASCII(
           "DownloadTest_BigZip.zip"));
-  ASSERT_TRUE(CreateDirectory(file_path.DirName()));
-  base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
-  ASSERT_TRUE(file.IsValid());
   int64_t size = 1 << 25;
-  EXPECT_EQ(1, file.Write(size, "a", 1));
-  file.Close();
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(CreateDirectory(file_path.DirName()));
+    base::File file(file_path,
+                    base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+    ASSERT_TRUE(file.IsValid());
+    EXPECT_EQ(1, file.Write(size, "a", 1));
+    file.Close();
 
 #if defined(OS_POSIX)
-  // Make it readable by chronos on chromeos
-  base::SetPosixFilePermissions(file_path, 0755);
+    // Make it readable by chronos on chromeos
+    base::SetPosixFilePermissions(file_path, 0755);
 #endif
 
-  // Ensure that we have enough disk space.
-  int64_t free_space =
-      base::SysInfo::AmountOfFreeDiskSpace(GetDownloadDirectory(browser()));
-  ASSERT_LE(size, free_space) << "Not enough disk space to download. Got "
-                              << free_space;
+    // Ensure that we have enough disk space.
+    int64_t free_space =
+        base::SysInfo::AmountOfFreeDiskSpace(GetDownloadDirectory(browser()));
+    ASSERT_LE(size, free_space)
+        << "Not enough disk space to download. Got " << free_space;
+  }
   GURL file_url(net::FilePathToFileURL(file_path));
   std::unique_ptr<content::DownloadTestObserver> progress_waiter(
       CreateInProgressWaiter(browser(), 1));
@@ -3124,6 +3144,7 @@
   ASSERT_EQ(100, download_items[0]->PercentComplete());
 
   // Check that the file downloaded correctly.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::PathExists(download_items[0]->GetTargetFilePath()));
   int64_t downloaded_size = 0;
   ASSERT_TRUE(base::GetFileSize(
@@ -3534,6 +3555,7 @@
   GetDownloads(browser(), &updated_downloads);
   ASSERT_EQ(std::size_t(1), updated_downloads.size());
   ASSERT_FALSE(updated_downloads[0]->IsDangerous());
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(PathExists(updated_downloads[0]->GetTargetFilePath()));
   updated_downloads[0]->Cancel(true);
 }
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index 3c771b36..9ed8b3a 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -21,6 +21,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_file_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
@@ -439,6 +440,7 @@
                  &full_file_name);
   ASSERT_FALSE(HasFailure());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(full_file_name));
   EXPECT_FALSE(base::PathExists(dir));
   EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("a.htm"), full_file_name));
@@ -526,6 +528,7 @@
   GetCurrentTab(browser())->Close();
   EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_FALSE(base::PathExists(full_file_name));
   EXPECT_FALSE(base::PathExists(dir));
 }
@@ -543,6 +546,7 @@
                  &dir, &full_file_name);
   ASSERT_FALSE(HasFailure());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(full_file_name));
   EXPECT_FALSE(base::PathExists(dir));
   EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("a.htm"), full_file_name));
@@ -556,6 +560,7 @@
                  &full_file_name);
   ASSERT_FALSE(HasFailure());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(full_file_name));
   EXPECT_TRUE(base::PathExists(dir));
 
@@ -631,6 +636,7 @@
   ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
   persisted.WaitForPersisted();
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(full_file_name));
   EXPECT_TRUE(base::PathExists(dir));
 
@@ -659,6 +665,7 @@
   downloads[0]->Remove();
   removed.WaitForRemoved();
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(full_file_name));
   EXPECT_FALSE(base::PathExists(dir));
   EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("a.htm"), full_file_name));
@@ -676,6 +683,7 @@
       download_dir.AppendASCII(std::string("test.exe") + kAppendedExtension);
   base::FilePath dir = download_dir.AppendASCII("test.exe_files");
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_FALSE(base::PathExists(full_file_name));
   GURL url = URLRequestMockHTTPJob::GetMockUrl("save_page/c.htm");
   ui_test_utils::NavigateToURL(browser(), url);
@@ -732,6 +740,7 @@
   ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
   persisted.WaitForPersisted();
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::PathExists(full_file_name));
   int64_t actual_file_size = -1;
   EXPECT_TRUE(base::GetFileSize(full_file_name, &actual_file_size));
@@ -757,6 +766,7 @@
   base::FilePath download_dir = DownloadPrefs::FromDownloadManager(
       GetDownloadManager())->DownloadPath();
   base::FilePath filename = download_dir.AppendASCII("dataurl.txt");
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::PathExists(filename));
   std::string contents;
   EXPECT_TRUE(base::ReadFileToString(filename, &contents));
@@ -776,6 +786,7 @@
                  "dubious-subresources", 2, &dir, &full_file_name);
   ASSERT_FALSE(HasFailure());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(full_file_name));
   EXPECT_TRUE(base::PathExists(dir.AppendASCII("not-a-crx.crx.download")));
 }
@@ -810,6 +821,7 @@
                  "iframe-src-is-a-download", 3, &dir, &full_file_name);
   ASSERT_FALSE(HasFailure());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(full_file_name));
   EXPECT_TRUE(base::PathExists(dir.AppendASCII("thisdayinhistory.html")));
   EXPECT_TRUE(base::PathExists(dir.AppendASCII("no-such-file.html")));
@@ -821,6 +833,7 @@
   GURL url = NavigateToMockURL("unauthorized-access");
 
   // Create a test file (that the web page should not have access to).
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir2;
   ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
   base::FilePath file_path =
@@ -888,6 +901,7 @@
                  "frames-xsite-complete-html", 5, &dir, &full_file_name);
   ASSERT_FALSE(HasFailure());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::DirectoryExists(dir));
   base::FilePath expected_files[] = {
       full_file_name,
@@ -948,7 +962,10 @@
   ASSERT_FALSE(HasFailure());
 
   std::string mhtml;
-  ASSERT_TRUE(base::ReadFileToString(full_file_name, &mhtml));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(base::ReadFileToString(full_file_name, &mhtml));
+  }
 
   // Verify content of main frame, subframes and some savable resources.
   EXPECT_THAT(
@@ -1014,6 +1031,7 @@
   SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML,
                  "frames-xsite-complete-html", 5, &dir, &full_file_name);
   ASSERT_FALSE(HasFailure());
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::DirectoryExists(dir));
   EXPECT_TRUE(base::PathExists(full_file_name));
 }
diff --git a/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc b/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc
index df4109d..22e2284 100644
--- a/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc
+++ b/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc
@@ -16,6 +16,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/common/content_switches.h"
@@ -388,6 +389,7 @@
   receiver->Stop();
 
   delete receiver;
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   cast_environment->Shutdown();
 }
 
diff --git a/chrome/browser/extensions/api/commands/command_service_browsertest.cc b/chrome/browser/extensions/api/commands/command_service_browsertest.cc
index 636cffe..cfd932f 100644
--- a/chrome/browser/extensions/api/commands/command_service_browsertest.cc
+++ b/chrome/browser/extensions/api/commands/command_service_browsertest.cc
@@ -5,6 +5,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/api/commands/command_service.h"
@@ -45,6 +46,7 @@
 typedef ExtensionApiTest CommandServiceTest;
 
 IN_PROC_BROWSER_TEST_F(CommandServiceTest, RemoveShortcutSurvivesUpdate) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index 13f90fe..1a4cb535 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/download/download_file_icon_extractor.h"
 #include "chrome/browser/download/download_service.h"
@@ -695,6 +696,7 @@
                                    const storage::FileSystemURL& path,
                                    const char* data,
                                    int length) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     // Create a temp file.
     base::FilePath temp_file;
     if (!base::CreateTemporaryFile(&temp_file) ||
@@ -1050,9 +1052,12 @@
   base::FilePath real_path = all_downloads[0]->GetTargetFilePath();
   base::FilePath fake_path = all_downloads[1]->GetTargetFilePath();
 
-  EXPECT_EQ(0, base::WriteFile(real_path, "", 0));
-  ASSERT_TRUE(base::PathExists(real_path));
-  ASSERT_FALSE(base::PathExists(fake_path));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    EXPECT_EQ(0, base::WriteFile(real_path, "", 0));
+    ASSERT_TRUE(base::PathExists(real_path));
+    ASSERT_FALSE(base::PathExists(fake_path));
+  }
 
   for (DownloadManager::DownloadVector::iterator iter = all_downloads.begin();
        iter != all_downloads.end();
@@ -2582,6 +2587,7 @@
                           "    \"previous\": \"in_progress\","
                           "    \"current\": \"complete\"}}]",
                           result_id)));
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   std::string disk_data;
   EXPECT_TRUE(base::ReadFileToString(item->GetTargetFilePath(), &disk_data));
   EXPECT_STREQ(kPayloadData, disk_data.c_str());
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index 2d57dda..5250c1e 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/browser_action_test_util.h"
@@ -71,6 +72,7 @@
 
 std::unique_ptr<base::ScopedTempDir> CreateAndSetDownloadsDirectory(
     PrefService* pref_service) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   std::unique_ptr<base::ScopedTempDir> dir(new base::ScopedTempDir);
 
   if (!dir->CreateUniqueTempDir())
@@ -1012,6 +1014,7 @@
   // Override the default downloads directory, so that the test can cleanup
   // after itself.  This section is based on CreateAndSetDownloadsDirectory
   // method defined in a few other source files with tests.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   std::unique_ptr<base::ScopedTempDir> downloads_directory =
       CreateAndSetDownloadsDirectory(browser()->profile()->GetPrefs());
   ASSERT_TRUE(downloads_directory);
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest.cc b/chrome/browser/extensions/api/file_system/file_system_apitest.cc
index 3a3b841..19dd525 100644
--- a/chrome/browser/extensions/api/file_system/file_system_apitest.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_apitest.cc
@@ -7,6 +7,7 @@
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "base/scoped_observer.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
@@ -85,6 +86,7 @@
  protected:
   base::FilePath TempFilePath(const std::string& destination_name,
                               bool copy_gold) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     if (!temp_dir_.CreateUniqueTempDir()) {
       ADD_FAILURE() << "CreateUniqueTempDir failed";
       return base::FilePath();
@@ -104,6 +106,7 @@
   std::vector<base::FilePath> TempFilePaths(
       const std::vector<std::string>& destination_names,
       bool copy_gold) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     if (!temp_dir_.CreateUniqueTempDir()) {
       ADD_FAILURE() << "CreateUniqueTempDir failed";
       return std::vector<base::FilePath>();
@@ -126,6 +129,7 @@
   }
 
   void CheckStoredDirectoryMatches(const base::FilePath& filename) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     const Extension* extension = GetSingleLoadedExtension();
     ASSERT_TRUE(extension);
     std::string extension_id = extension->id();
@@ -154,8 +158,11 @@
 
 #if defined(OS_WIN) || defined(OS_POSIX)
 IN_PROC_BROWSER_TEST_F(FileSystemApiTest, FileSystemApiGetDisplayPathPrettify) {
-  ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(base::DIR_HOME,
-      test_root_folder_, false, false));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
+        base::DIR_HOME, test_root_folder_, false, false));
+  }
 
   base::FilePath test_file = test_root_folder_.AppendASCII("gold.txt");
   FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
@@ -168,13 +175,17 @@
 #if defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(FileSystemApiTest,
     FileSystemApiGetDisplayPathPrettifyMac) {
-  // On Mac, "test.localized" will be localized into just "test".
-  base::FilePath test_path = TempFilePath("test.localized", false);
-  ASSERT_TRUE(base::CreateDirectory(test_path));
+  base::FilePath test_file;
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    // On Mac, "test.localized" will be localized into just "test".
+    base::FilePath test_path = TempFilePath("test.localized", false);
+    ASSERT_TRUE(base::CreateDirectory(test_path));
 
-  base::FilePath test_file = test_path.AppendASCII("gold.txt");
-  base::FilePath source = test_root_folder_.AppendASCII("gold.txt");
-  EXPECT_TRUE(base::CopyFile(source, test_file));
+    test_file = test_path.AppendASCII("gold.txt");
+    base::FilePath source = test_root_folder_.AppendASCII("gold.txt");
+    EXPECT_TRUE(base::CopyFile(source, test_file));
+  }
 
   FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
       &test_file);
@@ -214,8 +225,11 @@
     FileSystemApiOpenExistingFilePreviousPathDoesNotExistTest) {
   base::FilePath test_file = TempFilePath("open_existing.txt", true);
   ASSERT_FALSE(test_file.empty());
-  ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
-      chrome::DIR_USER_DOCUMENTS, test_file.DirName(), false, false));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
+        chrome::DIR_USER_DOCUMENTS, test_file.DirName(), false, false));
+  }
   FileSystemChooseEntryFunction::
       SkipPickerAndSelectSuggestedPathForTest();
   {
@@ -235,8 +249,11 @@
                        FileSystemApiOpenExistingFileDefaultPathTest) {
   base::FilePath test_file = TempFilePath("open_existing.txt", true);
   ASSERT_FALSE(test_file.empty());
-  ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
-      chrome::DIR_USER_DOCUMENTS, test_file.DirName(), false, false));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
+        chrome::DIR_USER_DOCUMENTS, test_file.DirName(), false, false));
+  }
   FileSystemChooseEntryFunction::
       SkipPickerAndSelectSuggestedPathForTest();
   ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_existing"))
@@ -247,8 +264,11 @@
 IN_PROC_BROWSER_TEST_F(FileSystemApiTest, FileSystemApiOpenMultipleSuggested) {
   base::FilePath test_file = TempFilePath("open_existing.txt", true);
   ASSERT_FALSE(test_file.empty());
-  ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
-      chrome::DIR_USER_DOCUMENTS, test_file.DirName(), false, false));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
+        chrome::DIR_USER_DOCUMENTS, test_file.DirName(), false, false));
+  }
   FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest();
   ASSERT_TRUE(RunPlatformAppTest(
       "api_test/file_system/open_multiple_with_suggested_name"))
@@ -326,8 +346,11 @@
   base::FilePath test_file = TempFilePath("open_existing.txt", true);
   ASSERT_FALSE(test_file.empty());
   base::FilePath test_directory = test_file.DirName();
-  ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
-      kGraylistedPath, test_directory, false, false));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
+        kGraylistedPath, test_directory, false, false));
+  }
   FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
       &test_directory);
   ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_directory"))
@@ -341,8 +364,11 @@
   base::FilePath test_file = TempFilePath("open_existing.txt", true);
   ASSERT_FALSE(test_file.empty());
   base::FilePath test_directory = test_file.DirName();
-  ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
-      kGraylistedPath, test_directory, false, false));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
+        kGraylistedPath, test_directory, false, false));
+  }
   FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
       &test_directory);
   ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_directory_cancel"))
@@ -357,8 +383,11 @@
   ASSERT_FALSE(test_file.empty());
   base::FilePath test_directory = test_file.DirName();
   base::FilePath parent_directory = test_directory.DirName();
-  ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
-      kGraylistedPath, test_directory, false, false));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
+        kGraylistedPath, test_directory, false, false));
+  }
   FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
       &parent_directory);
   ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_directory_cancel"))
@@ -376,8 +405,11 @@
   ASSERT_FALSE(test_file.empty());
   base::FilePath test_directory = test_file.DirName();
   base::FilePath parent_directory = test_directory.DirName();
-  ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
-      kGraylistedPath, parent_directory, false, false));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
+        kGraylistedPath, parent_directory, false, false));
+  }
   FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
       &test_directory);
   ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_directory"))
diff --git a/chrome/browser/extensions/api/i18n/i18n_apitest.cc b/chrome/browser/extensions/api/i18n/i18n_apitest.cc
index db534d2..0a1735a 100644
--- a/chrome/browser/extensions/api/i18n/i18n_apitest.cc
+++ b/chrome/browser/extensions/api/i18n/i18n_apitest.cc
@@ -6,6 +6,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -21,6 +22,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, I18NUpdate) {
   ASSERT_TRUE(embedded_test_server()->Start());
   // Create an Extension whose messages.json file will be updated.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir extension_dir;
   ASSERT_TRUE(extension_dir.CreateUniqueTempDir());
   base::CopyFile(
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client_browsertest.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client_browsertest.cc
index dd5006a..962a0b2 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client_browsertest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/common/extensions/removable_storage_writer.mojom.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/browser_thread.h"
@@ -21,12 +22,14 @@
 class ImageWriterUtilityClientTest : public InProcessBrowserTest {
  public:
   ImageWriterUtilityClientTest() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     test_device_ = base::FilePath().AppendASCII(
         extensions::mojom::RemovableStorageWriter::kTestDevice);
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
   }
 
   void FillImageFileWithPattern(char pattern) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &image_));
 
     base::RunLoop run_loop;
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
index 2c322b5..c47f6d8 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_timeouts.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/app_browsertest_util.h"
@@ -112,6 +113,7 @@
         test_data_dir_.AppendASCII(kTestDir + extension_name);
     from_dir = from_dir.NormalizePathSeparators();
 
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::ScopedTempDir temp_dir;
     if (!temp_dir.CreateUniqueTempDir())
       return false;
@@ -172,6 +174,7 @@
   // with no default media galleries, such as CHROMEOS. This fake gallery is
   // pre-populated with a test.jpg and test.txt.
   void MakeSingleFakeGallery(MediaGalleryPrefId* pref_id) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     ASSERT_FALSE(fake_gallery_temp_dir_.IsValid());
     ASSERT_TRUE(fake_gallery_temp_dir_.CreateUniqueTempDir());
 
@@ -203,6 +206,7 @@
   }
 
   void AddFileToSingleFakeGallery(const base::FilePath& source_path) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     ASSERT_TRUE(fake_gallery_temp_dir_.IsValid());
 
     ASSERT_TRUE(base::CopyFile(
@@ -212,6 +216,7 @@
 
 #if defined(OS_WIN) || defined(OS_MACOSX)
   void PopulatePicasaTestData(const base::FilePath& picasa_app_data_root) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath picasa_database_path =
         picasa::MakePicasaDatabasePath(picasa_app_data_root);
     base::FilePath picasa_temp_dir_path =
@@ -431,6 +436,7 @@
 
 IN_PROC_BROWSER_TEST_F(MediaGalleriesPlatformAppBrowserTest,
                        MAYBE_PicasaCustomLocation) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir custom_picasa_app_data_root;
   ASSERT_TRUE(custom_picasa_app_data_root.CreateUniqueTempDir());
   ensure_media_directories_exists()->SetCustomPicasaAppDataPath(
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_watch_apitest.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_watch_apitest.cc
index 5c0a500..e8e43de0 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_watch_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_watch_apitest.cc
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -109,6 +110,7 @@
   }
 
   bool AddNewFileInTestGallery() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath gallery_file =
         test_gallery_.GetPath().Append(FILE_PATH_LITERAL("test1.txt"));
     std::string content("new content");
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc b/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc
index ebd91a7..3c28d3e 100644
--- a/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc
+++ b/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc
@@ -12,6 +12,7 @@
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_paths.h"
@@ -68,6 +69,7 @@
 ScopedTestNativeMessagingHost::ScopedTestNativeMessagingHost() {}
 
 void ScopedTestNativeMessagingHost::RegisterTestHost(bool user_level) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   ScopedTestNativeMessagingHost test_host;
 
@@ -99,6 +101,9 @@
       test_user_data_dir.AppendASCII("missing_nm_binary.exe"), user_level));
 }
 
-ScopedTestNativeMessagingHost::~ScopedTestNativeMessagingHost() {}
+ScopedTestNativeMessagingHost::~ScopedTestNativeMessagingHost() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  ignore_result(temp_dir_.Delete());
+}
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
index 3cdf16b..035b462 100644
--- a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
+++ b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
@@ -4,6 +4,7 @@
 
 #include "base/base_switches.h"
 #include "base/command_line.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/extensions/api/page_capture/page_capture_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/common/chrome_switches.h"
@@ -54,6 +55,7 @@
   content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
   // Make sure the temporary file is destroyed once the javascript side reads
   // the contents.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_FALSE(base::PathExists(delegate.temp_file_));
 }
 
@@ -73,6 +75,7 @@
   ASSERT_FALSE(delegate.temp_file_.empty());
   content::RunAllPendingInMessageLoop(content::BrowserThread::FILE);
   content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_FALSE(base::PathExists(delegate.temp_file_));
 }
 
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
index 1339ae4..9495771 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/run_loop.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -150,6 +151,7 @@
   }
 
   void InitializeDownloadSettings() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     ASSERT_TRUE(browser());
     ASSERT_TRUE(downloads_dir_.CreateUniqueTempDir());
 
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
index 7ca55aa..9f82d5df 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
@@ -406,6 +407,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, Download) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir download_directory;
   ASSERT_TRUE(download_directory.CreateUniqueTempDir());
   DownloadPrefs* download_prefs =
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc
index 1726664..4c040ef0 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc
@@ -12,6 +12,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h"
@@ -65,6 +66,7 @@
       : found_(false), path_(path) {}
 
   bool Start() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     if (base::PathExists(path_)) {
       found_ = true;
       return true;
@@ -233,6 +235,7 @@
   ASSERT_TRUE(waiter->Start()) << "ERROR watching for "
                                << full_file_name.value();
   ASSERT_TRUE(waiter->WaitForFile());
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::PathExists(full_file_name));
   EXPECT_TRUE(base::GetFileSize(full_file_name, &file_size));
   EXPECT_GT(file_size, 0);
@@ -243,6 +246,7 @@
 
 IN_PROC_BROWSER_TEST_F(WebrtcEventLogApiTest,
                        TestStartTimedWebRtcEventLogging) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(embedded_test_server()->Start());
 
   content::WebContents* left_tab =
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
index 4dd5d71..f2ee8aab 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_util.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
@@ -218,6 +219,7 @@
 // Test having the default download directory missing.
 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, MissingDownloadDir) {
   // Set a non-existent directory as the download path.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath missing_directory = temp_dir.Take();
diff --git a/chrome/browser/extensions/app_background_page_apitest.cc b/chrome/browser/extensions/app_background_page_apitest.cc
index ad16e39..b6a70ee 100644
--- a/chrome/browser/extensions/app_background_page_apitest.cc
+++ b/chrome/browser/extensions/app_background_page_apitest.cc
@@ -7,6 +7,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/background/background_contents_service.h"
@@ -54,6 +55,7 @@
 
   bool CreateApp(const std::string& app_manifest,
                  base::FilePath* app_dir) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     if (!app_dir_.CreateUniqueTempDir()) {
       LOG(ERROR) << "Unable to create a temporary directory.";
       return false;
@@ -129,6 +131,7 @@
 
  protected:
   void LaunchTestingApp() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath app_dir;
     PathService::Get(chrome::DIR_GEN_TEST_DATA, &app_dir);
     app_dir = app_dir.AppendASCII(
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index 6abc403f..a08f254 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -304,11 +304,13 @@
 
   // Load an app as a bookmark app.
   std::string error;
-  scoped_refptr<const Extension> extension(extensions::file_util::LoadExtension(
-      test_data_dir_.AppendASCII("app_process"),
-      extensions::Manifest::UNPACKED,
-      Extension::FROM_BOOKMARK,
-      &error));
+  scoped_refptr<const Extension> extension;
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    extension = extensions::file_util::LoadExtension(
+        test_data_dir_.AppendASCII("app_process"),
+        extensions::Manifest::UNPACKED, Extension::FROM_BOOKMARK, &error);
+  }
   service->OnExtensionInstalled(extension.get(),
                                 syncer::StringOrdinal::CreateInitialOrdinal(),
                                 extensions::kInstallFlagInstallImmediately);
diff --git a/chrome/browser/extensions/content_verifier_browsertest.cc b/chrome/browser/extensions/content_verifier_browsertest.cc
index f44c9d2d..63c6b04 100644
--- a/chrome/browser/extensions/content_verifier_browsertest.cc
+++ b/chrome/browser/extensions/content_verifier_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/scoped_observer.h"
 #include "base/strings/string_split.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/browsertest_util.h"
 #include "chrome/browser/extensions/chrome_content_verifier_delegate.h"
@@ -542,7 +543,10 @@
     // being what was signed by the webstore.
     base::FilePath scriptfile = extension->path().AppendASCII(script_relpath);
     std::string extra = "some_extra_function_call();";
-    ASSERT_TRUE(base::AppendToFile(scriptfile, extra.data(), extra.size()));
+    {
+      base::ThreadRestrictions::ScopedAllowIO allow_io;
+      ASSERT_TRUE(base::AppendToFile(scriptfile, extra.data(), extra.size()));
+    }
     DisableExtension(id);
     job_observer.ExpectJobResult(id, script_relfilepath,
                                  JobObserver::Result::FAILURE);
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index af7b9e43..9e32e0d 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/download/download_crx_util.h"
 #include "chrome/browser/extensions/browser_action_test_util.h"
@@ -214,6 +215,7 @@
       bool strict_manifest_checks) {
     std::unique_ptr<WebstoreInstaller::Approval> result;
 
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath ext_path = test_data_dir_.AppendASCII(manifest_dir);
     std::string error;
     std::unique_ptr<base::DictionaryValue> parsed_manifest(
@@ -338,6 +340,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, BlockedFileTypes) {
   const Extension* extension =
       InstallExtension(test_data_dir_.AppendASCII("blocked_file_types.crx"), 1);
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(extension->path().AppendASCII("test.html")));
   EXPECT_TRUE(base::PathExists(extension->path().AppendASCII("test.nexe")));
   EXPECT_FALSE(base::PathExists(extension->path().AppendASCII("test1.EXE")));
@@ -349,6 +352,7 @@
       test_data_dir_.AppendASCII("theme_with_extension.crx"), 1);
   ASSERT_TRUE(extension);
   const base::FilePath& path = extension->path();
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(
       base::PathExists(path.AppendASCII("images/theme_frame_camo.PNG")));
   EXPECT_TRUE(
@@ -599,6 +603,7 @@
       crx_path, 1, extensions::Manifest::EXTERNAL_PREF);
   base::FilePath extension_path = extension->path();
   EXPECT_TRUE(cache_dir.GetPath().IsParent(extension_path));
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(base::PathExists(extension_path));
 
   std::string extension_id = extension->id();
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 1aa8bd6..b425a443 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -18,6 +18,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/browsertest_util.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
@@ -149,6 +150,7 @@
 const Extension* ExtensionBrowserTest::GetExtensionByPath(
     const extensions::ExtensionSet& extensions,
     const base::FilePath& path) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath extension_path = base::MakeAbsoluteFilePath(path);
   EXPECT_TRUE(!extension_path.empty());
   for (const scoped_refptr<const Extension>& extension : extensions) {
@@ -252,6 +254,7 @@
       profile())->extension_service();
   ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   std::string manifest;
   if (!base::ReadFileToString(path.Append(manifest_relative_path), &manifest)) {
     return NULL;
@@ -292,6 +295,7 @@
 
 base::FilePath ExtensionBrowserTest::PackExtension(
     const base::FilePath& dir_path) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath crx_path = temp_dir_.GetPath().AppendASCII("temp.crx");
   if (!base::DeleteFile(crx_path, false)) {
     ADD_FAILURE() << "Failed to delete crx: " << crx_path.value();
@@ -320,6 +324,7 @@
     const base::FilePath& crx_path,
     const base::FilePath& pem_path,
     const base::FilePath& pem_out_path) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (!base::PathExists(dir_path)) {
     ADD_FAILURE() << "Extension dir not found: " << dir_path.value();
     return base::FilePath();
diff --git a/chrome/browser/extensions/extension_keybinding_apitest.cc b/chrome/browser/extensions/extension_keybinding_apitest.cc
index be19bc2a..b477aad 100644
--- a/chrome/browser/extensions/extension_keybinding_apitest.cc
+++ b/chrome/browser/extensions/extension_keybinding_apitest.cc
@@ -4,6 +4,7 @@
 
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/extensions/active_tab_permission_granter.h"
@@ -558,6 +559,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(CommandsApiTest, ShortcutAddedOnUpdate) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.
@@ -603,6 +605,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(CommandsApiTest, ShortcutChangedOnUpdate) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.
@@ -651,6 +654,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(CommandsApiTest, ShortcutRemovedOnUpdate) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.
@@ -697,6 +701,7 @@
 
 IN_PROC_BROWSER_TEST_F(CommandsApiTest,
                        ShortcutAddedOnUpdateAfterBeingAssignedByUser) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.
@@ -747,6 +752,7 @@
 
 IN_PROC_BROWSER_TEST_F(CommandsApiTest,
                        ShortcutChangedOnUpdateAfterBeingReassignedByUser) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.
@@ -801,6 +807,7 @@
 // Test that Media keys do not overwrite previous settings.
 IN_PROC_BROWSER_TEST_F(CommandsApiTest,
     MediaKeyShortcutChangedOnUpdateAfterBeingReassignedByUser) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.
@@ -854,6 +861,7 @@
 
 IN_PROC_BROWSER_TEST_F(CommandsApiTest,
                        ShortcutRemovedOnUpdateAfterBeingReassignedByUser) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.
diff --git a/chrome/browser/extensions/extension_resource_request_policy_apitest.cc b/chrome/browser/extensions/extension_resource_request_policy_apitest.cc
index ad316d54..9049e91 100644
--- a/chrome/browser/extensions/extension_resource_request_policy_apitest.cc
+++ b/chrome/browser/extensions/extension_resource_request_policy_apitest.cc
@@ -77,9 +77,13 @@
   // A data URL. Data URLs should always be able to load chrome-extension://
   // resources.
   std::string file_source;
-  ASSERT_TRUE(base::ReadFileToString(
-      test_data_dir_.AppendASCII("extension_resource_request_policy")
-                    .AppendASCII("index.html"), &file_source));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(base::ReadFileToString(
+        test_data_dir_.AppendASCII("extension_resource_request_policy")
+            .AppendASCII("index.html"),
+        &file_source));
+  }
   ui_test_utils::NavigateToURL(browser(),
       GURL(std::string("data:text/html;charset=utf-8,") + file_source));
   ASSERT_TRUE(content::ExecuteScriptAndExtractString(
diff --git a/chrome/browser/extensions/extension_webui_apitest.cc b/chrome/browser/extensions/extension_webui_apitest.cc
index de1a34c7..1fd6e8c 100644
--- a/chrome/browser/extensions/extension_webui_apitest.cc
+++ b/chrome/browser/extensions/extension_webui_apitest.cc
@@ -6,6 +6,7 @@
 #include "base/files/file_util.h"
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -35,18 +36,21 @@
                                    const GURL& page_url,
                                    const GURL& frame_url,
                                    bool expected_result) {
-    // Tests are located in chrome/test/data/extensions/webui/$(name).
-    base::FilePath path;
-    PathService::Get(chrome::DIR_TEST_DATA, &path);
-    path =
-        path.AppendASCII("extensions").AppendASCII("webui").AppendASCII(name);
-
-    // Read the test.
-    if (!base::PathExists(path))
-      return testing::AssertionFailure() << "Couldn't find " << path.value();
     std::string script;
-    base::ReadFileToString(path, &script);
-    script = "(function(){'use strict';" + script + "}());";
+    {
+      base::ThreadRestrictions::ScopedAllowIO allow_io;
+      // Tests are located in chrome/test/data/extensions/webui/$(name).
+      base::FilePath path;
+      PathService::Get(chrome::DIR_TEST_DATA, &path);
+      path =
+          path.AppendASCII("extensions").AppendASCII("webui").AppendASCII(name);
+
+      // Read the test.
+      if (!base::PathExists(path))
+        return testing::AssertionFailure() << "Couldn't find " << path.value();
+      base::ReadFileToString(path, &script);
+      script = "(function(){'use strict';" + script + "}());";
+    }
 
     // Run the test.
     bool actual_result = false;
diff --git a/chrome/browser/extensions/lazy_background_page_apitest.cc b/chrome/browser/extensions/lazy_background_page_apitest.cc
index 5b0696b9..ead2b67 100644
--- a/chrome/browser/extensions/lazy_background_page_apitest.cc
+++ b/chrome/browser/extensions/lazy_background_page_apitest.cc
@@ -10,6 +10,7 @@
 #include "base/path_service.h"
 #include "base/scoped_observer.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/extensions/browser_action_test_util.h"
@@ -318,6 +319,7 @@
 IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, NaClInBackgroundPage) {
   {
     base::FilePath extdir;
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     ASSERT_TRUE(PathService::Get(chrome::DIR_GEN_TEST_DATA, &extdir));
     extdir = extdir.AppendASCII("ppapi/tests/extensions/load_unload/newlib");
     LazyBackgroundObserver page_complete;
@@ -354,6 +356,7 @@
   // page, and the Lazy Background Page stays alive.
   {
     base::FilePath extdir;
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     ASSERT_TRUE(PathService::Get(chrome::DIR_GEN_TEST_DATA, &extdir));
     extdir = extdir.AppendASCII("ppapi/tests/extensions/popup/newlib");
     ResultCatcher catcher;
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index 80336cee..9d2dd5de 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/gcm/fake_gcm_profile_service.h"
@@ -283,6 +284,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
@@ -323,6 +325,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateWithoutSkipWaiting) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir scoped_temp_dir;
   ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
   base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
diff --git a/chrome/browser/extensions/startup_helper_browsertest.cc b/chrome/browser/extensions/startup_helper_browsertest.cc
index f69701b..36fcc36 100644
--- a/chrome/browser/extensions/startup_helper_browsertest.cc
+++ b/chrome/browser/extensions/startup_helper_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/extensions/startup_helper.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
@@ -49,6 +50,7 @@
 
     std::string error;
     extensions::StartupHelper helper;
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     bool result = helper.ValidateCrx(command_line, &error);
     if (i->second) {
       EXPECT_TRUE(result) << path.LossyDisplayName()
diff --git a/chrome/browser/extensions/test_extension_dir.cc b/chrome/browser/extensions/test_extension_dir.cc
index a279182..daf2c76 100644
--- a/chrome/browser/extensions/test_extension_dir.cc
+++ b/chrome/browser/extensions/test_extension_dir.cc
@@ -9,17 +9,22 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/test/values_test_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/extensions/extension_creator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
 
 TestExtensionDir::TestExtensionDir() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(dir_.CreateUniqueTempDir());
   EXPECT_TRUE(crx_dir_.CreateUniqueTempDir());
 }
 
 TestExtensionDir::~TestExtensionDir() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  ignore_result(dir_.Delete());
+  ignore_result(crx_dir_.Delete());
 }
 
 void TestExtensionDir::WriteManifest(base::StringPiece manifest) {
@@ -35,6 +40,7 @@
 
 void TestExtensionDir::WriteFile(const base::FilePath::StringType& filename,
                                  base::StringPiece contents) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_EQ(base::checked_cast<int>(contents.size()),
             base::WriteFile(dir_.GetPath().Append(filename), contents.data(),
                             contents.size()));
@@ -43,6 +49,7 @@
 // This function packs the extension into a .crx, and returns the path to that
 // .crx. Multiple calls to Pack() will produce extensions with the same ID.
 base::FilePath TestExtensionDir::Pack() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ExtensionCreator creator;
   base::FilePath crx_path =
       crx_dir_.GetPath().Append(FILE_PATH_LITERAL("ext.crx"));
@@ -67,6 +74,7 @@
 }
 
 base::FilePath TestExtensionDir::UnpackedPath() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   // We make this absolute because it's possible that dir_ contains a symlink as
   // part of it's path. When UnpackedInstaller::GetAbsolutePath() runs as part
   // of loading the extension, the extension's path is converted to an absolute
diff --git a/chrome/browser/history/redirect_browsertest.cc b/chrome/browser/history/redirect_browsertest.cc
index 781bee29..ba0e687 100644
--- a/chrome/browser/history/redirect_browsertest.cc
+++ b/chrome/browser/history/redirect_browsertest.cc
@@ -21,6 +21,7 @@
 #include "base/task/cancelable_task_tracker.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -133,6 +134,7 @@
       final_url.spec().c_str());
 
   // Write the contents to a temporary file.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   base::FilePath temp_file;
diff --git a/chrome/browser/importer/edge_importer_browsertest_win.cc b/chrome/browser/importer/edge_importer_browsertest_win.cc
index 1f7bcac..65b7d90 100644
--- a/chrome/browser/importer/edge_importer_browsertest_win.cc
+++ b/chrome/browser/importer/edge_importer_browsertest_win.cc
@@ -203,8 +203,11 @@
   data_path = data_path.AppendASCII("edge_profile");
 
   base::FilePath temp_path = temp_dir_.GetPath();
-  ASSERT_TRUE(base::CopyDirectory(data_path, temp_path, true));
-  ASSERT_TRUE(DecompressDatabase(temp_path.AppendASCII("edge_profile")));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(base::CopyDirectory(data_path, temp_path, true));
+    ASSERT_TRUE(DecompressDatabase(temp_path.AppendASCII("edge_profile")));
+  }
 
   base::string16 key_path(importer::GetEdgeSettingsKey());
   base::win::RegKey key;
@@ -243,8 +246,11 @@
   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
   data_path = data_path.AppendASCII("edge_profile");
 
-  ASSERT_TRUE(base::CopyDirectory(data_path, temp_dir_.GetPath(), true));
-  ASSERT_TRUE(importer::IsEdgeFavoritesLegacyMode());
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(base::CopyDirectory(data_path, temp_dir_.GetPath(), true));
+    ASSERT_TRUE(importer::IsEdgeFavoritesLegacyMode());
+  }
 
   // Starts to import the above settings.
   // Deletes itself.
@@ -256,10 +262,13 @@
   importer::SourceProfile source_profile;
   source_profile.importer_type = importer::TYPE_EDGE;
   base::FilePath source_path = temp_dir_.GetPath().AppendASCII("edge_profile");
-  ASSERT_NE(-1,
-            base::WriteFile(
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_NE(
+        -1, base::WriteFile(
                 source_path.AppendASCII("Favorites\\Google.url:favicon:$DATA"),
                 kDummyFaviconImageData, sizeof(kDummyFaviconImageData)));
+  }
   source_profile.source_path = source_path;
 
   host->StartImportSettings(source_profile, browser()->profile(),
diff --git a/chrome/browser/importer/ie_importer_browsertest_win.cc b/chrome/browser/importer/ie_importer_browsertest_win.cc
index e306a43..ed6974f7 100644
--- a/chrome/browser/importer/ie_importer_browsertest_win.cc
+++ b/chrome/browser/importer/ie_importer_browsertest_win.cc
@@ -27,6 +27,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/win/registry.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_propvariant.h"
@@ -435,6 +436,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(IEImporterBrowserTest, IEImporter) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   // Sets up a favorites folder.
   base::FilePath path = temp_dir_.GetPath().AppendASCII("Favorites");
   CreateDirectory(path.value().c_str(), NULL);
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 3afae54..4e730e6c 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -26,7 +26,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
@@ -1080,9 +1080,12 @@
   job_factory->SetProtocolHandler(
       url::kFileScheme,
       base::MakeUnique<net::FileProtocolHandler>(
-          content::BrowserThread::GetBlockingPool()
-              ->GetTaskRunnerWithShutdownBehavior(
-                  base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
+          base::CreateTaskRunnerWithTraits(
+              base::TaskTraits()
+                  .MayBlock()
+                  .WithPriority(base::TaskPriority::USER_VISIBLE)
+                  .WithShutdownBehavior(
+                      base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN))));
 #if !BUILDFLAG(DISABLE_FTP_SUPPORT)
   job_factory->SetProtocolHandler(
       url::kFtpScheme,
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
index f711acc05..c25223d 100644
--- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc
+++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -10,6 +10,7 @@
 #include "base/command_line.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/background/background_mode_manager.h"
 #include "chrome/browser/browser_process.h"
@@ -1163,12 +1164,16 @@
 IN_PROC_BROWSER_TEST_P(BrowserCloseManagerWithDownloadsBrowserTest,
                        TestWithDownloadsFromDifferentProfiles) {
   ProfileManager* profile_manager = g_browser_process->profile_manager();
-  base::FilePath path =
-      profile_manager->user_data_dir().AppendASCII("test_profile");
-  if (!base::PathExists(path))
-    ASSERT_TRUE(base::CreateDirectory(path));
-  Profile* other_profile =
-      Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
+  Profile* other_profile = nullptr;
+  {
+    base::FilePath path =
+        profile_manager->user_data_dir().AppendASCII("test_profile");
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    if (!base::PathExists(path))
+      ASSERT_TRUE(base::CreateDirectory(path));
+    other_profile =
+        Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
+  }
   profile_manager->RegisterTestingProfile(other_profile, true, false);
   Browser* other_profile_browser = CreateBrowser(other_profile);
 
diff --git a/chrome/browser/media_galleries/fileapi/iapps_finder_impl_win_browsertest.cc b/chrome/browser/media_galleries/fileapi/iapps_finder_impl_win_browsertest.cc
index f2ca11d1..6d04416 100644
--- a/chrome/browser/media_galleries/fileapi/iapps_finder_impl_win_browsertest.cc
+++ b/chrome/browser/media_galleries/fileapi/iapps_finder_impl_win_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_path_override.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/in_process_browser_test.h"
 
@@ -33,6 +34,7 @@
 }
 
 void TouchFile(const base::FilePath& file) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_EQ(1, base::WriteFile(file, " ", 1));
 }
 
@@ -57,6 +59,7 @@
   const base::FilePath& music_dir() { return music_dir_.GetPath(); }
 
   void WritePrefFile(const std::string& data) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath pref_dir =
         app_data_dir().AppendASCII("Apple Computer").AppendASCII("iTunes");
     ASSERT_TRUE(base::CreateDirectory(pref_dir));
@@ -66,12 +69,14 @@
   }
 
   void TouchDefault() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath default_dir = music_dir().AppendASCII("iTunes");
     ASSERT_TRUE(base::CreateDirectory(default_dir));
     TouchFile(default_dir.AppendASCII("iTunes Music Library.xml"));
   }
 
   void TestFindITunesLibrary() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     test_finder_callback_called_ = false;
     result_.clear();
     base::RunLoop loop;
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.cc b/chrome/browser/media_galleries/media_galleries_test_util.cc
index 437e897..a7da77f 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.cc
+++ b/chrome/browser/media_galleries/media_galleries_test_util.cc
@@ -13,6 +13,7 @@
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/media_galleries/fileapi/picasa_finder.h"
@@ -96,6 +97,8 @@
   iapps::SetMacPreferencesForTesting(NULL);
   picasa::SetMacPreferencesForTesting(NULL);
 #endif  // OS_MACOSX
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  ignore_result(fake_dir_.Delete());
 }
 
 void EnsureMediaDirectoriesExists::ChangeMediaPathOverrides() {
@@ -131,6 +134,7 @@
 }
 
 base::FilePath EnsureMediaDirectoriesExists::GetFakeAppDataPath() const {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   DCHECK(fake_dir_.IsValid());
   return fake_dir_.GetPath().AppendASCII("appdata");
 }
diff --git a/chrome/browser/nacl_host/test/nacl_gdb_browsertest.cc b/chrome/browser/nacl_host/test/nacl_gdb_browsertest.cc
index 199e51667..1153f7c 100644
--- a/chrome/browser/nacl_host/test/nacl_gdb_browsertest.cc
+++ b/chrome/browser/nacl_host/test/nacl_gdb_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/environment.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/ppapi/ppapi_test.h"
@@ -56,6 +57,7 @@
         return;
     }
 #endif
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     EXPECT_TRUE(base::CreateTemporaryFile(&mock_nacl_gdb_file));
     env->SetVar("MOCK_NACL_GDB", mock_nacl_gdb_file.AsUTF8Unsafe());
     RunTestViaHTTP(test_name);
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc
index ec51d3b..dfd12f39 100644
--- a/chrome/browser/net/errorpage_browsertest.cc
+++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -17,11 +17,12 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
-
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/net/net_error_diagnostics_dialog.h"
 #include "chrome/browser/net/url_request_mock_util.h"
@@ -247,11 +248,14 @@
     base::FilePath root_http;
     PathService::Get(chrome::DIR_TEST_DATA, &root_http);
     return new net::URLRequestMockHTTPJob(
-        request,
-        network_delegate,
+        request, network_delegate,
         root_http.AppendASCII("mock-link-doctor.json"),
-        BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
-            base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+        base::CreateTaskRunnerWithTraits(
+            base::TaskTraits()
+                .MayBlock()
+                .WithPriority(base::TaskPriority::BACKGROUND)
+                .WithShutdownBehavior(
+                    base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN)));
   }
 
   void WaitForRequests(int requests_to_wait_for) {
@@ -541,6 +545,7 @@
 // button to launch a network diagnostics tool.
 IN_PROC_BROWSER_TEST_F(ErrorPageTest, FileNotFound) {
   // Create an empty temp directory, to be sure there's no file in it.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   GURL non_existent_file_url =
diff --git a/chrome/browser/net/file_downloader.cc b/chrome/browser/net/file_downloader.cc
index ffbb4f9..f8f3f792 100644
--- a/chrome/browser/net/file_downloader.cc
+++ b/chrome/browser/net/file_downloader.cc
@@ -8,7 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/post_task.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
@@ -43,9 +43,12 @@
     fetcher_->Start();
   } else {
     base::PostTaskAndReplyWithResult(
-        BrowserThread::GetBlockingPool()
-            ->GetTaskRunnerWithShutdownBehavior(
-                base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
+        base::CreateTaskRunnerWithTraits(
+            base::TaskTraits()
+                .MayBlock()
+                .WithPriority(base::TaskPriority::BACKGROUND)
+                .WithShutdownBehavior(
+                    base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN))
             .get(),
         FROM_HERE, base::Bind(&base::PathExists, local_path_),
         base::Bind(&FileDownloader::OnFileExistsCheckDone,
@@ -82,9 +85,12 @@
   }
 
   base::PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool()
-          ->GetTaskRunnerWithShutdownBehavior(
-              base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
+      base::CreateTaskRunnerWithTraits(
+          base::TaskTraits()
+              .MayBlock()
+              .WithPriority(base::TaskPriority::BACKGROUND)
+              .WithShutdownBehavior(
+                  base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN))
           .get(),
       FROM_HERE, base::Bind(&base::Move, response_path, local_path_),
       base::Bind(&FileDownloader::OnFileMoveDone,
diff --git a/chrome/browser/net/file_downloader_unittest.cc b/chrome/browser/net/file_downloader_unittest.cc
index c34763a..79fa18a4 100644
--- a/chrome/browser/net/file_downloader_unittest.cc
+++ b/chrome/browser/net/file_downloader_unittest.cc
@@ -7,11 +7,9 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_utils.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_test_util.h"
@@ -68,20 +66,14 @@
         TRAFFIC_ANNOTATION_FOR_TESTS);
     EXPECT_CALL(*this, OnDownloadFinished(expected_result));
     // Wait for the FileExists check to happen if necessary.
-    if (!overwrite)
-      content::BrowserThread::GetBlockingPool()->FlushForTesting();
-    // Wait for the actual download to happen.
-    base::RunLoop().RunUntilIdle();
-    // Wait for the FileMove to happen.
-    content::BrowserThread::GetBlockingPool()->FlushForTesting();
-    base::RunLoop().RunUntilIdle();
+    content::RunAllBlockingPoolTasksUntilIdle();
   }
 
  private:
   base::ScopedTempDir dir_;
   base::FilePath path_;
 
-  base::MessageLoop message_loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   scoped_refptr<net::TestURLRequestContextGetter> request_context_;
   net::FakeURLFetcherFactory url_fetcher_factory_;
 };
diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc
index ec12eae..d337df99 100644
--- a/chrome/browser/notifications/message_center_settings_controller.cc
+++ b/chrome/browser/notifications/message_center_settings_controller.cc
@@ -11,6 +11,7 @@
 #include "base/command_line.h"
 #include "base/i18n/string_compare.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
@@ -335,6 +336,7 @@
 
 #if defined(OS_CHROMEOS)
 void MessageCenterSettingsController::CreateNotifierGroupForGuestLogin() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   // Already created.
   if (!notifier_groups_.empty())
     return;
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 8d69c71..f7fc55f 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/test/histogram_tester.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
 #include "chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h"
@@ -319,6 +320,7 @@
 IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, IgnoreDownloads) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir downloads_directory;
   ASSERT_TRUE(downloads_directory.CreateUniqueTempDir());
   browser()->profile()->GetPrefs()->SetFilePath(
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index ac6d9bf..2034ad38 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
@@ -95,6 +96,7 @@
 };
 
 GURL GetFileURL(const char* filename) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath path;
   PathService::Get(chrome::DIR_TEST_DATA, &path);
   path = path.AppendASCII("password").AppendASCII(filename);
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 2a72ae44..0885bdca 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -16,6 +16,7 @@
 #include "base/path_service.h"
 #include "base/strings/pattern.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/component_loader.h"
@@ -141,19 +142,23 @@
     // loaded before continuing.
     WebContents* guest_contents = LoadPdfGetGuestContents(url);
     ASSERT_TRUE(guest_contents);
-
-    base::FilePath test_data_dir;
-    PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
-    test_data_dir = test_data_dir.Append(FILE_PATH_LITERAL("pdf"));
-    base::FilePath test_util_path = test_data_dir.AppendASCII("test_util.js");
     std::string test_util_js;
-    ASSERT_TRUE(base::ReadFileToString(test_util_path, &test_util_js));
 
-    base::FilePath test_file_path = test_data_dir.AppendASCII(filename);
-    std::string test_js;
-    ASSERT_TRUE(base::ReadFileToString(test_file_path, &test_js));
+    {
+      base::ThreadRestrictions::ScopedAllowIO allow_io;
+      base::FilePath test_data_dir;
+      PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
+      test_data_dir = test_data_dir.Append(FILE_PATH_LITERAL("pdf"));
+      base::FilePath test_util_path = test_data_dir.AppendASCII("test_util.js");
+      ASSERT_TRUE(base::ReadFileToString(test_util_path, &test_util_js));
 
-    test_util_js.append(test_js);
+      base::FilePath test_file_path = test_data_dir.AppendASCII(filename);
+      std::string test_js;
+      ASSERT_TRUE(base::ReadFileToString(test_file_path, &test_js));
+
+      test_util_js.append(test_js);
+    }
+
     ASSERT_TRUE(content::ExecuteScript(guest_contents, test_util_js));
 
     if (!catcher.GetNextResult())
@@ -188,6 +193,7 @@
   // the test if base::Hash(filename) mod kNumberLoadTestParts == k in order
   // to shard the files evenly across values of k in [0, kNumberLoadTestParts).
   void LoadAllPdfsTest(const std::string& dir_name, int k) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath test_data_dir;
     ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
     base::FileEnumerator file_enumerator(test_data_dir.AppendASCII(dir_name),
@@ -472,12 +478,16 @@
 
 // This test ensures that PDF can be loaded from local file
 IN_PROC_BROWSER_TEST_F(PDFExtensionTest, EnsurePDFFromLocalFileLoads) {
-  base::FilePath test_data_dir;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
-  test_data_dir = test_data_dir.Append(FILE_PATH_LITERAL("pdf"));
-  base::FilePath test_data_file = test_data_dir.AppendASCII("test.pdf");
-  ASSERT_TRUE(PathExists(test_data_file));
-  GURL test_pdf_url("file://" + test_data_file.MaybeAsASCII());
+  GURL test_pdf_url;
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    base::FilePath test_data_dir;
+    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
+    test_data_dir = test_data_dir.Append(FILE_PATH_LITERAL("pdf"));
+    base::FilePath test_data_file = test_data_dir.AppendASCII("test.pdf");
+    ASSERT_TRUE(PathExists(test_data_file));
+    test_pdf_url = GURL("file://" + test_data_file.MaybeAsASCII());
+  }
   WebContents* guest_contents = LoadPdfGetGuestContents(test_pdf_url);
   ASSERT_TRUE(guest_contents);
 }
diff --git a/chrome/browser/plugins/plugin_power_saver_browsertest.cc b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
index c0b1a0c..b8ad00c 100644
--- a/chrome/browser/plugins/plugin_power_saver_browsertest.cc
+++ b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -220,6 +221,7 @@
                                 const base::Closure& done_cb,
                                 const SkBitmap& bitmap,
                                 content::ReadbackResponse response) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   DCHECK(snapshot_matches);
   ASSERT_EQ(content::READBACK_SUCCESS, response);
 
diff --git a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
index 04705a3..65247d7b 100644
--- a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
@@ -14,6 +14,7 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
@@ -282,6 +283,7 @@
   }
 
   void SetServerPolicy(const std::string& policy) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     int result = base::WriteFile(policy_file_path(), policy.data(),
                                  policy.size());
     ASSERT_EQ(base::checked_cast<int>(policy.size()), result);
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc
index 327b14b..70b55ab 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
@@ -316,6 +317,7 @@
   base::Base64UrlEncode(
       kTestExtension, base::Base64UrlEncodePolicy::INCLUDE_PADDING,
       &cache_subkey);
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath cache_path = browser()->profile()->GetPath()
       .Append(FILE_PATH_LITERAL("Policy"))
       .Append(FILE_PATH_LITERAL("Components"))
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index a6c6d0fe..134d49d0 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -34,6 +34,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_file_util.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
@@ -876,6 +877,7 @@
   EXPECT_EQ(french_title, title);
 
   // Make sure this is really French and differs from the English title.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   std::string loaded =
       ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources("en-US");
   EXPECT_EQ("en-US", loaded);
@@ -1436,6 +1438,7 @@
   // Verifies that the download directory can be forced by policy.
 
   // Set the initial download directory.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir initial_dir;
   ASSERT_TRUE(initial_dir.CreateUniqueTempDir());
   browser()->profile()->GetPrefs()->SetFilePath(
@@ -1834,6 +1837,7 @@
       URLRequestMockHTTPJob::GetMockUrl("extensions/*"));
   const GURL referrer_url(URLRequestMockHTTPJob::GetMockUrl("policy/*"));
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir download_directory;
   ASSERT_TRUE(download_directory.CreateUniqueTempDir());
   DownloadPrefs* download_prefs =
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc
index 7517b24..d7f2b93 100644
--- a/chrome/browser/policy/policy_prefs_browsertest.cc
+++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -24,6 +24,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
@@ -232,6 +233,7 @@
   typedef PolicyTestCaseMap::const_iterator iterator;
 
   PolicyTestCases() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath path = ui_test_utils::GetTestFilePath(
         base::FilePath(FILE_PATH_LITERAL("policy")),
         base::FilePath(FILE_PATH_LITERAL("policy_test_cases.json")));
diff --git a/chrome/browser/policy/test/local_policy_test_server.cc b/chrome/browser/policy/test/local_policy_test_server.cc
index 0f9a9d9a4..731588ba 100644
--- a/chrome/browser/policy/test/local_policy_test_server.cc
+++ b/chrome/browser/policy/test/local_policy_test_server.cc
@@ -17,6 +17,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
@@ -63,6 +64,7 @@
     : net::LocalTestServer(net::BaseTestServer::TYPE_HTTP,
                            net::BaseTestServer::kLocalhost,
                            base::FilePath()) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   CHECK(server_data_dir_.CreateUniqueTempDir());
   config_file_ = server_data_dir_.GetPath().Append(kPolicyFileName);
 }
@@ -78,6 +80,7 @@
                            net::BaseTestServer::kLocalhost,
                            base::FilePath()) {
   // Read configuration from a file in chrome/test/data/policy.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath source_root;
   CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &source_root));
   config_file_ = source_root
@@ -92,6 +95,7 @@
 
 bool LocalPolicyTestServer::SetSigningKeyAndSignature(
     const crypto::RSAPrivateKey* key, const std::string& signature) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   CHECK(server_data_dir_.IsValid());
 
   std::vector<uint8_t> signing_key_bits;
@@ -147,6 +151,7 @@
 bool LocalPolicyTestServer::UpdatePolicy(const std::string& type,
                                          const std::string& entity_id,
                                          const std::string& policy) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   CHECK(server_data_dir_.IsValid());
 
   std::string selector = GetSelector(type, entity_id);
@@ -160,6 +165,7 @@
 bool LocalPolicyTestServer::UpdatePolicyData(const std::string& type,
                                              const std::string& entity_id,
                                              const std::string& data) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   CHECK(server_data_dir_.IsValid());
 
   std::string selector = GetSelector(type, entity_id);
@@ -175,6 +181,7 @@
 }
 
 bool LocalPolicyTestServer::SetPythonPath() const {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (!net::LocalTestServer::SetPythonPath())
     return false;
 
@@ -222,6 +229,7 @@
 
 bool LocalPolicyTestServer::GetTestServerPath(
     base::FilePath* testserver_path) const {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath source_root;
   if (!PathService::Get(base::DIR_SOURCE_ROOT, &source_root)) {
     LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT";
@@ -238,6 +246,7 @@
 
 bool LocalPolicyTestServer::GenerateAdditionalArguments(
     base::DictionaryValue* arguments) const {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (!net::LocalTestServer::GenerateAdditionalArguments(arguments))
     return false;
 
diff --git a/chrome/browser/prefs/pref_functional_browsertest.cc b/chrome/browser/prefs/pref_functional_browsertest.cc
index 56d90df..ec142db 100644
--- a/chrome/browser/prefs/pref_functional_browsertest.cc
+++ b/chrome/browser/prefs/pref_functional_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/net/prediction_options.h"
 #include "chrome/browser/ui/browser.h"
@@ -52,6 +53,7 @@
 
 IN_PROC_BROWSER_TEST_F(PrefsFunctionalTest, TestDownloadDirPref) {
   ASSERT_TRUE(embedded_test_server()->Start());
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir new_download_dir;
   ASSERT_TRUE(new_download_dir.CreateUniqueTempDir());
 
diff --git a/chrome/browser/prefs/pref_service_browsertest.cc b/chrome/browser/prefs/pref_service_browsertest.cc
index 8f1eec42..f65bbb9 100644
--- a/chrome/browser/prefs/pref_service_browsertest.cc
+++ b/chrome/browser/prefs/pref_service_browsertest.cc
@@ -10,6 +10,7 @@
 #include "base/json/json_file_value_serializer.h"
 #include "base/path_service.h"
 #include "base/test/test_file_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
@@ -87,7 +88,11 @@
   // The window should open with the new reference profile, with window
   // placement values stored in the user data directory.
   JSONFileValueDeserializer deserializer(original_pref_file_);
-  std::unique_ptr<base::Value> root = deserializer.Deserialize(NULL, NULL);
+  std::unique_ptr<base::Value> root;
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    root = deserializer.Deserialize(NULL, NULL);
+  }
 
   ASSERT_TRUE(root.get());
   ASSERT_TRUE(root->IsType(base::Value::Type::DICTIONARY));
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 647c65e..2b22d18a 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -27,6 +27,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/test_timeouts.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
@@ -3261,10 +3262,13 @@
 // Manager API. The page should be killed.
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, AutosigninInPrerenderer) {
   // Set up a credential in the password store.
-  PasswordStoreFactory::GetInstance()->SetTestingFactory(
-      current_browser()->profile(),
-      password_manager::BuildPasswordStore<
-          content::BrowserContext, password_manager::TestPasswordStore>);
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    PasswordStoreFactory::GetInstance()->SetTestingFactory(
+        current_browser()->profile(),
+        password_manager::BuildPasswordStore<
+            content::BrowserContext, password_manager::TestPasswordStore>);
+  }
   scoped_refptr<password_manager::TestPasswordStore> password_store =
       static_cast<password_manager::TestPasswordStore*>(
           PasswordStoreFactory::GetForProfile(
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index dd3f2bf..20b97e6 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task_scheduler/task_scheduler.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "base/version.h"
 #include "build/build_config.h"
@@ -342,6 +343,7 @@
 // Test OnProfileCreate is called with is_new_profile set to true when
 // creating a new profile synchronously.
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, CreateNewProfileSynchronous) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -367,6 +369,7 @@
 // Test OnProfileCreate is called with is_new_profile set to false when
 // creating a profile synchronously with an existing prefs file.
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, CreateOldProfileSynchronous) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   CreatePrefsFileInDirectory(temp_dir.GetPath());
@@ -388,6 +391,7 @@
 // creating a new profile asynchronously.
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest,
                        DISABLED_CreateNewProfileAsynchronous) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -422,6 +426,7 @@
 // creating a profile asynchronously with an existing prefs file.
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest,
                        DISABLED_CreateOldProfileAsynchronous) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   CreatePrefsFileInDirectory(temp_dir.GetPath());
@@ -448,6 +453,7 @@
 // Flaky: http://crbug.com/393177
 // Test that a README file is created for profiles that didn't have it.
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, DISABLED_ProfileReadmeCreated) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -475,6 +481,7 @@
 
 // Test that repeated setting of exit type is handled correctly.
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, ExitType) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -566,6 +573,7 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, URLRequestContextIsolation) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -601,6 +609,7 @@
 
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest,
                        OffTheRecordURLRequestContextIsolation) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -666,6 +675,7 @@
 
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest,
                        WritesProfilesSynchronouslyOnEndSession) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -777,6 +787,7 @@
 // Verifies the cache directory supports multiple profiles when it's overriden
 // by group policy or command line switches.
 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, DiskCacheDirOverride) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   int size;
   const base::FilePath::StringPieceType profile_name =
       FILE_PATH_LITERAL("Profile 1");
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
index 45c3b9be..2a06e4d9 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
@@ -114,6 +115,7 @@
 
   // Does not work on ChromeOS.
   Profile* CreateSecondaryProfile(int profile_num) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     ProfileManager* profile_manager = g_browser_process->profile_manager();
     base::FilePath profile_path = profile_manager->user_data_dir();
     profile_path = profile_path.AppendASCII(
diff --git a/chrome/browser/resources/cleanup_tool/cleanup_browser_proxy.js b/chrome/browser/resources/cleanup_tool/cleanup_browser_proxy.js
index d62dbe2f..ef22211 100644
--- a/chrome/browser/resources/cleanup_tool/cleanup_browser_proxy.js
+++ b/chrome/browser/resources/cleanup_tool/cleanup_browser_proxy.js
@@ -17,6 +17,15 @@
  */
 var LastScanResult;
 
+/**
+ * @typedef {{
+ *   wasCancelled: boolean,
+ *   uwsRemoved: Array<string>,
+ *   requiresReboot: boolean,
+ * }}
+ */
+var CleanupResult;
+
 cr.define('cleanup', function() {
   /** @interface */
   function CleanupBrowserProxy() {}
@@ -32,6 +41,12 @@
      * @return {!Promise<LastScanResult>}
      */
     startScan: function() {},
+
+    /**
+     * Opens the prompt to run the Chrome Cleanup Tool.
+     * @return {!Promise<CleanupResult>}
+     */
+    startCleanup: function() {},
   };
 
   /**
@@ -50,6 +65,10 @@
     startScan: function() {
       return cr.sendWithPromise('startScan');
     },
+    /** @override */
+    startCleanup: function() {
+      return cr.sendWithPromise('startCleanup');
+    },
   };
 
   return {
diff --git a/chrome/browser/resources/cleanup_tool/manager.html b/chrome/browser/resources/cleanup_tool/manager.html
index a1c8c4d..769e5cb9 100644
--- a/chrome/browser/resources/cleanup_tool/manager.html
+++ b/chrome/browser/resources/cleanup_tool/manager.html
@@ -117,15 +117,19 @@
               [[detectionTimeText]]
             </div>
           </div>
-          <div id="spinner-container" hidden="[[!isRunningScanner]]">
+          <div id="spinner-container" hidden="[[!isRunning]]">
             <paper-spinner active></paper-spinner>
           </div>
           <div id="tool-action-container">
             <div class="scan-or-cleanup-action"
-                hidden="[[!shouldShowScan_(hasScanResults, isRunningScanner)]]"
+                hidden="[[!shouldShowScan_(hasScanResults, isRunning)]]"
                 on-tap="onScanTap_">$i18n{scanAction}</div>
-            <div hidden="[[!isRunningScanner]]">$i18n{scanning}</div>
-            <div class="scan-or-cleanup-action" hidden="[[!hasScanResults]]"
+            <div hidden="[[!shouldShowScanning_(hasScanResults, isRunning)]]">
+                $i18n{scanning}</div>
+            <div hidden="[[!shouldShowCleaning_(hasScanResults, isRunning)]]">
+                $i18n{cleaning}</div>
+            <div class="scan-or-cleanup-action"
+                hidden="[[!shouldShowClean_(hasScanResults, isRunning)]]"
                 on-tap="onCleanupTap_">$i18n{cleanAction}</div>
           </div>
         </div>
diff --git a/chrome/browser/resources/cleanup_tool/manager.js b/chrome/browser/resources/cleanup_tool/manager.js
index d9bfa9a8..ce921d61d 100644
--- a/chrome/browser/resources/cleanup_tool/manager.js
+++ b/chrome/browser/resources/cleanup_tool/manager.js
@@ -16,7 +16,7 @@
       value: false,
     },
 
-    isRunningScanner: {
+    isRunning: {
       type: Boolean,
       value: false,
     },
@@ -68,7 +68,21 @@
    * @private
    */
   onCleanupTap_: function() {
-    // TODO implement me.
+    this.isRunning = true;
+    this.browserProxy_.startCleanup().then(this.onCleanupResult_.bind(this));
+  },
+
+  /**
+   * @param {CleanupResult} cleanupResults
+   */
+  onCleanupResult_: function(cleanupResults) {
+    this.isRunning = false;
+
+    if (!cleanupResults.wasCancelled)
+      // Assume cleanup was completed and clear infected status.
+      this.isInfected = false;
+
+    // TODO(proberge): Do something about cleanupResults.uwsRemoved.
   },
 
   /**
@@ -95,13 +109,43 @@
 
   /**
    * @param {boolean} hasScanResults
-   * @param {boolean} isRunningScanner
-   * @return {boolean} True if the "Scan" button should be displayed, false
-   *     otherwise.
+   * @param {boolean} isRunning
+   * @return {boolean} Whether the "Scan" button should be displayed.
    * @private
    */
-  shouldShowScan_: function(hasScanResults, isRunningScanner) {
-    return !hasScanResults && !isRunningScanner;
+  shouldShowScan_: function(hasScanResults, isRunning) {
+    return !hasScanResults && !isRunning;
+  },
+
+  /**
+   * @param {boolean} hasScanResults
+   * @param {boolean} isRunning
+   * @return {boolean} Whether the "Run Chrome Cleanup" button should be
+   *     displayed.
+   * @private
+   */
+  shouldShowClean_: function(hasScanResults, isRunning) {
+    return hasScanResults && !isRunning;
+  },
+
+  /**
+   * @param {boolean} hasScanResults
+   * @param {boolean} isRunning
+   * @return {boolean} True Whether the "Scanning" label should be displayed.
+   * @private
+   */
+  shouldShowScanning_: function(hasScanResults, isRunning) {
+    return !hasScanResults && isRunning;
+  },
+
+  /**
+   * @param {boolean} hasScanResults
+   * @param {boolean} isRunning
+   * @return {boolean} True Whether the "Cleaning" label should be displayed.
+   * @private
+   */
+  shouldShowCleaning_: function(hasScanResults, isRunning) {
+    return hasScanResults && isRunning;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
index bb50157..0738762 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
@@ -50,11 +50,12 @@
         <div id="passwordGroup">
           <paper-input id="passwordInput" always-float-label
               label="$i18n{editPasswordPasswordLabel}"
-              type="[[getPasswordInputType_(password)]]"
+              type="[[getPasswordInputType_(item, password)]]"
               value="[[getPassword_(item, password)]]" readonly
             on-tap="onReadonlyInputTap_">
           </paper-input>
           <paper-icon-button id="showPasswordButton"
+              hidden$="[[item.federationText]]"
               icon="settings:visibility" on-tap="onShowPasswordButtonTap_"
               title="[[showPasswordTitle_(password,
                   '$i18nPolymer{hidePassword}','$i18nPolymer{showPassword}')]]">
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js
index cb9aa3f..94f958b 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js
@@ -37,12 +37,11 @@
 
   /**
    * Gets the password input's type. Should be 'text' when password is visible
-   * and 'password' when it's not.
-   * @param {string} password
+   * or when there's federated text otherwise 'password'.
    * @private
    */
-  getPasswordInputType_: function(password) {
-    return password ? 'text' : 'password';
+  getPasswordInputType_: function() {
+    return this.password || this.item.federationText ? 'text' : 'password';
   },
 
   /**
@@ -58,15 +57,16 @@
 
   /**
    * Gets the text of the password. Will use the value of |password| unless it
-   * cannot be shown, in which case it will be spaces.
-   * @param {!chrome.passwordsPrivate.PasswordUiEntry} item
-   * @param {string} password
+   * cannot be shown, in which case it will be spaces. It can also be the
+   * federated text.
    * @private
    */
-  getPassword_: function(item, password) {
-    if (password)
-      return password;
-    return item ? ' '.repeat(item.numCharactersInPassword) : '';
+  getPassword_: function() {
+    if (!this.item)
+      return '';
+
+    return this.item.federationText || this.password ||
+        ' '.repeat(this.item.numCharactersInPassword);
   },
 
   /**
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
index daab3f7..1c65a29 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -225,6 +225,8 @@
     content::DownloadManager* manager =
         content::BrowserContext::GetDownloadManager(browser()->profile());
     manager->GetAllDownloads(&download_items);
+    if (download_items.empty())
+      DownloadItemCreatedObserver(manager).WaitForDownloadItem(&download_items);
     EXPECT_EQ(1U, download_items.size());
     return download_items[0];
   }
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index ab5ca80..03e93a4 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -1504,6 +1504,7 @@
   EXPECT_TRUE(csd_service->enabled());
 
   // Add a new Profile. SBS should keep running.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(temp_profile_dir_.CreateUniqueTempDir());
   std::unique_ptr<Profile> profile2(Profile::CreateProfile(
       temp_profile_dir_.GetPath(), nullptr, Profile::CREATE_MODE_SYNCHRONOUS));
@@ -1603,7 +1604,10 @@
   // Create an additional profile.  We need to use the ProfileManager so that
   // the profile will get destroyed in the normal browser shutdown process.
   ProfileManager* profile_manager = g_browser_process->profile_manager();
-  ASSERT_TRUE(temp_profile_dir_.CreateUniqueTempDir());
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(temp_profile_dir_.CreateUniqueTempDir());
+  }
   profile_manager->CreateProfileAsync(
       temp_profile_dir_.GetPath(),
       base::Bind(&SafeBrowsingServiceShutdownTest::OnUnblockOnProfileCreation,
diff --git a/chrome/browser/service_process/service_process_control_browsertest.cc b/chrome/browser/service_process/service_process_control_browsertest.cc
index 9a072501..a9340b1d 100644
--- a/chrome/browser/service_process/service_process_control_browsertest.cc
+++ b/chrome/browser/service_process/service_process_control_browsertest.cc
@@ -14,6 +14,7 @@
 #include "base/process/process_iterator.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/test_timeouts.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
@@ -99,6 +100,7 @@
   }
 
   void ProcessControlLaunched() {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::ProcessId service_pid;
     EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
     EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
@@ -304,6 +306,7 @@
   // Make sure we are connected to the service process.
   ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
   base::ProcessId service_pid;
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
   EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
   ForceServiceProcessShutdown(version_info::GetVersionNumber(), service_pid);
@@ -317,6 +320,7 @@
 #endif
 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_CheckPid) {
   base::ProcessId service_pid;
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_FALSE(GetServiceProcessData(NULL, &service_pid));
   // Launch the service process.
   LaunchServiceProcessControl(true);
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index 324bf09..db9b2bc 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/process/launch.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/defaults.h"
@@ -1450,6 +1451,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SessionRestoreTest, TabWithDownloadDoesNotGetRestored) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir download_directory;
   ASSERT_TRUE(download_directory.CreateUniqueTempDir());
   ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
index 0c3895a..21fe47eb 100644
--- a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
+++ b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
@@ -18,6 +18,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/spellchecker/spellcheck_factory.h"
@@ -269,10 +270,13 @@
   base::FilePath bdict_path =
       spellcheck::GetVersionedFileName("en-US", dict_dir);
 
-  size_t actual = base::WriteFile(bdict_path,
-      reinterpret_cast<const char*>(kCorruptedBDICT),
-      arraysize(kCorruptedBDICT));
-  EXPECT_EQ(arraysize(kCorruptedBDICT), actual);
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    size_t actual = base::WriteFile(
+        bdict_path, reinterpret_cast<const char*>(kCorruptedBDICT),
+        arraysize(kCorruptedBDICT));
+    EXPECT_EQ(arraysize(kCorruptedBDICT), actual);
+  }
 
   // Attach an event to the SpellcheckService object so we can receive its
   // status updates.
@@ -304,6 +308,7 @@
   content::RunAllPendingInMessageLoop(content::BrowserThread::UI);
   EXPECT_EQ(SpellcheckService::BDICT_CORRUPTED,
             SpellcheckService::GetStatusEvent());
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (base::PathExists(bdict_path)) {
     ADD_FAILURE();
     EXPECT_TRUE(base::DeleteFile(bdict_path, true));
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 8324db2e..09273e0a 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -20,6 +20,7 @@
 #include "base/test/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_clock.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_clock.h"
 #include "base/time/default_tick_clock.h"
@@ -1353,7 +1354,10 @@
   std::string pkcs12_data;
   base::FilePath cert_path = net::GetTestCertsDirectory().Append(
       FILE_PATH_LITERAL("websocket_client_cert.p12"));
-  EXPECT_TRUE(base::ReadFileToString(cert_path, &pkcs12_data));
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    EXPECT_TRUE(base::ReadFileToString(cert_path, &pkcs12_data));
+  }
   EXPECT_EQ(net::OK, cert_db_->ImportFromPKCS12(public_slot.get(), pkcs12_data,
                                                 base::string16(), true, NULL));
 
@@ -1436,6 +1440,7 @@
   GURL url_non_dangerous = embedded_test_server()->GetURL("/title1.html");
   GURL url_dangerous =
       https_server_expired_.GetURL("/downloads/dangerous/dangerous.exe");
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir downloads_directory_;
 
   // Need empty temp dir to avoid having Chrome ask us for a new filename
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.cc b/chrome/browser/sync/test/integration/bookmarks_helper.cc
index da2ab1c..cfc07f82 100644
--- a/chrome/browser/sync/test/integration/bookmarks_helper.cc
+++ b/chrome/browser/sync/test/integration/bookmarks_helper.cc
@@ -24,6 +24,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
@@ -852,6 +853,7 @@
 }
 
 gfx::Image Create1xFaviconFromPNGFile(const std::string& path) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   const char* kPNGExtension = ".png";
   if (!base::EndsWith(path, kPNGExtension,
                       base::CompareCase::INSENSITIVE_ASCII))
diff --git a/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
index 1768ca8c..ddf9c6f8 100644
--- a/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
@@ -10,6 +10,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
@@ -33,6 +34,7 @@
 // will avoid seeing any of those, and return iff Directory database files still
 // exist.
 bool FolderContainsFiles(const FilePath& folder) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (base::DirectoryExists(folder)) {
     return !FileEnumerator(folder, false, FileEnumerator::FILES).Next().empty();
   } else {
diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.cc b/chrome/browser/sync/test/integration/sync_extension_helper.cc
index 8fcfd61..55322db 100644
--- a/chrome/browser/sync/test/integration/sync_extension_helper.cc
+++ b/chrome/browser/sync/test/integration/sync_extension_helper.cc
@@ -15,6 +15,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
@@ -84,6 +85,7 @@
 
 std::string SyncExtensionHelper::InstallExtension(
     Profile* profile, const std::string& name, Manifest::Type type) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   scoped_refptr<Extension> extension = GetExtension(profile, name, type);
   if (!extension.get()) {
     NOTREACHED() << "Could not install extension " << name;
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index f2a9a285..c783c2b 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -25,6 +25,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -338,6 +339,7 @@
 }
 
 void SyncTest::CreateProfile(int index) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   tmp_profile_paths_[index] = new base::ScopedTempDir();
   if (UsingExternalServers() && num_clients_ > 1) {
     // For multi profile UI signin, profile paths should be outside user data
@@ -504,6 +506,7 @@
 }
 
 bool SyncTest::SetupClients() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (num_clients_ <= 0)
     LOG(FATAL) << "num_clients_ incorrectly initialized.";
   if (!profiles_.empty() || !browsers_.empty() || !clients_.empty())
@@ -646,6 +649,7 @@
 }
 
 bool SyncTest::SetupSync() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   // Create sync profiles and clients if they haven't already been created.
   if (profiles_.empty()) {
     if (!SetupClients()) {
diff --git a/chrome/browser/task_manager/providers/web_contents/tab_contents_tag_browsertest.cc b/chrome/browser/task_manager/providers/web_contents/tab_contents_tag_browsertest.cc
index 08e35d4..060453c 100644
--- a/chrome/browser/task_manager/providers/web_contents/tab_contents_tag_browsertest.cc
+++ b/chrome/browser/task_manager/providers/web_contents/tab_contents_tag_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/task_manager/mock_web_contents_task_manager.h"
 #include "chrome/browser/task_manager/providers/web_contents/web_contents_tags_manager.h"
 #include "chrome/browser/ui/browser.h"
@@ -294,8 +295,12 @@
   base::FilePath test_dir;
   PathService::Get(chrome::DIR_TEST_DATA, &test_dir);
   std::string favicon_string;
-  base::ReadFileToString(
-      test_dir.AppendASCII("favicon").AppendASCII("icon.png"), &favicon_string);
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    base::ReadFileToString(
+        test_dir.AppendASCII("favicon").AppendASCII("icon.png"),
+        &favicon_string);
+  }
   SkBitmap favicon_bitmap;
   gfx::PNGCodec::Decode(
       reinterpret_cast<const unsigned char*>(favicon_string.data()),
diff --git a/chrome/browser/themes/theme_service_browsertest.cc b/chrome/browser/themes/theme_service_browsertest.cc
index 182557bc..7ed17415 100644
--- a/chrome/browser/themes/theme_service_browsertest.cc
+++ b/chrome/browser/themes/theme_service_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/macros.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/profiles/profile.h"
@@ -68,6 +69,7 @@
   // Add a vestigial .pak file that should be removed when the new one is
   // created.
   // TODO(estade): remove when vestigial .pak file deletion is removed.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_EQ(
       1, base::WriteFile(profile->GetPrefs()
                              ->GetFilePath(prefs::kCurrentThemePackFilename)
@@ -99,6 +101,7 @@
           ->GetPrefs()
           ->GetFilePath(prefs::kCurrentThemePackFilename)
           .AppendASCII("Cached Theme Material Design.pak");
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   EXPECT_FALSE(base::PathExists(old_path)) << "File not deleted: "
                                            << old_path.value();
 }
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc
index 17d0c468..10ed864 100644
--- a/chrome/browser/ui/browser_focus_uitest.cc
+++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -14,6 +14,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -179,6 +180,7 @@
 class TestInterstitialPage : public content::InterstitialPageDelegate {
  public:
   explicit TestInterstitialPage(WebContents* tab) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath file_path;
     bool success = PathService::Get(chrome::DIR_TEST_DATA, &file_path);
     EXPECT_TRUE(success);
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm
index 111b4e9..62479d2 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm
@@ -8,6 +8,7 @@
 #include "base/files/file_util.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/common/chrome_paths.h"
 #include "extensions/common/extension.h"
 
@@ -18,6 +19,7 @@
 scoped_refptr<extensions::Extension> LoadInstallPromptExtension(
     const char* extension_dir_name,
     const char* manifest_file) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   scoped_refptr<Extension> extension;
 
   base::FilePath path;
@@ -49,6 +51,7 @@
 }
 
 gfx::Image LoadInstallPromptIcon() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath path;
   PathService::Get(chrome::DIR_TEST_DATA, &path);
   path = path.AppendASCII("extensions")
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.cc b/chrome/browser/ui/find_bar/find_bar_controller.cc
index db9cfce..cfacd76 100644
--- a/chrome/browser/ui/find_bar/find_bar_controller.cc
+++ b/chrome/browser/ui/find_bar/find_bar_controller.cc
@@ -58,6 +58,10 @@
                                        ResultAction result_action) {
   find_bar_->Hide(true);
 
+  // If the user searches again for this string, it should notify if the result
+  // comes back empty again.
+  alerted_search_.clear();
+
   // |web_contents_| can be NULL for a number of reasons, for example when the
   // tab is closing. We must guard against that case. See issue 8030.
   if (web_contents_) {
@@ -139,14 +143,24 @@
     // are actively tracking.
     if (content::Source<WebContents>(source).ptr() == web_contents_) {
       UpdateFindBarForCurrentResult();
+
+      // A final update can occur multiple times if the document changes.
       if (find_tab_helper->find_result().final_update() &&
           find_tab_helper->find_result().number_of_matches() == 0) {
         const base::string16& last_search =
             find_tab_helper->previous_find_text();
         const base::string16& current_search = find_tab_helper->find_text();
-        if (!base::StartsWith(last_search, current_search,
-                              base::CompareCase::SENSITIVE)) {
-          find_bar_->AudibleAlert();
+
+        // Alert the user once per unique search, if they aren't backspacing.
+        if (current_search != alerted_search_) {
+          // Keep track of the last notified search string, even if the
+          // notification itself is elided.
+          if (!base::StartsWith(last_search, current_search,
+                                base::CompareCase::SENSITIVE)) {
+            find_bar_->AudibleAlert();
+          }
+
+          alerted_search_ = current_search;
         }
       }
     }
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.h b/chrome/browser/ui/find_bar/find_bar_controller.h
index 89d252a..25ecaed1 100644
--- a/chrome/browser/ui/find_bar/find_bar_controller.h
+++ b/chrome/browser/ui/find_bar/find_bar_controller.h
@@ -99,6 +99,12 @@
   // UpdateFindBarForCurrentResult to avoid flickering.
   int last_reported_matchcount_;
 
+  // Used to keep track of whether the user has been notified that the find came
+  // up empty. A single find session can result in multiple final updates, if
+  // the document contents change dynamically. It's a nuisance to notify the
+  // user more than once that a search came up empty, however.
+  base::string16 alerted_search_;
+
   DISALLOW_COPY_AND_ASSIGN(FindBarController);
 };
 
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
index 1a1b9ffd..d729463 100644
--- a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
+++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -435,7 +435,10 @@
       base::FilePath().AppendASCII("find_in_page"),
       base::FilePath().AppendASCII("LongFind.txt"));
   std::string query;
-  base::ReadFileToString(path, &query);
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    base::ReadFileToString(path, &query);
+  }
   EXPECT_EQ(1, FindInPage16(web_contents, base::UTF8ToUTF16(query),
                             kFwd, kIgnoreCase, NULL));
 }
@@ -501,7 +504,10 @@
   ui_test_utils::NavigateToURL(browser(), net::FilePathToFileURL(path));
 
   std::string query;
-  base::ReadFileToString(path, &query);
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    base::ReadFileToString(path, &query);
+  }
   EXPECT_EQ(1, FindInPage16(web_contents, base::UTF8ToUTF16(query),
                             false, false, NULL));
 }
diff --git a/chrome/browser/ui/libgtkui/app_indicator_icon.cc b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
index d43f6760..e75711761 100644
--- a/chrome/browser/ui/libgtkui/app_indicator_icon.cc
+++ b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
@@ -14,7 +14,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/post_task.h"
 #include "chrome/browser/ui/libgtkui/app_indicator_icon_menu.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -193,8 +193,10 @@
   if (icon_) {
     app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE);
     g_object_unref(icon_);
-    content::BrowserThread::GetBlockingPool()->PostTask(
-        FROM_HERE, base::BindOnce(&DeleteTempDirectory, temp_dir_));
+    base::PostTaskWithTraits(FROM_HERE,
+                             base::TaskTraits().MayBlock().WithPriority(
+                                 base::TaskPriority::BACKGROUND),
+                             base::BindOnce(&DeleteTempDirectory, temp_dir_));
   }
 }
 
@@ -214,21 +216,23 @@
   // another thread.
   SkBitmap safe_bitmap = *image.bitmap();
 
-  scoped_refptr<base::TaskRunner> task_runner =
-      content::BrowserThread::GetBlockingPool()
-          ->GetTaskRunnerWithShutdownBehavior(
-                base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  const base::TaskTraits kTraits =
+      base::TaskTraits()
+          .MayBlock()
+          .WithPriority(base::TaskPriority::USER_VISIBLE)
+          .WithShutdownBehavior(base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN);
+
   if (desktop_env_ == base::nix::DESKTOP_ENVIRONMENT_KDE4 ||
       desktop_env_ == base::nix::DESKTOP_ENVIRONMENT_KDE5) {
-    base::PostTaskAndReplyWithResult(
-        task_runner.get(), FROM_HERE,
+    base::PostTaskWithTraitsAndReplyWithResult(
+        FROM_HERE, kTraits,
         base::Bind(AppIndicatorIcon::WriteKDE4TempImageOnWorkerThread,
                    safe_bitmap, temp_dir_),
         base::Bind(&AppIndicatorIcon::SetImageFromFile,
                    weak_factory_.GetWeakPtr()));
   } else {
-    base::PostTaskAndReplyWithResult(
-        task_runner.get(), FROM_HERE,
+    base::PostTaskWithTraitsAndReplyWithResult(
+        FROM_HERE, kTraits,
         base::Bind(AppIndicatorIcon::WriteUnityTempImageOnWorkerThread,
                    safe_bitmap, icon_change_count_, id_),
         base::Bind(&AppIndicatorIcon::SetImageFromFile,
@@ -361,8 +365,10 @@
   }
 
   if (temp_dir_ != params.parent_temp_dir) {
-    content::BrowserThread::GetBlockingPool()->PostTask(
-        FROM_HERE, base::BindOnce(&DeleteTempDirectory, temp_dir_));
+    base::PostTaskWithTraits(FROM_HERE,
+                             base::TaskTraits().MayBlock().WithPriority(
+                                 base::TaskPriority::BACKGROUND),
+                             base::BindOnce(&DeleteTempDirectory, temp_dir_));
     temp_dir_ = params.parent_temp_dir;
   }
 }
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc
index fbdd5aa..6e8fa4e10 100644
--- a/chrome/browser/ui/search/local_ntp_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/search/search.h"
@@ -40,6 +41,7 @@
 
 // Switches the browser language to French, and returns true iff successful.
 bool SwitchToFrench() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   // Make sure the default language is not French.
   std::string default_locale = g_browser_process->GetApplicationLocale();
   EXPECT_NE("fr", default_locale);
@@ -305,6 +307,7 @@
   EXPECT_NE("fr", default_locale);
 
   // Switch browser language to French.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   std::string loaded_locale =
       ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources("fr");
 
@@ -349,6 +352,7 @@
   }
 
   void SetUserSelectedDefaultSearchProvider(const std::string& base_url) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     TemplateURLData data;
     data.SetShortName(base::UTF8ToUTF16(base_url));
     data.SetKeyword(base::UTF8ToUTF16(base_url));
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 16b3334..b137627 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/histogram_tester.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -449,7 +450,11 @@
   base::FilePath dest_path = profile_manager->user_data_dir();
   dest_path = dest_path.Append(FILE_PATH_LITERAL("New Profile 1"));
 
-  Profile* other_profile = profile_manager->GetProfile(dest_path);
+  Profile* other_profile = nullptr;
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    other_profile = profile_manager->GetProfile(dest_path);
+  }
   ASSERT_TRUE(other_profile);
 
   // Use a couple arbitrary URLs.
@@ -635,6 +640,7 @@
   base::FilePath dest_path4 = profile_manager->user_data_dir().Append(
       FILE_PATH_LITERAL("New Profile 4"));
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   Profile* profile_home1 = profile_manager->GetProfile(dest_path1);
   ASSERT_TRUE(profile_home1);
   Profile* profile_home2 = profile_manager->GetProfile(dest_path2);
@@ -743,12 +749,18 @@
   base::FilePath dest_path3 = profile_manager->user_data_dir().Append(
       FILE_PATH_LITERAL("New Profile 3"));
 
-  Profile* profile_home = profile_manager->GetProfile(dest_path1);
-  ASSERT_TRUE(profile_home);
-  Profile* profile_last = profile_manager->GetProfile(dest_path2);
-  ASSERT_TRUE(profile_last);
-  Profile* profile_urls = profile_manager->GetProfile(dest_path3);
-  ASSERT_TRUE(profile_urls);
+  Profile* profile_home = nullptr;
+  Profile* profile_last = nullptr;
+  Profile* profile_urls = nullptr;
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    profile_home = profile_manager->GetProfile(dest_path1);
+    ASSERT_TRUE(profile_home);
+    profile_last = profile_manager->GetProfile(dest_path2);
+    ASSERT_TRUE(profile_last);
+    profile_urls = profile_manager->GetProfile(dest_path3);
+    ASSERT_TRUE(profile_urls);
+  }
 
   // Set the profiles to open the home page, last visited pages or URLs.
   SessionStartupPref pref_home(SessionStartupPref::DEFAULT);
@@ -1067,9 +1079,13 @@
   // Open the two profiles.
   base::FilePath dest_path = profile_manager->user_data_dir();
 
-  Profile* profile1 = Profile::CreateProfile(
-      dest_path.Append(FILE_PATH_LITERAL("New Profile 1")), nullptr,
-      Profile::CreateMode::CREATE_MODE_SYNCHRONOUS);
+  Profile* profile1 = nullptr;
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    profile1 = Profile::CreateProfile(
+        dest_path.Append(FILE_PATH_LITERAL("New Profile 1")), nullptr,
+        Profile::CreateMode::CREATE_MODE_SYNCHRONOUS);
+  }
   ASSERT_TRUE(profile1);
   profile_manager->RegisterTestingProfile(profile1, true, false);
 
diff --git a/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc b/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
index 4b1f1c48..97a9cc7 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
@@ -15,6 +15,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/test/test_file_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_window.h"
@@ -273,6 +274,7 @@
   CloseBrowsersSynchronouslyForProfileBasePath("Profile 1");
   CreateAndSwitchToProfile("Profile 2");
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetGuestProfilePath()));
   ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetSystemProfilePath()));
 }
@@ -302,6 +304,7 @@
   // Create the guest profile path, but not the system profile one. This will
   // make it impossible to create the system profile once the permissions are
   // locked down during setup.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetGuestProfilePath()));
 }
 
@@ -402,6 +405,7 @@
 // manager instead.
 IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
                        PRE_DeletedProfileFallbackToUserManager) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetGuestProfilePath()));
   ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetSystemProfilePath()));
 }
diff --git a/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc b/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc
index 5279bce..d664dc82 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
@@ -28,6 +29,7 @@
 // And this test is useless without that functionality.
 #if !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, LastUsedProfileActivated) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ProfileManager* profile_manager = g_browser_process->profile_manager();
 
   // Create 4 profiles, they will be scheduled for destruction when the last
diff --git a/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc b/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc
index cf25549..2c306aca 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc
@@ -10,6 +10,7 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/win/windows_version.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/keep_alive_types.h"
@@ -236,8 +237,12 @@
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   base::FilePath path =
       profile_manager->user_data_dir().AppendASCII("test_profile");
-  Profile* other_profile =
-      Profile::CreateProfile(path, nullptr, Profile::CREATE_MODE_SYNCHRONOUS);
+  Profile* other_profile = nullptr;
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    other_profile =
+        Profile::CreateProfile(path, nullptr, Profile::CREATE_MODE_SYNCHRONOUS);
+  }
   profile_manager->RegisterTestingProfile(other_profile, true, false);
 
   // Use a couple same-site HTTP URLs.
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
index c038dde..46b8fc0 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/signin/fake_signin_manager_builder.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -82,17 +83,20 @@
 
 IN_PROC_BROWSER_TEST_F(BookmarkBubbleViewBrowserTest,
                        InvokeDialog_bookmark_details) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   RunDialog();
 }
 
 IN_PROC_BROWSER_TEST_F(BookmarkBubbleViewBrowserTest,
                        InvokeDialog_bookmark_details_signed_in) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   RunDialog();
 }
 
 #if defined(OS_WIN)
 IN_PROC_BROWSER_TEST_F(BookmarkBubbleViewBrowserTest,
                        InvokeDialog_ios_promotion) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   RunDialog();
 }
 #endif
diff --git a/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc
index 66f7dae..ee6d9a0 100644
--- a/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc
@@ -57,7 +57,8 @@
   ExpectBodyContains({"\"billingAddress\": {", "\"666 Erebus St.\"",
                       "\"Apt 8\"", "\"city\": \"Elysium\"",
                       "\"country\": \"US\"", "\"organization\": \"Underworld\"",
-                      "\"phone\": \"16502111111\"", "\"postalCode\": \"91111\"",
+                      "\"phone\": \"+16502111111\"",
+                      "\"postalCode\": \"91111\"",
                       "\"recipient\": \"John H. Doe\"", "\"region\": \"CA\""});
 }
 
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_chooser_view_browsertest.cc
index 9893a37..34df889 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/histogram_tester.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
@@ -41,6 +42,7 @@
 namespace {
 
 Profile* CreateTestingProfile(const std::string& profile_name) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   size_t starting_number_of_profiles = profile_manager->GetNumberOfProfiles();
 
@@ -59,6 +61,7 @@
 }
 
 Profile* CreateProfileOutsideUserDataDir() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath path;
   if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &path))
     NOTREACHED() << "Could not create directory at " << path.MaybeAsASCII();
@@ -73,6 +76,7 @@
 // Set up the profiles to enable Lock. Takes as parameter a profile that will be
 // signed in, and also creates a supervised user (necessary for lock).
 void SetupProfilesForLock(Profile* signed_in) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   const char signed_in_email[] = "me@google.com";
 
   // Set up the |signed_in| profile.
diff --git a/chrome/browser/ui/webui/cleanup_tool/cleanup_action_handler.cc b/chrome/browser/ui/webui/cleanup_tool/cleanup_action_handler.cc
index e6bd13e7..d1e6bacc 100644
--- a/chrome/browser/ui/webui/cleanup_tool/cleanup_action_handler.cc
+++ b/chrome/browser/ui/webui/cleanup_tool/cleanup_action_handler.cc
@@ -5,10 +5,10 @@
 #include "chrome/browser/ui/webui/cleanup_tool/cleanup_action_handler.h"
 
 #include "base/bind.h"
-#include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/sw_reporter_installer_win.h"
+#include "components/component_updater/component_updater_service.h"
 
 namespace {
 
@@ -22,6 +22,18 @@
          component_ids.end();
 }
 
+// TODO(proberge): Connect this to the Cleanup Tool manager class once that's
+// implemented.
+void StartScan(base::Closure callback) {
+  callback.Run();
+}
+
+// TODO(proberge): Connect this to the Cleanup Tool manager class once that's
+// implemented.
+void StartCleanup(base::Closure callback) {
+  callback.Run();
+}
+
 // TODO(proberge): Localize strings once they are finalized.
 constexpr char kDetectionOkText[] = "No problems detected";
 constexpr char kDetectionUwSText[] = "2 potentially harmful programs detected";
@@ -44,6 +56,9 @@
   web_ui()->RegisterMessageCallback(
       "startScan", base::Bind(&CleanupActionHandler::HandleStartScan,
                               base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "startCleanup", base::Bind(&CleanupActionHandler::HandleStartCleanup,
+                                 base::Unretained(this)));
 }
 
 void CleanupActionHandler::OnJavascriptDisallowed() {
@@ -52,8 +67,8 @@
 
 void CleanupActionHandler::HandleRequestLastScanResult(
     const base::ListValue* args) {
-  std::string webui_callback_id;
   CHECK_EQ(1U, args->GetSize());
+  std::string webui_callback_id;
   bool success = args->GetString(0, &webui_callback_id);
   DCHECK(success);
 
@@ -86,9 +101,9 @@
     return;
   }
 
-  component_updater::RegisterUserInitiatedSwReporterScan(
-      base::Bind(&CleanupActionHandler::ReportScanResults,
-                 callback_weak_ptr_factory_.GetWeakPtr(), webui_callback_id));
+  StartScan(base::Bind(&CleanupActionHandler::ReportScanResults,
+                       callback_weak_ptr_factory_.GetWeakPtr(),
+                       webui_callback_id));
 }
 
 void CleanupActionHandler::ReportScanResults(const std::string& callback_id) {
@@ -102,3 +117,23 @@
   AllowJavascript();
   ResolveJavascriptCallback(base::Value(callback_id), scan_results);
 }
+
+void CleanupActionHandler::HandleStartCleanup(const base::ListValue* args) {
+  CHECK_EQ(1U, args->GetSize());
+  std::string webui_callback_id;
+  bool success = args->GetString(0, &webui_callback_id);
+  DCHECK(success);
+
+  StartCleanup(base::Bind(&CleanupActionHandler::ReportCleanupResults,
+                          base::Unretained(this), webui_callback_id));
+}
+
+void CleanupActionHandler::ReportCleanupResults(
+    const std::string& callback_id) {
+  base::DictionaryValue cleanup_results;
+  // TODO(proberge): Return real information about the cleanup.
+  cleanup_results.SetBoolean("wasCancelled", true);
+  cleanup_results.SetBoolean("requiresReboot", false);
+
+  ResolveJavascriptCallback(base::Value(callback_id), cleanup_results);
+}
diff --git a/chrome/browser/ui/webui/cleanup_tool/cleanup_action_handler.h b/chrome/browser/ui/webui/cleanup_tool/cleanup_action_handler.h
index 894fc45..97c87f0 100644
--- a/chrome/browser/ui/webui/cleanup_tool/cleanup_action_handler.h
+++ b/chrome/browser/ui/webui/cleanup_tool/cleanup_action_handler.h
@@ -8,7 +8,6 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "components/component_updater/component_updater_service.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 // The handler for Javascript messages related to the "Chrome Cleanup" view.
@@ -26,11 +25,16 @@
 
   void HandleRequestLastScanResult(const base::ListValue* args);
   void HandleStartScan(const base::ListValue* args);
+  void HandleStartCleanup(const base::ListValue* args);
 
   // Returns the scan result initiated by HandleStartScan() to the Javascript
   // caller refererenced by |callback_id|.
   void ReportScanResults(const std::string& callback_id);
 
+  // Returns the cleanup result initiated by HandleStartCleanup() to the
+  // Javascript caller refererenced by |callback_id|.
+  void ReportCleanupResults(const std::string& callback_id);
+
   // Used to cancel callbacks when JavaScript becomes disallowed.
   base::WeakPtrFactory<CleanupActionHandler> callback_weak_ptr_factory_;
 
diff --git a/chrome/browser/ui/webui/cleanup_tool/cleanup_tool_ui.cc b/chrome/browser/ui/webui/cleanup_tool/cleanup_tool_ui.cc
index ee09615..c227104 100644
--- a/chrome/browser/ui/webui/cleanup_tool/cleanup_tool_ui.cc
+++ b/chrome/browser/ui/webui/cleanup_tool/cleanup_tool_ui.cc
@@ -20,6 +20,7 @@
   html_source->AddString("sectionHeader",
                          "Remove suspicious or unwanted programs");
   html_source->AddString("scanAction", "Scan Now");
+  html_source->AddString("cleaning", "Cleaning");
   html_source->AddString("scanning", "Scanning");
   html_source->AddString("cleanAction", "Run Chrome Cleanup");
   html_source->AddString("about", "About Chrome Cleanup");
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
index b9b21f5..f0ce3fa 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/io_thread.h"
@@ -290,6 +291,7 @@
 
 void NetInternalsTest::MessageHandler::GetNetLogFileContents(
     const base::ListValue* list_value) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   base::FilePath temp_file;
diff --git a/chrome/browser/ui/webui/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy_ui_browsertest.cc
index c6ed1f25..5514daf 100644
--- a/chrome/browser/ui/webui/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy_ui_browsertest.cc
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
@@ -280,6 +281,7 @@
 
 IN_PROC_BROWSER_TEST_F(PolicyUITest, ExtensionLoadAndSendPolicy) {
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIPolicyURL));
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir_;
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 
diff --git a/chrome/browser/ui/webui/test_files_request_filter.cc b/chrome/browser/ui/webui/test_files_request_filter.cc
index 4c69de5..2d52912 100644
--- a/chrome/browser/ui/webui/test_files_request_filter.cc
+++ b/chrome/browser/ui/webui/test_files_request_filter.cc
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/path_service.h"
 #include "base/strings/string_split.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/common/chrome_paths.h"
 
 namespace {
@@ -16,6 +17,7 @@
 bool HandleTestFileRequestCallback(
     const std::string& path,
     const content::WebUIDataSource::GotDataCallback& callback) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   std::vector<std::string> url_substr =
       base::SplitString(path, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
   if (url_substr.size() != 2 || url_substr[0] != "test")
diff --git a/chrome/renderer/resources/extensions/media_router_bindings.js b/chrome/renderer/resources/extensions/media_router_bindings.js
index 1bd47e01..4eac395 100644
--- a/chrome/renderer/resources/extensions/media_router_bindings.js
+++ b/chrome/renderer/resources/extensions/media_router_bindings.js
@@ -933,7 +933,7 @@
     this.handlers_.onBeforeInvokeHandler();
     return this.handlers_
         .createMediaRouteController(routeId, controllerRequest, observer)
-        .then(() => {success: true}, e => {success: false});
+        .then(() => ({success: true}), e => ({success: false}));
   };
 
   mediaRouter = new MediaRouter(new mediaRouterMojom.MediaRouterPtr(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 961fd6b..d2ccf4f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -619,6 +619,8 @@
         "../browser/chromeos/login/screenshot_testing/SkImageDiffer.h",
         "../browser/chromeos/login/screenshot_testing/SkPMetric.cpp",
         "../browser/chromeos/login/screenshot_testing/SkPMetric.h",
+        "../browser/chromeos/login/screenshot_testing/SkPMetricUtil_gen.h",
+        "../browser/chromeos/login/screenshot_testing/login_screen_areas.h",
         "../browser/chromeos/login/screenshot_testing/screenshot_tester.cc",
         "../browser/chromeos/login/screenshot_testing/screenshot_tester.h",
         "../browser/chromeos/login/screenshot_testing/screenshot_testing_mixin.cc",
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index 867c5ca5..19b7c7b 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -299,6 +299,7 @@
 }
 
 bool InProcessBrowserTest::RunAccessibilityChecks(std::string* error_message) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (!browser()) {
     *error_message = "browser is NULL";
     return false;
diff --git a/chrome/test/base/javascript_browser_test.cc b/chrome/test/base/javascript_browser_test.cc
index c70778b..e1f1829e 100644
--- a/chrome/test/base/javascript_browser_test.cc
+++ b/chrome/test/base/javascript_browser_test.cc
@@ -7,6 +7,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/web_ui.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -66,6 +67,7 @@
 // calls.
 void JavaScriptBrowserTest::BuildJavascriptLibraries(
     std::vector<base::string16>* libraries) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(libraries != NULL);
   std::vector<base::FilePath>::iterator user_libraries_iterator;
   for (user_libraries_iterator = user_libraries_.begin();
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index edeed785..c43d29f 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -16,6 +16,7 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/autocomplete/in_memory_url_index_factory.h"
@@ -391,6 +392,7 @@
 }
 
 void TestingProfile::CreateTempProfileDir() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (!temp_dir_.CreateUniqueTempDir()) {
     LOG(ERROR) << "Failed to create unique temporary directory.";
 
@@ -418,6 +420,7 @@
 }
 
 void TestingProfile::Init() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   // If threads have been initialized, we should be on the UI thread.
   DCHECK(!content::BrowserThread::IsThreadInitialized(
              content::BrowserThread::UI) ||
@@ -561,6 +564,9 @@
     resource_context_ = NULL;
     content::RunAllPendingInMessageLoop(BrowserThread::IO);
   }
+
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  ignore_result(temp_dir_.Delete());
 }
 
 void TestingProfile::CreateFaviconService() {
diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc
index d74c337f..dbfc6b7f 100644
--- a/chrome/test/base/ui_test_utils.cc
+++ b/chrome/test/base/ui_test_utils.cc
@@ -19,6 +19,7 @@
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_timeouts.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -281,6 +282,7 @@
 
 base::FilePath GetTestFilePath(const base::FilePath& dir,
                                const base::FilePath& file) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath path;
   PathService::Get(chrome::DIR_TEST_DATA, &path);
   return path.Append(dir).Append(file);
@@ -291,6 +293,7 @@
 }
 
 bool GetRelativeBuildDirectory(base::FilePath* build_dir) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   // This function is used to find the build directory so TestServer can serve
   // built files (nexes, etc).  TestServer expects a path relative to the source
   // root.
@@ -363,6 +366,7 @@
 }
 
 void DownloadURL(Browser* browser, const GURL& download_url) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir downloads_directory;
   ASSERT_TRUE(downloads_directory.CreateUniqueTempDir());
   browser->profile()->GetPrefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
diff --git a/chrome/test/base/web_ui_browser_test.cc b/chrome/test/base/web_ui_browser_test.cc
index 2313b2c..755e38d 100644
--- a/chrome/test/base/web_ui_browser_test.cc
+++ b/chrome/test/base/web_ui_browser_test.cc
@@ -15,6 +15,7 @@
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/profiles/profile.h"
@@ -493,6 +494,7 @@
 
 GURL WebUIBrowserTest::WebUITestDataPathToURL(
     const base::FilePath::StringType& path) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath dir_test_data;
   EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &dir_test_data));
   base::FilePath test_path(dir_test_data.Append(kWebUITestFolder).Append(path));
diff --git a/chrome/test/data/android/webvr_instrumentation/html/test_screen_taps_registered_on_cardboard.html b/chrome/test/data/android/webvr_instrumentation/html/test_screen_taps_registered.html
similarity index 80%
rename from chrome/test/data/android/webvr_instrumentation/html/test_screen_taps_registered_on_cardboard.html
rename to chrome/test/data/android/webvr_instrumentation/html/test_screen_taps_registered.html
index e74d5f6..6e53492 100644
--- a/chrome/test/data/android/webvr_instrumentation/html/test_screen_taps_registered_on_cardboard.html
+++ b/chrome/test/data/android/webvr_instrumentation/html/test_screen_taps_registered.html
@@ -1,7 +1,8 @@
 <!doctype html>
 <!--
-Tests that screen taps are registered while in VR when viewer is
-Cardboard
+Tests that either screen taps are registered in VR when viewer is Cardboard
+or that controller clicks are registered as screen taps in VR when viewer is
+Daydream View.
 -->
 <html>
   <head>
@@ -13,7 +14,7 @@
     <script src="../resources/webvr_e2e.js"></script>
     <script src="../resources/webvr_boilerplate.js"></script>
     <script>
-      var t = async_test("Screen taps registered when in VR w/ Cardboard");
+      var t = async_test("Screen taps/clicks registered when in VR");
       window.addEventListener("vrdisplaypresentchange",
           () => {finishJavaScriptStep();}, false);
       var numTaps = 0;
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index bd9d622..74a26091 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -1138,7 +1138,7 @@
 };
 
 // Failing on ChromiumOS dbg. https://crbug.com/709442
-GEN('#if defined(OS_CHROMEOS) && !defined(NDEBUG)');
+GEN('#if (defined(OS_WIN) || defined(OS_CHROMEOS)) && !defined(NDEBUG)');
 GEN('#define MAYBE_All DISABLED_All');
 GEN('#else');
 GEN('#define MAYBE_All All');
diff --git a/chrome/test/data/webui/settings/site_settings_page_browsertest.js b/chrome/test/data/webui/settings/site_settings_page_browsertest.js
index 0b9ade75..fc4929e 100644
--- a/chrome/test/data/webui/settings/site_settings_page_browsertest.js
+++ b/chrome/test/data/webui/settings/site_settings_page_browsertest.js
@@ -16,7 +16,7 @@
 };
 
 // Failing on ChromiumOS dbg. https://crbug.com/709442
-GEN('#if defined(OS_CHROMEOS) && !defined(NDEBUG)');
+GEN('#if (defined(OS_WIN) || defined(OS_CHROMEOS))  && !defined(NDEBUG)');
 GEN('#define MAYBE_labels DISABLED_labels');
 GEN('#else');
 GEN('#define MAYBE_labels labels');
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index bcf0a4a..5eb35753 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "base/test/test_timeouts.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
@@ -1259,7 +1260,10 @@
 
   void LaunchTestingApp(const std::string& extension_dirname) {
     base::FilePath data_dir;
-    ASSERT_TRUE(PathService::Get(chrome::DIR_GEN_TEST_DATA, &data_dir));
+    {
+      base::ThreadRestrictions::ScopedAllowIO allow_io;
+      ASSERT_TRUE(PathService::Get(chrome::DIR_GEN_TEST_DATA, &data_dir));
+    }
     base::FilePath app_dir = data_dir.AppendASCII("ppapi")
                                      .AppendASCII("tests")
                                      .AppendASCII("extensions")
diff --git a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
index ae3c0a628..897e15b 100644
--- a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/ppapi/ppapi_test.h"
@@ -270,6 +271,7 @@
 
 IN_PROC_BROWSER_TEST_F(PPAPIFileChooserTest, FileChooser_Open_Success) {
   const char kContents[] = "Hello from browser";
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -294,6 +296,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PPAPIFileChooserTest, FileChooser_SaveAs_Success) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath suggested_filename = temp_dir.GetPath().AppendASCII("foo");
@@ -310,6 +313,7 @@
 
 IN_PROC_BROWSER_TEST_F(PPAPIFileChooserTest,
                        FileChooser_SaveAs_SafeDefaultName) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath suggested_filename = temp_dir.GetPath().AppendASCII("foo");
@@ -332,6 +336,7 @@
 
 IN_PROC_BROWSER_TEST_F(PPAPIFileChooserTest,
                        FileChooser_SaveAs_UnsafeDefaultName) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath suggested_filename = temp_dir.GetPath().AppendASCII("foo");
@@ -366,6 +371,7 @@
 // file is created. This MOTW prevents the file being opened without due
 // security warnings if the file is executable.
 IN_PROC_BROWSER_TEST_F(PPAPIFileChooserTest, FileChooser_Quarantine) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath suggested_filename = temp_dir.GetPath().AppendASCII("foo");
@@ -392,6 +398,7 @@
 
 IN_PROC_BROWSER_TEST_F(PPAPIFileChooserTestWithSBService,
                        FileChooser_SaveAs_DangerousExecutable_Allowed) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   safe_browsing_test_configuration_.default_result =
       DownloadProtectionService::DANGEROUS;
   safe_browsing_test_configuration_.result_map.insert(
diff --git a/chrome/test/ppapi/ppapi_test.cc b/chrome/test/ppapi/ppapi_test.cc
index 250c0bc..9ec1b00 100644
--- a/chrome/test/ppapi/ppapi_test.cc
+++ b/chrome/test/ppapi/ppapi_test.cc
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -153,6 +154,7 @@
 }
 
 GURL PPAPITestBase::GetTestFileUrl(const std::string& test_case) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
   base::FilePath test_path;
   EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_path));
   test_path = test_path.Append(FILE_PATH_LITERAL("ppapi"));
diff --git a/chrome/test/remoting/qunit_browser_test_runner.cc b/chrome/test/remoting/qunit_browser_test_runner.cc
index c309649..b84a30a 100644
--- a/chrome/test/remoting/qunit_browser_test_runner.cc
+++ b/chrome/test/remoting/qunit_browser_test_runner.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -39,8 +40,11 @@
 }
 
 void QUnitBrowserTestRunner::RunTest(const base::FilePath& file) {
-  ASSERT_TRUE(PathExists(file)) << "Error: The QUnit test suite <"
-                                << file.value() << "> does not exist.";
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ASSERT_TRUE(PathExists(file)) << "Error: The QUnit test suite <"
+                                  << file.value() << "> does not exist.";
+  }
   ui_test_utils::NavigateToURL(browser(), net::FilePathToFileURL(file));
 
   content::WebContents* web_contents =
diff --git a/chromecast/public/media/media_pipeline_backend.h b/chromecast/public/media/media_pipeline_backend.h
index e6ef3c9..1f346a3 100644
--- a/chromecast/public/media/media_pipeline_backend.h
+++ b/chromecast/public/media/media_pipeline_backend.h
@@ -136,7 +136,8 @@
 
     // Returns the pipeline latency: i.e. the amount of data
     // in the pipeline that have not been rendered yet, in microseconds.
-    // Returns delay = INT64_MIN if the latency is not available.
+    // Returns a RenderingDelay.timestamp = INT64_MIN if the latency is not
+    // available.
     // Only called when the backend is playing.
     virtual RenderingDelay GetRenderingDelay() = 0;
 
diff --git a/chromecast/renderer/media/key_systems_cast.cc b/chromecast/renderer/media/key_systems_cast.cc
index 1e29715..df31180a 100644
--- a/chromecast/renderer/media/key_systems_cast.cc
+++ b/chromecast/renderer/media/key_systems_cast.cc
@@ -49,6 +49,12 @@
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
     codecs |= ::media::EME_CODEC_MP4_HEVC;
 #endif
+#if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
+    codecs |= ::media::EME_CODEC_MP4_DV_AVC;
+#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
+    codecs |= ::media::EME_CODEC_MP4_DV_HEVC;
+#endif
+#endif
     return codecs;
   }
 
@@ -111,6 +117,12 @@
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
   codecs |= ::media::EME_CODEC_MP4_HEVC;
 #endif
+#if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
+  codecs |= ::media::EME_CODEC_MP4_DV_AVC;
+#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
+  codecs |= ::media::EME_CODEC_MP4_DV_HEVC;
+#endif
+#endif
   key_systems_properties->emplace_back(new cdm::WidevineKeySystemProperties(
       codecs,                     // Regular codecs.
       Robustness::HW_SECURE_ALL,  // Max audio robustness.
diff --git a/components/autofill/core/browser/data_driven_test.cc b/components/autofill/core/browser/data_driven_test.cc
index c339758..e778a8a7 100644
--- a/components/autofill/core/browser/data_driven_test.cc
+++ b/components/autofill/core/browser/data_driven_test.cc
@@ -7,6 +7,7 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace autofill {
@@ -35,6 +36,7 @@
     const base::FilePath& input_directory,
     const base::FilePath& output_directory,
     const base::FilePath::StringType& file_name_pattern) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   ASSERT_TRUE(base::DirectoryExists(input_directory));
   ASSERT_TRUE(base::DirectoryExists(output_directory));
   base::FileEnumerator input_files(input_directory,
@@ -52,6 +54,7 @@
 void DataDrivenTest::RunOneDataDrivenTest(
     const base::FilePath& test_file_name,
     const base::FilePath& output_directory) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   // iOS doesn't get rid of removed test files. TODO(estade): remove this after
   // all iOS bots are clobbered.
   if (test_file_name.BaseName().value() == FILE_PATH_LITERAL("multimerge.in"))
@@ -64,7 +67,9 @@
   ReadFile(test_file_name, &input);
 
   std::string output;
+  base::ThreadRestrictions::SetIOAllowed(false);
   GenerateResults(input, &output);
+  base::ThreadRestrictions::SetIOAllowed(true);
 
   base::FilePath output_file = output_directory.Append(
       test_file_name.BaseName().StripTrailingSeparators().ReplaceExtension(
diff --git a/components/cdm/browser/cdm_message_filter_android.cc b/components/cdm/browser/cdm_message_filter_android.cc
index 849b716..4d7e99d 100644
--- a/components/cdm/browser/cdm_message_filter_android.cc
+++ b/components/cdm/browser/cdm_message_filter_android.cc
@@ -41,6 +41,12 @@
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
     {media::EME_CODEC_MP4_HEVC, media::kCodecHEVC, "video/mp4"},
 #endif
+#if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
+    {media::EME_CODEC_MP4_DV_AVC, media::kCodecDolbyVision, "video/mp4"},
+#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
+    {media::EME_CODEC_MP4_DV_HEVC, media::kCodecDolbyVision, "video/mp4"},
+#endif
+#endif
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 };
 
diff --git a/components/cronet/ios/Cronet.h b/components/cronet/ios/Cronet.h
index 4a29721..f7f6cbe 100644
--- a/components/cronet/ios/Cronet.h
+++ b/components/cronet/ios/Cronet.h
@@ -52,6 +52,11 @@
 // before |start| is called.
 + (void)addQuicHint:(NSString*)host port:(int)port altPort:(int)altPort;
 
+// Set experimental Cronet options.  Argument is a JSON string; see
+// |URLRequestContextConfig| for more details.  This method only has
+// any effect before |start| is called.
++ (void)setExperimentalOptions:(NSString*)experimentalOptions;
+
 // Sets the User-Agent request header string to be sent with all requests.
 // If |partial| is set to YES, then actual user agent value is based on device
 // model, OS version, and |userAgent| argument. For example "Foo/3.0.0.0" is
diff --git a/components/cronet/ios/Cronet.mm b/components/cronet/ios/Cronet.mm
index b883049..3adc491 100644
--- a/components/cronet/ios/Cronet.mm
+++ b/components/cronet/ios/Cronet.mm
@@ -37,6 +37,7 @@
 cronet::URLRequestContextConfig::HttpCacheType gHttpCache =
     cronet::URLRequestContextConfig::HttpCacheType::DISK;
 ScopedVector<cronet::URLRequestContextConfig::QuicHint> gQuicHints;
+NSString* gExperimentalOptions = @"{}";
 NSString* gUserAgent = nil;
 BOOL gUserAgentPartial = NO;
 NSString* gSslKeyLogFileName = nil;
@@ -168,6 +169,11 @@
       base::SysNSStringToUTF8(host), port, altPort));
 }
 
++ (void)setExperimentalOptions:(NSString*)experimentalOptions {
+  [self checkNotStarted];
+  gExperimentalOptions = experimentalOptions;
+}
+
 + (void)setUserAgent:(NSString*)userAgent partial:(BOOL)partial {
   [self checkNotStarted];
   gUserAgent = userAgent;
@@ -176,7 +182,7 @@
 
 + (void)setSslKeyLogFileName:(NSString*)sslKeyLogFileName {
   [self checkNotStarted];
-  gSslKeyLogFileName = sslKeyLogFileName;
+  gSslKeyLogFileName = [self getNetLogPathForFile:sslKeyLogFileName];
 }
 
 + (void)setHttpCacheType:(CRNHttpCacheType)httpCacheType {
@@ -213,6 +219,8 @@
 
   gChromeNet.Get()->set_http2_enabled(gHttp2Enabled);
   gChromeNet.Get()->set_quic_enabled(gQuicEnabled);
+  gChromeNet.Get()->set_experimental_options(
+      base::SysNSStringToUTF8(gExperimentalOptions));
   gChromeNet.Get()->set_http_cache(gHttpCache);
   gChromeNet.Get()->set_ssl_key_log_file_name(
       base::SysNSStringToUTF8(gSslKeyLogFileName));
diff --git a/components/cronet/ios/cronet_environment.h b/components/cronet/ios/cronet_environment.h
index 59cb796..a419c2b 100644
--- a/components/cronet/ios/cronet_environment.h
+++ b/components/cronet/ios/cronet_environment.h
@@ -91,6 +91,10 @@
     http_cache_ = http_cache;
   }
 
+  void set_experimental_options(const std::string& experimental_options) {
+    experimental_options_ = experimental_options;
+  }
+
   void SetHostResolverRules(const std::string& host_resolver_rules);
 
   void set_ssl_key_log_file_name(const std::string& ssl_key_log_file_name) {
@@ -134,6 +138,7 @@
   bool quic_enabled_;
   std::string quic_user_agent_id_;
   std::string accept_language_;
+  std::string experimental_options_;
   std::string ssl_key_log_file_name_;
   URLRequestContextConfig::HttpCacheType http_cache_;
 
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm
index 651af1d..408fa0e 100644
--- a/components/cronet/ios/cronet_environment.mm
+++ b/components/cronet/ios/cronet_environment.mm
@@ -266,12 +266,9 @@
   static bool ssl_key_log_file_set = false;
   if (!ssl_key_log_file_set && !ssl_key_log_file_name_.empty()) {
     ssl_key_log_file_set = true;
-    base::FilePath ssl_key_log_file;
-    if (!PathService::Get(base::DIR_HOME, &ssl_key_log_file))
-      return;
-    net::SSLClientSocket::SetSSLKeyLogFile(
-        ssl_key_log_file.Append(ssl_key_log_file_name_),
-        file_thread_->task_runner());
+    base::FilePath ssl_key_log_file(ssl_key_log_file_name_);
+    net::SSLClientSocket::SetSSLKeyLogFile(ssl_key_log_file,
+                                           file_thread_->task_runner());
   }
 
   if (user_agent_partial_)
@@ -291,6 +288,8 @@
       cache_path.value();  // Storage path for http cache and cookie storage.
   context_config_builder.user_agent =
       user_agent_;  // User-Agent request header field.
+  context_config_builder.experimental_options =
+      experimental_options_;  // Set experimental Cronet options.
   context_config_builder.mock_cert_verifier = std::move(
       mock_cert_verifier_);  // MockCertVerifier to use for testing purposes.
   std::unique_ptr<URLRequestContextConfig> config =
diff --git a/components/cronet/ios/test/cronet_http_test.mm b/components/cronet/ios/test/cronet_http_test.mm
index 5818508..b83a8a1 100644
--- a/components/cronet/ios/test/cronet_http_test.mm
+++ b/components/cronet/ios/test/cronet_http_test.mm
@@ -174,6 +174,17 @@
   base::scoped_nsobject<TestDelegate> delegate_;
 };
 
+TEST_F(HttpTest, CreateFile) {
+  bool ssl_file_created = [[NSFileManager defaultManager]
+      fileExistsAtPath:[Cronet getNetLogPathForFile:@"SSLKEYLOGFILE"]];
+
+  [[NSFileManager defaultManager]
+      removeItemAtPath:[Cronet getNetLogPathForFile:@"SSLKEYLOGFILE"]
+                 error:nil];
+
+  EXPECT_TRUE(ssl_file_created);
+}
+
 TEST_F(HttpTest, NSURLSessionReceivesData) {
   NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
   __block BOOL block_used = NO;
diff --git a/components/cronet/ios/test/start_cronet.mm b/components/cronet/ios/test/start_cronet.mm
index ca3a8998..f7eee77 100644
--- a/components/cronet/ios/test/start_cronet.mm
+++ b/components/cronet/ios/test/start_cronet.mm
@@ -21,7 +21,12 @@
     [Cronet setHttp2Enabled:true];
     [Cronet setQuicEnabled:true];
     [Cronet setAcceptLanguages:@"en-US,en"];
-    [Cronet setSslKeyLogFileName:@"SSLKEYLOGFILE"];
+    [Cronet
+        setExperimentalOptions:
+            [NSString
+                stringWithFormat:@"{\"ssl_key_log_file\":\"%@\"}",
+                                 [Cronet
+                                     getNetLogPathForFile:@"SSLKEYLOGFILE"]]];
     [Cronet addQuicHint:@"test.example.com" port:443 altPort:443];
     [Cronet enableTestCertVerifierForTesting];
     [Cronet setHttpCacheType:CRNHttpCacheTypeDisabled];
diff --git a/components/drive/service/fake_drive_service.cc b/components/drive/service/fake_drive_service.cc
index 9f06ff8..662557b4 100644
--- a/components/drive/service/fake_drive_service.cc
+++ b/components/drive/service/fake_drive_service.cc
@@ -22,6 +22,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "components/drive/drive_api_util.h"
@@ -813,6 +814,7 @@
     const DownloadActionCallback& download_action_callback,
     const GetContentCallback& get_content_callback,
     const ProgressCallback& progress_callback) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!download_action_callback.is_null());
 
diff --git a/components/exo/wm_helper_ash.cc b/components/exo/wm_helper_ash.cc
index 4460612..a7ae496 100644
--- a/components/exo/wm_helper_ash.cc
+++ b/components/exo/wm_helper_ash.cc
@@ -13,7 +13,7 @@
 #include "base/memory/singleton.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/display/manager/display_manager.h"
-#include "ui/events/devices/device_data_manager.h"
+#include "ui/events/devices/input_device_manager.h"
 #include "ui/wm/public/activation_client.h"
 
 namespace exo {
@@ -31,9 +31,7 @@
   aura::client::FocusClient* focus_client =
       aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
   focus_client->AddObserver(this);
-  // TODO(crbug.com/709225): Mushrome doesn't have a DeviceDataManager.
-  if (ash::ShellPort::Get()->GetAshConfig() != ash::Config::MUS)
-    ui::DeviceDataManager::GetInstance()->AddObserver(this);
+  ui::InputDeviceManager::GetInstance()->AddObserver(this);
   ash::Shell::Get()->system_tray_notifier()->AddAccessibilityObserver(this);
 }
 
@@ -49,9 +47,7 @@
     ash::Shell::Get()->cursor_manager()->RemoveObserver(this);
   ash::Shell::Get()->activation_client()->RemoveObserver(this);
   ash::Shell::Get()->RemoveShellObserver(this);
-  // TODO(crbug.com/709225): Mushrome doesn't have a DeviceDataManager.
-  if (ash::ShellPort::Get()->GetAshConfig() != ash::Config::MUS)
-    ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
+  ui::InputDeviceManager::GetInstance()->RemoveObserver(this);
   ash::Shell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(this);
 }
 
diff --git a/components/payments/content/payment_response_helper.h b/components/payments/content/payment_response_helper.h
index fde039d7..83a66aa 100644
--- a/components/payments/content/payment_response_helper.h
+++ b/components/payments/content/payment_response_helper.h
@@ -20,7 +20,7 @@
 // before adding them to the PaymentResponse.
 // A helper class to facilitate the creation of the PaymentResponse.
 class PaymentResponseHelper : public PaymentInstrument::Delegate,
-                              AddressNormalizer::Delegate {
+                              public AddressNormalizer::Delegate {
  public:
   class Delegate {
    public:
diff --git a/components/payments/content/payment_response_helper_unittest.cc b/components/payments/content/payment_response_helper_unittest.cc
index 658ffac..e1c6f93 100644
--- a/components/payments/content/payment_response_helper_unittest.cc
+++ b/components/payments/content/payment_response_helper_unittest.cc
@@ -24,6 +24,8 @@
 
 namespace payments {
 
+namespace {
+
 class FakeAddressNormalizer : public AddressNormalizer {
  public:
   FakeAddressNormalizer() {}
@@ -53,6 +55,7 @@
       : personal_data_manager_(personal_data_manager),
         locale_("en-US"),
         last_committed_url_("https://shop.com") {}
+
   void ShowDialog(PaymentRequest* request) override {}
 
   void CloseDialog() override {}
@@ -95,6 +98,8 @@
   DISALLOW_COPY_AND_ASSIGN(FakePaymentRequestDelegate);
 };
 
+}  // namespace
+
 class PaymentResponseHelperTest : public testing::Test,
                                   public PaymentResponseHelper::Delegate {
  protected:
diff --git a/components/payments/core/autofill_payment_instrument.cc b/components/payments/core/autofill_payment_instrument.cc
index 04017e4..e74b389 100644
--- a/components/payments/core/autofill_payment_instrument.cc
+++ b/components/payments/core/autofill_payment_instrument.cc
@@ -7,9 +7,11 @@
 #include "base/json/json_writer.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_clock.h"
 #include "components/payments/core/basic_card_response.h"
@@ -50,6 +52,31 @@
   DCHECK(!delegate_);
   delegate_ = delegate;
 
+  // Get the billing address.
+  // TODO(crbug.com/709776): Make sure the billing address is valid before
+  // getting here.
+  if (!credit_card_.billing_address_id().empty()) {
+    autofill::AutofillProfile* billing_address =
+        autofill::PersonalDataManager::GetProfileFromProfilesByGUID(
+            credit_card_.billing_address_id(), billing_profiles_);
+    if (billing_address)
+      billing_address_ = *billing_address;
+  }
+
+  is_waiting_for_billing_address_normalization_ = true;
+  is_waiting_for_card_unmask_ = true;
+
+  // Start the normalization of the billing address.
+  // Use the country code from the profile if it is set, otherwise infer it
+  // from the |app_locale_|.
+  std::string country_code = base::UTF16ToUTF8(
+      billing_address_.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
+  if (!autofill::data_util::IsValidCountryCode(country_code)) {
+    country_code = autofill::AutofillCountry::CountryCodeForLocale(app_locale_);
+  }
+  payment_request_delegate_->GetAddressNormalizer()->StartAddressNormalization(
+      billing_address_, country_code, /*timeout_seconds=*/5, this);
+
   payment_request_delegate_->DoFullCardRequest(credit_card_,
                                                weak_ptr_factory_.GetWeakPtr());
 }
@@ -78,14 +105,11 @@
     const base::string16& cvc) {
   DCHECK(delegate_);
   credit_card_ = card;
-  std::unique_ptr<base::DictionaryValue> response_value =
-      payments::data_util::GetBasicCardResponseFromAutofillCreditCard(
-          credit_card_, cvc, billing_profiles_, app_locale_)
-          .ToDictionaryValue();
-  std::string stringified_details;
-  base::JSONWriter::Write(*response_value, &stringified_details);
-  delegate_->OnInstrumentDetailsReady(method_name(), stringified_details);
-  delegate_ = nullptr;
+  cvc_ = cvc;
+  is_waiting_for_card_unmask_ = false;
+
+  if (!is_waiting_for_billing_address_normalization_)
+    GenerateBasicCardResponse();
 }
 
 void AutofillPaymentInstrument::OnFullCardRequestFailed() {
@@ -93,4 +117,39 @@
   delegate_ = nullptr;
 }
 
+void AutofillPaymentInstrument::OnAddressNormalized(
+    const autofill::AutofillProfile& normalized_profile) {
+  DCHECK(is_waiting_for_billing_address_normalization_);
+
+  billing_address_ = normalized_profile;
+  is_waiting_for_billing_address_normalization_ = false;
+
+  if (!is_waiting_for_card_unmask_)
+    GenerateBasicCardResponse();
+}
+
+void AutofillPaymentInstrument::OnCouldNotNormalize(
+    const autofill::AutofillProfile& profile) {
+  // Since the phone number is formatted in either case, this profile should be
+  // used.
+  OnAddressNormalized(profile);
+}
+
+void AutofillPaymentInstrument::GenerateBasicCardResponse() {
+  DCHECK(!is_waiting_for_billing_address_normalization_);
+  DCHECK(!is_waiting_for_card_unmask_);
+  DCHECK(delegate_);
+
+  std::unique_ptr<base::DictionaryValue> response_value =
+      payments::data_util::GetBasicCardResponseFromAutofillCreditCard(
+          credit_card_, cvc_, billing_address_, app_locale_)
+          .ToDictionaryValue();
+  std::string stringified_details;
+  base::JSONWriter::Write(*response_value, &stringified_details);
+  delegate_->OnInstrumentDetailsReady(method_name(), stringified_details);
+
+  delegate_ = nullptr;
+  cvc_ = base::UTF8ToUTF16("");
+}
+
 }  // namespace payments
diff --git a/components/payments/core/autofill_payment_instrument.h b/components/payments/core/autofill_payment_instrument.h
index c0e49215..315e07e 100644
--- a/components/payments/core/autofill_payment_instrument.h
+++ b/components/payments/core/autofill_payment_instrument.h
@@ -10,14 +10,12 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/payments/full_card_request.h"
+#include "components/payments/core/address_normalizer.h"
 #include "components/payments/core/payment_instrument.h"
 
-namespace autofill {
-class AutofillProfile;
-}
-
 namespace payments {
 
 class PaymentRequestDelegate;
@@ -26,7 +24,8 @@
 // Request.
 class AutofillPaymentInstrument
     : public PaymentInstrument,
-      public autofill::payments::FullCardRequest::ResultDelegate {
+      public autofill::payments::FullCardRequest::ResultDelegate,
+      public AddressNormalizer::Delegate {
  public:
   // |billing_profiles| is owned by the caller and should outlive this object.
   // |payment_request_delegate| must outlive this object.
@@ -49,9 +48,17 @@
                                   const base::string16& cvc) override;
   void OnFullCardRequestFailed() override;
 
+  // AddressNormalizer::Delegate:
+  void OnAddressNormalized(
+      const autofill::AutofillProfile& normalized_profile) override;
+  void OnCouldNotNormalize(const autofill::AutofillProfile& profile) override;
+
   autofill::CreditCard* credit_card() { return &credit_card_; }
 
  private:
+  // Generates the basic card response and sends it to the delegate.
+  void GenerateBasicCardResponse();
+
   // A copy of the card is owned by this object.
   autofill::CreditCard credit_card_;
   // Not owned by this object, should outlive this.
@@ -61,6 +68,12 @@
 
   PaymentInstrument::Delegate* delegate_;
   PaymentRequestDelegate* payment_request_delegate_;
+  autofill::AutofillProfile billing_address_;
+
+  base::string16 cvc_;
+
+  bool is_waiting_for_card_unmask_;
+  bool is_waiting_for_billing_address_normalization_;
 
   base::WeakPtrFactory<AutofillPaymentInstrument> weak_ptr_factory_;
 
diff --git a/components/payments/core/autofill_payment_instrument_unittest.cc b/components/payments/core/autofill_payment_instrument_unittest.cc
index 622a4e9..6735be8 100644
--- a/components/payments/core/autofill_payment_instrument_unittest.cc
+++ b/components/payments/core/autofill_payment_instrument_unittest.cc
@@ -10,12 +10,134 @@
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/credit_card.h"
+#include "components/payments/core/address_normalizer.h"
+#include "components/payments/core/payment_request_delegate.h"
 #include "components/strings/grit/components_strings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace payments {
 
+namespace {
+
+class FakePaymentInstrumentDelegate : public PaymentInstrument::Delegate {
+ public:
+  FakePaymentInstrumentDelegate() {}
+
+  void OnInstrumentDetailsReady(
+      const std::string& method_name,
+      const std::string& stringified_details) override {
+    on_instrument_details_ready_called_ = true;
+  }
+
+  void OnInstrumentDetailsError() override {
+    on_instrument_details_error_called_ = true;
+  }
+
+  bool WasOnInstrumentDetailsReadyCalled() {
+    return on_instrument_details_ready_called_;
+  }
+
+  bool WasOnInstrumentDetailsErrorCalled() {
+    return on_instrument_details_error_called_;
+  }
+
+ private:
+  bool on_instrument_details_ready_called_ = false;
+  bool on_instrument_details_error_called_ = false;
+};
+
+class FakeAddressNormalizer : public AddressNormalizer {
+ public:
+  FakeAddressNormalizer() {}
+
+  void LoadRulesForRegion(const std::string& region_code) override {}
+
+  bool AreRulesLoadedForRegion(const std::string& region_code) override {
+    return true;
+  }
+
+  void StartAddressNormalization(
+      const autofill::AutofillProfile& profile,
+      const std::string& region_code,
+      int timeout_seconds,
+      AddressNormalizer::Delegate* requester) override {
+    profile_ = profile;
+    requester_ = requester;
+  }
+
+  void OnAddressValidationRulesLoaded(const std::string& region_code,
+                                      bool success) override {}
+
+  void CompleteAddressNormalization() {
+    requester_->OnAddressNormalized(profile_);
+  }
+
+ private:
+  autofill::AutofillProfile profile_;
+  AddressNormalizer::Delegate* requester_;
+};
+
+class FakePaymentRequestDelegate : public PaymentRequestDelegate {
+ public:
+  FakePaymentRequestDelegate()
+      : locale_("en-US"), last_committed_url_("https://shop.com") {}
+  void ShowDialog(PaymentRequest* request) override {}
+
+  void CloseDialog() override {}
+
+  void ShowErrorMessage() override {}
+
+  autofill::PersonalDataManager* GetPersonalDataManager() override {
+    return nullptr;
+  }
+
+  const std::string& GetApplicationLocale() const override { return locale_; }
+
+  bool IsIncognito() const override { return false; }
+
+  bool IsSslCertificateValid() override { return true; }
+
+  const GURL& GetLastCommittedURL() const override {
+    return last_committed_url_;
+  }
+
+  void DoFullCardRequest(
+      const autofill::CreditCard& credit_card,
+      base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
+          result_delegate) override {
+    full_card_request_card_ = credit_card;
+    full_card_result_delegate_ = result_delegate;
+  }
+
+  AddressNormalizer* GetAddressNormalizer() override {
+    return &address_normalizer_;
+  }
+
+  FakeAddressNormalizer* GetTestAddressNormalizer() {
+    return &address_normalizer_;
+  }
+
+  void CompleteFullCardRequest() {
+    full_card_result_delegate_->OnFullCardRequestSucceeded(
+        full_card_request_card_, base::ASCIIToUTF16("123"));
+  }
+
+  autofill::RegionDataLoader* GetRegionDataLoader() override { return nullptr; }
+
+ private:
+  std::string locale_;
+  const GURL last_committed_url_;
+  FakeAddressNormalizer address_normalizer_;
+
+  autofill::CreditCard full_card_request_card_;
+  base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
+      full_card_result_delegate_;
+  DISALLOW_COPY_AND_ASSIGN(FakePaymentRequestDelegate);
+};
+
+}  // namespace
+
 class AutofillPaymentInstrumentTest : public testing::Test {
  protected:
   AutofillPaymentInstrumentTest()
@@ -157,4 +279,56 @@
   EXPECT_FALSE(instrument.IsValidForCanMakePayment());
 }
 
+// Tests that the autofill instrument only calls OnInstrumentDetailsReady when
+// the billing address has been normalized and the card has been unmasked.
+TEST_F(AutofillPaymentInstrumentTest,
+       InvokePaymentApp_NormalizationBeforeUnmask) {
+  FakePaymentRequestDelegate delegate;
+
+  autofill::CreditCard& card = local_credit_card();
+  card.SetNumber(base::ASCIIToUTF16(""));
+  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+                                       "en-US", &delegate);
+
+  FakePaymentInstrumentDelegate instrument_delegate;
+
+  instrument.InvokePaymentApp(&instrument_delegate);
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsReadyCalled());
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsErrorCalled());
+
+  delegate.GetTestAddressNormalizer()->CompleteAddressNormalization();
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsReadyCalled());
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsErrorCalled());
+
+  delegate.CompleteFullCardRequest();
+  EXPECT_TRUE(instrument_delegate.WasOnInstrumentDetailsReadyCalled());
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsErrorCalled());
+}
+
+// Tests that the autofill instrument only calls OnInstrumentDetailsReady when
+// the billing address has been normalized and the card has been unmasked.
+TEST_F(AutofillPaymentInstrumentTest,
+       InvokePaymentApp_UnmaskBeforeNormalization) {
+  FakePaymentRequestDelegate delegate;
+
+  autofill::CreditCard& card = local_credit_card();
+  card.SetNumber(base::ASCIIToUTF16(""));
+  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
+                                       "en-US", &delegate);
+
+  FakePaymentInstrumentDelegate instrument_delegate;
+
+  instrument.InvokePaymentApp(&instrument_delegate);
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsReadyCalled());
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsErrorCalled());
+
+  delegate.CompleteFullCardRequest();
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsReadyCalled());
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsErrorCalled());
+
+  delegate.GetTestAddressNormalizer()->CompleteAddressNormalization();
+  EXPECT_TRUE(instrument_delegate.WasOnInstrumentDetailsReadyCalled());
+  EXPECT_FALSE(instrument_delegate.WasOnInstrumentDetailsErrorCalled());
+}
+
 }  // namespace payments
diff --git a/components/payments/core/payment_request_data_util.cc b/components/payments/core/payment_request_data_util.cc
index 596a20e8..3fd13c9 100644
--- a/components/payments/core/payment_request_data_util.cc
+++ b/components/payments/core/payment_request_data_util.cc
@@ -71,7 +71,7 @@
 BasicCardResponse GetBasicCardResponseFromAutofillCreditCard(
     const autofill::CreditCard& card,
     const base::string16& cvc,
-    const std::vector<autofill::AutofillProfile*>& billing_profiles,
+    const autofill::AutofillProfile& billing_profile,
     const std::string& app_locale) {
   BasicCardResponse response;
   response.cardholder_name = card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL);
@@ -81,16 +81,8 @@
       card.GetRawInfo(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR);
   response.card_security_code = cvc;
 
-  // TODO(crbug.com/602666): Ensure we reach here only if the card has a billing
-  // address. Then add DCHECK(!card->billing_address_id().empty()).
-  if (!card.billing_address_id().empty()) {
-    const autofill::AutofillProfile* billing_address =
-        autofill::PersonalDataManager::GetProfileFromProfilesByGUID(
-            card.billing_address_id(), billing_profiles);
-    DCHECK(billing_address);
-    response.billing_address =
-        GetPaymentAddressFromAutofillProfile(*billing_address, app_locale);
-  }
+  response.billing_address =
+      GetPaymentAddressFromAutofillProfile(billing_profile, app_locale);
 
   return response;
 }
diff --git a/components/payments/core/payment_request_data_util.h b/components/payments/core/payment_request_data_util.h
index e69807fb..984fc8b 100644
--- a/components/payments/core/payment_request_data_util.h
+++ b/components/payments/core/payment_request_data_util.h
@@ -35,7 +35,7 @@
 BasicCardResponse GetBasicCardResponseFromAutofillCreditCard(
     const autofill::CreditCard& card,
     const base::string16& cvc,
-    const std::vector<autofill::AutofillProfile*>& billing_profiles,
+    const autofill::AutofillProfile& billing_profile,
     const std::string& app_locale);
 
 // Parse the supported card networks from supportedMethods and  "basic-card"'s
diff --git a/components/payments/core/payment_request_data_util_unittest.cc b/components/payments/core/payment_request_data_util_unittest.cc
index 5ad7e10..df86baee 100644
--- a/components/payments/core/payment_request_data_util_unittest.cc
+++ b/components/payments/core/payment_request_data_util_unittest.cc
@@ -49,8 +49,7 @@
   card.set_billing_address_id(address.guid());
   std::unique_ptr<base::DictionaryValue> response_value =
       payments::data_util::GetBasicCardResponseFromAutofillCreditCard(
-          card, base::ASCIIToUTF16("123"),
-          std::vector<autofill::AutofillProfile*>{&address}, "en-US")
+          card, base::ASCIIToUTF16("123"), address, "en-US")
           .ToDictionaryValue();
   std::string json_response;
   base::JSONWriter::Write(*response_value, &json_response);
diff --git a/components/security_interstitials/content/security_interstitial_page.cc b/components/security_interstitials/content/security_interstitial_page.cc
index f0733f0..3b64147 100644
--- a/components/security_interstitials/content/security_interstitial_page.cc
+++ b/components/security_interstitials/content/security_interstitial_page.cc
@@ -14,7 +14,6 @@
 #include "components/safe_browsing_db/safe_browsing_prefs.h"
 #include "components/security_interstitials/content/security_interstitial_controller_client.h"
 #include "components/security_interstitials/core/common_string_util.h"
-#include "components/security_interstitials/core/metrics_helper.h"
 #include "content/public/browser/interstitial_page.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents.h"
@@ -93,11 +92,6 @@
   return controller_.get();
 }
 
-security_interstitials::MetricsHelper*
-SecurityInterstitialPage::metrics_helper() {
-  return controller_->metrics_helper();
-}
-
 void SecurityInterstitialPage::UpdateMetricsAfterSecurityInterstitial() {
   if (controller_->GetPrefService()) {
     safe_browsing::UpdateMetricsAfterSecurityInterstitial(
diff --git a/components/security_interstitials/content/security_interstitial_page.h b/components/security_interstitials/content/security_interstitial_page.h
index 1b24add..60fa290 100644
--- a/components/security_interstitials/content/security_interstitial_page.h
+++ b/components/security_interstitials/content/security_interstitial_page.h
@@ -22,7 +22,6 @@
 }
 
 namespace security_interstitials {
-class MetricsHelper;
 class SecurityInterstitialControllerClient;
 
 class SecurityInterstitialPage : public content::InterstitialPageDelegate {
@@ -66,8 +65,6 @@
 
   SecurityInterstitialControllerClient* controller();
 
-  MetricsHelper* metrics_helper();
-
   // Update metrics when the interstitial is closed.
   void UpdateMetricsAfterSecurityInterstitial();
 
@@ -90,8 +87,6 @@
   // For subclasses that don't have their own ControllerClients yet.
   std::unique_ptr<SecurityInterstitialControllerClient> controller_;
 
-  std::unique_ptr<MetricsHelper> metrics_helper_;
-
   DISALLOW_COPY_AND_ASSIGN(SecurityInterstitialPage);
 };
 
diff --git a/components/subresource_filter/core/common/test_ruleset_creator.cc b/components/subresource_filter/core/common/test_ruleset_creator.cc
index 408a984..939dff3 100644
--- a/components/subresource_filter/core/common/test_ruleset_creator.cc
+++ b/components/subresource_filter/core/common/test_ruleset_creator.cc
@@ -8,7 +8,9 @@
 
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "components/subresource_filter/core/common/indexed_ruleset.h"
 #include "components/subresource_filter/core/common/proto/rules.pb.h"
 #include "components/subresource_filter/core/common/test_ruleset_utils.h"
@@ -25,6 +27,7 @@
 
 void WriteRulesetContents(const std::vector<uint8_t>& contents,
                           base::FilePath path) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   int ruleset_size_as_int = base::checked_cast<int>(contents.size());
   int num_bytes_written =
       base::WriteFile(path, reinterpret_cast<const char*>(contents.data()),
@@ -65,6 +68,7 @@
 
 // static
 base::File TestRuleset::Open(const TestRuleset& ruleset) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::File file;
   file.Initialize(ruleset.path, base::File::FLAG_OPEN | base::File::FLAG_READ |
                                     base::File::FLAG_SHARE_DELETE);
@@ -105,8 +109,13 @@
 
 // TestRulesetCreator ----------------------------------------------------------
 
-TestRulesetCreator::TestRulesetCreator() = default;
-TestRulesetCreator::~TestRulesetCreator() = default;
+TestRulesetCreator::TestRulesetCreator()
+    : scoped_temp_dir_(base::MakeUnique<base::ScopedTempDir>()) {}
+
+TestRulesetCreator::~TestRulesetCreator() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  scoped_temp_dir_.reset();
+}
 
 void TestRulesetCreator::CreateRulesetToDisallowURLsWithPathSuffix(
     base::StringPiece suffix,
@@ -161,9 +170,10 @@
 
 void TestRulesetCreator::GetUniqueTemporaryPath(base::FilePath* path) {
   DCHECK(path);
-  ASSERT_TRUE(scoped_temp_dir_.IsValid() ||
-              scoped_temp_dir_.CreateUniqueTempDir());
-  *path = scoped_temp_dir_.GetPath().AppendASCII(
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  ASSERT_TRUE(scoped_temp_dir_->IsValid() ||
+              scoped_temp_dir_->CreateUniqueTempDir());
+  *path = scoped_temp_dir_->GetPath().AppendASCII(
       base::IntToString(next_unique_file_suffix++));
 }
 
diff --git a/components/subresource_filter/core/common/test_ruleset_creator.h b/components/subresource_filter/core/common/test_ruleset_creator.h
index 88338f6..cb07526 100644
--- a/components/subresource_filter/core/common/test_ruleset_creator.h
+++ b/components/subresource_filter/core/common/test_ruleset_creator.h
@@ -98,7 +98,7 @@
   void CreateTestRulesetFromContents(std::vector<uint8_t> ruleset_contents,
                                      TestRuleset* ruleset);
 
-  base::ScopedTempDir scoped_temp_dir_;
+  std::unique_ptr<base::ScopedTempDir> scoped_temp_dir_;
   int next_unique_file_suffix = 1;
 
   DISALLOW_COPY_AND_ASSIGN(TestRulesetCreator);
diff --git a/components/webcrypto/algorithms/hkdf.cc b/components/webcrypto/algorithms/hkdf.cc
index f3381100..be01683 100644
--- a/components/webcrypto/algorithms/hkdf.cc
+++ b/components/webcrypto/algorithms/hkdf.cc
@@ -71,6 +71,9 @@
     if (!has_optional_length_bits)
       return Status::ErrorHkdfDeriveBitsLengthNotSpecified();
 
+    if (optional_length_bits % 8)
+      return Status::ErrorHkdfLengthNotWholeByte();
+
     const blink::WebCryptoHkdfParams* params = algorithm.HkdfParams();
 
     const EVP_MD* digest_algorithm = GetDigest(params->GetHash());
@@ -78,7 +81,7 @@
       return Status::ErrorUnsupported();
 
     // Size output to fit length
-    unsigned int derived_bytes_len = NumBitsToBytes(optional_length_bits);
+    unsigned int derived_bytes_len = optional_length_bits / 8;
     derived_bytes->resize(derived_bytes_len);
 
     // Algorithm dispatch checks that the algorithm in |base_key| matches
@@ -96,7 +99,6 @@
       return Status::OperationError();
     }
 
-    TruncateToBitLength(optional_length_bits, derived_bytes);
     return Status::Success();
   }
 
diff --git a/components/webcrypto/status.cc b/components/webcrypto/status.cc
index 7dcbb93c..3645279c 100644
--- a/components/webcrypto/status.cc
+++ b/components/webcrypto/status.cc
@@ -331,6 +331,11 @@
                 "The length provided for HKDF is too large.");
 }
 
+Status Status::ErrorHkdfLengthNotWholeByte() {
+  return Status(blink::kWebCryptoErrorTypeOperation,
+                "The length provided for HKDF is not a multiple of 8 bits.");
+}
+
 Status Status::ErrorHkdfDeriveBitsLengthNotSpecified() {
   // TODO(nharper): The spec might change so that an OperationError should be
   // thrown here instead of a TypeError.
diff --git a/components/webcrypto/status.h b/components/webcrypto/status.h
index 5933623..2c7dfa7 100644
--- a/components/webcrypto/status.h
+++ b/components/webcrypto/status.h
@@ -258,6 +258,9 @@
   // The requested length for HKDF was too large.
   static Status ErrorHkdfLengthTooLong();
 
+  // The length to HKDF's deriveBits() was not a multiple of 8.
+  static Status ErrorHkdfLengthNotWholeByte();
+
   // No length parameter was provided for HKDF's Derive Bits operation.
   static Status ErrorHkdfDeriveBitsLengthNotSpecified();
 
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index dffa556..2016a617 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -603,7 +603,6 @@
     crypto::EarlySetupForNSSInit();
 #endif
 
-    ui::RegisterPathProvider();
     RegisterPathProvider();
     RegisterContentSchemes(true);
 
diff --git a/content/browser/child_process_launcher_helper.cc b/content/browser/child_process_launcher_helper.cc
index 9aa83459..5d6e9aa 100644
--- a/content/browser/child_process_launcher_helper.cc
+++ b/content/browser/child_process_launcher_helper.cc
@@ -104,30 +104,27 @@
   AfterLaunchOnLauncherThread(process, options);
 
   if (is_synchronous_launch) {
-    PostLaunchOnLauncherThread(std::move(process), launch_result, false);
+    PostLaunchOnLauncherThread(std::move(process), launch_result);
   }
 }
 
 void ChildProcessLauncherHelper::PostLaunchOnLauncherThread(
     ChildProcessLauncherHelper::Process process,
-    int launch_result,
-    bool post_launch_on_client_thread_called) {
+    int launch_result) {
   // Release the client handle now that the process has been started (the pipe
   // may not signal when the process dies otherwise and we would not detect the
   // child process died).
   mojo_client_handle_.reset();
 
   if (process.process.IsValid()) {
-    RecordHistogramsOnLauncherThread(
-        base::TimeTicks::Now() - begin_launch_time_);
+    RecordHistogramsOnLauncherThread(base::TimeTicks::Now() -
+                                     begin_launch_time_);
   }
 
-  if (!post_launch_on_client_thread_called) {
-    BrowserThread::PostTask(
-        client_thread_id_, FROM_HERE,
-        base::Bind(&ChildProcessLauncherHelper::PostLaunchOnClientThread,
-            this, base::Passed(&process), launch_result));
-  }
+  BrowserThread::PostTask(
+      client_thread_id_, FROM_HERE,
+      base::Bind(&ChildProcessLauncherHelper::PostLaunchOnClientThread, this,
+                 base::Passed(&process), launch_result));
 }
 
 void ChildProcessLauncherHelper::PostLaunchOnClientThread(
diff --git a/content/browser/child_process_launcher_helper.h b/content/browser/child_process_launcher_helper.h
index 6c8ed7d..7132956 100644
--- a/content/browser/child_process_launcher_helper.h
+++ b/content/browser/child_process_launcher_helper.h
@@ -122,14 +122,10 @@
       const base::LaunchOptions& options);
 
   // Called once the process has been created, successfully or not.
-  // If |post_launch_on_client_thread_called| is false,
-  // this calls PostLaunchOnClientThread on the client thread.
   void PostLaunchOnLauncherThread(ChildProcessLauncherHelper::Process process,
-                                  int launch_result,
-                                  bool post_launch_on_client_thread_called);
+                                  int launch_result);
 
-  // Note that this could be called before PostLaunchOnLauncherThread() is
-  // called.
+  // Posted by PostLaunchOnLauncherThread onto the client thread.
   void PostLaunchOnClientThread(ChildProcessLauncherHelper::Process process,
                                 int error_code);
 
diff --git a/content/browser/child_process_launcher_helper_android.cc b/content/browser/child_process_launcher_helper_android.cc
index b498bb4f..fafbc5d 100644
--- a/content/browser/child_process_launcher_helper_android.cc
+++ b/content/browser/child_process_launcher_helper_android.cc
@@ -199,14 +199,14 @@
   return base::File(base::android::OpenApkAsset(path.value(), region));
 }
 
-// Called from ChildProcessLauncher.java when the ChildProcess was
-// started.
+// Called from ChildProcessLauncher.java when the ChildProcess was started.
 // |handle| is the processID of the child process as originated in Java, 0 if
 // the ChildProcess could not be created.
 void ChildProcessLauncherHelper::OnChildProcessStarted(
     JNIEnv*,
     const base::android::JavaParamRef<jobject>& obj,
     jint handle) {
+  DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
   scoped_refptr<ChildProcessLauncherHelper> ref(this);
   Release();  // Balances with LaunchProcessOnLauncherThread.
 
@@ -214,28 +214,9 @@
                           ? LAUNCH_RESULT_FAILURE
                           : LAUNCH_RESULT_SUCCESS;
 
-  // TODO(jcivelli): Remove this by defining better what happens on what thread
-  // in the corresponding Java code.
   ChildProcessLauncherHelper::Process process;
   process.process = base::Process(handle);
-  if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
-    PostLaunchOnLauncherThread(std::move(process), launch_result,
-                               false);  // post_launch_on_client_thread_called
-    return;
-  }
-
-  bool on_client_thread = BrowserThread::CurrentlyOn(
-      static_cast<BrowserThread::ID>(client_thread_id()));
-  BrowserThread::PostTask(
-      BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
-      base::Bind(&ChildProcessLauncherHelper::PostLaunchOnLauncherThread, this,
-                 base::Passed(std::move(process)), launch_result,
-                 on_client_thread));
-  if (on_client_thread) {
-    ChildProcessLauncherHelper::Process process;
-    process.process = base::Process(handle);
-    PostLaunchOnClientThread(std::move(process), launch_result);
-  }
+  PostLaunchOnLauncherThread(std::move(process), launch_result);
 }
 
 // static
diff --git a/content/browser/download/download_file_impl.cc b/content/browser/download/download_file_impl.cc
index dd2cb85..b17e42bb 100644
--- a/content/browser/download/download_file_impl.cc
+++ b/content/browser/download/download_file_impl.cc
@@ -476,7 +476,7 @@
     source_stream->stream_reader()->RegisterCallback(base::Closure());
     source_stream->set_finished(true);
     if (should_terminate)
-      CancelRequestOnUIThread(source_stream->offset());
+      CancelRequest(source_stream->offset());
     if (source_stream->length() == DownloadSaveInfo::kLengthFullContent) {
       SetPotentialFileLength(source_stream->offset() +
                              source_stream->bytes_written());
@@ -650,7 +650,7 @@
           DCHECK_EQ(stream.second->bytes_written(), 0);
           stream.second->stream_reader()->RegisterCallback(base::Closure());
           stream.second->set_finished(true);
-          CancelRequestOnUIThread(stream.second->offset());
+          CancelRequest(stream.second->offset());
           num_active_streams_--;
         }
       }
@@ -690,7 +690,7 @@
   return ret;
 }
 
-void DownloadFileImpl::CancelRequestOnUIThread(int64_t offset) {
+void DownloadFileImpl::CancelRequest(int64_t offset) {
   if (!cancel_request_callback_.is_null()) {
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                             base::Bind(cancel_request_callback_, offset));
diff --git a/content/browser/download/download_file_impl.h b/content/browser/download/download_file_impl.h
index 5376b33..23d6ce58 100644
--- a/content/browser/download/download_file_impl.h
+++ b/content/browser/download/download_file_impl.h
@@ -231,7 +231,7 @@
   SourceStream* FindPrecedingNeighbor(SourceStream* source_stream);
 
   // See |cancel_request_callback_|.
-  void CancelRequestOnUIThread(int64_t offset);
+  void CancelRequest(int64_t offset);
 
   // Print the internal states for debugging.
   void DebugStates() const;
diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc
index 11b943e..808926b 100644
--- a/content/browser/download/download_file_unittest.cc
+++ b/content/browser/download/download_file_unittest.cc
@@ -989,7 +989,7 @@
   DestroyDownloadFile(0, false);
 }
 
-//  Activate and deplete one stream, later add the second stream.
+// Activate and deplete one stream, later add the second stream.
 TEST_F(DownloadFileTest, MutipleStreamsFirstStreamWriteAllData) {
   int64_t stream_0_length = GetBuffersLength(kTestData8, 4);
 
diff --git a/content/browser/download/download_job.cc b/content/browser/download/download_job.cc
index cbdf35f..cd7f619 100644
--- a/content/browser/download/download_job.cc
+++ b/content/browser/download/download_job.cc
@@ -62,7 +62,9 @@
   }
 }
 
-void DownloadJob::CancelRequestWithOffset(int64_t offset) {}
+void DownloadJob::CancelRequestWithOffset(int64_t offset) {
+  NOTREACHED();
+}
 
 bool DownloadJob::IsParallelizable() const {
   return false;
diff --git a/content/browser/download/download_job.h b/content/browser/download/download_job.h
index 2f12b18b..cae4f1ab 100644
--- a/content/browser/download/download_job.h
+++ b/content/browser/download/download_job.h
@@ -46,6 +46,7 @@
 
   // Cancel a particular request starts from |offset|, while the download is not
   // canceled. Used in parallel download.
+  // TODO(xingliu): Remove this function if download job owns download file.
   virtual void CancelRequestWithOffset(int64_t offset);
 
  protected:
diff --git a/content/browser/download/parallel_download_job.cc b/content/browser/download/parallel_download_job.cc
index b6e5cae5..5f282c3 100644
--- a/content/browser/download/parallel_download_job.cc
+++ b/content/browser/download/parallel_download_job.cc
@@ -100,8 +100,8 @@
   }
 
   auto it = workers_.find(offset);
-  if (it != workers_.end())
-    it->second->Cancel();
+  DCHECK(it != workers_.end());
+  it->second->Cancel();
 }
 
 void ParallelDownloadJob::BuildParallelRequestAfterDelay() {
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 40b9c06..e42f92e 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -3331,17 +3331,14 @@
 
 void RenderFrameHostImpl::GetInterfaceProvider(
     service_manager::mojom::InterfaceProviderRequest interfaces) {
-  service_manager::InterfaceProviderSpec browser_spec, renderer_spec;
-  // TODO(beng): CHECK these return true.
-  service_manager::GetInterfaceProviderSpec(
-      mojom::kNavigation_FrameSpec, browser_info_.interface_provider_specs,
-      &browser_spec);
-  service_manager::GetInterfaceProviderSpec(
-      mojom::kNavigation_FrameSpec, renderer_info_.interface_provider_specs,
-      &renderer_spec);
-  interface_registry_->Bind(std::move(interfaces),
-                            browser_info_.identity, browser_spec,
-                            renderer_info_.identity, renderer_spec);
+  service_manager::Identity child_identity = GetProcess()->GetChildIdentity();
+  child_identity.set_user_id(
+      BrowserContext::GetServiceUserIdFor(GetProcess()->GetBrowserContext()));
+  service_manager::Connector* connector =
+      BrowserContext::GetConnectorFor(GetProcess()->GetBrowserContext());
+  connector->FilterInterfaces(
+      mojom::kNavigation_FrameSpec, child_identity, std::move(interfaces),
+      interface_provider_bindings_.CreateInterfacePtrAndBind(this));
 }
 
 #if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
@@ -3641,6 +3638,15 @@
   media_interface_proxy_.reset();
 }
 
+void RenderFrameHostImpl::GetInterface(
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle interface_pipe) {
+  if (interface_registry_.get()) {
+    interface_registry_->BindInterface(interface_name,
+                                       std::move(interface_pipe));
+  }
+}
+
 std::unique_ptr<NavigationHandleImpl>
 RenderFrameHostImpl::TakeNavigationHandleForCommit(
     const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index b2e398f..c28f7d5 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -43,6 +43,7 @@
 #include "content/public/common/javascript_dialog_type.h"
 #include "content/public/common/previews_state.h"
 #include "media/mojo/interfaces/interface_factory.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/http/http_response_headers.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
@@ -117,6 +118,7 @@
       public SiteInstanceImpl::Observer,
       public NON_EXPORTED_BASE(
           service_manager::InterfaceFactory<media::mojom::InterfaceFactory>),
+      public NON_EXPORTED_BASE(service_manager::mojom::InterfaceProvider),
       public CSPContext {
  public:
   using AXTreeSnapshotCallback =
@@ -894,6 +896,10 @@
   // Callback for connection error on the media::mojom::InterfaceFactory client.
   void OnMediaInterfaceFactoryConnectionError();
 
+  // service_manager::mojom::InterfaceProvider:
+  void GetInterface(const std::string& interface_name,
+                    mojo::ScopedMessagePipeHandle interface_pipe) override;
+
   // Allows tests to disable the swapout event timer to simulate bugs that
   // happen before it fires (to avoid flakiness).
   void DisableSwapOutTimerForTesting();
@@ -1184,6 +1190,9 @@
   std::unique_ptr<service_manager::InterfaceRegistry> java_interface_registry_;
 #endif
 
+  mojo::BindingSet<service_manager::mojom::InterfaceProvider>
+      interface_provider_bindings_;
+
   // NOTE: This must be the last member.
   base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
 
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
index 78a05f95..655418b 100644
--- a/content/browser/media/capture/desktop_capture_device.cc
+++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -18,6 +18,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
@@ -435,6 +436,7 @@
 
 void DesktopCaptureDevice::StopAndDeAllocate() {
   if (core_) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     thread_.task_runner()->DeleteSoon(FROM_HERE, core_.release());
     thread_.Stop();
   }
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 04f3a54..553ca5e 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1455,6 +1455,11 @@
   child_connection_->BindInterface(interface_name, std::move(interface_pipe));
 }
 
+const service_manager::Identity& RenderProcessHostImpl::GetChildIdentity()
+    const {
+  return child_connection_->child_identity();
+}
+
 std::unique_ptr<base::SharedPersistentMemoryAllocator>
 RenderProcessHostImpl::TakeMetricsAllocator() {
   return std::move(metrics_allocator_);
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 72df6663..fce8dc8f 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -169,6 +169,7 @@
   void ResumeDeferredNavigation(const GlobalRequestID& request_id) override;
   void BindInterface(const std::string& interface_name,
                      mojo::ScopedMessagePipeHandle interface_pipe) override;
+  const service_manager::Identity& GetChildIdentity() const override;
   std::unique_ptr<base::SharedPersistentMemoryAllocator> TakeMetricsAllocator()
       override;
   const base::TimeTicks& GetInitTimeForNavigationMetrics() const override;
diff --git a/content/public/android/java/src/org/chromium/content/browser/BindingManager.java b/content/public/android/java/src/org/chromium/content/browser/BindingManager.java
index dfa3581..3f38056 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BindingManager.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BindingManager.java
@@ -48,7 +48,7 @@
      * binding. It's safe to call it multiple times, only the first call matters.
      * @param pid handle of the service process
      */
-    void determinedVisibility(int pid);
+    void onDeterminedVisibility(int pid);
 
     /**
      * Called when the embedding application is sent to background. We want to maintain a strong
diff --git a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
index 81ee555..583a76c 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
@@ -9,7 +9,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.Build;
-import android.os.Handler;
 import android.util.LruCache;
 import android.util.SparseArray;
 
@@ -20,12 +19,10 @@
 import org.chromium.base.metrics.RecordHistogram;
 
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.annotation.concurrent.GuardedBy;
 
 /**
  * Manages oom bindings used to bound child services.
+ * This object must only be accessed from the launcher thread.
  */
 class BindingManagerImpl implements BindingManager {
     private static final String TAG = "cr.BindingManager";
@@ -48,38 +45,46 @@
 
     private static class ModerateBindingPool
             extends LruCache<Integer, ManagedConnection> implements ComponentCallbacks2 {
-        private final Object mDelayedClearerLock = new Object();
-
-        @GuardedBy("mDelayedClearerLock")
         private Runnable mDelayedClearer;
 
-        private final Handler mHandler = new Handler(ThreadUtils.getUiThreadLooper());
-
         public ModerateBindingPool(int maxSize) {
             super(maxSize);
         }
 
         @Override
-        public void onTrimMemory(int level) {
-            Log.i(TAG, "onTrimMemory: level=%d, size=%d", level, size());
-            if (size() > 0) {
-                if (level <= TRIM_MEMORY_RUNNING_MODERATE) {
-                    reduce(MODERATE_BINDING_LOW_REDUCE_RATIO);
-                } else if (level <= TRIM_MEMORY_RUNNING_LOW) {
-                    reduce(MODERATE_BINDING_HIGH_REDUCE_RATIO);
-                } else if (level == TRIM_MEMORY_UI_HIDDEN) {
-                    // This will be handled by |mDelayedClearer|.
-                    return;
-                } else {
-                    evictAll();
+        public void onTrimMemory(final int level) {
+            ThreadUtils.assertOnUiThread();
+            LauncherThread.post(new Runnable() {
+                @Override
+                public void run() {
+                    Log.i(TAG, "onTrimMemory: level=%d, size=%d", level, size());
+                    if (size() <= 0) {
+                        return;
+                    }
+                    if (level <= TRIM_MEMORY_RUNNING_MODERATE) {
+                        reduce(MODERATE_BINDING_LOW_REDUCE_RATIO);
+                    } else if (level <= TRIM_MEMORY_RUNNING_LOW) {
+                        reduce(MODERATE_BINDING_HIGH_REDUCE_RATIO);
+                    } else if (level == TRIM_MEMORY_UI_HIDDEN) {
+                        // This will be handled by |mDelayedClearer|.
+                        return;
+                    } else {
+                        evictAll();
+                    }
                 }
-            }
+            });
         }
 
         @Override
         public void onLowMemory() {
-            Log.i(TAG, "onLowMemory: evict %d bindings", size());
-            evictAll();
+            ThreadUtils.assertOnUiThread();
+            LauncherThread.post(new Runnable() {
+                @Override
+                public void run() {
+                    Log.i(TAG, "onLowMemory: evict %d bindings", size());
+                    evictAll();
+                }
+            });
         }
 
         @Override
@@ -135,37 +140,31 @@
 
         void onSentToBackground(final boolean onTesting) {
             if (size() == 0) return;
-            synchronized (mDelayedClearerLock) {
-                mDelayedClearer = new Runnable() {
-                    @Override
-                    public void run() {
-                        synchronized (mDelayedClearerLock) {
-                            if (mDelayedClearer == null) return;
-                            mDelayedClearer = null;
-                        }
-                        Log.i(TAG, "Release moderate connections: %d", size());
-                        if (!onTesting) {
-                            RecordHistogram.recordCountHistogram(
-                                    "Android.ModerateBindingCount", size());
-                        }
-                        evictAll();
+            mDelayedClearer = new Runnable() {
+                @Override
+                public void run() {
+                    if (mDelayedClearer == null) return;
+                    mDelayedClearer = null;
+                    Log.i(TAG, "Release moderate connections: %d", size());
+                    if (!onTesting) {
+                        RecordHistogram.recordCountHistogram(
+                                "Android.ModerateBindingCount", size());
                     }
-                };
-                mHandler.postDelayed(mDelayedClearer, MODERATE_BINDING_POOL_CLEARER_DELAY_MILLIS);
-            }
+                    evictAll();
+                }
+            };
+            LauncherThread.postDelayed(mDelayedClearer, MODERATE_BINDING_POOL_CLEARER_DELAY_MILLIS);
         }
 
         void onBroughtToForeground() {
-            synchronized (mDelayedClearerLock) {
-                if (mDelayedClearer == null) return;
-                mHandler.removeCallbacks(mDelayedClearer);
+            if (mDelayedClearer != null) {
+                LauncherThread.removeCallbacks(mDelayedClearer);
                 mDelayedClearer = null;
             }
         }
     }
 
-    private final AtomicReference<ModerateBindingPool> mModerateBindingPool =
-            new AtomicReference<>();
+    private ModerateBindingPool mModerateBindingPool;
 
     /**
      * Wraps ManagedChildProcessConnection keeping track of additional information needed to manage
@@ -204,8 +203,7 @@
             if (connection == null) return;
 
             connection.addStrongBinding();
-            ModerateBindingPool moderateBindingPool = mModerateBindingPool.get();
-            if (moderateBindingPool != null) moderateBindingPool.removeConnection(this);
+            if (mModerateBindingPool != null) mModerateBindingPool.removeConnection(this);
         }
 
         /** Removes a strong service binding. */
@@ -232,7 +230,7 @@
             if (mIsLowMemoryDevice) {
                 doUnbind.run();
             } else {
-                ThreadUtils.postOnUiThreadDelayed(doUnbind, DETACH_AS_ACTIVE_HIGH_END_DELAY_MILLIS);
+                LauncherThread.postDelayed(doUnbind, DETACH_AS_ACTIVE_HIGH_END_DELAY_MILLIS);
             }
         }
 
@@ -242,9 +240,8 @@
          * @param connection The ChildProcessConnection to add to the moderate binding pool.
          */
         private void addConnectionToModerateBindingPool(ManagedChildProcessConnection connection) {
-            ModerateBindingPool moderateBindingPool = mModerateBindingPool.get();
-            if (moderateBindingPool != null && !connection.isStrongBindingBound()) {
-                moderateBindingPool.addConnection(ManagedConnection.this);
+            if (mModerateBindingPool != null && !connection.isStrongBindingBound()) {
+                mModerateBindingPool.addConnection(ManagedConnection.this);
             }
         }
 
@@ -295,7 +292,7 @@
         /**
          * Called when it is safe to rely on setInForeground() for binding management.
          */
-        void determinedVisibility() {
+        void onDeterminedVisibility() {
             if (!removeInitialBinding()) return;
             // Decrease the likelihood of a recently created background tab getting evicted by
             // immediately adding moderate binding.
@@ -317,26 +314,20 @@
         }
 
         void clearConnection() {
-            ModerateBindingPool moderateBindingPool = mModerateBindingPool.get();
-            if (moderateBindingPool != null) moderateBindingPool.removeConnection(this);
+            if (mModerateBindingPool != null) mModerateBindingPool.removeConnection(this);
             mConnection = null;
         }
     }
 
-    // This can be manipulated on different threads, synchronize access on mManagedConnections.
     private final SparseArray<ManagedConnection> mManagedConnections =
             new SparseArray<ManagedConnection>();
 
     // The connection that was most recently set as foreground (using setInForeground()). This is
     // used to add additional binding on it when the embedder goes to background. On low-end, this
-    // is also used to drop process bidnings when a new one is created, making sure that only one
+    // is also used to drop process bindings when a new one is created, making sure that only one
     // renderer process at a time is protected from oom killing.
     private ManagedConnection mLastInForeground;
 
-    // Synchronizes operations that access mLastInForeground: setInForeground() and
-    // addNewConnection().
-    private final Object mLastInForegroundLock = new Object();
-
     // The connection bound with additional binding in onSentToBackground().
     private ManagedConnection mBoundForBackgroundPeriod;
 
@@ -348,11 +339,13 @@
      * Use factory methods to create an instance.
      */
     private BindingManagerImpl(boolean isLowMemoryDevice, boolean onTesting) {
+        assert LauncherThread.runningOnLauncherThread();
         mIsLowMemoryDevice = isLowMemoryDevice;
         mOnTesting = onTesting;
     }
 
     public static BindingManagerImpl createBindingManager() {
+        assert LauncherThread.runningOnLauncherThread();
         return new BindingManagerImpl(SysUtils.isLowEndDevice(), false);
     }
 
@@ -362,92 +355,78 @@
      * @param isLowEndDevice true iff the created instance should apply low-end binding policies
      */
     public static BindingManagerImpl createBindingManagerForTesting(boolean isLowEndDevice) {
+        assert LauncherThread.runningOnLauncherThread();
         return new BindingManagerImpl(isLowEndDevice, true);
     }
 
     @Override
     public void addNewConnection(int pid, ManagedChildProcessConnection connection) {
+        assert LauncherThread.runningOnLauncherThread();
         // This will reset the previous entry for the pid in the unlikely event of the OS
         // reusing renderer pids.
-        synchronized (mManagedConnections) {
-            mManagedConnections.put(pid, new ManagedConnection(connection));
-        }
+        mManagedConnections.put(pid, new ManagedConnection(connection));
     }
 
     @Override
     public void setInForeground(int pid, boolean inForeground) {
-        ManagedConnection managedConnection;
-        synchronized (mManagedConnections) {
-            managedConnection = mManagedConnections.get(pid);
-        }
-
+        assert LauncherThread.runningOnLauncherThread();
+        ManagedConnection managedConnection = mManagedConnections.get(pid);
         if (managedConnection == null) {
             Log.w(TAG, "Cannot setInForeground() - never saw a connection for the pid: %d", pid);
             return;
         }
 
-        synchronized (mLastInForegroundLock) {
-            if (inForeground && mIsLowMemoryDevice && mLastInForeground != null
-                    && mLastInForeground != managedConnection) {
-                mLastInForeground.dropBindings();
-            }
-
-            managedConnection.setInForeground(inForeground);
-            if (inForeground) mLastInForeground = managedConnection;
+        if (inForeground && mIsLowMemoryDevice && mLastInForeground != null
+                && mLastInForeground != managedConnection) {
+            mLastInForeground.dropBindings();
         }
+
+        managedConnection.setInForeground(inForeground);
+        if (inForeground) mLastInForeground = managedConnection;
     }
 
     @Override
-    public void determinedVisibility(int pid) {
-        ManagedConnection managedConnection;
-        synchronized (mManagedConnections) {
-            managedConnection = mManagedConnections.get(pid);
-        }
-
+    public void onDeterminedVisibility(int pid) {
+        assert LauncherThread.runningOnLauncherThread();
+        ManagedConnection managedConnection = mManagedConnections.get(pid);
         if (managedConnection == null) {
             Log.w(TAG, "Cannot call determinedVisibility() - never saw a connection for the pid: "
                     + "%d", pid);
             return;
         }
 
-        managedConnection.determinedVisibility();
+        managedConnection.onDeterminedVisibility();
     }
 
     @Override
     public void onSentToBackground() {
+        assert LauncherThread.runningOnLauncherThread();
         assert mBoundForBackgroundPeriod == null;
-        synchronized (mLastInForegroundLock) {
-            // mLastInForeground can be null at this point as the embedding application could be
-            // used in foreground without spawning any renderers.
-            if (mLastInForeground != null) {
-                mLastInForeground.setBoundForBackgroundPeriod(true);
-                mBoundForBackgroundPeriod = mLastInForeground;
-            }
+        // mLastInForeground can be null at this point as the embedding application could be
+        // used in foreground without spawning any renderers.
+        if (mLastInForeground != null) {
+            mLastInForeground.setBoundForBackgroundPeriod(true);
+            mBoundForBackgroundPeriod = mLastInForeground;
         }
-        ModerateBindingPool moderateBindingPool = mModerateBindingPool.get();
-        if (moderateBindingPool != null) moderateBindingPool.onSentToBackground(mOnTesting);
+        if (mModerateBindingPool != null) mModerateBindingPool.onSentToBackground(mOnTesting);
     }
 
     @Override
     public void onBroughtToForeground() {
+        assert LauncherThread.runningOnLauncherThread();
         if (mBoundForBackgroundPeriod != null) {
             mBoundForBackgroundPeriod.setBoundForBackgroundPeriod(false);
             mBoundForBackgroundPeriod = null;
         }
-        ModerateBindingPool moderateBindingPool = mModerateBindingPool.get();
-        if (moderateBindingPool != null) moderateBindingPool.onBroughtToForeground();
+        if (mModerateBindingPool != null) mModerateBindingPool.onBroughtToForeground();
     }
 
     @Override
     public void removeConnection(int pid) {
-        ManagedConnection managedConnection;
-        synchronized (mManagedConnections) {
-            managedConnection = mManagedConnections.get(pid);
-            if (managedConnection != null) {
-                mManagedConnections.remove(pid);
-            }
-        }
+        assert LauncherThread.runningOnLauncherThread();
+        ManagedConnection managedConnection = mManagedConnections.get(pid);
         if (managedConnection != null) {
+            mManagedConnections.remove(pid);
             managedConnection.clearConnection();
         }
     }
@@ -455,27 +434,32 @@
     /** @return true iff the connection reference is no longer held */
     @VisibleForTesting
     public boolean isConnectionCleared(int pid) {
-        synchronized (mManagedConnections) {
-            return mManagedConnections.get(pid) == null;
-        }
+        assert LauncherThread.runningOnLauncherThread();
+        return mManagedConnections.get(pid) == null;
     }
 
     @Override
     public void startModerateBindingManagement(Context context, int maxSize) {
+        assert LauncherThread.runningOnLauncherThread();
         if (mIsLowMemoryDevice) return;
-        ModerateBindingPool pool = new ModerateBindingPool(maxSize);
-        if (mModerateBindingPool.compareAndSet(null, pool)) {
+
+        if (mModerateBindingPool == null) {
             Log.i(TAG, "Moderate binding enabled: maxSize=%d", maxSize);
-            if (context != null) context.registerComponentCallbacks(pool);
+            mModerateBindingPool = new ModerateBindingPool(maxSize);
+            if (context != null) {
+                // Note that it is safe to call Context.registerComponentCallbacks from a background
+                // thread.
+                context.registerComponentCallbacks(mModerateBindingPool);
+            }
         }
     }
 
     @Override
     public void releaseAllModerateBindings() {
-        ModerateBindingPool moderateBindingPool = mModerateBindingPool.get();
-        if (moderateBindingPool != null) {
-            Log.i(TAG, "Release all moderate bindings: %d", moderateBindingPool.size());
-            moderateBindingPool.evictAll();
+        assert LauncherThread.runningOnLauncherThread();
+        if (mModerateBindingPool != null) {
+            Log.i(TAG, "Release all moderate bindings: %d", mModerateBindingPool.size());
+            mModerateBindingPool.evictAll();
         }
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
index 611e2a1b..df63669 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
@@ -222,16 +222,49 @@
      * Called when the renderer commits a navigation. This signals a time at which it is safe to
      * rely on renderer visibility signalled through setInForeground. See http://crbug.com/421041.
      */
-    public static void determinedVisibility(int pid) {
-        getBindingManager().determinedVisibility(pid);
+    public static void determinedVisibility(final int pid) {
+        assert ThreadUtils.runningOnUiThread();
+        LauncherThread.post(new Runnable() {
+            @Override
+            public void run() {
+                getBindingManager().onDeterminedVisibility(pid);
+            }
+        });
     }
 
     /**
      * Called when the embedding application is sent to background.
      */
     public static void onSentToBackground() {
+        assert ThreadUtils.runningOnUiThread();
         sApplicationInForeground = false;
-        getBindingManager().onSentToBackground();
+        LauncherThread.post(new Runnable() {
+            @Override
+            public void run() {
+                getBindingManager().onSentToBackground();
+            }
+        });
+    }
+
+    /**
+     * Called when the embedding application is brought to foreground.
+     */
+    public static void onBroughtToForeground() {
+        assert ThreadUtils.runningOnUiThread();
+        sApplicationInForeground = true;
+        LauncherThread.post(new Runnable() {
+            @Override
+            public void run() {
+                getBindingManager().onBroughtToForeground();
+            }
+        });
+    }
+
+    /**
+     * Returns whether the application is currently in the foreground.
+     */
+    static boolean isApplicationInForeground() {
+        return sApplicationInForeground;
     }
 
     /**
@@ -244,25 +277,16 @@
      * binding to a render process when it is created and remove the moderate binding when Chrome is
      * sent to the background.
      */
-    public static void startModerateBindingManagement(Context context) {
-        getBindingManager().startModerateBindingManagement(context,
-                ChildConnectionAllocator.getNumberOfServices(
-                        context, true, context.getPackageName()));
-    }
-
-    /**
-     * Called when the embedding application is brought to foreground.
-     */
-    public static void onBroughtToForeground() {
-        sApplicationInForeground = true;
-        getBindingManager().onBroughtToForeground();
-    }
-
-    /**
-     * Returns whether the application is currently in the foreground.
-     */
-    static boolean isApplicationInForeground() {
-        return sApplicationInForeground;
+    public static void startModerateBindingManagement(final Context context) {
+        assert ThreadUtils.runningOnUiThread();
+        LauncherThread.post(new Runnable() {
+            @Override
+            public void run() {
+                getBindingManager().startModerateBindingManagement(context,
+                        ChildConnectionAllocator.getNumberOfServices(
+                                context, true, context.getPackageName()));
+            }
+        });
     }
 
     /**
@@ -322,15 +346,14 @@
     }
 
     /**
-     * Spawns and connects to a child process. May be called on any thread. It will not block, but
-     * will instead callback to {@link #nativeOnChildProcessStarted} when the connection is
-     * established. Note this callback will not necessarily be from the same thread (currently it
-     * always comes from the main thread).
+     * Spawns and connects to a child process. It will not block, but will instead callback to
+     * {@link #LaunchCallback} on the launcher thread when the connection is established on.
      *
      * @param context Context used to obtain the application context.
      * @param paramId Key used to retrieve ChildProcessCreationParams.
      * @param commandLine The child process command line argv.
      * @param filesToBeMapped File IDs, FDs, offsets, and lengths to pass through.
+     * @param launchCallback Callback invoked when the connection is established.
      */
     static void start(Context context, int paramId, final String[] commandLine, int childProcessId,
             FileDescriptorInfo[] filesToBeMapped, LaunchCallback launchCallback) {
@@ -473,6 +496,7 @@
                 new BaseChildProcessConnection.ConnectionCallback() {
                     @Override
                     public void onConnected(BaseChildProcessConnection connection) {
+                        assert LauncherThread.runningOnLauncherThread();
                         if (connection != null) {
                             int pid = connection.getPid();
                             Log.d(TAG, "on connect callback, pid=%d", pid);
diff --git a/content/public/android/java/src/org/chromium/content/browser/LauncherThread.java b/content/public/android/java/src/org/chromium/content/browser/LauncherThread.java
index f9732a60..6069269 100644
--- a/content/public/android/java/src/org/chromium/content/browser/LauncherThread.java
+++ b/content/public/android/java/src/org/chromium/content/browser/LauncherThread.java
@@ -34,6 +34,10 @@
         sHandler.postDelayed(r, delayMillis);
     }
 
+    public static void removeCallbacks(Runnable r) {
+        sHandler.removeCallbacks(r);
+    }
+
     public static boolean runningOnLauncherThread() {
         return sHandler.getLooper() == Looper.myLooper();
     }
diff --git a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
index f10218b..425782383 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
@@ -297,7 +297,7 @@
     }
 
     /**
-     * Verifies that the initial binding is removed after determinedVisibility() is called.
+     * Verifies that the initial binding is removed after onDeterminedVisibility() is called.
      */
     @Test
     @Feature({"ProcessManagement"})
@@ -315,8 +315,8 @@
             // Verify that the initial binding is held.
             Assert.assertTrue(connection.isInitialBindingBound());
 
-            // Call determinedVisibility() and verify that the initial binding was released.
-            manager.determinedVisibility(connection.getPid());
+            // Call onDeterminedVisibility() and verify that the initial binding was released.
+            manager.onDeterminedVisibility(connection.getPid());
             Assert.assertFalse(connection.isInitialBindingBound());
         }
     }
@@ -344,7 +344,7 @@
 
             // After initial binding is removed, the connection is no longer oom protected.
             manager.setInForeground(connection.getPid(), false);
-            manager.determinedVisibility(connection.getPid());
+            manager.onDeterminedVisibility(connection.getPid());
             ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
             Assert.assertFalse(message, connection.isOomProtectedOrWasWhenDied());
 
@@ -624,7 +624,7 @@
         Assert.assertFalse(connection.isModerateBindingBound());
 
         manager.setInForeground(connection.getPid(), false);
-        manager.determinedVisibility(connection.getPid());
+        manager.onDeterminedVisibility(connection.getPid());
         Assert.assertFalse(connection.isInitialBindingBound());
         Assert.assertTrue(connection.isModerateBindingBound());
     }
@@ -647,7 +647,7 @@
         Assert.assertFalse(connection.isModerateBindingBound());
 
         manager.setInForeground(connection.getPid(), true);
-        manager.determinedVisibility(connection.getPid());
+        manager.onDeterminedVisibility(connection.getPid());
         Assert.assertFalse(connection.isInitialBindingBound());
         Assert.assertTrue(connection.isStrongBindingBound());
         Assert.assertFalse(connection.isModerateBindingBound());
@@ -667,7 +667,7 @@
         connection.start(null /* startCallback */);
         manager.addNewConnection(connection.getPid(), connection);
         manager.setInForeground(connection.getPid(), false);
-        manager.determinedVisibility(connection.getPid());
+        manager.onDeterminedVisibility(connection.getPid());
         Assert.assertTrue(connection.isModerateBindingBound());
 
         manager.onSentToBackground();
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 1330045..6a3b7c9e 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -29,6 +29,10 @@
 class TimeDelta;
 }
 
+namespace service_manager {
+class Identity;
+}
+
 namespace content {
 class BrowserContext;
 class BrowserMessageFilter;
@@ -279,6 +283,8 @@
   virtual void BindInterface(const std::string& interface_name,
                              mojo::ScopedMessagePipeHandle interface_pipe) = 0;
 
+  virtual const service_manager::Identity& GetChildIdentity() const = 0;
+
   // Extracts any persistent-memory-allocator used for renderer metrics.
   // Ownership is passed to the caller. To support sharing of histogram data
   // between the Renderer and the Browser, the allocator is created when the
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 69afea6..c424c6ec 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -305,7 +305,7 @@
 
     bool old_io_allowed_value = false;
     if (!disable_io_checks_)
-      base::ThreadRestrictions::SetIOAllowed(false);
+      old_io_allowed_value = base::ThreadRestrictions::SetIOAllowed(false);
     RunTestOnMainThread();
     if (!disable_io_checks_)
       base::ThreadRestrictions::SetIOAllowed(old_io_allowed_value);
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index cb56a83..878462df 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -270,6 +270,11 @@
     binder_overrides_[interface_name].Run(std::move(interface_pipe));
 }
 
+const service_manager::Identity& MockRenderProcessHost::GetChildIdentity()
+    const {
+  return child_identity_;
+}
+
 std::unique_ptr<base::SharedPersistentMemoryAllocator>
 MockRenderProcessHost::TakeMetricsAllocator() {
   return nullptr;
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index fbb4934..2e751dd3 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -19,6 +19,7 @@
 #include "ipc/ipc_test_sink.h"
 #include "media/media_features.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "services/service_manager/public/cpp/identity.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 
 class StoragePartition;
@@ -104,6 +105,7 @@
   void ResumeDeferredNavigation(const GlobalRequestID& request_id) override;
   void BindInterface(const std::string& interface_name,
                      mojo::ScopedMessagePipeHandle interface_pipe) override;
+  const service_manager::Identity& GetChildIdentity() const override;
   std::unique_ptr<base::SharedPersistentMemoryAllocator> TakeMetricsAllocator()
       override;
   const base::TimeTicks& GetInitTimeForNavigationMetrics() const override;
@@ -171,6 +173,7 @@
   std::unique_ptr<mojo::AssociatedInterfacePtr<mojom::Renderer>>
       renderer_interface_;
   std::map<std::string, InterfaceBinder> binder_overrides_;
+  service_manager::Identity child_identity_;
 
   DISALLOW_COPY_AND_ASSIGN(MockRenderProcessHost);
 };
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index f09319c7..3666836 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -949,6 +949,9 @@
                                              callback, base::Passed(&result)));
           },
           callback, base::Passed(&main_thread_task_runner)));
+  // Force a redraw to ensure that the copy swap promise isn't cancelled due to
+  // no damage.
+  SetNeedsForcedRedraw();
   layer_tree_host_->QueueSwapPromise(
       delegate_->RequestCopyOfOutputForLayoutTest(std::move(request)));
 
diff --git a/content/renderer/media/android/media_player_renderer_client_factory.cc b/content/renderer/media/android/media_player_renderer_client_factory.cc
index 0776318..09dad61 100644
--- a/content/renderer/media/android/media_player_renderer_client_factory.cc
+++ b/content/renderer/media/android/media_player_renderer_client_factory.cc
@@ -43,4 +43,9 @@
       std::move(stream_texture_wrapper), video_renderer_sink);
 }
 
+media::MediaResource::Type
+MediaPlayerRendererClientFactory::GetRequiredMediaResourceType() {
+  return media::MediaResource::Type::URL;
+}
+
 }  // namespace content
diff --git a/content/renderer/media/android/media_player_renderer_client_factory.h b/content/renderer/media/android/media_player_renderer_client_factory.h
index eaaee06..a0809fec 100644
--- a/content/renderer/media/android/media_player_renderer_client_factory.h
+++ b/content/renderer/media/android/media_player_renderer_client_factory.h
@@ -36,6 +36,9 @@
       media::VideoRendererSink* video_renderer_sink,
       const media::RequestSurfaceCB& request_surface_cb) override;
 
+  // The MediaPlayerRenderer uses a Type::URL.
+  media::MediaResource::Type GetRequiredMediaResourceType() override;
+
  private:
   GetStreamTextureWrapperCB get_stream_texture_wrapper_cb_;
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index e20d9dfc..d11d877 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -177,6 +177,7 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/http/http_util.h"
 #include "ppapi/features/features.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
@@ -1319,6 +1320,12 @@
   blame_context_->Initialize();
 }
 
+void RenderFrameImpl::GetInterface(
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle interface_pipe) {
+  interface_registry_->BindInterface(interface_name, std::move(interface_pipe));
+}
+
 RenderWidget* RenderFrameImpl::GetRenderWidget() {
   return GetLocalRoot()->render_widget_.get();
 }
@@ -2734,21 +2741,12 @@
 
 void RenderFrameImpl::GetInterfaceProvider(
     service_manager::mojom::InterfaceProviderRequest request) {
-  service_manager::ServiceInfo child_info =
-      ChildThreadImpl::current()->GetChildServiceInfo();
   service_manager::ServiceInfo browser_info =
       ChildThreadImpl::current()->GetBrowserServiceInfo();
-
-  service_manager::InterfaceProviderSpec child_spec, browser_spec;
-  // TODO(beng): CHECK these return true.
-  service_manager::GetInterfaceProviderSpec(
-      mojom::kNavigation_FrameSpec, child_info.interface_provider_specs,
-      &child_spec);
-  service_manager::GetInterfaceProviderSpec(
-      mojom::kNavigation_FrameSpec, browser_info.interface_provider_specs,
-      &browser_spec);
-  interface_registry_->Bind(std::move(request), child_info.identity, child_spec,
-                            browser_info.identity, browser_spec);
+  service_manager::Connector* connector = ChildThread::Get()->GetConnector();
+  connector->FilterInterfaces(
+      mojom::kNavigation_FrameSpec, browser_info.identity, std::move(request),
+      interface_provider_bindings_.CreateInterfacePtrAndBind(this));
 }
 
 void RenderFrameImpl::AllowBindings(int32_t enabled_bindings_flags) {
@@ -2897,63 +2895,67 @@
   std::unique_ptr<media::MediaLog> media_log(
       new RenderMediaLog(url::Origin(security_origin).GetURL()));
 
-  bool use_fallback_path = false;
+  auto factory_selector = base::MakeUnique<media::RendererFactorySelector>();
+
 #if defined(OS_ANDROID)
-  use_fallback_path = UseMediaPlayerRenderer(url);
+  // The only MojoRendererService that is registered at the RenderFrameHost
+  // level uses the MediaPlayerRenderer as its underlying media::Renderer.
+  auto mojo_media_player_renderer_factory =
+      base::MakeUnique<media::MojoRendererFactory>(
+          media::MojoRendererFactory::GetGpuFactoriesCB(),
+          GetRemoteInterfaces()->get());
+
+  // Always give |factory_selector| a MediaPlayerRendererClient factory. WMPI
+  // might fallback to it if the final redirected URL is an HLS url.
+  factory_selector->AddFactory(
+      media::RendererFactorySelector::FactoryType::MEDIA_PLAYER,
+      base::MakeUnique<MediaPlayerRendererClientFactory>(
+          render_thread->compositor_task_runner(),
+          std::move(mojo_media_player_renderer_factory),
+          base::Bind(&StreamTextureWrapperImpl::Create,
+                     render_thread->EnableStreamTextureCopy(),
+                     render_thread->GetStreamTexureFactory(),
+                     base::ThreadTaskRunnerHandle::Get())));
+
+  factory_selector->SetUseMediaPlayer(UseMediaPlayerRenderer(url));
 #endif  // defined(OS_ANDROID)
 
+  // |factory_type| will be overwritten in all possible path below, and the
+  // DEFAULT value is not accurate. However, this prevents the compiler from
+  // issuing a -Wsometimes-uninitialized warning.
+  // TODO(tguilbert): Remove |factory_type|, and clean up the logic. The work is
+  // already completed and incrementally being submitted. See crbug.com/663503.
+  auto factory_type = media::RendererFactorySelector::FactoryType::DEFAULT;
   std::unique_ptr<media::RendererFactory> media_renderer_factory;
-  media::RendererFactorySelector::FactoryType factory_type;
-  if (use_fallback_path) {
-#if defined(OS_ANDROID)
-    auto mojo_renderer_factory = base::MakeUnique<media::MojoRendererFactory>(
-        media::MojoRendererFactory::GetGpuFactoriesCB(),
-        GetRemoteInterfaces()->get());
 
-    media_renderer_factory = base::MakeUnique<MediaPlayerRendererClientFactory>(
-        render_thread->compositor_task_runner(),
-        std::move(mojo_renderer_factory),
-        base::Bind(&StreamTextureWrapperImpl::Create,
-                   render_thread->EnableStreamTextureCopy(),
-                   render_thread->GetStreamTexureFactory(),
-                   base::ThreadTaskRunnerHandle::Get()));
-#endif  // defined(OS_ANDROID)
-
-    // TODO(tguilbert): Move this line back into an #if defined(OS_ANDROID).
-    // This will never be reached, unless we are on Android. Moving this line
-    // outside of the #if/#endif block fixes a "sometimes-uninitialized" error
-    // on desktop. This will be fixed with the next CL for crbug.com/663503.
-    factory_type = media::RendererFactorySelector::FactoryType::MEDIA_PLAYER;
-  } else {
 #if defined(ENABLE_MOJO_RENDERER)
 #if BUILDFLAG(ENABLE_RUNTIME_MEDIA_RENDERER_SELECTION)
-    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableMojoRenderer)) {
-      media_renderer_factory = base::MakeUnique<media::DefaultRendererFactory>(
-          media_log.get(), GetDecoderFactory(),
-          base::Bind(&RenderThreadImpl::GetGpuFactories,
-                     base::Unretained(render_thread)));
-
-      factory_type = media::RendererFactorySelector::FactoryType::DEFAULT;
-    }
-#endif  // BUILDFLAG(ENABLE_RUNTIME_MEDIA_RENDERER_SELECTION)
-    if (!media_renderer_factory) {
-      media_renderer_factory = base::MakeUnique<media::MojoRendererFactory>(
-          base::Bind(&RenderThreadImpl::GetGpuFactories,
-                     base::Unretained(render_thread)),
-          GetMediaInterfaceProvider());
-
-      factory_type = media::RendererFactorySelector::FactoryType::MOJO;
-    }
-#else
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableMojoRenderer)) {
     media_renderer_factory = base::MakeUnique<media::DefaultRendererFactory>(
         media_log.get(), GetDecoderFactory(),
         base::Bind(&RenderThreadImpl::GetGpuFactories,
                    base::Unretained(render_thread)));
 
     factory_type = media::RendererFactorySelector::FactoryType::DEFAULT;
-#endif  // defined(ENABLE_MOJO_RENDERER)
   }
+#endif  // BUILDFLAG(ENABLE_RUNTIME_MEDIA_RENDERER_SELECTION)
+  if (!media_renderer_factory) {
+    media_renderer_factory = base::MakeUnique<media::MojoRendererFactory>(
+        base::Bind(&RenderThreadImpl::GetGpuFactories,
+                   base::Unretained(render_thread)),
+        GetMediaInterfaceProvider());
+
+    factory_type = media::RendererFactorySelector::FactoryType::MOJO;
+  }
+#else
+  media_renderer_factory = base::MakeUnique<media::DefaultRendererFactory>(
+      media_log.get(), GetDecoderFactory(),
+      base::Bind(&RenderThreadImpl::GetGpuFactories,
+                 base::Unretained(render_thread)));
+
+  factory_type = media::RendererFactorySelector::FactoryType::DEFAULT;
+#endif  // defined(ENABLE_MOJO_RENDERER)
 
 #if BUILDFLAG(ENABLE_MEDIA_REMOTING)
   media_renderer_factory =
@@ -2966,8 +2968,6 @@
   if (!url_index_.get() || url_index_->frame() != frame_)
     url_index_.reset(new media::UrlIndex(frame_));
 
-  auto factory_selector = base::MakeUnique<media::RendererFactorySelector>();
-
   factory_selector->AddFactory(factory_type, std::move(media_renderer_factory));
   factory_selector->SetBaseFactoryType(factory_type);
 
@@ -2997,7 +2997,6 @@
 #if defined(OS_ANDROID)  // WMPI_CAST
   media_player->SetMediaPlayerManager(GetMediaPlayerManager());
   media_player->SetDeviceScaleFactor(render_view_->GetDeviceScaleFactor());
-  media_player->SetUseFallbackPath(use_fallback_path);
 #endif  // defined(OS_ANDROID)
 
   return media_player;
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 4884aac..7c44d2b 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -52,6 +52,7 @@
 #include "media/mojo/interfaces/remoting.mojom.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "ppapi/features/features.h"
 #include "services/service_manager/public/cpp/service_info.h"
@@ -187,7 +188,8 @@
       NON_EXPORTED_BASE(mojom::HostZoom),
       NON_EXPORTED_BASE(mojom::FrameBindingsControl),
       NON_EXPORTED_BASE(public blink::WebFrameClient),
-      NON_EXPORTED_BASE(public blink::WebFrameSerializerClient) {
+      NON_EXPORTED_BASE(public blink::WebFrameSerializerClient),
+      NON_EXPORTED_BASE(service_manager::mojom::InterfaceProvider) {
  public:
   // Creates a new RenderFrame as the main frame of |render_view|.
   static RenderFrameImpl* CreateMainFrame(
@@ -1123,6 +1125,10 @@
 
   void InitializeBlameContext(RenderFrameImpl* parent_frame);
 
+  // service_manager::mojom::InterfaceProvider:
+  void GetInterface(const std::string& interface_name,
+                    mojo::ScopedMessagePipeHandle interface_pipe) override;
+
   // Stores the WebLocalFrame we are associated with.  This is null from the
   // constructor until BindToWebFrame is called, and it is null after
   // frameDetached is called until destruction (which is asynchronous in the
@@ -1427,6 +1433,9 @@
   // is used and released in didStartProvisionalLoad().
   std::unique_ptr<PendingNavigationInfo> pending_navigation_info_;
 
+  mojo::BindingSet<service_manager::mojom::InterfaceProvider>
+      interface_provider_bindings_;
+
   base::WeakPtrFactory<RenderFrameImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderFrameImpl);
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index 9c19b34..5b003d7 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -354,7 +354,7 @@
         std::move(compositor_context_provider),
         std::move(worker_context_provider), nullptr /* shared_bitmap_manager */,
         gpu_memory_buffer_manager, settings.renderer_settings, task_runner,
-        synchronous_composite, false /* force_disable_reclaim_resources */);
+        synchronous_composite);
     compositor_frame_sink->SetClient(this);
     compositor_frame_sinks_[routing_id] = compositor_frame_sink.get();
     return std::move(compositor_frame_sink);
diff --git a/device/vr/vr_math.cc b/device/vr/vr_math.cc
index cd95d5eb..567fe6f 100644
--- a/device/vr/vr_math.cc
+++ b/device/vr/vr_math.cc
@@ -177,6 +177,69 @@
            {{0.0f, 0.0f, 0.0f, 1.0f}}}};
 }
 
+vr::Quatf GetVectorRotation(const gfx::Vector3dF& from,
+                            const gfx::Vector3dF& to) {
+  float dot = gfx::DotProduct(from, to);
+  float norm = sqrt(from.LengthSquared() * to.LengthSquared());
+  float real = norm + dot;
+  gfx::Vector3dF w;
+  if (real < 1.e-6f * norm) {
+    real = 0.0f;
+    w = fabsf(from.x()) > fabsf(from.z())
+            ? gfx::Vector3dF{-from.y(), from.x(), 0.0f}
+            : gfx::Vector3dF{0.0f, -from.z(), from.y()};
+  } else {
+    w = gfx::CrossProduct(from, to);
+  }
+  vr::Quatf result{w.x(), w.y(), w.z(), real};
+  NormalizeQuat(&result);
+  return result;
+}
+
+vr::Quatf QuatSum(const vr::Quatf& a, const vr::Quatf& b) {
+  return {a.qx + b.qx, a.qy + b.qy, a.qz + b.qz, a.qw + b.qw};
+}
+
+vr::Quatf QuatProduct(const vr::Quatf& a, const vr::Quatf& b) {
+  return {a.qw * b.qx + a.qx * b.qw + a.qy * b.qz - a.qz * b.qy,
+          a.qw * b.qy - a.qx * b.qz + a.qy * b.qw + a.qz * b.qx,
+          a.qw * b.qz + a.qx * b.qy - a.qy * b.qx + a.qz * b.qw,
+          a.qw * b.qw - a.qx * b.qx - a.qy * b.qy - a.qz * b.qz};
+}
+
+vr::Quatf ScaleQuat(const vr::Quatf& q, float s) {
+  return {q.qx * s, q.qy * s, q.qz * s, q.qw * s};
+}
+
+vr::Quatf InvertQuat(const vr::Quatf& quat) {
+  return {-quat.qx, -quat.qy, -quat.qz, quat.qw};
+}
+
+float QuatAngleDegrees(const vr::Quatf& a, const vr::Quatf& b) {
+  return QuatProduct(b, InvertQuat(a)).qw;
+}
+
+vr::Quatf QuatLerp(const vr::Quatf& a, const vr::Quatf& b, float t) {
+  auto result = QuatSum(ScaleQuat(a, 1.0f - t), ScaleQuat(b, t));
+  NormalizeQuat(&result);
+  return result;
+}
+
+gfx::Vector3dF QuatSlerp(const gfx::Vector3dF& v_start,
+                         const gfx::Vector3dF& v_end,
+                         float percent) {
+  auto start = v_start;
+  auto end = v_end;
+  NormalizeVector(&start);
+  NormalizeVector(&end);
+  float dot = Clampf(gfx::DotProduct(start, end), -1.0f, 1.0f);
+  float theta = acos(dot) * percent;
+  auto relative_vec = end - gfx::ScaleVector3d(start, dot);
+  NormalizeVector(&relative_vec);
+  return gfx::ScaleVector3d(start, cos(theta)) +
+         gfx::ScaleVector3d(relative_vec, sin(theta));
+}
+
 gfx::Point3F GetRayPoint(const gfx::Point3F& rayOrigin,
                          const gfx::Vector3dF& rayVector,
                          float scale) {
@@ -199,4 +262,28 @@
   return true;
 }
 
+gfx::Vector3dF ToVector(const gfx::Point3F& p) {
+  return {p.x(), p.y(), p.z()};
+}
+
+gfx::Point3F ToPoint(const gfx::Vector3dF& p) {
+  return {p.x(), p.y(), p.z()};
+}
+
+gfx::Point3F ScalePoint(const gfx::Point3F& p, const gfx::Vector3dF& s) {
+  return gfx::ScalePoint(p, s.x(), s.y(), s.z());
+}
+
+gfx::Vector3dF ScaleVector(const gfx::Vector3dF& v, const gfx::Vector3dF& s) {
+  return gfx::ScaleVector3d(v, s.x(), s.y(), s.z());
+}
+
+float Clampf(float value, float min, float max) {
+  if (value < min)
+    return min;
+  if (value > max)
+    return max;
+  return value;
+}
+
 }  // namespace vr
diff --git a/device/vr/vr_math.h b/device/vr/vr_math.h
index 2426b3dc..55c165c 100644
--- a/device/vr/vr_math.h
+++ b/device/vr/vr_math.h
@@ -33,6 +33,27 @@
 
 void DEVICE_VR_EXPORT QuatToMatrix(const Quatf& quat, Mat4f* out);
 
+// Creates a rotation which rotates `from` vector to `to`.
+vr::Quatf DEVICE_VR_EXPORT GetVectorRotation(const gfx::Vector3dF& from,
+                                             const gfx::Vector3dF& to);
+
+vr::Quatf DEVICE_VR_EXPORT QuatSum(const vr::Quatf& a, const vr::Quatf& b);
+vr::Quatf DEVICE_VR_EXPORT QuatProduct(const vr::Quatf& a, const vr::Quatf& b);
+vr::Quatf DEVICE_VR_EXPORT ScaleQuat(const vr::Quatf& q, float s);
+
+vr::Quatf DEVICE_VR_EXPORT InvertQuat(const vr::Quatf& quat);
+
+float DEVICE_VR_EXPORT QuatAngleDegrees(const vr::Quatf& a, const vr::Quatf& b);
+
+vr::Quatf DEVICE_VR_EXPORT QuatLerp(const vr::Quatf& a,
+                                    const vr::Quatf& b,
+                                    float t);
+
+// Spherical linear interpolation.
+gfx::Vector3dF DEVICE_VR_EXPORT QuatSlerp(const gfx::Vector3dF& v_start,
+                                          const gfx::Vector3dF& v_end,
+                                          float percent);
+
 // Normalize a vector, and return its original length.
 float DEVICE_VR_EXPORT NormalizeVector(gfx::Vector3dF* vec);
 
@@ -49,6 +70,20 @@
                               const gfx::Vector3dF& vec2,
                               float* angle);
 
+gfx::Vector3dF DEVICE_VR_EXPORT ToVector(const gfx::Point3F& p);
+
+gfx::Point3F DEVICE_VR_EXPORT ToPoint(const gfx::Vector3dF& p);
+
+// Scale components of the point by the components of the vector.
+gfx::Point3F DEVICE_VR_EXPORT ScalePoint(const gfx::Point3F& p,
+                                         const gfx::Vector3dF& s);
+
+// Scale components of a vector by the components of another.
+gfx::Vector3dF DEVICE_VR_EXPORT ScaleVector(const gfx::Vector3dF& p,
+                                            const gfx::Vector3dF& s);
+
+float DEVICE_VR_EXPORT Clampf(float value, float min, float max);
+
 }  // namespace vr
 
 #endif  // DEVICE_VR_VR_MATH_H_
diff --git a/extensions/browser/api/printer_provider/printer_provider_apitest.cc b/extensions/browser/api/printer_provider/printer_provider_apitest.cc
index d0b8cb40..b53ac100 100644
--- a/extensions/browser/api/printer_provider/printer_provider_apitest.cc
+++ b/extensions/browser/api/printer_provider/printer_provider_apitest.cc
@@ -18,6 +18,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "device/usb/mock_usb_device.h"
 #include "device/usb/mock_usb_service.h"
 #include "extensions/browser/api/printer_provider/printer_provider_api.h"
@@ -99,7 +100,10 @@
   };
 
   PrinterProviderApiTest() {}
-  ~PrinterProviderApiTest() override {}
+  ~PrinterProviderApiTest() override {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    ignore_result(data_dir_.Delete());
+  }
 
   void StartGetPrintersRequest(
       const PrinterProviderAPI::GetPrintersCallback& callback) {
@@ -238,10 +242,12 @@
       case PRINT_REQUEST_DATA_TYPE_FILE:
         ASSERT_TRUE(StartPrintRequestUsingFileInfo(extension_id, callback));
         break;
-      case PRINT_REQUEST_DATA_TYPE_FILE_DELETED:
+      case PRINT_REQUEST_DATA_TYPE_FILE_DELETED: {
         ASSERT_TRUE(StartPrintRequestUsingFileInfo(extension_id, callback));
+        base::ThreadRestrictions::ScopedAllowIO allow_io;
         ASSERT_TRUE(data_dir_.Delete());
         break;
+      }
       case PRINT_REQUEST_DATA_TYPE_BYTES:
         StartPrintRequestUsingDocumentBytes(extension_id, callback);
         break;
@@ -349,6 +355,7 @@
                                   int size,
                                   base::FilePath* path,
                                   base::File::Info* file_info) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     if (!data_dir_.IsValid() && !data_dir_.CreateUniqueTempDir())
       return false;
 
diff --git a/extensions/browser/guest_view/app_view/app_view_apitest.cc b/extensions/browser/guest_view/app_view/app_view_apitest.cc
index ffa7020..276c4b1 100644
--- a/extensions/browser/guest_view/app_view/app_view_apitest.cc
+++ b/extensions/browser/guest_view/app_view/app_view_apitest.cc
@@ -5,6 +5,7 @@
 #include "base/command_line.h"
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
 #include "components/guest_view/browser/guest_view_manager.h"
 #include "components/guest_view/browser/guest_view_manager_factory.h"
 #include "components/guest_view/browser/test_guest_view_manager.h"
@@ -112,6 +113,7 @@
   }
 
   const Extension* LoadApp(const std::string& app_location) {
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
     base::FilePath test_data_dir;
     PathService::Get(DIR_TEST_DATA, &test_data_dir);
     test_data_dir = test_data_dir.AppendASCII(app_location.c_str());
diff --git a/extensions/browser/guest_view/web_view/web_view_apitest.cc b/extensions/browser/guest_view/web_view/web_view_apitest.cc
index 6206dd12..aef32e9 100644
--- a/extensions/browser/guest_view/web_view/web_view_apitest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_apitest.cc
@@ -11,6 +11,7 @@
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "components/guest_view/browser/guest_view_manager.h"
 #include "components/guest_view/browser/guest_view_manager_delegate.h"
@@ -138,6 +139,7 @@
 }
 
 void WebViewAPITest::LaunchApp(const std::string& app_location) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath test_data_dir;
   PathService::Get(DIR_TEST_DATA, &test_data_dir);
   test_data_dir = test_data_dir.AppendASCII(app_location.c_str());
@@ -203,6 +205,7 @@
 
   test_config_.SetInteger(kTestServerPort, embedded_test_server()->port());
 
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath test_data_dir;
   PathService::Get(DIR_TEST_DATA, &test_data_dir);
   test_data_dir = test_data_dir.AppendASCII(app_location.c_str());
diff --git a/extensions/renderer/api_binding.cc b/extensions/renderer/api_binding.cc
index 9e1aee5..8652b713 100644
--- a/extensions/renderer/api_binding.cc
+++ b/extensions/renderer/api_binding.cc
@@ -257,24 +257,32 @@
       std::vector<std::string> rule_conditions;
       const base::DictionaryValue* options = nullptr;
       bool supports_rules = false;
-      if (event_dict->GetDictionary("options", &options) &&
-          options->GetBoolean("supportsRules", &supports_rules) &&
-          supports_rules) {
-        bool supports_listeners = false;
-        DCHECK(options->GetBoolean("supportsListeners", &supports_listeners));
-        DCHECK(!supports_listeners)
-            << "Events cannot support rules and listeners.";
-        auto get_values = [options](base::StringPiece name,
-                                    std::vector<std::string>* out_value) {
-          const base::ListValue* list = nullptr;
-          CHECK(options->GetList(name, &list));
-          for (const auto& entry : *list) {
-            DCHECK(entry.is_string());
-            out_value->push_back(entry.GetString());
-          }
-        };
-        get_values("actions", &rule_actions);
-        get_values("conditions", &rule_conditions);
+      if (event_dict->GetDictionary("options", &options)) {
+        bool temp_supports_filters = false;
+        // TODO(devlin): For some reason, schemas indicate supporting filters
+        // either through having a 'filters' property *or* through having
+        // a 'supportsFilters' property. We should clean that up.
+        supports_filters |=
+            (options->GetBoolean("supportsFilters", &temp_supports_filters) &&
+             temp_supports_filters);
+        if (options->GetBoolean("supportsRules", &supports_rules) &&
+            supports_rules) {
+          bool supports_listeners = false;
+          DCHECK(options->GetBoolean("supportsListeners", &supports_listeners));
+          DCHECK(!supports_listeners)
+              << "Events cannot support rules and listeners.";
+          auto get_values = [options](base::StringPiece name,
+                                      std::vector<std::string>* out_value) {
+            const base::ListValue* list = nullptr;
+            CHECK(options->GetList(name, &list));
+            for (const auto& entry : *list) {
+              DCHECK(entry.is_string());
+              out_value->push_back(entry.GetString());
+            }
+          };
+          get_values("actions", &rule_actions);
+          get_values("conditions", &rule_conditions);
+        }
       }
 
       events_.push_back(base::MakeUnique<EventData>(
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/api_binding_unittest.cc
index 389fe96..fc82ff4 100644
--- a/extensions/renderer/api_binding_unittest.cc
+++ b/extensions/renderer/api_binding_unittest.cc
@@ -1188,4 +1188,69 @@
   reset_last_request();
 }
 
+TEST_F(APIBindingUnittest, FilteredEvents) {
+  const char kEvents[] =
+      "[{"
+      "  'name': 'unfilteredOne',"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'unfilteredTwo',"
+      "  'filters': [],"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'unfilteredThree',"
+      "  'options': {'supportsFilters': false},"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'filteredOne',"
+      "  'options': {'supportsFilters': true},"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'filteredTwo',"
+      "  'filters': ["
+      "    {'name': 'url', 'type': 'array', 'items': {'type': 'any'}}"
+      "  ],"
+      "  'parameters': []"
+      "}]";
+  SetEvents(kEvents);
+  InitializeBinding();
+
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = MainContext();
+
+  v8::Local<v8::Object> binding_object =
+      binding()->CreateInstance(context, base::Bind(&AllowAllAPIs));
+
+  const char kAddFilteredListener[] =
+      "(function(evt) {\n"
+      "  evt.addListener(function() {},\n"
+      "                  {url: [{pathContains: 'simple2.html'}]});\n"
+      "})";
+  v8::Local<v8::Function> function =
+      FunctionFromString(context, kAddFilteredListener);
+  ASSERT_FALSE(function.IsEmpty());
+
+  auto check_supports_filters = [context, binding_object, function](
+                                    base::StringPiece name,
+                                    bool expect_supports) {
+    SCOPED_TRACE(name);
+    v8::Local<v8::Value> event =
+        GetPropertyFromObject(binding_object, context, name);
+    v8::Local<v8::Value> args[] = {event};
+    if (expect_supports) {
+      RunFunction(function, context, context->Global(), arraysize(args), args);
+    } else {
+      RunFunctionAndExpectError(
+          function, context, context->Global(), arraysize(args), args,
+          "Uncaught TypeError: This event does not support filters");
+    }
+  };
+
+  check_supports_filters("unfilteredOne", false);
+  check_supports_filters("unfilteredTwo", false);
+  check_supports_filters("unfilteredThree", false);
+  check_supports_filters("filteredOne", true);
+  check_supports_filters("filteredTwo", true);
+}
+
 }  // namespace extensions
diff --git a/extensions/shell/test/shell_apitest.cc b/extensions/shell/test/shell_apitest.cc
index c5aa1182..b8b7829 100644
--- a/extensions/shell/test/shell_apitest.cc
+++ b/extensions/shell/test/shell_apitest.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_path.h"
 #include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
 #include "content/public/browser/notification_service.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/notification_types.h"
@@ -22,6 +23,7 @@
 }
 
 const Extension* ShellApiTest::LoadApp(const std::string& app_dir) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath test_data_dir;
   PathService::Get(extensions::DIR_TEST_DATA, &test_data_dir);
   test_data_dir = test_data_dir.AppendASCII(app_dir);
diff --git a/extensions/shell/test/shell_test.cc b/extensions/shell/test/shell_test.cc
index a6930d9..ccfaed9 100644
--- a/extensions/shell/test/shell_test.cc
+++ b/extensions/shell/test/shell_test.cc
@@ -55,9 +55,6 @@
   extension_system_->Init();
   DCHECK(base::MessageLoopForUI::IsCurrent());
   base::RunLoop().RunUntilIdle();
-
-  // TODO(jam): remove this.
-  disable_io_checks();
 }
 
 void AppShellTest::PostRunTestOnMainThread() {
diff --git a/headless/lib/browser/headless_tab_socket_impl.h b/headless/lib/browser/headless_tab_socket_impl.h
index 7990dc7..93cc610 100644
--- a/headless/lib/browser/headless_tab_socket_impl.h
+++ b/headless/lib/browser/headless_tab_socket_impl.h
@@ -31,14 +31,15 @@
   void CreateMojoService(mojo::InterfaceRequest<TabSocket> request);
 
  private:
-  mojo::BindingSet<TabSocket> mojo_bindings_;
-
   base::Lock lock_;  // Protects everything below.
   AwaitNextMessageFromEmbedderCallback waiting_for_message_cb_;
   std::list<std::string> outgoing_message_queue_;
   std::list<std::string> incoming_message_queue_;
   Listener* listener_;  // NOT OWNED
 
+  // Must be listed last so it gets destructed before |waiting_for_message_cb_|.
+  mojo::BindingSet<TabSocket> mojo_bindings_;
+
   DISALLOW_COPY_AND_ASSIGN(HeadlessTabSocketImpl);
 };
 
diff --git a/headless/lib/headless_web_contents_browsertest.cc b/headless/lib/headless_web_contents_browsertest.cc
index 07a542fa..bf11b95 100644
--- a/headless/lib/headless_web_contents_browsertest.cc
+++ b/headless/lib/headless_web_contents_browsertest.cc
@@ -190,6 +190,11 @@
 class HeadlessTabSocketTest : public HeadlessAsyncDevTooledBrowserTest,
                               public HeadlessTabSocket::Listener {
  public:
+  void SetUp() override {
+    options()->mojo_service_names.insert("headless::TabSocket");
+    HeadlessAsyncDevTooledBrowserTest::SetUp();
+  }
+
   void RunDevTooledTest() override {
     devtools_client_->GetRuntime()->Evaluate(
         R"(window.TabSocket.onmessage =
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
index f0e9e6d6..68fb049 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
@@ -220,8 +220,23 @@
           ? base::ASCIIToUTF16("basic-card")
           : base::ASCIIToUTF16(basic_card_type);
 
+  // Get the billing address
+  autofill::AutofillProfile billingAddress;
+
+  // TODO(crbug.com/714768): Make sure the billing address is set and valid
+  // before getting here. Once the bug is addressed, there will be no need to
+  // copy the address, *billing_address_ptr can be used to get the basic card
+  // response.
+  if (!card.billing_address_id().empty()) {
+    autofill::AutofillProfile* billingAddressPtr =
+        autofill::PersonalDataManager::GetProfileFromProfilesByGUID(
+            card.billing_address_id(), _paymentRequest->billing_profiles());
+    if (billingAddressPtr)
+      billingAddress = *billingAddressPtr;
+  }
+
   paymentResponse.details = GetBasicCardResponseFromAutofillCreditCard(
-      card, cvc, _paymentRequest->billing_profiles(),
+      card, cvc, billingAddress,
       GetApplicationContext()->GetApplicationLocale());
 
   if (_paymentRequest->request_shipping()) {
diff --git a/ios/web/app/web_main_loop.mm b/ios/web/app/web_main_loop.mm
index 55c274d..8d79449 100644
--- a/ios/web/app/web_main_loop.mm
+++ b/ios/web/app/web_main_loop.mm
@@ -71,6 +71,10 @@
 WebMainLoop::WebMainLoop() : result_code_(0), created_threads_(false) {
   DCHECK(!g_current_web_main_loop);
   g_current_web_main_loop = this;
+
+  // Use an empty string as TaskScheduler name to match the suffix of browser
+  // process TaskScheduler histograms.
+  base::TaskScheduler::Create("");
 }
 
 WebMainLoop::~WebMainLoop() {
@@ -145,14 +149,15 @@
 }
 
 int WebMainLoop::CreateThreads() {
-  auto task_scheduler_init_params =
-      GetWebClient()->GetTaskSchedulerInitParams();
-  if (!task_scheduler_init_params)
-    task_scheduler_init_params = GetDefaultTaskSchedulerInitParams();
-  DCHECK(task_scheduler_init_params);
-
-  base::TaskScheduler::CreateAndSetDefaultTaskScheduler(
-      "", *task_scheduler_init_params.get());
+  {
+    auto task_scheduler_init_params =
+        GetWebClient()->GetTaskSchedulerInitParams();
+    if (!task_scheduler_init_params)
+      task_scheduler_init_params = GetDefaultTaskSchedulerInitParams();
+    DCHECK(task_scheduler_init_params);
+    base::TaskScheduler::GetInstance()->Start(
+        *task_scheduler_init_params.get());
+  }
 
   GetWebClient()->PerformExperimentalTaskSchedulerRedirections();
 
diff --git a/media/base/eme_constants.h b/media/base/eme_constants.h
index 1d9fd910..a3acdb9 100644
--- a/media/base/eme_constants.h
+++ b/media/base/eme_constants.h
@@ -31,18 +31,28 @@
   EME_CODEC_MP4_AVC1 = 1 << 5,
   EME_CODEC_COMMON_VP9 = 1 << 6,
   EME_CODEC_MP4_HEVC = 1 << 7,
+  EME_CODEC_MP4_DV_AVC = 1 << 8,
+  EME_CODEC_MP4_DV_HEVC = 1 << 9,
   EME_CODEC_WEBM_AUDIO_ALL = EME_CODEC_WEBM_OPUS | EME_CODEC_WEBM_VORBIS,
   EME_CODEC_WEBM_VIDEO_ALL =
       (EME_CODEC_WEBM_VP8 | EME_CODEC_WEBM_VP9 | EME_CODEC_COMMON_VP9),
   EME_CODEC_WEBM_ALL = (EME_CODEC_WEBM_AUDIO_ALL | EME_CODEC_WEBM_VIDEO_ALL),
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
   EME_CODEC_MP4_AUDIO_ALL = EME_CODEC_MP4_AAC,
-#if !BUILDFLAG(ENABLE_HEVC_DEMUXING)
-  EME_CODEC_MP4_VIDEO_ALL = (EME_CODEC_MP4_AVC1 | EME_CODEC_COMMON_VP9),
-#else
-  EME_CODEC_MP4_VIDEO_ALL =
-      (EME_CODEC_MP4_AVC1 | EME_CODEC_COMMON_VP9 | EME_CODEC_MP4_HEVC),
-#endif
+  EME_CODEC_MP4_VIDEO_ALL = (EME_CODEC_MP4_AVC1 | EME_CODEC_COMMON_VP9
+#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
+                             |
+                             EME_CODEC_MP4_HEVC
+#endif  // BUILDFLAG(ENABLE_HEVC_DEMUXING)
+#if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
+                             |
+                             EME_CODEC_MP4_DV_AVC
+#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
+                             |
+                             EME_CODEC_MP4_DV_HEVC
+#endif  // BUILDFLAG(ENABLE_HEVC_DEMUXING)
+#endif  // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
+                             ),
   EME_CODEC_MP4_ALL = (EME_CODEC_MP4_AUDIO_ALL | EME_CODEC_MP4_VIDEO_ALL),
   EME_CODEC_AUDIO_ALL = (EME_CODEC_WEBM_AUDIO_ALL | EME_CODEC_MP4_AUDIO_ALL),
   EME_CODEC_VIDEO_ALL = (EME_CODEC_WEBM_VIDEO_ALL | EME_CODEC_MP4_VIDEO_ALL),
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc
index 41f83b58..708750a 100644
--- a/media/base/key_systems.cc
+++ b/media/base/key_systems.cc
@@ -45,7 +45,7 @@
     {"video/webm", EME_CODEC_WEBM_VIDEO_ALL},
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
     {"audio/mp4", EME_CODEC_MP4_AUDIO_ALL},
-    {"video/mp4", EME_CODEC_MP4_VIDEO_ALL}
+    {"video/mp4", EME_CODEC_MP4_VIDEO_ALL},
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 };
 
@@ -66,6 +66,14 @@
     {"hev1", EME_CODEC_MP4_HEVC},  // HEV1.
     {"hvc1", EME_CODEC_MP4_HEVC},  // HVC1.
 #endif
+#if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING)
+    {"dva1", EME_CODEC_MP4_DV_AVC},  // DolbyVision AVC
+    {"dvav", EME_CODEC_MP4_DV_AVC},  // DolbyVision AVC
+#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
+    {"dvh1", EME_CODEC_MP4_DV_HEVC},  // DolbyVision HEVC
+    {"dvhe", EME_CODEC_MP4_DV_HEVC},  // DolbyVision HEVC
+#endif
+#endif
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 };
 
diff --git a/media/base/media_url_demuxer.cc b/media/base/media_url_demuxer.cc
index 190ff244..653d481 100644
--- a/media/base/media_url_demuxer.cc
+++ b/media/base/media_url_demuxer.cc
@@ -75,13 +75,9 @@
 
 void MediaUrlDemuxer::OnEnabledAudioTracksChanged(
     const std::vector<MediaTrack::Id>& track_ids,
-    base::TimeDelta curr_time) {
-  NOTIMPLEMENTED();
-}
+    base::TimeDelta curr_time) {}
 void MediaUrlDemuxer::OnSelectedVideoTrackChanged(
     base::Optional<MediaTrack::Id> selected_track_id,
-    base::TimeDelta curr_time) {
-  NOTIMPLEMENTED();
-}
+    base::TimeDelta curr_time) {}
 
 }  // namespace media
diff --git a/media/base/renderer_factory.cc b/media/base/renderer_factory.cc
index 2824baa..693520b 100644
--- a/media/base/renderer_factory.cc
+++ b/media/base/renderer_factory.cc
@@ -6,10 +6,12 @@
 
 namespace media {
 
-RendererFactory::RendererFactory() {
-}
+RendererFactory::RendererFactory() {}
 
-RendererFactory::~RendererFactory() {
+RendererFactory::~RendererFactory() {}
+
+MediaResource::Type RendererFactory::GetRequiredMediaResourceType() {
+  return MediaResource::Type::STREAM;
 }
 
 }  // namespace media
diff --git a/media/base/renderer_factory.h b/media/base/renderer_factory.h
index f0a375f..c65f960 100644
--- a/media/base/renderer_factory.h
+++ b/media/base/renderer_factory.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "media/base/media_export.h"
+#include "media/base/media_resource.h"
 #include "media/base/renderer.h"
 #include "media/base/surface_manager.h"
 
@@ -41,6 +42,11 @@
       VideoRendererSink* video_renderer_sink,
       const RequestSurfaceCB& request_surface_cb) = 0;
 
+  // Returns the MediaResource::Type that should be used with the renderers
+  // created by this factory.
+  // NOTE: Returns Type::STREAM by default.
+  virtual MediaResource::Type GetRequiredMediaResourceType();
+
  private:
   DISALLOW_COPY_AND_ASSIGN(RendererFactory);
 };
diff --git a/media/base/renderer_factory_selector.cc b/media/base/renderer_factory_selector.cc
index 49e3fce0..3eb41fc 100644
--- a/media/base/renderer_factory_selector.cc
+++ b/media/base/renderer_factory_selector.cc
@@ -23,22 +23,38 @@
 void RendererFactorySelector::SetBaseFactoryType(FactoryType type) {
   DCHECK(factories_[type]);
   base_factory_type_ = type;
+  current_factory_needs_update_ = true;
 }
 
-RendererFactory* RendererFactorySelector::GetCurrentFactory() {
+// For the moment, this method should only be called once or twice.
+// This method will be regularly called whenever the logic in choosing a
+// renderer type is moved out of the AdaptiveRendererFactory, into this method.
+void RendererFactorySelector::UpdateCurrentFactory() {
   DCHECK(base_factory_type_);
   FactoryType next_factory_type = base_factory_type_.value();
 
-  RendererFactory* factory = factories_[next_factory_type].get();
+  if (use_media_player_)
+    next_factory_type = FactoryType::MEDIA_PLAYER;
 
-  if (factory == nullptr) {
-    NOTREACHED();
-    return nullptr;
-  }
+  DVLOG(1) << __func__ << " Selecting factory type: " << next_factory_type;
 
-  DVLOG(1) << __func__ << " Selected factory type: " << next_factory_type;
-
-  return factory;
+  current_factory_ = factories_[next_factory_type].get();
+  current_factory_needs_update_ = false;
 }
 
+RendererFactory* RendererFactorySelector::GetCurrentFactory() {
+  if (current_factory_needs_update_)
+    UpdateCurrentFactory();
+
+  DCHECK(current_factory_);
+  return current_factory_;
+}
+
+#if defined(OS_ANDROID)
+void RendererFactorySelector::SetUseMediaPlayer(bool use_media_player) {
+  use_media_player_ = use_media_player;
+  current_factory_needs_update_ = true;
+}
+#endif
+
 }  // namespace media
diff --git a/media/base/renderer_factory_selector.h b/media/base/renderer_factory_selector.h
index 4a6f4e05..d40c20a 100644
--- a/media/base/renderer_factory_selector.h
+++ b/media/base/renderer_factory_selector.h
@@ -36,11 +36,24 @@
   // be used by default.
   void SetBaseFactoryType(FactoryType type);
 
-  // SetBaseFactoryType() must be called before calling this method.
-  // NOTE: This only returns the base factory type at the moment.
+  // Updates |current_factory_| if necessary, and returns its value.
+  // NOTE: SetBaseFactoryType() must be called before calling this method.
   RendererFactory* GetCurrentFactory();
 
+#if defined(OS_ANDROID)
+  // Sets whether we should be using the MEDIA_PLAYER factory instead of the
+  // base factory.
+  void SetUseMediaPlayer(bool use_media_player);
+#endif
+
  private:
+  void UpdateCurrentFactory();
+
+  bool use_media_player_ = false;
+
+  bool current_factory_needs_update_ = true;
+  RendererFactory* current_factory_ = nullptr;
+
   base::Optional<FactoryType> base_factory_type_;
   std::unique_ptr<RendererFactory> factories_[FACTORY_TYPE_MAX + 1];
   DISALLOW_COPY_AND_ASSIGN(RendererFactorySelector);
diff --git a/media/base/renderer_factory_selector_unittest.cc b/media/base/renderer_factory_selector_unittest.cc
index b920866..20241264 100644
--- a/media/base/renderer_factory_selector_unittest.cc
+++ b/media/base/renderer_factory_selector_unittest.cc
@@ -70,4 +70,21 @@
   EXPECT_EQ(FactoryType::MOJO, GetCurrentlySelectedFactoryType());
 }
 
+#if defined(OS_ANDROID)
+TEST_F(RendererFactorySelectorTest, SetUseMediaPlayer) {
+  AddFactory(FactoryType::DEFAULT);
+  AddFactory(FactoryType::MEDIA_PLAYER);
+  selector_.SetBaseFactoryType(FactoryType::DEFAULT);
+
+  selector_.SetUseMediaPlayer(false);
+  EXPECT_EQ(FactoryType::DEFAULT, GetCurrentlySelectedFactoryType());
+
+  selector_.SetUseMediaPlayer(true);
+  EXPECT_EQ(FactoryType::MEDIA_PLAYER, GetCurrentlySelectedFactoryType());
+
+  selector_.SetUseMediaPlayer(false);
+  EXPECT_EQ(FactoryType::DEFAULT, GetCurrentlySelectedFactoryType());
+}
+#endif
+
 }  // namespace media
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index e1f11db4..97695bee 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -235,7 +235,6 @@
       overlay_surface_id_(SurfaceManager::kNoSurfaceID),
       suppress_destruction_errors_(false),
       suspend_enabled_(params->allow_suspend()),
-      use_fallback_path_(false),
       is_encrypted_(false),
       preroll_attempt_pending_(false),
       observer_(params->media_observer()),
@@ -405,8 +404,8 @@
   // Set subresource URL for crash reporting.
   base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
 
-  if (use_fallback_path_)
-    fallback_url_ = gurl;
+  // Used for HLS playback.
+  loaded_url_ = gurl;
 
   load_type_ = load_type;
 
@@ -816,9 +815,10 @@
   const bool is_finite_stream = data_source_ && data_source_->IsStreaming() &&
                                 std::isfinite(seekable_end);
 
-  // Do not change the seekable range when using the fallback path.
-  // The MediaPlayerRenderer will take care of dropping invalid seeks.
-  const bool force_seeks_to_zero = !use_fallback_path_ && is_finite_stream;
+  // Do not change the seekable range when using the MediaPlayerRenderer. It
+  // will take care of dropping invalid seeks.
+  const bool force_seeks_to_zero =
+      !using_media_player_renderer_ && is_finite_stream;
 
   // TODO(dalecurtis): Technically this allows seeking on media which return an
   // infinite duration so long as DataSource::IsStreaming() is false. While not
@@ -1611,10 +1611,6 @@
   cast_impl_.SetDeviceScaleFactor(scale_factor);
 }
 
-void WebMediaPlayerImpl::SetUseFallbackPath(bool use_fallback_path) {
-  use_fallback_path_ = use_fallback_path;
-}
-
 void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
   cast_impl_.setPoster(poster);
 }
@@ -1626,18 +1622,15 @@
 
 #if defined(OS_ANDROID)
   // We can't play HLS URLs with WebMediaPlayerImpl, so in cases where they are
-  // encountered, instruct the HTML media element to create a new WebMediaPlayer
-  // instance with the correct URL to trigger the creation of WMPI with a
-  // MediaPlayerRendererFactory instead.
+  // encountered, instruct the HTML media element to use the MediaPlayerRenderer
+  // instead.
   //
-  // TODO(tguilbert): Allow 'hotswapping' renderer factories to prevent reloads
-  // and/or rely on demuxer extracted MediaContainerNames. See crbug.com/663503.
-  if (data_source_ && !use_fallback_path_) {
+  // TODO(tguilbert): Detect the presence of HLS based on demuxing results,
+  // rather than the URL string. See crbug.com/663503.
+  if (data_source_) {
     const GURL url_after_redirects = data_source_->GetUrlAfterRedirects();
     if (MediaCodecUtil::IsHLSURL(url_after_redirects)) {
-      client_->RequestReload(url_after_redirects);
-      // |this| may be destructed, do nothing after this.
-      return;
+      renderer_factory_selector_->SetUseMediaPlayer(true);
     }
   }
 #endif
@@ -1683,7 +1676,6 @@
     const SurfaceCreatedCB& set_surface_cb) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   DCHECK(surface_manager_);
-  DCHECK(!use_fallback_path_);
 
   // A null callback indicates that the decoder is going away.
   if (set_surface_cb.is_null()) {
@@ -1733,9 +1725,20 @@
       BindToCurrentLoop(base::Bind(
           &WebMediaPlayerImpl::OnEncryptedMediaInitData, AsWeakPtr()));
 
-  if (use_fallback_path_) {
+  if (renderer_factory_selector_->GetCurrentFactory()
+          ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
+    if (data_source_)
+      loaded_url_ = data_source_->GetUrlAfterRedirects();
+
+    // MediaPlayerRendererClient factory is the only factory that a
+    // MediaResource::Type::URL for the moment. This might no longer be true
+    // when we remove WebMediaPlayerCast.
+    //
+    // TODO(tguilbert/avayvod): Update this flag when removing |cast_impl_|.
+    using_media_player_renderer_ = true;
+
     demuxer_.reset(
-        new MediaUrlDemuxer(media_task_runner_, fallback_url_,
+        new MediaUrlDemuxer(media_task_runner_, loaded_url_,
                             frame_->GetDocument().FirstPartyForCookies()));
     pipeline_controller_.Start(demuxer_.get(), this, false, false);
     return;
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index dd29a33..de05e09 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -656,8 +656,15 @@
 
   // Used for HLS playback and in certain fallback paths (e.g. on older devices
   // that can't support the unified media pipeline).
-  GURL fallback_url_;
-  bool use_fallback_path_;
+  GURL loaded_url_;
+
+  // NOTE: |using_media_player_renderer_| is set based on the usage of a
+  // MediaResource::Type::URL in StartPipeline(). This currently works because
+  // the MediaPlayerRendererClient factory is the only factory that returns that
+  // Type, but this may no longer be accurate when we remove |cast_impl_| and
+  // WebMediaPlayerCast. This flag should be renamed/updated accordingly when
+  // removing |cast_impl_|.
+  bool using_media_player_renderer_ = false;
 
   // Called sometime after the media is suspended in a playing state in
   // OnFrameHidden(), causing the state to change to paused.
diff --git a/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom b/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom
index 3858330a..6df1e8b 100644
--- a/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom
@@ -40,6 +40,11 @@
   Send(int32 value);
 };
 
+interface StringSender {
+  Echo(string value) => (string value);
+  Send(string value);
+};
+
 interface IntegerSenderConnection {
   GetSender(associated IntegerSender& sender);
   AsyncGetSender() => (associated IntegerSender sender);
@@ -50,6 +55,11 @@
   SetSender(associated IntegerSender sender) => (int32 value);
 };
 
+interface SenderConnection {
+  GetIntegerSender(associated IntegerSender& sender);
+  GetStringSender(associated StringSender& sender);
+};
+
 interface AssociatedPingProvider {
   GetPing(associated PingService& request);
 };
diff --git a/mojo/public/js/connector.js b/mojo/public/js/connector.js
index 012e3c7..d51b429 100644
--- a/mojo/public/js/connector.js
+++ b/mojo/public/js/connector.js
@@ -18,6 +18,7 @@
     this.incomingReceiver_ = null;
     this.readWatcher_ = null;
     this.errorHandler_ = null;
+    this.paused_ = false;
 
     if (handle) {
       this.readWatcher_ = support.watch(handle,
@@ -37,6 +38,31 @@
     }
   };
 
+  Connector.prototype.pauseIncomingMethodCallProcessing = function() {
+    if (this.paused_) {
+      return;
+    }
+    this.paused_= true;
+
+    if (this.readWatcher_) {
+      support.cancelWatch(this.readWatcher_);
+      this.readWatcher_ = null;
+    }
+  };
+
+  Connector.prototype.resumeIncomingMethodCallProcessing = function() {
+    if (!this.paused_) {
+      return;
+    }
+    this.paused_= false;
+
+    if (this.handle_) {
+      this.readWatcher_ = support.watch(this.handle_,
+                                        core.HANDLE_SIGNAL_READABLE,
+                                        this.readMore_.bind(this));
+    }
+  };
+
   Connector.prototype.accept = function(message) {
     if (this.error_)
       return false;
@@ -85,6 +111,10 @@
 
   Connector.prototype.readMore_ = function(result) {
     for (;;) {
+      if (this.paused_) {
+        return;
+      }
+
       var read = core.readMessage(this.handle_,
                                   core.READ_MESSAGE_FLAG_NONE);
       if (this.handle_ == null) // The connector has been closed.
diff --git a/mojo/public/js/router.js b/mojo/public/js/router.js
index 401a222..dfe7c28 100644
--- a/mojo/public/js/router.js
+++ b/mojo/public/js/router.js
@@ -72,6 +72,9 @@
     });
 
     this.setInterfaceIdNamespaceBit_ = setInterfaceIdNamespaceBit;
+    // |cachedMessageData| caches infomation about a message, so it can be
+    // processed later if a client is not yet attached to the target endpoint.
+    this.cachedMessageData = null;
     this.controlMessageHandler_ = new PipeControlMessageHandler(this);
     this.controlMessageProxy_ = new PipeControlMessageProxy(this.connector_);
     this.nextInterfaceIdValue_ = 1;
@@ -132,6 +135,31 @@
           endpoint.client.notifyError.bind(endpoint.client));
     }
 
+    if (this.cachedMessageData && interfaceEndpointHandle.id() ===
+        this.cachedMessageData.message.getInterfaceId()) {
+      timer.createOneShot(0, (function() {
+        if (!this.cachedMessageData) {
+          return;
+        }
+
+        var targetEndpoint = this.endpoints_.get(
+            this.cachedMessageData.message.getInterfaceId());
+        // Check that the target endpoint's client still exists.
+        if (targetEndpoint && targetEndpoint.client) {
+          var message = this.cachedMessageData.message;
+          var messageValidator = this.cachedMessageData.messageValidator;
+          this.cachedMessageData = null;
+          this.connector_.resumeIncomingMethodCallProcessing();
+          var ok = endpoint.client.handleIncomingMessage(message,
+              messageValidator);
+
+          if (!ok) {
+            this.handleInvalidIncomingMessage_();
+          }
+        }
+      }).bind(this));
+    }
+
     return endpoint;
   };
 
@@ -199,9 +227,10 @@
         if (!endpoint.client) {
           // We need to wait until a client is attached in order to dispatch
           // further messages.
-          // TODO(wangjimmy): Cache the message and send when the appropriate
-          // endpoint client is attached.
-          return false;
+          this.cachedMessageData = {message: message,
+              messageValidator: messageValidator};
+          this.connector_.pauseIncomingMethodCallProcessing();
+          return true;
         }
         ok = endpoint.client.handleIncomingMessage(message, messageValidator);
       }
@@ -290,6 +319,12 @@
     if (!types.isMasterInterfaceId(interfaceId) || reason) {
       this.controlMessageProxy_.notifyPeerEndpointClosed(interfaceId, reason);
     }
+
+    if (this.cachedMessageData && interfaceId ===
+        this.cachedMessageData.message.getInterfaceId()) {
+      this.cachedMessageData = null;
+      this.connector_.resumeIncomingMethodCallProcessing();
+    }
   };
 
   Router.prototype.updateEndpointStateMayRemove = function(endpoint,
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index 968cffa..42f8c17 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -96,28 +96,29 @@
 //-----------------------------------------------------------------------------
 
 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry)
-    : disk_entry(entry),
-      writer(NULL),
-      will_process_pending_queue(false),
-      doomed(false) {
-}
+    : disk_entry(entry) {}
 
 HttpCache::ActiveEntry::~ActiveEntry() {
   if (disk_entry) {
     disk_entry->Close();
-    disk_entry = NULL;
+    disk_entry = nullptr;
   }
 }
 
 size_t HttpCache::ActiveEntry::EstimateMemoryUsage() const {
   // Skip |disk_entry| which is tracked in simple_backend_impl; Skip |readers|
-  // and |pending_queue| because the Transactions are owned by their respective
-  // URLRequestHttpJobs.
+  // and |add_to_entry_queue| because the Transactions are owned by their
+  // respective URLRequestHttpJobs.
   return 0;
 }
 
 bool HttpCache::ActiveEntry::HasNoTransactions() {
-  return !writer && readers.empty() && pending_queue.empty();
+  return !writer && readers.empty() && add_to_entry_queue.empty() &&
+         done_headers_queue.empty() && !headers_transaction;
+}
+
+bool HttpCache::ActiveEntry::HasNoActiveTransactions() {
+  return !writer && readers.empty() && !headers_transaction;
 }
 
 //-----------------------------------------------------------------------------
@@ -342,15 +343,17 @@
   weak_factory_.InvalidateWeakPtrs();
 
   // If we have any active entries remaining, then we need to deactivate them.
-  // We may have some pending calls to OnProcessPendingQueue, but since those
-  // won't run (due to our destruction), we can simply ignore the corresponding
-  // will_process_pending_queue flag.
+  // We may have some pending tasks to process queued transactions ,but since
+  // those won't run (due to our destruction), we can simply ignore the
+  // corresponding flags.
   while (!active_entries_.empty()) {
     ActiveEntry* entry = active_entries_.begin()->second.get();
-    entry->will_process_pending_queue = false;
-    entry->pending_queue.clear();
+    entry->will_process_queued_transactions = false;
+    entry->add_to_entry_queue.clear();
     entry->readers.clear();
-    entry->writer = NULL;
+    entry->done_headers_queue.clear();
+    entry->headers_transaction = nullptr;
+    entry->writer = nullptr;
     DeactivateEntry(entry);
   }
 
@@ -611,7 +614,8 @@
   entry_ptr->doomed = true;
 
   DCHECK(entry_ptr->writer || !entry_ptr->readers.empty() ||
-         entry_ptr->will_process_pending_queue);
+         entry_ptr->headers_transaction ||
+         entry_ptr->will_process_queued_transactions);
   return OK;
 }
 
@@ -667,7 +671,7 @@
 
 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
   auto it = active_entries_.find(key);
-  return it != active_entries_.end() ? it->second.get() : NULL;
+  return it != active_entries_.end() ? it->second.get() : nullptr;
 }
 
 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
@@ -679,7 +683,7 @@
 }
 
 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
-  DCHECK(!entry->will_process_pending_queue);
+  DCHECK(!entry->will_process_queued_transactions);
   DCHECK(!entry->doomed);
   DCHECK(entry->disk_entry);
   DCHECK(entry->HasNoTransactions());
@@ -809,121 +813,261 @@
   }
 }
 
-int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) {
+int HttpCache::AddTransactionToEntry(ActiveEntry* entry,
+                                     Transaction* transaction) {
   DCHECK(entry);
   DCHECK(entry->disk_entry);
-
-  // We implement a basic reader/writer lock for the disk cache entry.  If
-  // there is already a writer, then everyone has to wait for the writer to
-  // finish before they can access the cache entry.  There can be multiple
-  // readers.
-  //
-  // NOTE: If the transaction can only write, then the entry should not be in
-  // use (since any existing entry should have already been doomed).
-
-  if (entry->writer || entry->will_process_pending_queue) {
-    entry->pending_queue.push_back(trans);
-    return ERR_IO_PENDING;
-  }
-
-  if (trans->mode() & Transaction::WRITE) {
-    // transaction needs exclusive access to the entry
-    if (entry->readers.empty()) {
-      entry->writer = trans;
-    } else {
-      entry->pending_queue.push_back(trans);
-      return ERR_IO_PENDING;
-    }
-  } else {
-    // transaction needs read access to the entry
-    entry->readers.insert(trans);
-  }
-
-  // We do this before calling EntryAvailable to force any further calls to
-  // AddTransactionToEntry to add their transaction to the pending queue, which
-  // ensures FIFO ordering.
-  if (!entry->writer && !entry->pending_queue.empty())
-    ProcessPendingQueue(entry);
-
-  return OK;
+  // Always add a new transaction to the queue to maintain FIFO order.
+  entry->add_to_entry_queue.push_back(transaction);
+  ProcessQueuedTransactions(entry);
+  return ERR_IO_PENDING;
 }
 
-void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
+int HttpCache::DoneWithResponseHeaders(ActiveEntry* entry,
+                                       Transaction* transaction) {
+  // If |transaction| is the current writer, do nothing. This can happen for
+  // range requests since they can go back to headers phase after starting to
+  // write.
+  if (entry->writer == transaction)
+    return OK;
+
+  DCHECK_EQ(entry->headers_transaction, transaction);
+
+  entry->headers_transaction = nullptr;
+
+  // If transaction is responsible for writing the response body, then do not go
+  // through done_headers_queue for performance benefit. (Also, in case of
+  // writer transaction, the consumer sometimes depend on synchronous behaviour
+  // e.g. while computing raw headers size. (crbug.com/711766))
+  if (transaction->mode() & Transaction::WRITE) {
+    DCHECK(entry->done_headers_queue.empty());
+    DCHECK(!entry->writer);
+    entry->writer = transaction;
+    ProcessQueuedTransactions(entry);
+    return OK;
+  }
+
+  // If this is not the first transaction in done_headers_queue, it should be a
+  // read-mode transaction.
+  DCHECK(entry->done_headers_queue.empty() ||
+         !(transaction->mode() & Transaction::WRITE));
+
+  entry->done_headers_queue.push_back(transaction);
+  ProcessQueuedTransactions(entry);
+  return ERR_IO_PENDING;
+}
+
+void HttpCache::DoneWithEntry(ActiveEntry* entry,
+                              Transaction* transaction,
                               bool cancel) {
-  // If we already posted a task to move on to the next transaction and this was
-  // the writer, there is nothing to cancel.
-  if (entry->will_process_pending_queue && entry->readers.empty())
+  // Transaction is waiting in the done_headers_queue.
+  auto it = std::find(entry->done_headers_queue.begin(),
+                      entry->done_headers_queue.end(), transaction);
+  if (it != entry->done_headers_queue.end()) {
+    entry->done_headers_queue.erase(it);
+    if (cancel)
+      ProcessEntryFailure(entry);
     return;
+  }
 
-  if (entry->writer) {
-    DCHECK(trans == entry->writer);
+  // Transaction is removed in the headers phase.
+  if (transaction == entry->headers_transaction) {
+    // If the response is not written (cancel is true), consider it a failure.
+    DoneWritingToEntry(entry, !cancel, transaction);
+    return;
+  }
 
+  // Transaction is removed in the writing phase.
+  if (transaction == entry->writer) {
     // Assume there was a failure.
     bool success = false;
     if (cancel) {
       DCHECK(entry->disk_entry);
       // This is a successful operation in the sense that we want to keep the
       // entry.
-      success = trans->AddTruncatedFlag();
+      success = transaction->AddTruncatedFlag();
       // The previous operation may have deleted the entry.
-      if (!trans->entry())
+      if (!transaction->entry())
         return;
     }
-    DoneWritingToEntry(entry, success);
-  } else {
-    DoneReadingFromEntry(entry, trans);
+    DoneWritingToEntry(entry, success, transaction);
+    return;
   }
+
+  // Transaction is reading from the entry.
+  DoneReadingFromEntry(entry, transaction);
 }
 
-void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) {
-  DCHECK(entry->readers.empty());
+void HttpCache::DoneWritingToEntry(ActiveEntry* entry,
+                                   bool success,
+                                   Transaction* transaction) {
+  DCHECK(transaction == entry->writer ||
+         transaction == entry->headers_transaction);
 
-  entry->writer = NULL;
+  if (transaction == entry->writer)
+    entry->writer = nullptr;
+  else
+    entry->headers_transaction = nullptr;
 
-  if (success) {
-    ProcessPendingQueue(entry);
-  } else {
-    DCHECK(!entry->will_process_pending_queue);
-
-    // We failed to create this entry.
-    TransactionList pending_queue;
-    pending_queue.swap(entry->pending_queue);
-
-    entry->disk_entry->Doom();
-    DestroyEntry(entry);
-
-    // We need to do something about these pending entries, which now need to
-    // be added to a new entry.
-    while (!pending_queue.empty()) {
-      // ERR_CACHE_RACE causes the transaction to restart the whole process.
-      pending_queue.front()->io_callback().Run(ERR_CACHE_RACE);
-      pending_queue.pop_front();
-    }
+  // If writer fails, restart the headers_transaction by setting its state.
+  // Since the headers_transactions is awaiting an asynchronous operation
+  // completion, when it's IO callback is invoked, it will be restarted.
+  if (!success && entry->headers_transaction) {
+    entry->headers_transaction->SetValidatingCannotProceed();
+    entry->headers_transaction = nullptr;
+    DCHECK(entry->HasNoActiveTransactions());
   }
+  if (!success)
+    ProcessEntryFailure(entry);
+  else
+    ProcessQueuedTransactions(entry);
 }
 
-void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
+void HttpCache::DoneReadingFromEntry(ActiveEntry* entry,
+                                     Transaction* transaction) {
   DCHECK(!entry->writer);
-
-  auto it = entry->readers.find(trans);
+  auto it = entry->readers.find(transaction);
   DCHECK(it != entry->readers.end());
-
   entry->readers.erase(it);
 
-  ProcessPendingQueue(entry);
+  ProcessQueuedTransactions(entry);
 }
 
-void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
-  DCHECK(entry->writer);
-  DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
-  DCHECK(entry->readers.empty());
+void HttpCache::RemoveAllQueuedTransactions(ActiveEntry* entry,
+                                            TransactionList* list) {
+  // Process done_headers_queue before add_to_entry_queue to maintain FIFO
+  // order.
+  for (auto* transaction : entry->done_headers_queue)
+    list->push_back(transaction);
+  entry->done_headers_queue.clear();
 
-  Transaction* trans = entry->writer;
+  for (auto* transaction : entry->add_to_entry_queue)
+    list->push_back(transaction);
+  entry->add_to_entry_queue.clear();
+}
 
-  entry->writer = NULL;
-  entry->readers.insert(trans);
+void HttpCache::ProcessEntryFailure(ActiveEntry* entry) {
+  // Failure case is either writer failing to completely write the response to
+  // the cache or validating transaction received a non-304 response.
+  TransactionList list;
+  if (entry->HasNoActiveTransactions() &&
+      !entry->will_process_queued_transactions) {
+    entry->disk_entry->Doom();
+    RemoveAllQueuedTransactions(entry, &list);
+    DestroyEntry(entry);
+  } else {
+    DoomActiveEntry(entry->disk_entry->GetKey());
+    RemoveAllQueuedTransactions(entry, &list);
+  }
+  // ERR_CACHE_RACE causes the transaction to restart the whole process.
+  for (auto* transaction : list)
+    transaction->io_callback().Run(net::ERR_CACHE_RACE);
+}
 
-  ProcessPendingQueue(entry);
+void HttpCache::ProcessQueuedTransactions(ActiveEntry* entry) {
+  // Multiple readers may finish with an entry at once, so we want to batch up
+  // calls to OnProcessQueuedTransactions. This flag also tells us that we
+  // should not delete the entry before OnProcessQueuedTransactions runs.
+  if (entry->will_process_queued_transactions)
+    return;
+
+  entry->will_process_queued_transactions = true;
+
+  // Post a task instead of invoking the io callback of another transaction here
+  // to avoid re-entrancy.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&HttpCache::OnProcessQueuedTransactions, GetWeakPtr(), entry));
+}
+
+void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) {
+  DCHECK(!entry->add_to_entry_queue.empty());
+
+  // Note the entry may be new or may already have a response body written to
+  // it. In both cases, a transaction needs to wait since only one transaction
+  // can be in the headers phase at a time.
+  if (entry->headers_transaction) {
+    return;
+  }
+  Transaction* transaction = entry->add_to_entry_queue.front();
+  entry->add_to_entry_queue.erase(entry->add_to_entry_queue.begin());
+  entry->headers_transaction = transaction;
+
+  transaction->io_callback().Run(OK);
+}
+
+void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) {
+  DCHECK(!entry->writer);
+  DCHECK(!entry->done_headers_queue.empty());
+
+  Transaction* transaction = entry->done_headers_queue.front();
+
+  // If this transaction is responsible for writing the response body.
+  if (transaction->mode() & Transaction::WRITE) {
+    entry->writer = transaction;
+  } else {
+    // If a transaction is in front of this queue with only read mode set and
+    // there is no writer, it implies response body is already written, convert
+    // to a reader.
+    auto return_val = entry->readers.insert(transaction);
+    DCHECK_EQ(return_val.second, true);
+  }
+
+  // Post another task to give a chance to more transactions to either join
+  // readers or another transaction to start parallel validation.
+  ProcessQueuedTransactions(entry);
+
+  entry->done_headers_queue.erase(entry->done_headers_queue.begin());
+  transaction->io_callback().Run(OK);
+}
+
+bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry,
+                                                   Transaction* transaction,
+                                                   bool is_match) const {
+  if (transaction != entry->headers_transaction)
+    return false;
+
+  if (!(transaction->mode() & Transaction::WRITE))
+    return false;
+
+  // If its not a match then check if it is the transaction responsible for
+  // writing the response body.
+  if (!is_match) {
+    return !entry->writer && entry->done_headers_queue.empty() &&
+           entry->readers.empty();
+  }
+
+  return true;
+}
+
+bool HttpCache::IsTransactionWritingIncomplete(
+    ActiveEntry* entry,
+    Transaction* transaction,
+    const std::string& method) const {
+  if (transaction == entry->writer)
+    return true;
+
+  if (method == "HEAD" || method == "DELETE")
+    return false;
+
+  // Check if transaction is about to start writing to the cache.
+
+  // Transaction's mode may have been set to NONE if StopCaching was invoked.
+  if (!(transaction->mode() & Transaction::WRITE ||
+        transaction->mode() == Transaction::NONE)) {
+    return false;
+  }
+
+  // If a transaction is completing headers or done with headers phase with
+  // write mode then it should be the future writer. Just checking the front of
+  // done_headers_queue since the rest should anyways be READ mode transactions
+  // as they would be a result of validation match.
+  return transaction == entry->headers_transaction ||
+         transaction == entry->done_headers_queue.front();
+}
+
+bool HttpCache::IsWritingInProgress(ActiveEntry* entry) const {
+  return entry->writer != nullptr;
 }
 
 LoadState HttpCache::GetLoadStateForPendingTransaction(
@@ -973,14 +1117,15 @@
 }
 
 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
-                                                  Transaction* trans) {
-  TransactionList& pending_queue = entry->pending_queue;
+                                                  Transaction* transaction) {
+  TransactionList& add_to_entry_queue = entry->add_to_entry_queue;
 
-  auto j = find(pending_queue.begin(), pending_queue.end(), trans);
-  if (j == pending_queue.end())
+  auto j =
+      find(add_to_entry_queue.begin(), add_to_entry_queue.end(), transaction);
+  if (j == add_to_entry_queue.end())
     return false;
 
-  pending_queue.erase(j);
+  add_to_entry_queue.erase(j);
   return true;
 }
 
@@ -1002,22 +1147,11 @@
   return false;
 }
 
-void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
-  // Multiple readers may finish with an entry at once, so we want to batch up
-  // calls to OnProcessPendingQueue.  This flag also tells us that we should
-  // not delete the entry before OnProcessPendingQueue runs.
-  if (entry->will_process_pending_queue)
-    return;
-  entry->will_process_pending_queue = true;
+void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) {
+  entry->will_process_queued_transactions = false;
 
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry));
-}
-
-void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
-  entry->will_process_pending_queue = false;
-  DCHECK(!entry->writer);
+  // Note that this function should only invoke one transaction's IO callback
+  // since its possible for IO callbacks' consumers to destroy the cache/entry.
 
   // If no one is interested in this entry, then we can deactivate it.
   if (entry->HasNoTransactions()) {
@@ -1025,20 +1159,22 @@
     return;
   }
 
-  if (entry->pending_queue.empty())
+  if (entry->done_headers_queue.empty() && entry->add_to_entry_queue.empty())
     return;
 
-  // Promote next transaction from the pending queue.
-  Transaction* next = entry->pending_queue.front();
-  if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
-    return;  // Have to wait.
+  // To maintain FIFO order of transactions, done_headers_queue should be
+  // checked for processing before add_to_entry_queue.
 
-  entry->pending_queue.erase(entry->pending_queue.begin());
-
-  int rv = AddTransactionToEntry(entry, next);
-  if (rv != ERR_IO_PENDING) {
-    next->io_callback().Run(rv);
+  // If another transaction is writing the response, let validated transactions
+  // wait till the response is complete. If the response is not yet started, the
+  // done_headers_queue transaction should start writing it.
+  if (!entry->writer && !entry->done_headers_queue.empty()) {
+    ProcessDoneHeadersQueue(entry);
+    return;
   }
+
+  if (!entry->add_to_entry_queue.empty())
+    ProcessAddToEntryQueue(entry);
 }
 
 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index 635cb92d..ca8ba08 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -244,10 +244,32 @@
   friend class ViewCacheHelper;
   struct PendingOp;  // Info for an entry under construction.
 
+  // To help with testing.
+  friend class MockHttpCache;
+
   using TransactionList = std::list<Transaction*>;
   using TransactionSet = std::unordered_set<Transaction*>;
   typedef std::list<std::unique_ptr<WorkItem>> WorkItemList;
 
+  // We implement a basic reader/writer lock for the disk cache entry. If there
+  // is a writer, then all transactions must wait to read the body. But the
+  // waiting transactions can start their headers phase in parallel. Headers
+  // phase is allowed for one transaction at a time so that if it doesn't match
+  // the existing headers, remaining transactions do not also try to match the
+  // existing entry in parallel leading to wasted network requests. If the
+  // headers do not match, this entry will be doomed.
+  //
+  // A transaction goes through these state transitions.
+  //
+  // Write mode transactions:
+  // add_to_entry_queue-> headers_transaction -> writer
+  // add_to_entry_queue-> headers_transaction -> done_headers_queue -> readers
+  // (once the data is written to the cache by another writer)
+  //
+  // Read only transactions:
+  // add_to_entry_queue-> headers_transaction -> done_headers_queue -> readers
+  // (once the data is written to the cache by the writer)
+
   struct ActiveEntry {
     explicit ActiveEntry(disk_cache::Entry* entry);
     ~ActiveEntry();
@@ -256,12 +278,36 @@
     // Returns true if no transactions are associated with this entry.
     bool HasNoTransactions();
 
-    disk_cache::Entry* disk_entry;
-    Transaction*       writer;
+    // Returns true if no active readers/writer transactions are associated
+    // with this entry.
+    bool HasNoActiveTransactions();
+
+    disk_cache::Entry* disk_entry = nullptr;
+
+    // Transactions waiting to be added to entry.
+    TransactionList add_to_entry_queue;
+
+    // Transaction currently in the headers phase, either validating the
+    // response or getting new headers. This can exist simultaneously with
+    // writer or readers while validating existing headers.
+    Transaction* headers_transaction = nullptr;
+
+    // Transactions that have completed their headers phase and are waiting
+    // to read the response body or write the response body.
+    TransactionList done_headers_queue;
+
+    // Transaction currently reading from the network and writing to the cache.
+    Transaction* writer = nullptr;
+
+    // Transactions that can only read from the cache. Only one of writer or
+    // readers can exist at a time.
     TransactionSet readers;
-    TransactionList    pending_queue;
-    bool               will_process_pending_queue;
-    bool               doomed;
+
+    // The following variables are true if OnProcessQueuedTransactions is posted
+    bool will_process_queued_transactions = false;
+
+    // True if entry is doomed.
+    bool doomed = false;
   };
 
   using ActiveEntriesMap =
@@ -342,28 +388,73 @@
   // Destroys an ActiveEntry (active or doomed).
   void DestroyEntry(ActiveEntry* entry);
 
-  // Adds a transaction to an ActiveEntry. If this method returns ERR_IO_PENDING
-  // the transaction will be notified about completion via its IO callback. This
-  // method returns ERR_CACHE_RACE to signal the transaction that it cannot be
-  // added to the provided entry, and it should retry the process with another
-  // one (in this case, the entry is no longer valid).
-  int AddTransactionToEntry(ActiveEntry* entry, Transaction* trans);
+  // Adds a transaction to an ActiveEntry. This method returns ERR_IO_PENDING
+  // and the transaction will be notified about completion via its IO callback.
+  // In a failure case, the callback will be invoked with ERR_CACHE_RACE.
+  int AddTransactionToEntry(ActiveEntry* entry, Transaction* transaction);
+
+  // Transaction invokes this when its response headers phase is complete
+  // If the transaction is responsible for writing the response body,
+  // it becomes the writer and returns OK. In other cases ERR_IO_PENDING is
+  // returned and the transaction will be notified about completion via its
+  // IO callback. In a failure case, the callback will be invoked with
+  // ERR_CACHE_RACE.
+  int DoneWithResponseHeaders(ActiveEntry* entry, Transaction* transaction);
 
   // Called when the transaction has finished working with this entry. |cancel|
   // is true if the operation was cancelled by the caller instead of running
   // to completion.
-  void DoneWithEntry(ActiveEntry* entry, Transaction* trans, bool cancel);
+  void DoneWithEntry(ActiveEntry* entry, Transaction* transaction, bool cancel);
 
   // Called when the transaction has finished writing to this entry. |success|
   // is false if the cache entry should be deleted.
-  void DoneWritingToEntry(ActiveEntry* entry, bool success);
+  void DoneWritingToEntry(ActiveEntry* entry,
+                          bool success,
+                          Transaction* transaction);
 
   // Called when the transaction has finished reading from this entry.
-  void DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans);
+  void DoneReadingFromEntry(ActiveEntry* entry, Transaction* transaction);
 
-  // Converts the active writer transaction to a reader so that other
-  // transactions can start reading from this entry.
-  void ConvertWriterToReader(ActiveEntry* entry);
+  // Removes and returns all queued transactions in |entry| in FIFO order. This
+  // includes transactions that have completed the headers phase and those that
+  // have not been added to the entry yet in that order. |list| is the output
+  // argument.
+  void RemoveAllQueuedTransactions(ActiveEntry* entry, TransactionList* list);
+
+  // Processes either writer's failure to write response body or
+  // headers_transactions's failure to write headers. Also invoked when headers
+  // transaction's validation result is not a match.
+  void ProcessEntryFailure(ActiveEntry* entry);
+
+  // Resumes processing the queued transactions of |entry|.
+  void ProcessQueuedTransactions(ActiveEntry* entry);
+
+  // Checks if a transaction can be added to the entry. If yes, it will
+  // invoke the IO callback of the transaction. This is a helper function for
+  // OnProcessQueuedTransactions. It will take a transaction from
+  // add_to_entry_queue and make it a headers_transaction, if one doesn't exist
+  // already.
+  void ProcessAddToEntryQueue(ActiveEntry* entry);
+
+  // Invoked when a transaction that has already completed the response headers
+  // phase can resume reading/writing the response body. It will invoke the IO
+  // callback of the transaction. This is a helper function for
+  // OnProcessQueuedTransactions.
+  void ProcessDoneHeadersQueue(ActiveEntry* entry);
+
+  // Returns true if this transaction can write headers to the entry.
+  bool CanTransactionWriteResponseHeaders(ActiveEntry* entry,
+                                          Transaction* transaction,
+                                          bool is_match) const;
+
+  // Returns true if |transaction| is about to start writing response body or
+  // already started but not yet finished.
+  bool IsTransactionWritingIncomplete(ActiveEntry* entry,
+                                      Transaction* transaction,
+                                      const std::string& method) const;
+
+  // Returns true if a transaction is currently writing the response body.
+  bool IsWritingInProgress(ActiveEntry* entry) const;
 
   // Returns the LoadState of the provided pending transaction.
   LoadState GetLoadStateForPendingTransaction(const Transaction* trans);
@@ -379,12 +470,10 @@
   // Removes the transaction |trans|, from the pending list of |pending_op|.
   bool RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
                                              Transaction* trans);
-  // Resumes processing the pending list of |entry|.
-  void ProcessPendingQueue(ActiveEntry* entry);
 
   // Events (called via PostTask) ---------------------------------------------
 
-  void OnProcessPendingQueue(ActiveEntry* entry);
+  void OnProcessQueuedTransactions(ActiveEntry* entry);
 
   // Callbacks ----------------------------------------------------------------
 
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 5189446..b10bf90 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -156,6 +156,7 @@
       new_entry_(NULL),
       new_response_(NULL),
       mode_(NONE),
+      original_mode_(NONE),
       reading_(false),
       invalid_range_(false),
       truncated_(false),
@@ -196,16 +197,12 @@
 
   if (cache_) {
     if (entry_) {
-      bool cancel_request = reading_ && response_.headers.get();
-      if (cancel_request) {
-        if (partial_) {
-          entry_->disk_entry->CancelSparseIO();
-        } else {
-          cancel_request &= (response_.headers->response_code() == 200);
-        }
-      }
+      bool writing_incomplete = cache_->IsTransactionWritingIncomplete(
+          entry_, this, request_->method);
+      if (writing_incomplete && partial_)
+        entry_->disk_entry->CancelSparseIO();
 
-      cache_->DoneWithEntry(entry_, this, cancel_request);
+      cache_->DoneWithEntry(entry_, this, writing_incomplete);
     } else if (cache_pending_) {
       cache_->RemovePendingTransaction(this);
     }
@@ -565,6 +562,12 @@
               old_connection_attempts_.end());
 }
 
+void HttpCache::Transaction::SetValidatingCannotProceed() {
+  DCHECK(!reading_);
+  next_state_ = STATE_HEADERS_PHASE_CANNOT_PROCEED;
+  entry_ = nullptr;
+}
+
 size_t HttpCache::Transaction::EstimateMemoryUsage() const {
   // TODO(xunjieli): Consider improving the coverage. crbug.com/669108.
   return 0;
@@ -579,7 +582,7 @@
 //   GetBackend* -> InitEntry -> OpenEntry* -> CreateEntry* -> AddToEntry* ->
 //   SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse ->
 //   CacheWriteResponse* -> TruncateCachedData* -> TruncateCachedMetadata* ->
-//   PartialHeadersReceived
+//   PartialHeadersReceived -> FinishHeaders*
 //
 //   Read():
 //   NetworkRead* -> CacheWriteData*
@@ -588,7 +591,7 @@
 //   Start():
 //   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
 //   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
-//   BeginCacheValidation() -> SetupEntryForRead()
+//   BeginCacheValidation() -> SetupEntryForRead() -> FinishHeaders*
 //
 //   Read():
 //   CacheReadData*
@@ -600,7 +603,7 @@
 //   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
 //   UpdateCachedResponse -> CacheWriteUpdatedResponse* ->
 //   UpdateCachedResponseComplete -> OverwriteCachedResponse ->
-//   PartialHeadersReceived
+//   PartialHeadersReceived -> FinishHeaders*
 //
 //   Read():
 //   CacheReadData*
@@ -611,7 +614,7 @@
 //   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
 //   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
 //   OverwriteCachedResponse -> CacheWriteResponse* -> DoTruncateCachedData* ->
-//   TruncateCachedMetadata* -> PartialHeadersReceived
+//   TruncateCachedMetadata* -> PartialHeadersReceived -> FinishHeaders*
 //
 //   Read():
 //   NetworkRead* -> CacheWriteData*
@@ -625,7 +628,7 @@
 //   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
 //   UpdateCachedResponse -> CacheWriteUpdatedResponse* ->
 //   UpdateCachedResponseComplete -> OverwriteCachedResponse ->
-//   PartialHeadersReceived
+//   PartialHeadersReceived -> FinishHeaders*
 //
 //   Read() 1:
 //   NetworkRead* -> CacheWriteData*
@@ -666,7 +669,7 @@
 //   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
 //   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
 //   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
-//   OverwriteCachedResponse
+//   OverwriteCachedResponse -> FinishHeaders*
 //
 // 10. HEAD. Sparse entry, partially cached:
 //   Serve the request from the cache, as long as it doesn't require
@@ -691,7 +694,7 @@
 //   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
 //   -> CacheToggleUnusedSincePrefetch* -> CacheDispatchValidation ->
 //   BeginPartialCacheValidation() -> BeginCacheValidation() ->
-//   SetupEntryForRead()
+//   SetupEntryForRead() -> FinishHeaders*
 //
 //   Read():
 //   CacheReadData*
@@ -705,8 +708,9 @@
   DCHECK(!in_do_loop_);
 
   int rv = result;
+  State state = next_state_;
   do {
-    State state = next_state_;
+    state = next_state_;
     next_state_ = STATE_UNSET;
     base::AutoReset<bool> scoped_in_do_loop(&in_do_loop_, true);
 
@@ -843,6 +847,15 @@
       case STATE_CACHE_READ_METADATA_COMPLETE:
         rv = DoCacheReadMetadataComplete(rv);
         break;
+      case STATE_HEADERS_PHASE_CANNOT_PROCEED:
+        rv = DoHeadersPhaseCannotProceed();
+        break;
+      case STATE_FINISH_HEADERS:
+        rv = DoFinishHeaders(rv);
+        break;
+      case STATE_FINISH_HEADERS_COMPLETE:
+        rv = DoFinishHeadersComplete(rv);
+        break;
       case STATE_NETWORK_READ:
         DCHECK_EQ(OK, rv);
         rv = DoNetworkRead();
@@ -879,8 +892,13 @@
 
   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
 
+  // Assert Start() state machine's allowed last state in successful cases when
+  // caching is happening.
+  DCHECK(reading_ || rv != OK || !entry_ ||
+         state == STATE_FINISH_HEADERS_COMPLETE);
+
   if (rv != ERR_IO_PENDING && !callback_.is_null()) {
-    read_buf_ = NULL;  // Release the buffer before invoking the callback.
+    read_buf_ = nullptr;  // Release the buffer before invoking the callback.
     base::ResetAndReturn(&callback_).Run(rv);
   }
 
@@ -907,7 +925,7 @@
     if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
       if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
         // The client has asked for nonsense.
-        TransitionToState(STATE_NONE);
+        TransitionToState(STATE_FINISH_HEADERS);
         return ERR_CACHE_MISS;
       }
       mode_ = READ;
@@ -946,7 +964,7 @@
   // If must use cache, then we must fail.  This can happen for back/forward
   // navigations to a page generated via a form post.
   if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return ERR_CACHE_MISS;
   }
 
@@ -963,6 +981,9 @@
   // This is only set if we have something to do with the response.
   range_requested_ = (partial_.get() != NULL);
 
+  // mode_ may change later, save the initial mode in case we need to restart
+  // this request.
+  original_mode_ = mode_;
   return OK;
 }
 
@@ -971,7 +992,7 @@
   DCHECK(!new_entry_);
 
   if (!cache_.get()) {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return ERR_UNEXPECTED;
   }
 
@@ -1008,7 +1029,7 @@
   }
 
   if (result == ERR_CACHE_RACE) {
-    TransitionToState(STATE_INIT_ENTRY);
+    TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
     return OK;
   }
 
@@ -1034,7 +1055,7 @@
 
   // The entry does not exist, and we are not permitted to create a new entry,
   // so we must fail.
-  TransitionToState(STATE_NONE);
+  TransitionToState(STATE_FINISH_HEADERS);
   return ERR_CACHE_MISS;
 }
 
@@ -1053,8 +1074,9 @@
   net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_DOOM_ENTRY,
                                     result);
   cache_pending_ = false;
-  TransitionToState(result == ERR_CACHE_RACE ? STATE_INIT_ENTRY
-                                             : STATE_CREATE_ENTRY);
+  TransitionToState(result == ERR_CACHE_RACE
+                        ? STATE_HEADERS_PHASE_CANNOT_PROCEED
+                        : STATE_CREATE_ENTRY);
   return OK;
 }
 
@@ -1081,7 +1103,7 @@
       break;
 
     case ERR_CACHE_RACE:
-      TransitionToState(STATE_INIT_ENTRY);
+      TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
       break;
 
     default:
@@ -1162,13 +1184,13 @@
   new_entry_ = NULL;
 
   if (result == ERR_CACHE_RACE) {
-    TransitionToState(STATE_INIT_ENTRY);
+    TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
     return OK;
   }
 
   if (result == ERR_CACHE_LOCK_TIMEOUT) {
     if (mode_ == READ) {
-      TransitionToState(STATE_NONE);
+      TransitionToState(STATE_FINISH_HEADERS);
       return ERR_CACHE_MISS;
     }
 
@@ -1182,12 +1204,16 @@
     return OK;
   }
 
-  open_entry_last_used_ = entry_->disk_entry->GetLastUsed();
+  // TODO(crbug.com/713354) Access timestamp for histograms only if entry is
+  // already written, to avoid data race since cache thread can also access
+  // this.
+  if (!cache_->IsWritingInProgress(entry_))
+    open_entry_last_used_ = entry_->disk_entry->GetLastUsed();
 
   // TODO(jkarlin): We should either handle the case or DCHECK.
   if (result != OK) {
     NOTREACHED();
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return result;
   }
 
@@ -1226,29 +1252,37 @@
     return OnCacheReadError(result, true);
   }
 
-  int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
-  int64_t full_response_length = response_.headers->GetContentLength();
+  // TODO(crbug.com/713354) Only get data size if there is no other transaction
+  // currently writing the response body due to the data race mentioned in the
+  // associated bug.
+  if (!cache_->IsWritingInProgress(entry_)) {
+    int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
+    int64_t full_response_length = response_.headers->GetContentLength();
 
-  // Some resources may have slipped in as truncated when they're not.
-  if (full_response_length == current_size)
-    truncated_ = false;
+    // Some resources may have slipped in as truncated when they're not.
+    if (full_response_length == current_size)
+      truncated_ = false;
 
-  // The state machine's handling of StopCaching unfortunately doesn't deal well
-  // with resources that are larger than 2GB when there is a truncated or sparse
-  // cache entry. While the state machine is reworked to resolve this, the
-  // following logic is put in place to defer such requests to the network. The
-  // cache should not be storing multi gigabyte resources. See
-  // http://crbug.com/89567.
-  if ((truncated_ || response_.headers->response_code() == 206) &&
-      !range_requested_ &&
-      full_response_length > std::numeric_limits<int32_t>::max()) {
-    // Does not release the cache entry. If another transaction wants to use
-    // this cache entry while this transaction is active, the second transaction
-    // will fall back to the network after the timeout.
-    DCHECK(!partial_);
-    mode_ = NONE;
-    TransitionToState(STATE_SEND_REQUEST);
-    return OK;
+    // The state machine's handling of StopCaching unfortunately doesn't deal
+    // well with resources that are larger than 2GB when there is a truncated or
+    // sparse cache entry. While the state machine is reworked to resolve this,
+    // the following logic is put in place to defer such requests to the
+    // network. The cache should not be storing multi gigabyte resources. See
+    // http://crbug.com/89567.
+    if ((truncated_ || response_.headers->response_code() == 206) &&
+        !range_requested_ &&
+        full_response_length > std::numeric_limits<int32_t>::max()) {
+      DCHECK(!partial_);
+
+      // Doom the entry so that no other transaction gets added to this entry
+      // and avoid a race of not being able to check this condition because
+      // writing is in progress.
+      cache_->DoneWritingToEntry(entry_, false, this);
+      entry_ = nullptr;
+      mode_ = NONE;
+      TransitionToState(STATE_SEND_REQUEST);
+      return OK;
+    }
   }
 
   if (response_.unused_since_prefetch !=
@@ -1330,7 +1364,7 @@
 int HttpCache::Transaction::DoCacheQueryDataComplete(int result) {
   DCHECK_EQ(OK, result);
   if (!cache_.get()) {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return ERR_UNEXPECTED;
   }
 
@@ -1340,7 +1374,7 @@
 // We may end up here multiple times for a given request.
 int HttpCache::Transaction::DoStartPartialCacheValidation() {
   if (mode_ == NONE) {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return OK;
   }
 
@@ -1357,12 +1391,12 @@
       cache_->DoneReadingFromEntry(entry_, this);
       entry_ = NULL;
     }
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return result;
   }
 
   if (result < 0) {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return result;
   }
 
@@ -1388,7 +1422,7 @@
   int rv =
       cache_->network_layer_->CreateTransaction(priority_, &network_trans_);
   if (rv != OK) {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return rv;
   }
   network_trans_->SetBeforeNetworkStartCallback(before_network_start_callback_);
@@ -1410,7 +1444,7 @@
 int HttpCache::Transaction::DoSendRequestComplete(int result) {
   TRACE_EVENT0("io", "HttpCacheTransaction::DoSendRequestComplete");
   if (!cache_.get()) {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return ERR_UNEXPECTED;
   }
 
@@ -1441,7 +1475,7 @@
     DoneWritingToEntry(true);
   }
 
-  TransitionToState(STATE_NONE);
+  TransitionToState(STATE_FINISH_HEADERS);
   return result;
 }
 
@@ -1455,7 +1489,7 @@
       new_response->headers->response_code() == 407) {
     SetAuthResponse(*new_response);
     if (!reading_) {
-      TransitionToState(STATE_NONE);
+      TransitionToState(STATE_FINISH_HEADERS);
       return OK;
     }
 
@@ -1480,7 +1514,7 @@
     mode_ = NONE;
     partial_.reset();
     ResetNetworkTransaction();
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return ERR_CACHE_AUTH_FAILURE_AFTER_READ;
   }
 
@@ -1518,7 +1552,7 @@
       int ret = cache_->DoomEntry(cache_key_, NULL);
       DCHECK_EQ(OK, ret);
     }
-    cache_->DoneWritingToEntry(entry_, true);
+    cache_->DoneWritingToEntry(entry_, true, this);
     entry_ = NULL;
     mode_ = NONE;
   }
@@ -1536,7 +1570,7 @@
       (request_->method == "GET" || request_->method == "POST")) {
     // If there is an active entry it may be destroyed with this transaction.
     SetResponse(*new_response_);
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return OK;
   }
 
@@ -1624,7 +1658,6 @@
   } else if (entry_ && !handling_206_) {
     DCHECK_EQ(READ_WRITE, mode_);
     if (!partial_ || partial_->IsLastRange()) {
-      cache_->ConvertWriterToReader(entry_);
       mode_ = READ;
     }
     // We no longer need the network transaction, so destroy it.
@@ -1662,7 +1695,7 @@
     DoneWritingToEntry(false);
     mode_ = NONE;
     new_response_ = NULL;
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return OK;
   }
 
@@ -1683,6 +1716,19 @@
 int HttpCache::Transaction::DoCacheWriteResponse() {
   TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse");
   TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE);
+
+  // Invalidate any current entry with a successful response if this transaction
+  // cannot write to this entry. This transaction then continues to read from
+  // the network without writing to the backend.
+  bool is_match = response_.headers->response_code() == 304;
+  if (entry_ && response_.headers &&
+      !cache_->CanTransactionWriteResponseHeaders(entry_, this, is_match)) {
+    cache_->DoneWritingToEntry(entry_, false, this);
+    entry_ = nullptr;
+    mode_ = NONE;
+    return OK;
+  }
+
   return WriteResponseInfoToEntry(truncated_);
 }
 
@@ -1744,10 +1790,12 @@
   new_response_ = NULL;
 
   if (!partial_) {
-    if (entry_ && entry_->disk_entry->GetDataSize(kMetadataIndex))
+    if (entry_ && entry_->disk_entry->GetDataSize(kMetadataIndex)) {
       TransitionToState(STATE_CACHE_READ_METADATA);
-    else
-      TransitionToState(STATE_NONE);
+    } else {
+      DCHECK(!reading_);
+      TransitionToState(STATE_FINISH_HEADERS);
+    }
     return OK;
   }
 
@@ -1761,13 +1809,63 @@
     // We are about to return the headers for a byte-range request to the user,
     // so let's fix them.
     partial_->FixResponseHeaders(response_.headers.get(), true);
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
   } else {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
   }
   return OK;
 }
 
+int HttpCache::Transaction::DoHeadersPhaseCannotProceed() {
+  // If its the Start state machine and it cannot proceed due to a cache
+  // failure, restart this transaction.
+  DCHECK(!reading_);
+  TransitionToState(STATE_INIT_ENTRY);
+  cache_entry_status_ = CacheEntryStatus::ENTRY_UNDEFINED;
+  entry_ = nullptr;
+  mode_ = original_mode_;
+  if (network_trans_)
+    network_trans_.reset();
+  return OK;
+}
+
+int HttpCache::Transaction::DoFinishHeaders(int result) {
+  if (!entry_ || result != OK) {
+    TransitionToState(STATE_NONE);
+    return result;
+  }
+
+  TransitionToState(STATE_FINISH_HEADERS_COMPLETE);
+
+  // If it was an auth failure or 416, this transaction should continue to be
+  // headers_transaction till consumer takes an action, so no need to do
+  // anything now.
+  if (auth_response_.headers.get() ||
+      (new_response_ && new_response_->headers &&
+       new_response_->headers->response_code() == 416))
+    return OK;
+
+  // If there is no response body to be written or read, it does not need to
+  // wait.
+  if (request_->method == "HEAD")
+    return OK;
+
+  // If the transaction needs to wait because another transaction is still
+  // writing the response body, it will return ERR_IO_PENDING now and the
+  // io_callback_ will be invoked when the wait is done.
+  return cache_->DoneWithResponseHeaders(entry_, this);
+}
+
+int HttpCache::Transaction::DoFinishHeadersComplete(int rv) {
+  if (rv == ERR_CACHE_RACE) {
+    TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
+    return OK;
+  }
+
+  TransitionToState(STATE_NONE);
+  return rv;
+}
+
 int HttpCache::Transaction::DoCacheReadMetadata() {
   TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadMetadata");
   DCHECK(entry_);
@@ -1790,7 +1888,8 @@
                                     result);
   if (result != response_.metadata->size())
     return OnCacheReadError(result, false);
-  TransitionToState(STATE_NONE);
+
+  TransitionToState(STATE_FINISH_HEADERS);
   return OK;
 }
 
@@ -2087,18 +2186,18 @@
   // TODO(jkarlin): Either handle this case or DCHECK.
   if (response_.headers->response_code() == 206 || partial_) {
     NOTREACHED();
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return ERR_CACHE_MISS;
   }
 
   // We don't have the whole resource.
   if (truncated_) {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return ERR_CACHE_MISS;
   }
 
   if (RequiresValidation()) {
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
     return ERR_CACHE_MISS;
   }
 
@@ -2108,7 +2207,7 @@
   if (entry_->disk_entry->GetDataSize(kMetadataIndex))
     TransitionToState(STATE_CACHE_READ_METADATA);
   else
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
 
   return OK;
 }
@@ -2568,7 +2667,7 @@
       partial_.reset();
     }
   }
-  cache_->ConvertWriterToReader(entry_);
+
   mode_ = READ;
 
   if (request_->method == "HEAD")
@@ -2577,7 +2676,7 @@
   if (entry_->disk_entry->GetDataSize(kMetadataIndex))
     TransitionToState(STATE_CACHE_READ_METADATA);
   else
-    TransitionToState(STATE_NONE);
+    TransitionToState(STATE_FINISH_HEADERS);
   return OK;
 }
 
@@ -2656,7 +2755,7 @@
 
   RecordHistograms();
 
-  cache_->DoneWritingToEntry(entry_, success);
+  cache_->DoneWritingToEntry(entry_, success, this);
   entry_ = NULL;
   mode_ = NONE;  // switch to 'pass through' mode
 }
@@ -2867,10 +2966,14 @@
        cache_entry_status_ == CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE);
   int64_t freshness_periods_since_last_used = 0;
 
-  if (stale_request) {
+  if (stale_request && !open_entry_last_used_.is_null()) {
+    // Note that we are not able to capture those transactions' histograms which
+    // when added to entry, the response was being written by another
+    // transaction because getting the last used timestamp might lead to a data
+    // race in that case. TODO(crbug.com/713354).
+
     // For stale entries, record how many freshness periods have elapsed since
     // the entry was last used.
-    DCHECK(!open_entry_last_used_.is_null());
     DCHECK(!stale_entry_freshness_.is_zero());
     base::TimeDelta time_since_use = base::Time::Now() - open_entry_last_used_;
     freshness_periods_since_last_used =
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 51c0db7..6811dd4 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -164,6 +164,10 @@
   int ResumeNetworkStart() override;
   void GetConnectionAttempts(ConnectionAttempts* out) const override;
 
+  // Invoked when parallel validation cannot proceed due to response failure
+  // and this transaction needs to be restarted.
+  void SetValidatingCannotProceed();
+
   // Returns the estimate of dynamically allocated memory in bytes.
   size_t EstimateMemoryUsage() const;
 
@@ -220,6 +224,9 @@
     STATE_PARTIAL_HEADERS_RECEIVED,
     STATE_CACHE_READ_METADATA,
     STATE_CACHE_READ_METADATA_COMPLETE,
+    STATE_HEADERS_PHASE_CANNOT_PROCEED,
+    STATE_FINISH_HEADERS,
+    STATE_FINISH_HEADERS_COMPLETE,
 
     // These states are entered from Read/AddTruncatedFlag.
     STATE_NETWORK_READ,
@@ -288,6 +295,9 @@
   int DoPartialHeadersReceived();
   int DoCacheReadMetadata();
   int DoCacheReadMetadataComplete(int result);
+  int DoHeadersPhaseCannotProceed();
+  int DoFinishHeaders(int result);
+  int DoFinishHeadersComplete(int result);
   int DoNetworkRead();
   int DoNetworkReadComplete(int result);
   int DoCacheReadData();
@@ -430,7 +440,12 @@
   void SyncCacheEntryStatusToResponse();
   void RecordHistograms();
 
-  // Called to signal completion of asynchronous IO.
+  // Called to signal completion of asynchronous IO. Note that this callback is
+  // used in the conventional sense where one layer calls the callback of the
+  // layer above it e.g. this callback gets called from the network transaction
+  // layer. In addition, it is also used for HttpCache layer to let this
+  // transaction know when it is out of a queued state in ActiveEntry and can
+  // continue its processing.
   void OnIOComplete(int result);
 
   // When in a DoLoop, use this to set the next state as it verifies that the
@@ -456,6 +471,7 @@
   const HttpResponseInfo* new_response_;
   std::string cache_key_;
   Mode mode_;
+  Mode original_mode_;  // Used when restarting the transaction.
   bool reading_;  // We are already reading. Never reverts to false once set.
   bool invalid_range_;  // We may bypass the cache for this request.
   bool truncated_;  // We don't have all the response data.
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index ca9c5d9..626f46a 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -147,6 +147,10 @@
   EXPECT_TRUE(load_timing_info.receive_headers_end.is_null());
 }
 
+void DeferNetworkStart(bool* defer) {
+  *defer = true;
+}
+
 class DeleteCacheCompletionCallback : public TestCompletionCallbackBase {
  public:
   explicit DeleteCacheCompletionCallback(MockHttpCache* cache)
@@ -1350,12 +1354,12 @@
 
   MockHttpRequest request(kSimpleGET_Transaction);
 
-  std::vector<Context*> context_list;
+  std::vector<std::unique_ptr<Context>> context_list;
   const int kNumTransactions = 5;
 
   for (int i = 0; i < kNumTransactions; ++i) {
-    context_list.push_back(new Context());
-    Context* c = context_list[i];
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
 
     c->result = cache.CreateTransaction(&c->trans);
     ASSERT_THAT(c->result, IsOk());
@@ -1366,16 +1370,19 @@
   }
 
   // All requests are waiting for the active entry.
-  for (int i = 0; i < kNumTransactions; ++i) {
-    Context* c = context_list[i];
-    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, context->trans->GetLoadState());
   }
 
   // Allow all requests to move from the Create queue to the active entry.
   base::RunLoop().RunUntilIdle();
 
   // The first request should be a writer at this point, and the subsequent
-  // requests should be pending.
+  // requests should have passed the validation phase and waiting for the
+  // response to be written to the cache before they can read.
+  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+  EXPECT_EQ(kNumTransactions - 1,
+            cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
 
   EXPECT_EQ(1, cache.network_layer()->transaction_count());
   EXPECT_EQ(0, cache.disk_cache()->open_count());
@@ -1383,15 +1390,21 @@
 
   // All requests depend on the writer, and the writer is between Start and
   // Read, i.e. idle.
-  for (int i = 0; i < kNumTransactions; ++i) {
-    Context* c = context_list[i];
-    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
   }
 
   for (int i = 0; i < kNumTransactions; ++i) {
-    Context* c = context_list[i];
+    auto& c = context_list[i];
     if (c->result == ERR_IO_PENDING)
       c->result = c->callback.WaitForResult();
+
+    if (i > 0) {
+      EXPECT_FALSE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+      EXPECT_EQ(kNumTransactions - i,
+                cache.GetCountReaders(kSimpleGET_Transaction.url));
+    }
+
     ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
   }
 
@@ -1400,11 +1413,479 @@
   EXPECT_EQ(1, cache.network_layer()->transaction_count());
   EXPECT_EQ(0, cache.disk_cache()->open_count());
   EXPECT_EQ(1, cache.disk_cache()->create_count());
+}
+
+// Parallel validation results in 200.
+TEST(HttpCache, SimpleGET_ParallelValidationNoMatch) {
+  MockHttpCache cache;
+
+  MockHttpRequest request(kSimpleGET_Transaction);
+  request.load_flags |= LOAD_VALIDATE_CACHE;
+
+  std::vector<std::unique_ptr<Context>> context_list;
+  const int kNumTransactions = 5;
 
   for (int i = 0; i < kNumTransactions; ++i) {
-    Context* c = context_list[i];
-    delete c;
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+    c->result =
+        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
   }
+
+  // All requests are waiting for the active entry.
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, context->trans->GetLoadState());
+  }
+
+  // Allow all requests to move from the Create queue to the active entry.
+  base::RunLoop().RunUntilIdle();
+
+  // The first request should be a writer at this point, and the subsequent
+  // requests should have passed the validation phase and created their own
+  // entries since none of them matched the headers of the earlier one.
+  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+
+  // Note that there are only 3 entries created and not 5 since every other
+  // transaction would have gone to the network.
+  EXPECT_EQ(5, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(3, cache.disk_cache()->create_count());
+
+  // All requests depend on the writer, and the writer is between Start and
+  // Read, i.e. idle.
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
+  }
+
+  for (auto& context : context_list) {
+    if (context->result == ERR_IO_PENDING)
+      context->result = context->callback.WaitForResult();
+    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
+  }
+
+  EXPECT_EQ(5, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(3, cache.disk_cache()->create_count());
+}
+
+// Tests that a GET followed by a DELETE results in DELETE immediately starting
+// the headers phase and the entry is doomed.
+TEST(HttpCache, SimpleGET_ParallelValidationDelete) {
+  MockHttpCache cache;
+
+  MockHttpRequest request(kSimpleGET_Transaction);
+  request.load_flags |= LOAD_VALIDATE_CACHE;
+
+  MockHttpRequest delete_request(kSimpleGET_Transaction);
+  delete_request.method = "DELETE";
+
+  std::vector<std::unique_ptr<Context>> context_list;
+  const int kNumTransactions = 2;
+
+  for (int i = 0; i < kNumTransactions; ++i) {
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    MockHttpRequest* this_request = &request;
+    if (i == 1)
+      this_request = &delete_request;
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+    c->result = c->trans->Start(this_request, c->callback.callback(),
+                                NetLogWithSource());
+  }
+
+  // All requests are waiting for the active entry.
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, context->trans->GetLoadState());
+  }
+
+  // Allow all requests to move from the Create queue to the active entry.
+  base::RunLoop().RunUntilIdle();
+
+  // The first request should be a writer at this point, and the subsequent
+  // request should have passed the validation phase and doomed the existing
+  // entry.
+  EXPECT_TRUE(
+      cache.disk_cache()->IsDiskEntryDoomed(kSimpleGET_Transaction.url));
+
+  EXPECT_EQ(2, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+  // All requests depend on the writer, and the writer is between Start and
+  // Read, i.e. idle.
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
+  }
+
+  for (auto& context : context_list) {
+    if (context->result == ERR_IO_PENDING)
+      context->result = context->callback.WaitForResult();
+    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
+  }
+
+  EXPECT_EQ(2, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+}
+
+// Tests that a transaction which is in validated queue can be destroyed without
+// any impact to other transactions.
+TEST(HttpCache, SimpleGET_ParallelValidationCancelValidated) {
+  MockHttpCache cache;
+
+  MockHttpRequest request(kSimpleGET_Transaction);
+
+  std::vector<std::unique_ptr<Context>> context_list;
+  const int kNumTransactions = 2;
+
+  for (int i = 0; i < kNumTransactions; ++i) {
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+
+    c->result =
+        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+  }
+
+  // Allow all requests to move from the Create queue to the active entry.
+  base::RunLoop().RunUntilIdle();
+
+  // The first request should be a writer at this point, and the subsequent
+  // requests should have completed validation.
+
+  EXPECT_EQ(1, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+  EXPECT_EQ(1, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
+
+  context_list[1].reset();
+
+  EXPECT_EQ(0, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
+
+  // Complete the rest of the transactions.
+  for (auto& context : context_list) {
+    if (!context)
+      continue;
+    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
+  }
+
+  EXPECT_EQ(1, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+}
+
+// Tests that a transaction which is in readers can be destroyed without
+// any impact to other transactions.
+TEST(HttpCache, SimpleGET_ParallelValidationCancelReader) {
+  MockHttpCache cache;
+
+  MockHttpRequest request(kSimpleGET_Transaction);
+
+  MockTransaction transaction(kSimpleGET_Transaction);
+  transaction.load_flags |= LOAD_VALIDATE_CACHE;
+  MockHttpRequest validate_request(transaction);
+
+  int kNumTransactions = 4;
+  std::vector<std::unique_ptr<Context>> context_list;
+
+  for (int i = 0; i < kNumTransactions; ++i) {
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+
+    MockHttpRequest* this_request = &request;
+    if (i == 3) {
+      this_request = &validate_request;
+      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
+    }
+
+    c->result = c->trans->Start(this_request, c->callback.callback(),
+                                NetLogWithSource());
+  }
+
+  // Allow all requests to move from the Create queue to the active entry.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(2, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+  EXPECT_EQ(2, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
+  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
+
+  // Complete the response body.
+  auto& c = context_list[0];
+  ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
+
+  // Rest of the transactions should move to readers.
+  EXPECT_FALSE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+  EXPECT_EQ(2, cache.GetCountReaders(kSimpleGET_Transaction.url));
+  EXPECT_EQ(0, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
+  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
+
+  // Add 2 new transactions.
+  kNumTransactions = 6;
+
+  for (int i = 4; i < kNumTransactions; ++i) {
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+
+    c->result =
+        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+  }
+
+  EXPECT_EQ(2, cache.GetCountAddToEntryQueue(kSimpleGET_Transaction.url));
+
+  // Delete a reader.
+  context_list[1].reset();
+
+  // Deleting the reader did not impact any other transaction.
+  EXPECT_EQ(1, cache.GetCountReaders(kSimpleGET_Transaction.url));
+  EXPECT_EQ(2, cache.GetCountAddToEntryQueue(kSimpleGET_Transaction.url));
+  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
+
+  // Resume network start for headers_transaction. It will doom the entry as it
+  // will be a 200 and will go to network for the response body.
+  auto& context = context_list[3];
+  context->trans->ResumeNetworkStart();
+
+  // The pending transactions will be added to a new entry.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
+  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+
+  // Complete the rest of the transactions.
+  for (int i = 2; i < kNumTransactions; ++i) {
+    auto& c = context_list[i];
+    ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
+  }
+
+  EXPECT_EQ(3, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
+// Tests that a transaction is in validated queue and writer is destroyed
+// leading to restarting the validated transaction.
+TEST(HttpCache, SimpleGET_ParallelValidationCancelWriter) {
+  MockHttpCache cache;
+
+  MockHttpRequest request(kSimpleGET_Transaction);
+
+  MockTransaction transaction(kSimpleGET_Transaction);
+  transaction.load_flags |= LOAD_VALIDATE_CACHE;
+  MockHttpRequest validate_request(transaction);
+
+  const int kNumTransactions = 3;
+  std::vector<std::unique_ptr<Context>> context_list;
+
+  for (int i = 0; i < kNumTransactions; ++i) {
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+
+    MockHttpRequest* this_request = &request;
+    if (i == 2) {
+      this_request = &validate_request;
+      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
+    }
+
+    c->result = c->trans->Start(this_request, c->callback.callback(),
+                                NetLogWithSource());
+  }
+
+  // Allow all requests to move from the Create queue to the active entry.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(2, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
+  EXPECT_EQ(1, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
+
+  // Deleting the writer at this point will lead to destroying the entry and
+  // restarting the remaining transactions which will then create a new entry.
+  context_list[0].reset();
+
+  // Resume network start for headers_transaction. It should be restarted due to
+  // writer cancellation.
+  auto& c = context_list[2];
+  c->trans->ResumeNetworkStart();
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
+
+  // Resume network start for the transaction the second time.
+  c->trans->ResumeNetworkStart();
+  base::RunLoop().RunUntilIdle();
+
+  // Headers transaction would have doomed the new entry created.
+  EXPECT_TRUE(
+      cache.disk_cache()->IsDiskEntryDoomed(kSimpleGET_Transaction.url));
+
+  // Complete the rest of the transactions.
+  for (auto& context : context_list) {
+    if (!context)
+      continue;
+    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
+  }
+
+  EXPECT_EQ(4, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
+// Tests that a transaction is currently in headers phase and is destroyed
+// leading to destroying the entry.
+TEST(HttpCache, SimpleGET_ParallelValidationCancelHeaders) {
+  MockHttpCache cache;
+
+  MockHttpRequest request(kSimpleGET_Transaction);
+
+  const int kNumTransactions = 2;
+  std::vector<std::unique_ptr<Context>> context_list;
+
+  for (int i = 0; i < kNumTransactions; ++i) {
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+
+    if (i == 0)
+      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
+
+    c->result =
+        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+  }
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(cache.IsHeadersTransactionPresent(kSimpleGET_Transaction.url));
+  EXPECT_EQ(1, cache.GetCountAddToEntryQueue(kSimpleGET_Transaction.url));
+
+  EXPECT_EQ(1, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+  // Delete the headers transaction.
+  context_list[0].reset();
+
+  base::RunLoop().RunUntilIdle();
+
+  // Complete the rest of the transactions.
+  for (auto& context : context_list) {
+    if (!context)
+      continue;
+    ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction);
+  }
+
+  EXPECT_EQ(2, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
+// Similar to the above test, except here cache write fails and the
+// validated transactions should be restarted.
+TEST(HttpCache, SimpleGET_ParallelValidationFailWrite) {
+  MockHttpCache cache;
+
+  MockHttpRequest request(kSimpleGET_Transaction);
+
+  const int kNumTransactions = 5;
+  std::vector<std::unique_ptr<Context>> context_list;
+
+  for (int i = 0; i < kNumTransactions; ++i) {
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+    c->result =
+        c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+  }
+
+  // All requests are waiting for the active entry.
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, context->trans->GetLoadState());
+  }
+
+  // Allow all requests to move from the Create queue to the active entry.
+  base::RunLoop().RunUntilIdle();
+
+  // The first request should be a writer at this point, and the subsequent
+  // requests should have passed the validation phase and waiting for the
+  // response to be written to the cache before they can read.
+  EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url));
+  EXPECT_EQ(4, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url));
+
+  // All requests depend on the writer, and the writer is between Start and
+  // Read, i.e. idle.
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
+  }
+
+  // The first request should be a writer at this point, and the subsequent
+  // requests should have passed the validation phase and waiting for the
+  // response to be written to the cache before they can read.
+
+  EXPECT_EQ(1, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+  // Fail the request.
+  cache.disk_cache()->set_soft_failures(true);
+  // We have to open the entry again to propagate the failure flag.
+  disk_cache::Entry* en;
+  cache.OpenBackendEntry(kSimpleGET_Transaction.url, &en);
+  en->Close();
+
+  for (int i = 0; i < kNumTransactions; ++i) {
+    auto& c = context_list[i];
+    if (c->result == ERR_IO_PENDING)
+      c->result = c->callback.WaitForResult();
+    if (i == 1) {
+      // The earlier entry must be destroyed and its disk entry doomed.
+      EXPECT_TRUE(
+          cache.disk_cache()->IsDiskEntryDoomed(kSimpleGET_Transaction.url));
+    }
+    ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
+  }
+
+  // Since validated transactions were restarted and new entry read/write
+  // operations would also fail, all requests would have gone to the network.
+  EXPECT_EQ(5, cache.network_layer()->transaction_count());
+  EXPECT_EQ(1, cache.disk_cache()->open_count());
+  EXPECT_EQ(5, cache.disk_cache()->create_count());
 }
 
 // This is a test for http://code.google.com/p/chromium/issues/detail?id=4769.
@@ -1451,11 +1932,12 @@
   c->result = c->callback.WaitForResult();
   ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
 
-  // Now we have 2 active readers and two queued transactions.
-
+  // Now all transactions should be waiting for read to be invoked. Two readers
+  // are because of the load flags and remaining two transactions were converted
+  // to readers after skipping validation. Note that the remaining two went on
+  // to process the headers in parallel with readers present on the entry.
   EXPECT_EQ(LOAD_STATE_IDLE, context_list[2]->trans->GetLoadState());
-  EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE,
-            context_list[3]->trans->GetLoadState());
+  EXPECT_EQ(LOAD_STATE_IDLE, context_list[3]->trans->GetLoadState());
 
   c = context_list[1];
   ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
@@ -1520,12 +2002,16 @@
                                 NetLogWithSource());
   }
 
+  base::RunLoop().RunUntilIdle();
+
   // The first request should be a writer at this point, and the two subsequent
   // requests should be pending. The last request doomed the first entry.
 
   EXPECT_EQ(2, cache.network_layer()->transaction_count());
 
-  // Cancel the first queued transaction.
+  // Cancel the second transaction. Note that this and the 3rd transactions
+  // would have completed their headers phase and would be waiting in the
+  // done_headers_queue when the 2nd transaction is cancelled.
   context_list[1].reset();
 
   for (int i = 0; i < kNumTransactions; ++i) {
@@ -1567,11 +2053,12 @@
   base::RunLoop().RunUntilIdle();
 
   // The first request should be a writer at this point, and the subsequent
-  // requests should be pending.
+  // requests should have completed validation. Since the validation does not
+  // result in a match, a new entry would be created.
 
-  EXPECT_EQ(1, cache.network_layer()->transaction_count());
+  EXPECT_EQ(3, cache.network_layer()->transaction_count());
   EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
+  EXPECT_EQ(2, cache.disk_cache()->create_count());
 
   // Now, make sure that the second request asks for the entry not to be stored.
   request_handler.set_no_store(true);
@@ -1625,6 +2112,9 @@
     if (c->result == ERR_IO_PENDING)
       c->result = c->callback.WaitForResult();
     // Destroy only the first transaction.
+    // This should lead to all transactions to restart, even those that have
+    // validated themselves and were waiting for the writer transaction to
+    // complete writing to the cache.
     if (i == 0) {
       delete c;
       context_list[i] = NULL;
@@ -2540,6 +3030,8 @@
 //     be returned.
 // (4) loads |kUrl| from cache only -- expects |cached_response_2| to be
 //     returned.
+// The entry will be created once and will be opened for the 3 subsequent
+// requests.
 static void ConditionalizedRequestUpdatesCacheHelper(
     const Response& net_response_1,
     const Response& net_response_2,
@@ -6115,12 +6607,14 @@
   EXPECT_EQ(5, c->callback.GetResult(rv));
 
   // Cancel the requests.
+  // Since |pending| is currently validating the already written headers
+  // it will be restarted as well.
   delete c;
   delete pending;
 
   EXPECT_EQ(1, cache.network_layer()->transaction_count());
   EXPECT_EQ(1, cache.disk_cache()->open_count());
-  EXPECT_EQ(2, cache.disk_cache()->create_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
 
   base::RunLoop().RunUntilIdle();
   RemoveMockTransaction(&transaction);
@@ -6845,46 +7339,6 @@
   EXPECT_EQ(1, cache.disk_cache()->create_count());
 }
 
-// Tests that if a metadata writer transaction hits cache lock timeout, it will
-// error out.
-TEST(HttpCache, WriteMetadata_CacheLockTimeout) {
-  MockHttpCache cache;
-
-  // Write to the cache
-  HttpResponseInfo response;
-  RunTransactionTestWithResponseInfo(cache.http_cache(), kSimpleGET_Transaction,
-                                     &response);
-  EXPECT_FALSE(response.metadata.get());
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-  Context c1;
-  ASSERT_THAT(cache.CreateTransaction(&c1.trans), IsOk());
-  ASSERT_EQ(ERR_IO_PENDING, c1.trans->Start(&request, c1.callback.callback(),
-                                            NetLogWithSource()));
-
-  cache.SimulateCacheLockTimeout();
-
-  // Write meta data to the same entry.
-  scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(50));
-  memset(buf->data(), 0, buf->size());
-  base::strlcpy(buf->data(), "Hi there", buf->size());
-  cache.http_cache()->WriteMetadata(GURL(kSimpleGET_Transaction.url),
-                                    DEFAULT_PRIORITY, response.response_time,
-                                    buf.get(), buf->size());
-
-  // Release the buffer before the operation takes place.
-  buf = NULL;
-
-  // Makes sure we finish pending operations.
-  base::RunLoop().RunUntilIdle();
-
-  RunTransactionTestWithResponseInfo(cache.http_cache(), kSimpleGET_Transaction,
-                                     &response);
-
-  // The writer transaction should fail due to cache lock timeout.
-  ASSERT_FALSE(response.metadata.get());
-}
-
 // Tests that we ignore VARY checks when writing metadata since the request
 // headers for the WriteMetadata transaction are made up.
 TEST(HttpCache, WriteMetadata_IgnoreVary) {
@@ -7212,10 +7666,6 @@
     EXPECT_THAT(callback.GetResult(rv), IsOk());
 
     trans->StopCaching();
-
-    scoped_refptr<IOBuffer> buf(new IOBuffer(256));
-    rv = trans->Read(buf.get(), 10, callback.callback());
-    EXPECT_EQ(callback.GetResult(rv), 10);
   }
   RemoveMockTransaction(&mock_transaction);
 
diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc
index a5b5746..fa42dd7 100644
--- a/net/http/http_transaction_test_util.cc
+++ b/net/http/http_transaction_test_util.cc
@@ -409,13 +409,6 @@
   if (!t)
     return ERR_FAILED;
 
-  if (!before_network_start_callback_.is_null()) {
-    bool defer = false;
-    before_network_start_callback_.Run(&defer);
-    if (defer)
-      return net::ERR_IO_PENDING;
-  }
-
   test_mode_ = t->test_mode;
 
   // Return immediately if we're returning an error.
@@ -466,6 +459,16 @@
   if (request_->load_flags & LOAD_PREFETCH)
     response_.unused_since_prefetch = true;
 
+  // Pause and resume.
+  if (!before_network_start_callback_.is_null()) {
+    bool defer = false;
+    before_network_start_callback_.Run(&defer);
+    if (defer) {
+      callback_ = callback;
+      return net::ERR_IO_PENDING;
+    }
+  }
+
   if (test_mode_ & TEST_MODE_SYNC_NET_START)
     return OK;
 
@@ -482,8 +485,9 @@
     const BeforeHeadersSentCallback& callback) {}
 
 int MockNetworkTransaction::ResumeNetworkStart() {
-  // Should not get here.
-  return ERR_FAILED;
+  DCHECK(!callback_.is_null());
+  CallbackLater(callback_, OK);
+  return ERR_IO_PENDING;
 }
 
 void MockNetworkTransaction::GetConnectionAttempts(
diff --git a/net/http/http_transaction_test_util.h b/net/http/http_transaction_test_util.h
index e936ac9d..dbd2670 100644
--- a/net/http/http_transaction_test_util.h
+++ b/net/http/http_transaction_test_util.h
@@ -280,6 +280,8 @@
 
   bool done_reading_called_;
 
+  CompletionCallback callback_;  // used for pause and restart.
+
   base::WeakPtrFactory<MockNetworkTransaction> weak_factory_;
 
 };
diff --git a/net/http/mock_http_cache.cc b/net/http/mock_http_cache.cc
index 47125a30..e676122 100644
--- a/net/http/mock_http_cache.cc
+++ b/net/http/mock_http_cache.cc
@@ -534,6 +534,13 @@
       FROM_HERE, base::Bind(&CallbackForwader, callback, result));
 }
 
+bool MockDiskCache::IsDiskEntryDoomed(const std::string& key) {
+  auto it = entries_.find(key);
+  if (it == entries_.end())
+    return false;
+  return it->second->is_doomed();
+}
+
 //-----------------------------------------------------------------------------
 
 int MockBackendFactory::CreateBackend(
@@ -647,6 +654,41 @@
   g_test_mode = test_mode;
 }
 
+bool MockHttpCache::IsWriterPresent(const std::string& key) {
+  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
+  if (entry)
+    return entry->writer;
+  return false;
+}
+
+bool MockHttpCache::IsHeadersTransactionPresent(const std::string& key) {
+  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
+  if (entry)
+    return entry->headers_transaction;
+  return false;
+}
+
+int MockHttpCache::GetCountReaders(const std::string& key) {
+  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
+  if (entry)
+    return entry->readers.size();
+  return false;
+}
+
+int MockHttpCache::GetCountAddToEntryQueue(const std::string& key) {
+  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
+  if (entry)
+    return entry->add_to_entry_queue.size();
+  return false;
+}
+
+int MockHttpCache::GetCountDoneHeadersQueue(const std::string& key) {
+  HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key);
+  if (entry)
+    return entry->done_headers_queue.size();
+  return false;
+}
+
 //-----------------------------------------------------------------------------
 
 int MockDiskCacheNoCB::CreateEntry(const std::string& key,
diff --git a/net/http/mock_http_cache.h b/net/http/mock_http_cache.h
index a24200b..7718f351 100644
--- a/net/http/mock_http_cache.h
+++ b/net/http/mock_http_cache.h
@@ -158,6 +158,8 @@
 
   void ReleaseAll();
 
+  bool IsDiskEntryDoomed(const std::string& key);
+
  private:
   using EntryMap = std::unordered_map<std::string, MockDiskEntry*>;
   class NotImplementedIterator;
@@ -234,6 +236,14 @@
   // the test! (by setting test_mode to zero).
   static void SetTestMode(int test_mode);
 
+  // Functions to test the state of ActiveEntry.
+
+  bool IsWriterPresent(const std::string& key);
+  bool IsHeadersTransactionPresent(const std::string& key);
+  int GetCountReaders(const std::string& key);
+  int GetCountAddToEntryQueue(const std::string& key);
+  int GetCountDoneHeadersQueue(const std::string& key);
+
  private:
   HttpCache http_cache_;
 };
diff --git a/net/test/cert_test_util.cc b/net/test/cert_test_util.cc
index 8da3aecf..2c22d84f 100644
--- a/net/test/cert_test_util.cc
+++ b/net/test/cert_test_util.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "net/cert/ev_root_ca_metadata.h"
 #include "net/cert/x509_certificate.h"
 #include "net/test/test_data_directory.h"
@@ -63,6 +64,7 @@
 scoped_refptr<X509Certificate> ImportCertFromFile(
     const base::FilePath& certs_dir,
     const std::string& cert_file) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   base::FilePath cert_path = certs_dir.AppendASCII(cert_file);
   std::string cert_data;
   if (!base::ReadFileToString(cert_path, &cert_data))
diff --git a/net/url_request/url_request_quic_unittest.cc b/net/url_request/url_request_quic_unittest.cc
index ff887060..8c3f560 100644
--- a/net/url_request/url_request_quic_unittest.cc
+++ b/net/url_request/url_request_quic_unittest.cc
@@ -305,15 +305,14 @@
 
   EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_1);
-  // No net error code for this lookup transaction, the push is found.
-  EXPECT_FALSE(entries[1].GetIntegerValue("net_error", &net_error));
-
-  EXPECT_TRUE(entries[2].GetStringValue("push_url", &value));
+  EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_2);
   // Net error code -400 is found for this lookup transaction, the push is not
   // found in the cache.
-  EXPECT_TRUE(entries[3].GetIntegerValue("net_error", &net_error));
+  EXPECT_TRUE(entries[2].GetIntegerValue("net_error", &net_error));
   EXPECT_EQ(net_error, -400);
+  // No net error code for this lookup transaction, the push is found.
+  EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
 
   // Verify the reset error count received on the server side.
   EXPECT_LE(1u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
@@ -392,11 +391,13 @@
 
   EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_1);
-  // No net error code for this lookup transaction, the push is found.
-  EXPECT_FALSE(entries[1].GetIntegerValue("net_error", &net_error));
 
-  EXPECT_TRUE(entries[2].GetStringValue("push_url", &value));
+  EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_2);
+
+  // No net error code for this lookup transaction, the push is found.
+  EXPECT_FALSE(entries[2].GetIntegerValue("net_error", &net_error));
+
   // No net error code for this lookup transaction, the push is found.
   EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
 
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 7282a0e5..341f870 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -4138,14 +4138,14 @@
         context.CreateRequest(url, DEFAULT_PRIORITY, &d));
     r->Start();
 
+    base::RunLoop().Run();
+
     {
       HttpRequestHeaders headers;
       EXPECT_TRUE(r->GetFullRequestHeaders(&headers));
-      EXPECT_FALSE(headers.HasHeader("Authorization"));
+      EXPECT_TRUE(headers.HasHeader("Authorization"));
     }
 
-    base::RunLoop().Run();
-
     EXPECT_EQ(OK, d.request_status());
     EXPECT_EQ(200, r->GetResponseCode());
     EXPECT_TRUE(d.auth_required_called());
diff --git a/services/service_manager/embedder/main.cc b/services/service_manager/embedder/main.cc
index 86a6a62..24b9d66 100644
--- a/services/service_manager/embedder/main.cc
+++ b/services/service_manager/embedder/main.cc
@@ -266,7 +266,6 @@
 }
 
 void InitializeResources() {
-  ui::RegisterPathProvider();
   const std::string locale =
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           ::switches::kLang);
@@ -392,6 +391,8 @@
   mojo::edk::SetMaxMessageSize(kMaximumMojoMessageSize);
   mojo::edk::Init();
 
+  ui::RegisterPathProvider();
+
   base::debug::GlobalActivityTracker* tracker =
       base::debug::GlobalActivityTracker::Get();
   int exit_code = delegate->Initialize(init_params);
diff --git a/services/service_manager/public/cpp/connector.h b/services/service_manager/public/cpp/connector.h
index ae15116..9f232287 100644
--- a/services/service_manager/public/cpp/connector.h
+++ b/services/service_manager/public/cpp/connector.h
@@ -113,6 +113,11 @@
   // to pass again.
   virtual std::unique_ptr<Connector> Clone() = 0;
 
+  virtual void FilterInterfaces(const std::string& spec,
+                                const Identity& source_identity,
+                                mojom::InterfaceProviderRequest request,
+                                mojom::InterfaceProviderPtr target) = 0;
+
   // Binds a Connector request to the other end of this Connector.
   virtual void BindConnectorRequest(mojom::ConnectorRequest request) = 0;
 
diff --git a/services/service_manager/public/cpp/lib/connector_impl.cc b/services/service_manager/public/cpp/lib/connector_impl.cc
index 0040a32..bd6e7a54 100644
--- a/services/service_manager/public/cpp/lib/connector_impl.cc
+++ b/services/service_manager/public/cpp/lib/connector_impl.cc
@@ -84,6 +84,14 @@
   return base::MakeUnique<ConnectorImpl>(connector.PassInterface());
 }
 
+void ConnectorImpl::FilterInterfaces(const std::string& spec,
+                                     const Identity& source_identity,
+                                     mojom::InterfaceProviderRequest request,
+                                     mojom::InterfaceProviderPtr target) {
+  connector_->FilterInterfaces(spec, source_identity, std::move(request),
+                               std::move(target));
+}
+
 void ConnectorImpl::BindConnectorRequest(mojom::ConnectorRequest request) {
   if (!BindConnectorIfNecessary())
     return;
diff --git a/services/service_manager/public/cpp/lib/connector_impl.h b/services/service_manager/public/cpp/lib/connector_impl.h
index b07fb2b..68728c8 100644
--- a/services/service_manager/public/cpp/lib/connector_impl.h
+++ b/services/service_manager/public/cpp/lib/connector_impl.h
@@ -34,6 +34,10 @@
                      const std::string& interface_name,
                      mojo::ScopedMessagePipeHandle interface_pipe) override;
   std::unique_ptr<Connector> Clone() override;
+  void FilterInterfaces(const std::string& spec,
+                        const Identity& source_identity,
+                        mojom::InterfaceProviderRequest request,
+                        mojom::InterfaceProviderPtr target) override;
   void BindConnectorRequest(mojom::ConnectorRequest request) override;
   base::WeakPtr<Connector> GetWeakPtr() override;
   void OverrideBinderForTesting(const std::string& service_name,
diff --git a/services/service_manager/public/interfaces/connector.mojom b/services/service_manager/public/interfaces/connector.mojom
index 63168e4a..d403bd5a 100644
--- a/services/service_manager/public/interfaces/connector.mojom
+++ b/services/service_manager/public/interfaces/connector.mojom
@@ -164,4 +164,20 @@
 
   // Clones this Connector so it can be passed to another thread.
   Clone(Connector& request);
+
+  // Filter interface requests received from |source| according to the policy
+  // specified in this service's manifest in an InterfaceProviderSpec named
+  // |spec|.
+  //
+  // The flow is basically - remote service wishes to (generically) request
+  // interfaces from this service, and so sends us an InterfaceProvider request
+  // (|source_request|) which it would like us to bind. We forward this request
+  // to the Service Manager, passing our actual InterfaceProvider implementation
+  // in |target|. The Service Manager will only forward interface requests that
+  // were permitted by intersecting |source|'s manifest requirements with the
+  // contents of |spec|.
+  FilterInterfaces(string spec,
+                   Identity source,
+                   InterfaceProvider& source_request,
+                   InterfaceProvider target);
 };
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc
index 6e492932..c2259d4 100644
--- a/services/service_manager/service_manager.cc
+++ b/services/service_manager/service_manager.cc
@@ -22,6 +22,7 @@
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/catalog/public/interfaces/constants.mojom.h"
 #include "services/service_manager/connect_util.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -77,6 +78,25 @@
   return it->second.find(capability) != it->second.end();
 }
 
+bool AllowsInterface(const Identity& source,
+                     const InterfaceProviderSpec& source_spec,
+                     const Identity& target,
+                     const InterfaceProviderSpec& target_spec,
+                     const std::string& interface_name) {
+  InterfaceSet exposed =
+      GetInterfacesToExpose(source_spec, target, target_spec);
+  bool allowed = (exposed.size() == 1 && exposed.count("*") == 1) ||
+                 exposed.count(interface_name) > 0;
+  if (!allowed) {
+    std::stringstream ss;
+    ss << "Connection InterfaceProviderSpec prevented service: "
+       << source.name() << " from binding interface: " << interface_name
+       << " exposed by: " << target.name();
+    LOG(ERROR) << ss.str();
+  }
+  return allowed;
+}
+
 // Encapsulates a connection to an instance of a service, tracked by the
 // Service Manager.
 class ServiceManager::Instance
@@ -145,17 +165,8 @@
       source_connection_spec = source->GetConnectionSpec();
     }
 
-    InterfaceSet exposed = GetInterfacesToExpose(source_connection_spec,
-                                                 identity_,
-                                                 GetConnectionSpec());
-    bool allowed = (exposed.size() == 1 && exposed.count("*") == 1) ||
-        exposed.count(params->interface_name()) > 0;
-    if (!allowed) {
-      std::stringstream ss;
-      ss << "Connection InterfaceProviderSpec prevented service: "
-         << params->source().name() << " from binding interface: "
-         << params->interface_name() << " exposed by: " << identity_.name();
-      LOG(ERROR) << ss.str();
+    if (!AllowsInterface(params->source(), source_connection_spec, identity_,
+                         GetConnectionSpec(), params->interface_name())) {
       params->set_response_data(mojom::ConnectResult::ACCESS_DENIED, identity_);
       return false;
     }
@@ -215,10 +226,17 @@
   }
 
   const InterfaceProviderSpec& GetConnectionSpec() const {
-    auto it = interface_provider_specs_.find(
-        mojom::kServiceManager_ConnectorSpec);
+    return GetSpec(mojom::kServiceManager_ConnectorSpec);
+  }
+  bool HasSpec(const std::string& spec) const {
+    auto it = interface_provider_specs_.find(spec);
+    return it != interface_provider_specs_.end();
+  }
+  const InterfaceProviderSpec& GetSpec(const std::string& spec) const {
+    auto it = interface_provider_specs_.find(spec);
     return it != interface_provider_specs_.end() ? it->second : empty_spec_;
   }
+
   const Identity& identity() const { return identity_; }
   void set_identity(const Identity& identity) { identity_ = identity; }
   uint32_t id() const { return id_; }
@@ -252,6 +270,62 @@
     STARTED
   };
 
+  class InterfaceProviderImpl : public mojom::InterfaceProvider {
+   public:
+    InterfaceProviderImpl(const std::string& spec,
+                          const Identity& source_identity,
+                          const Identity& target_identity,
+                          service_manager::ServiceManager* service_manager,
+                          mojom::InterfaceProviderPtr target,
+                          mojom::InterfaceProviderRequest source_request)
+        : spec_(spec),
+          source_identity_(source_identity),
+          target_identity_(target_identity),
+          service_manager_(service_manager),
+          target_(std::move(target)),
+          source_binding_(this, std::move(source_request)) {}
+    ~InterfaceProviderImpl() override {}
+
+   private:
+    // mojom::InterfaceProvider:
+    void GetInterface(const std::string& interface_name,
+                      mojo::ScopedMessagePipeHandle interface_pipe) override {
+      Instance* source =
+          service_manager_->GetExistingInstance(source_identity_);
+      Instance* target =
+          service_manager_->GetExistingInstance(target_identity_);
+      if (!source || !target)
+        return;
+      if (!ValidateSpec(source) || !ValidateSpec(target))
+        return;
+
+      if (AllowsInterface(source_identity_, source->GetSpec(spec_),
+                          target_identity_, target->GetSpec(spec_),
+                          interface_name)) {
+        target_->GetInterface(interface_name, std::move(interface_pipe));
+      }
+    }
+
+    bool ValidateSpec(Instance* instance) const {
+      if (!instance->HasSpec(spec_)) {
+        LOG(ERROR) << "Instance for: " << instance->identity().name()
+                   << " did not have spec named: " << spec_;
+        return false;
+      }
+      return true;
+    }
+
+    const std::string spec_;
+    const Identity source_identity_;
+    const Identity target_identity_;
+    const service_manager::ServiceManager* service_manager_;
+
+    mojom::InterfaceProviderPtr target_;
+    mojo::Binding<mojom::InterfaceProvider> source_binding_;
+
+    DISALLOW_COPY_AND_ASSIGN(InterfaceProviderImpl);
+  };
+
   // mojom::Connector implementation:
   void BindInterface(const service_manager::Identity& in_target,
                      const std::string& interface_name,
@@ -320,6 +394,15 @@
     connectors_.AddBinding(this, std::move(request));
   }
 
+  void FilterInterfaces(const std::string& spec,
+                        const Identity& source,
+                        mojom::InterfaceProviderRequest source_request,
+                        mojom::InterfaceProviderPtr target) override {
+    filters_.push_back(base::MakeUnique<InterfaceProviderImpl>(
+        spec, source, identity_, service_manager_, std::move(target),
+        std::move(source_request)));
+  }
+
   // mojom::PIDReceiver:
   void SetPID(uint32_t pid) override {
     PIDAvailable(pid);
@@ -500,6 +583,8 @@
   base::ProcessId pid_ = base::kNullProcessId;
   State state_;
 
+  std::vector<std::unique_ptr<InterfaceProviderImpl>> filters_;
+
   // The number of outstanding OnBindInterface requests which are in flight.
   int pending_service_connections_ = 0;
 
diff --git a/services/service_manager/standalone/BUILD.gn b/services/service_manager/standalone/BUILD.gn
index 63d18d8..4c8ba4f3 100644
--- a/services/service_manager/standalone/BUILD.gn
+++ b/services/service_manager/standalone/BUILD.gn
@@ -30,8 +30,4 @@
     "//services/tracing/public/interfaces",
     "//url",
   ]
-
-  data_deps = [
-    "//services/tracing",
-  ]
 }
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 2038d0d1..6d08ac4 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -202,10 +202,6 @@
 #   define SK_IGNORE_ETC1_SUPPORT
 #endif
 
-#ifndef    SK_SUPPORT_GPU_REF_ENCODED_DATA
-#   define SK_SUPPORT_GPU_REF_ENCODED_DATA
-#endif
-
 #ifndef    SK_IGNORE_GPU_DITHER
 #   define SK_IGNORE_GPU_DITHER
 #endif
diff --git a/sql/test/test_helpers.cc b/sql/test/test_helpers.cc
index 0e32164..20e2316 100644
--- a/sql/test/test_helpers.cc
+++ b/sql/test/test_helpers.cc
@@ -12,6 +12,7 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
+#include "base/threading/thread_restrictions.h"
 #include "sql/connection.h"
 #include "sql/statement.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -100,6 +101,7 @@
 }
 
 bool CorruptSizeInHeaderWithLock(const base::FilePath& db_path) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   sql::Connection db;
   if (!db.Open(db_path))
     return false;
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 5527629..661fa50 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -953,21 +953,6 @@
             ]
         }
     ],
-    "EnableWelcomeWin10": [
-        {
-            "platforms": [
-                "win"
-            ],
-            "experiments": [
-                {
-                    "name": "Inline",
-                    "enable_features": [
-                        "EnableWelcomeWin10"
-                    ]
-                }
-            ]
-        }
-    ],
     "ExpectCTReporting": [
         {
             "platforms": [
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 5ad1c8d..7d5d9a22 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -67,6 +67,7 @@
 /google_toolbox_for_mac/src
 /googlemac
 /gvr-android-sdk/common_library.aar
+/gvr-android-sdk/test-libraries/controller_test_api.aar
 /gvr-android-sdk/libgvr_shim_static_arm.a
 /gvr-android-sdk/libgvr_shim_static_arm64.a
 /gvr-android-sdk/src
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 2b1b4374..20216d4 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -3236,8 +3236,6 @@
 crbug.com/669473 external/wpt/css/css-ui-3/outline-014.html [ Failure ]
 crbug.com/669473 external/wpt/css/css-ui-3/outline-015.html [ Failure ]
 crbug.com/669473 external/wpt/css/css-ui-3/outline-016.html [ Failure ]
-crbug.com/669473 external/wpt/css/css-ui-3/text-overflow-002.html [ Failure ]
-crbug.com/669473 external/wpt/css/css-ui-3/text-overflow-004.html [ Failure ]
 
 crbug.com/670024 external/wpt/webmessaging/broadcastchannel/sandbox.html [ Failure ]
 crbug.com/660384 external/wpt/webmessaging/with-ports/001.html [ Failure ]
@@ -3424,6 +3422,8 @@
 
 # Sheriff failures 2017-04-19
 crbug.com/713094 [ Win ] virtual/sharedarraybuffer/fast/css/fontfaceset-check-platform-fonts.html [ Failure Pass ]
+# Sheriff failure 2017-04-26
+crbug.com/713094 [ Win ] fast/css/fontfaceset-check-platform-fonts.html [ Failure Pass ]
 
 # Sheriff failures 2017-04-24
 crbug.com/714862 [ Android ] tables/mozilla/collapsing_borders/bug41262-3.html [ Failure ]
@@ -3441,3 +3441,12 @@
 crbug.com/713685 [ Linux ] virtual/sharedarraybuffer/fast/workers/termination-early.html [ Crash Pass ]
 
 crbug.com/715405 [ Win Mac ] virtual/mojo-loading/http/tests/inspector/network/waterfall-images.html [ Failure Pass ]
+
+crbug.com/715718 external/wpt/media-source/mediasource-activesourcebuffers.html [ Failure Pass ]
+crbug.com/715718 external/wpt/media-source/mediasource-remove.html [ Failure Pass ]
+crbug.com/715718 [ Win ] external/wpt/XMLHttpRequest/FormData-append.html [ Failure Pass ]
+crbug.com/715718 [ Win ] external/wpt/XMLHttpRequest/timeout-multiple-fetches.html [ Failure Pass ]
+crbug.com/715718 [ Win ] external/wpt/css/css-flexbox-1/align-items-004.htm [ Failure Pass ]
+crbug.com/715718 [ Win ] external/wpt/css/css-flexbox-1/flex-minimum-width-flex-items-001.xht [ Failure Pass ]
+crbug.com/715718 [ Win ] external/wpt/css/css-flexbox-1/flex-minimum-width-flex-items-003.xht [ Failure Pass ]
+crbug.com/715718 [ Win ] external/wpt/css/css-flexbox-1/flexbox_flex-natural-mixed-basis-auto.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-expected.txt
index cbcf052..81b8870 100644
--- a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-expected.txt
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-expected.txt
@@ -5,9 +5,9 @@
 
 Derive 0 bits from the HKDF key
 PASS derivedBits.byteLength is 0
-Derive 4 bits from the HKDF key
+Derive 8 bits from the HKDF key
 PASS derivedBits.byteLength is 1
-PASS derivedBits.getUint8(0) is 0x80
+PASS derivedBits.getUint8(0) is 141
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-failures-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-failures-expected.txt
index f2be32a..d405e3c2 100644
--- a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-failures-expected.txt
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-failures-expected.txt
@@ -12,6 +12,9 @@
 
 deriveBits() with length of 65281...
 error is: OperationError: The length provided for HKDF is too large.
+
+deriveBits() with length of 15...
+error is: OperationError: The length provided for HKDF is not a multiple of 8 bits.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-failures.html b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-failures.html
index 55ae7f4..a661f4e 100644
--- a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-failures.html
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits-failures.html
@@ -47,9 +47,15 @@
     // The maximum length (in bytes) of output material for HKDF is 255 times
     // the digest length. In this case, the digest length (in bytes) of
     // SHA-256 is 32; 32*255 = 8160. deriveBits expects the length to be in
-    // bits, so 8160*8=65280 and add 1 to exceed the maximum length.
+    // bits, so 8160*8=65280 and add 8 to exceed the maximum length.
     debug("\nderiveBits() with length of 65281...");
-    return crypto.subtle.deriveBits({name: "HKDF", hash: "SHA-256", salt: new Uint8Array(), info: new Uint8Array()}, hkdfKey, 65281);
+    return crypto.subtle.deriveBits({name: "HKDF", hash: "SHA-256", salt: new Uint8Array(), info: new Uint8Array()}, hkdfKey, 65288);
+}).then(failAndFinishJSTest, function(result) {
+    logError(result);
+
+    // Use a bit length that is not a multiple of 8.
+    debug("\nderiveBits() with length of 15...");
+    return crypto.subtle.deriveBits({name: "HKDF", hash: "SHA-256", salt: new Uint8Array(), info: new Uint8Array()}, hkdfKey, 15);
 }).then(failAndFinishJSTest, function(result) {
     logError(result);
 }).then(finishJSTest, failAndFinishJSTest);
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits.html b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits.html
index a6d11fa..d4afc51 100644
--- a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits.html
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/deriveBits.html
@@ -36,15 +36,13 @@
 
     shouldBe("derivedBits.byteLength", "0");
 
-    debug("Derive 4 bits from the HKDF key");
-    return crypto.subtle.deriveBits(kHkdfAlgorithm, baseKey, 4);
+    debug("Derive 8 bits from the HKDF key");
+    return crypto.subtle.deriveBits(kHkdfAlgorithm, baseKey, 8);
 }).then(function(result) {
     derivedBits = new DataView(result);
 
     shouldBe("derivedBits.byteLength", "1");
-    // The last 4 bits should be zeroes.
-    shouldBe("derivedBits.getUint8(0)", "0x80");
-
+    shouldBe("derivedBits.getUint8(0)", "141");
 }).then(finishJSTest, failAndFinishJSTest);
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/deprecated-zoom-properties-expected.txt b/third_party/WebKit/LayoutTests/fast/css/deprecated-zoom-properties-expected.txt
deleted file mode 100644
index ae000bf..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/deprecated-zoom-properties-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-CONSOLE WARNING: "zoom: reset" is deprecated and will be removed in M59, around June 2017. See https://www.chromestatus.com/features/4997605029314560 for more details.
-CONSOLE WARNING: "zoom: document" is deprecated and will be removed in M59, around June 2017. See https://www.chromestatus.com/features/4997605029314560 for more details.
-
diff --git a/third_party/WebKit/LayoutTests/fast/css/deprecated-zoom-properties.html b/third_party/WebKit/LayoutTests/fast/css/deprecated-zoom-properties.html
deleted file mode 100644
index 9f52d01a..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/deprecated-zoom-properties.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<head>
-<script>
-if (window.testRunner)
-  testRunner.dumpAsText();
-</script>
-</head>
-<body>
-<div style="zoom:reset"></div>
-<div style="zoom:document"></div>
-</body>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Element/getBoundingClientRect-vertical-child.html b/third_party/WebKit/LayoutTests/fast/dom/Element/getBoundingClientRect-vertical-child.html
new file mode 100644
index 0000000..1c38ddca
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/Element/getBoundingClientRect-vertical-child.html
@@ -0,0 +1,63 @@
+<style>
+  td { padding: 10px }
+</style>
+<div style="-webkit-writing-mode: vertical-rl; writing-mode: vertical-rl">
+  <table>
+    <tr id="tr1">
+      <td id="td1a"><span id="s1a">1-A</span></td>
+      <td id="td1b"><span id="s1b">1-B</span></td>
+    </tr>
+    <tr id="tr2">
+      <td id="td2a"><span id="s2a">2-A</span></td>
+      <td id="td2b"><span id="s2b">2-B</span></td>
+    </tr>
+  </table>
+  <script src="../../../resources/testharness.js"></script>
+  <script src="../../../resources/testharnessreport.js"></script>
+  <script>
+    function doesRectContainRect(parent, child) {
+      if (child.top < parent.top) {
+        return false;
+      }
+      if (child.bottom > parent.bottom) {
+        return false;
+      }
+      if (child.left < parent.left) {
+        return false;
+      }
+      if (child.right > parent.right) {
+        return false;
+      }
+      return true;
+    }
+
+    function rectToString(rect) {
+      return "(" + rect.left + " " + rect.top + " - " + rect.right + " " + rect.bottom + ")"
+    }
+
+    function assert_contains(parent, child, description) {
+      assert_true(doesRectContainRect(parent, child),
+                  description + " " + rectToString(parent) + " should contain " + rectToString(child));
+    }
+
+    function checkRowColumn(row, column) {
+      var columnName = ["a", "b", "c", "d", "e"];
+      var trId = "tr" + (row + 1);
+      var tr = document.getElementById(trId);
+      var trRect = tr.getBoundingClientRect();
+      var name = (row + 1).toString() + "-" + columnName[column].toUpperCase();
+      var spanId = "s" + (row + 1) + columnName[column];
+      var span = document.getElementById(spanId);
+      var spanRect = span.getBoundingClientRect();
+      assert_contains(trRect, spanRect, name);
+    }
+
+    test(function() {
+      for (var row = 0; row < 2; row++) {
+        for (var column = 0; column < 2; column++) {
+          checkRowColumn(row, column);
+        }
+      }
+    }, "The child of td should be inside of tr in vertical table");
+  </script>
+</div>
diff --git a/third_party/WebKit/LayoutTests/mojo/associated_interface_ptr.html b/third_party/WebKit/LayoutTests/mojo/associated_interface_ptr.html
index 361cff3..ecccfec3 100644
--- a/third_party/WebKit/LayoutTests/mojo/associated_interface_ptr.html
+++ b/third_party/WebKit/LayoutTests/mojo/associated_interface_ptr.html
@@ -13,20 +13,23 @@
     "mojo/public/js/bindings",
 ], function(testAssociatedInterfaces, associatedBindings, bindings) {
 
-  function IntegerSenderImpl(callback) {
+  function SenderImpl(callback) {
     this.callback = callback;
   }
 
-  IntegerSenderImpl.prototype.echo = function(value) {
+  SenderImpl.prototype.echo = function(value) {
     return Promise.resolve({value: value});
   };
 
-  IntegerSenderImpl.prototype.send = function(value) {
+  SenderImpl.prototype.send = function(value) {
     if (this.callback) {
       this.callback(value);
     }
   };
 
+  var IntegerSenderImpl = SenderImpl;
+  var StringSenderImpl = SenderImpl;
+
   function IntegerSenderConnectionImpl() {
     this.integerSenderBinding_ = null;
   }
@@ -58,8 +61,8 @@
   IntegerSenderConnectionAtBothEndsImpl.prototype.setSender = function(
       integerSenderPtrInfo) {
     this.integerSender_ = new
-        testAssociatedInterfaces.AssociatedIntegerSenderPtr();
-    this.integerSender_.ptr.bind(integerSenderPtrInfo);
+        testAssociatedInterfaces.AssociatedIntegerSenderPtr(
+            integerSenderPtrInfo);
     return this.integerSender_.echo(456);
   };
 
@@ -77,6 +80,56 @@
         {custom_reason: 42, description: 'hey'});
   };
 
+  function SenderConnectionBindLaterImpl({getIntegerSenderCallback,
+      getStringSenderCallback} = {}) {
+    this.getIntegerSenderCallback = getIntegerSenderCallback;
+    this.getStringSenderCallback = getStringSenderCallback;
+    this.integerSenderBinding_ = null;
+    this.stringSenderBinding_ = null;
+  }
+
+  SenderConnectionBindLaterImpl.prototype.getIntegerSender =
+      function(integerSenderRequest) {
+    setTimeout(() => {
+      this.integerSenderBinding_ = new associatedBindings.AssociatedBinding(
+          testAssociatedInterfaces.IntegerSender,
+          new IntegerSenderImpl(this.getIntegerSenderCallback),
+          integerSenderRequest);
+    }, 0);
+  };
+
+  SenderConnectionBindLaterImpl.prototype.getStringSender =
+      function(stringSenderRequest) {
+    this.stringSenderBinding_ = new associatedBindings.AssociatedBinding(
+        testAssociatedInterfaces.StringSender,
+        new StringSenderImpl(this.getStringSenderCallback),
+        stringSenderRequest);
+  };
+
+  function SenderConnectionImpl({getIntegerSenderCallback,
+      getStringSenderCallback} = {}) {
+    this.getIntegerSenderCallback = getIntegerSenderCallback;
+    this.getStringSenderCallback = getStringSenderCallback;
+    this.integerSenderBinding_ = null;
+    this.stringSenderBinding_ = null;
+  }
+
+  SenderConnectionImpl.prototype.getIntegerSender =
+      function(integerSenderRequest) {
+    this.integerSenderBinding_ = new associatedBindings.AssociatedBinding(
+        testAssociatedInterfaces.IntegerSender,
+        new IntegerSenderImpl(this.getIntegerSenderCallback),
+        integerSenderRequest);
+  };
+
+  SenderConnectionImpl.prototype.getStringSender =
+      function(stringSenderRequest) {
+    this.stringSenderBinding_ = new associatedBindings.AssociatedBinding(
+        testAssociatedInterfaces.StringSender,
+        new StringSenderImpl(this.getStringSenderCallback),
+        stringSenderRequest);
+  };
+
   promise_test(async () => {
     var integerSenderConnection = new
         testAssociatedInterfaces.IntegerSenderConnectionPtr();
@@ -92,8 +145,8 @@
         integerSenderPtrInfo0);
 
     var integerSender0 = new
-        testAssociatedInterfaces.AssociatedIntegerSenderPtr();
-    integerSender0.ptr.bind(integerSenderPtrInfo0);
+        testAssociatedInterfaces.AssociatedIntegerSenderPtr(
+            integerSenderPtrInfo0);
 
     integerSenderConnection.getSender(integerSenderRequest0);
     assert_equals((await integerSender0.echo(123)).value, 123);
@@ -102,8 +155,8 @@
     var integerSenderPtrInfo1 =
         (await integerSenderConnection.asyncGetSender()).sender;
     var integerSender1 = new
-        testAssociatedInterfaces.AssociatedIntegerSenderPtr();
-    integerSender1.ptr.bind(integerSenderPtrInfo1);
+        testAssociatedInterfaces.AssociatedIntegerSenderPtr(
+            integerSenderPtrInfo1);
     assert_equals((await integerSender1.echo(456)).value, 456);
   }, 'pass associated interfaces');
 
@@ -125,8 +178,8 @@
         integerSenderPtrInfo0);
 
     var integerSender0 = new
-        testAssociatedInterfaces.AssociatedIntegerSenderPtr();
-    integerSender0.ptr.bind(integerSenderPtrInfo0);
+        testAssociatedInterfaces.AssociatedIntegerSenderPtr(
+            integerSenderPtrInfo0);
 
     integerSenderConnectionAtBothEnds.getSender(integerSenderRequest0);
     assert_equals((await integerSender0.echo(123)).value, 123);
@@ -162,8 +215,8 @@
         integerSenderPtrInfo0);
 
     var integerSender0 = new
-        testAssociatedInterfaces.AssociatedIntegerSenderPtr();
-    integerSender0.ptr.bind(integerSenderPtrInfo0);
+        testAssociatedInterfaces.AssociatedIntegerSenderPtr(
+            integerSenderPtrInfo0);
 
     integerSenderConnection.getSender(integerSenderRequest0);
     await new Promise((resolve, reject) => {
@@ -190,16 +243,16 @@
     var integerSenderRequest0 = associatedBindings.makeRequest(
         integerSenderPtrInfo0);
     var integerSender0 = new
-        testAssociatedInterfaces.AssociatedIntegerSenderPtr();
-    integerSender0.ptr.bind(integerSenderPtrInfo0);
+        testAssociatedInterfaces.AssociatedIntegerSenderPtr(
+            integerSenderPtrInfo0);
     integerSenderConnection.getSender(integerSenderRequest0);
 
     // Recieving AssociatedInterfacePtrInfo.
     var integerSenderPtrInfo1 =
         (await integerSenderConnection.asyncGetSender()).sender;
     var integerSender1 = new
-        testAssociatedInterfaces.AssociatedIntegerSenderPtr();
-    integerSender1.ptr.bind(integerSenderPtrInfo1);
+        testAssociatedInterfaces.AssociatedIntegerSenderPtr(
+            integerSenderPtrInfo1);
 
     // Master InterfacePtrController reset triggers connection error handler on
     // interface endpoint clients for all associated endpoints.
@@ -220,6 +273,103 @@
     await Promise.all([connectionErrorHandler0, connectionErrorHandler1]);
   }, 'all endpoints connectionErrorHandler called on master interface reset');
 
+  // Cache the current message and pause processing incoming messages if
+  // endpoint does not have client attached yet to ensure fifo message arrival.
+  promise_test(async () => {
+    var senderConnection = new
+        testAssociatedInterfaces.SenderConnectionPtr();
+    var senderConnectionBindLaterImpl = new SenderConnectionBindLaterImpl();
+    var senderConnectionBinding = new bindings.Binding(
+        testAssociatedInterfaces.SenderConnection,
+        senderConnectionBindLaterImpl,
+        bindings.makeRequest(senderConnection));
+
+    // AssociatedInterfaceRequest for stringSender.
+    var stringSenderPtrInfo = new
+        associatedBindings.AssociatedInterfacePtrInfo();
+    var stringSenderRequest = associatedBindings.makeRequest(
+        stringSenderPtrInfo);
+    var stringSender =
+        new testAssociatedInterfaces.AssociatedStringSenderPtr(
+            stringSenderPtrInfo);
+
+    // AssociatedInterfaceRequest for integerSender.
+    var integerSenderPtrInfo = new
+        associatedBindings.AssociatedInterfacePtrInfo();
+    var integerSenderRequest = associatedBindings.makeRequest(
+        integerSenderPtrInfo);
+    var integerSender = new
+        testAssociatedInterfaces.AssociatedIntegerSenderPtr(
+            integerSenderPtrInfo);
+
+    var value = await new Promise(function(resolve, reject) {
+      senderConnectionBindLaterImpl.getIntegerSenderCallback = resolve;
+      senderConnectionBindLaterImpl.getStringSenderCallback= reject;
+      senderConnection.getStringSender(stringSenderRequest);
+      senderConnection.getIntegerSender(integerSenderRequest);
+      // Test FIFO arrival order of message.
+      integerSender.send(456); // This message should arrive first.
+      stringSender.send('goodbye');
+    });
+
+    assert_equals(value, 456);
+  }, 'fifo order should be preserved for messages');
+
+  promise_test(async () => {
+    var senderConnection = new
+        testAssociatedInterfaces.SenderConnectionPtr();
+    var senderConnectionImpl = new SenderConnectionImpl();
+    var senderConnectionBinding = new bindings.Binding(
+        testAssociatedInterfaces.SenderConnection,
+        senderConnectionImpl,
+        bindings.makeRequest(senderConnection));
+
+    // AssociatedInterfaceRequest for stringSender.
+    var stringSenderPtrInfo = new
+        associatedBindings.AssociatedInterfacePtrInfo();
+    var stringSenderRequest = associatedBindings.makeRequest(
+        stringSenderPtrInfo);
+    var stringSender =
+        new testAssociatedInterfaces.AssociatedStringSenderPtr(
+            stringSenderPtrInfo);
+
+    // AssociatedInterfaceRequest for integerSender.
+    var integerSenderPtrInfo = new
+        associatedBindings.AssociatedInterfacePtrInfo();
+    var integerSenderRequest = associatedBindings.makeRequest(
+        integerSenderPtrInfo);
+    var integerSender = new
+        testAssociatedInterfaces.AssociatedIntegerSenderPtr(
+            integerSenderPtrInfo);
+
+    var value = await new Promise(function(resolve, reject) {
+      senderConnectionImpl.getIntegerSenderCallback = reject;
+      senderConnectionImpl.getStringSenderCallback= resolve;
+      senderConnection.getStringSender(stringSenderRequest);
+      senderConnection.getIntegerSender(integerSenderRequest);
+
+      // Wait for integerSenderBinding to be created.
+      integerSender.echo(100).then(function(result) {
+        assert_equals(result.value, 100);
+
+        // This causes this endpoint handle's endpoint client to be detached.
+        var handle = senderConnectionImpl.integerSenderBinding_.
+            interfaceEndpointClient_.passHandle();
+
+        // Cache message. Connector will pause processing incoming messages.
+        integerSender.send(456);
+        stringSender.send('goodbye');
+
+        // Closing the target endpoint handle of the cached message will cause
+        // the cached message to be discarded and the connector to resume
+        // processing incoming messages.
+        setTimeout(handle.reset.bind(handle), 0);
+      });
+    });
+
+    assert_equals(value, 'goodbye');
+  }, 'discard cached message if target endpoint closed');
+
   done();
 });
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-neuter.html b/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-neuter.html
index 0374bef..e112223ea 100644
--- a/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-neuter.html
+++ b/third_party/WebKit/LayoutTests/webaudio/decodeAudioData/decode-audio-data-neuter.html
@@ -62,6 +62,19 @@
             .then(() => task.done());
       });
 
+      audit.define('decode neuters buffer and view', (task, should) => {
+        // The ArrayBuffer and any views of the ArrayBuffer must be neutered.
+        let buffer = new ArrayBuffer(1000);
+        let view = new Uint32Array(buffer);
+
+        context.decodeAudioData(buffer);
+
+        // Now buffer and view should be neutered.
+        should(buffer.byteLength, 'buffer.byteLength').beEqualTo(0);
+        should(view.length, 'view.length').beEqualTo(0);
+        task.done();
+      });
+
       audit.run();
     </script>
   </body>
diff --git a/third_party/WebKit/PerformanceTests/TestData/append-child-measure-time.html b/third_party/WebKit/PerformanceTests/TestData/append-child-measure-time.html
new file mode 100644
index 0000000..99491ef
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/TestData/append-child-measure-time.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<body>
+  <div id="holder">
+  </div>
+<script src="../resources/runner.js"></script>
+</script>
+<script>
+var holderElement = document.getElementById("holder");
+
+PerfTestRunner.measureTime({
+    description: "Measures performance of layout when adding many child elements.",
+
+    setup: function() {
+      while (holderElement.firstChild) {
+        holderElement.removeChild(holderElement.firstChild);
+      }
+    },
+
+    run: function() {
+        for (var i = 0; i < 50; ++i) {
+            var element = document.createElement("div");
+            element.title = 'dummy';
+            element.innerText = "FOO";
+            holderElement.appendChild(element);
+            PerfTestRunner.forceLayout();
+        }
+    },
+    warmUpCount: 3,
+    iterationCount: 10,
+    tracingCategories: 'blink',
+    traceEventsToMeasure: ['FrameView::layout', 'UpdateLayoutTree']
+});
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/PerformanceTests/TestData/color-changes-measure-frame-time.html b/third_party/WebKit/PerformanceTests/TestData/color-changes-measure-frame-time.html
new file mode 100644
index 0000000..a55b247
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/TestData/color-changes-measure-frame-time.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<body>
+<script src="../resources/runner.js"></script>
+<style>
+  span {
+    padding: 1px;
+  }
+  .changeColor {
+    background-color: green;
+  }
+</style>
+<script>
+// This test measures the lifecycle update performance of changing background
+// colors in large trees.
+
+function buildTree(parent, depth, arity, tagNameCallback, createElementCallback) {
+  for (var child = 0; child < arity; child++) {
+    var element = document.createElement(tagNameCallback(depth));
+    parent.appendChild(element);
+    createElementCallback(element, depth);
+    if (depth > 1)
+      buildTree(element, depth - 1, arity, tagNameCallback, createElementCallback);
+  }
+}
+
+// Build a tall tree that is skinny. A middle layer of
+// the tree should have the changeColor class.
+buildTree(document.body, 15, 2,
+  function(depth) {
+    // Use divs at upper levels to avoid too much layout time.
+    return depth > 9 ? 'div' : 'span';
+  },
+  function(element, depth) {
+    element.style.backgroundColor = 'green';
+    if (depth == 5)
+      element.setAttribute('class', 'changeColor');
+  }
+);
+
+// Build a short tree that is fat. A middle layer of
+// the tree should have the changeColor class.
+buildTree(document.body, 6, 7,
+  function(depth) {
+    // Use divs at upper levels to avoid too much layout time.
+    return depth > 4 ? 'div' : 'span';
+  },
+  function(element, depth) {
+    element.style.backgroundColor = 'orange';
+    if (depth == 3)
+      element.setAttribute('class', 'changeColor');
+  }
+);
+
+var runCount = 0;
+var elementsToChange = document.getElementsByClassName('changeColor');
+var colors = [
+ "rgb(128, 18, 237)",
+ "rgb(191, 1, 191)",
+ "rgb(237, 18, 128)",
+ "rgb(255, 64, 64)",
+ "rgb(237, 127, 18)",
+ "rgb(191, 191, 1)",
+ "rgb(128, 237, 18)",
+ "rgb(64, 255, 64)",
+ "rgb(18, 237, 127)",
+ "rgb(1, 191, 191)",
+ "rgb(18, 128, 237)",
+ "rgb(64, 64, 255)"
+];
+
+PerfTestRunner.measureFrameTime({
+  run: function() {
+    runCount++;
+    var newColor = colors[runCount % colors.length];
+    for (var index = 0; index < elementsToChange.length; index++)
+      elementsToChange[index].style.backgroundColor = newColor;
+  },
+   warmUpCount: 3,
+   iterationCount: 10,
+   tracingCategories: 'blink',
+   traceEventsToMeasure: ['FrameView::prePaint', 'FrameView::paintTree']
+});
+</script>
+</body>
diff --git a/third_party/WebKit/PerformanceTests/resources/runner.js b/third_party/WebKit/PerformanceTests/resources/runner.js
index 22a5e8e..7ce98b7 100644
--- a/third_party/WebKit/PerformanceTests/resources/runner.js
+++ b/third_party/WebKit/PerformanceTests/resources/runner.js
@@ -157,8 +157,16 @@
         PerfTestRunner.log("Running " + iterationCount + " times");
         if (test.doNotIgnoreInitialRun)
             completedIterations++;
-        if (runner)
+
+        if (runner && test.tracingCategories && window.testRunner &&
+            window.testRunner.supportTracing) {
+            window.testRunner.traceEventsToMeasure = test.traceEventsToMeasure;
+            window.testRunner.startTracing(test.tracingCategories, function() {
+                scheduleNextRun(scheduler, runner);
+            });
+        } else if (runner) {
             scheduleNextRun(scheduler, runner);
+        }
     }
 
     function scheduleNextRun(scheduler, runner) {
@@ -225,8 +233,17 @@
             logInDocument("Got an exception while finalizing the test with name=" + exception.name + ", message=" + exception.message);
         }
 
-        if (window.testRunner)
-            testRunner.notifyDone();
+        if (window.testRunner) {
+            if (currentTest.traceEventsToMeasure &&
+                testRunner.supportTracing) {
+                testRunner.stopTracingAndMeasure(
+                    currentTest.traceEventsToMeasure, function() {
+                        testRunner.notifyDone();
+                    });
+            } else {
+                testRunner.notifyDone();
+            }
+        }
     }
 
     PerfTestRunner.prepareToMeasureValuesAsync = function (test) {
@@ -248,6 +265,25 @@
             finish();
     }
 
+    function addRunTestStartMarker() {
+      if (!window.testRunner || !window.testRunner.supportTracing)
+          return;
+      if (completedIterations < 0)
+          console.time('blink_perf.runTest.warmup');
+      else
+          console.time('blink_perf.runTest');
+    }
+
+    function addRunTestEndMarker() {
+      if (!window.testRunner || !window.testRunner.supportTracing)
+          return;
+      if (completedIterations < 0)
+          console.timeEnd('blink_perf.runTest.warmup');
+      else
+          console.timeEnd('blink_perf.runTest');
+    }
+
+
     PerfTestRunner.measureFrameTime = function (test) {
         PerfTestRunner.unit = "ms";
         PerfTestRunner.bufferedLog = true;
@@ -261,9 +297,12 @@
 
     var lastFrameTime = -1;
     function measureFrameTimeOnce() {
+        if (lastFrameTime != -1)
+          addRunTestEndMarker();
         var now = PerfTestRunner.now();
         var result = lastFrameTime == -1 ? -1 : now - lastFrameTime;
         lastFrameTime = now;
+        addRunTestStartMarker();
 
         var returnValue = currentTest.run();
         if (returnValue - 0 === returnValue) {
@@ -290,7 +329,9 @@
         PerfTestRunner.gc();
 
         var start = PerfTestRunner.now();
+        addRunTestStartMarker();
         var returnValue = currentTest.run();
+        addRunTestEndMarker();
         var end = PerfTestRunner.now();
 
         if (returnValue - 0 === returnValue) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptController.h b/third_party/WebKit/Source/bindings/core/v8/ScriptController.h
index 72950f0..94203c3 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptController.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptController.h
@@ -56,7 +56,9 @@
 
 typedef WTF::Vector<v8::Extension*> V8Extensions;
 
-
+// This class exposes methods to run script in a frame (in the main world and
+// in isolated worlds). An instance can be obtained by using
+// LocalFrame::GetScriptController().
 class CORE_EXPORT ScriptController final
     : public GarbageCollected<ScriptController> {
   WTF_MAKE_NONCOPYABLE(ScriptController);
diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
index d060856..6ad7cfd 100644
--- a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
@@ -272,19 +272,6 @@
   }
 }
 
-static void AccumulateArrayBuffersForAllWorlds(
-    v8::Isolate* isolate,
-    DOMArrayBuffer* object,
-    Vector<v8::Local<v8::ArrayBuffer>, 4>& buffers) {
-  Vector<RefPtr<DOMWrapperWorld>> worlds;
-  DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
-  for (const auto& world : worlds) {
-    v8::Local<v8::Object> wrapper = world->DomDataStore().Get(object, isolate);
-    if (!wrapper.IsEmpty())
-      buffers.push_back(v8::Local<v8::ArrayBuffer>::Cast(wrapper));
-  }
-}
-
 std::unique_ptr<SerializedScriptValue::ImageBitmapContentsArray>
 SerializedScriptValue::TransferImageBitmapContents(
     v8::Isolate* isolate,
@@ -480,14 +467,16 @@
 
   HeapHashSet<Member<DOMArrayBufferBase>> visited;
   for (auto it = array_buffers.begin(); it != array_buffers.end(); ++it) {
-    DOMArrayBufferBase* array_buffer = *it;
-    if (visited.Contains(array_buffer))
+    DOMArrayBufferBase* array_buffer_base = *it;
+    if (visited.Contains(array_buffer_base))
       continue;
-    visited.insert(array_buffer);
+    visited.insert(array_buffer_base);
 
     size_t index = std::distance(array_buffers.begin(), it);
-    if (array_buffer->IsShared()) {
-      if (!array_buffer->ShareContentsWith(contents->at(index))) {
+    if (array_buffer_base->IsShared()) {
+      DOMSharedArrayBuffer* shared_array_buffer =
+          static_cast<DOMSharedArrayBuffer*>(array_buffer_base);
+      if (!shared_array_buffer->ShareContentsWith(contents->at(index))) {
         exception_state.ThrowDOMException(kDataCloneError,
                                           "SharedArrayBuffer at index " +
                                               String::Number(index) +
@@ -495,31 +484,15 @@
         return nullptr;
       }
     } else {
-      Vector<v8::Local<v8::ArrayBuffer>, 4> buffer_handles;
-      v8::HandleScope handle_scope(isolate);
-      AccumulateArrayBuffersForAllWorlds(
-          isolate, static_cast<DOMArrayBuffer*>(it->Get()), buffer_handles);
-      bool is_neuterable = true;
-      for (const auto& buffer_handle : buffer_handles)
-        is_neuterable &= buffer_handle->IsNeuterable();
+      DOMArrayBuffer* array_buffer =
+          static_cast<DOMArrayBuffer*>(array_buffer_base);
 
-      DOMArrayBufferBase* to_transfer = array_buffer;
-      if (!is_neuterable) {
-        to_transfer =
-            DOMArrayBuffer::Create(array_buffer->Buffer()->Data(),
-                                   array_buffer->Buffer()->ByteLength());
-      }
-      if (!to_transfer->Transfer(contents->at(index))) {
+      if (!array_buffer->Transfer(isolate, contents->at(index))) {
         exception_state.ThrowDOMException(
             kDataCloneError, "ArrayBuffer at index " + String::Number(index) +
                                  " could not be transferred.");
         return nullptr;
       }
-
-      if (is_neuterable) {
-        for (const auto& buffer_handle : buffer_handles)
-          buffer_handle->Neuter();
-      }
     }
   }
   return contents;
diff --git a/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp b/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp
index c2979fc..3eee75d 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp
+++ b/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp
@@ -135,7 +135,7 @@
 constexpr static size_t kSSVHeaderBlinkVersionTagOffset = 0;
 constexpr static size_t kSSVHeaderBlinkVersionOffset = 1;
 constexpr static size_t kSSVHeaderV8VersionTagOffset = 2;
-constexpr static size_t kSSVHeaderV8VersionOffset = 3;
+// constexpr static size_t kSSVHeaderV8VersionOffset = 3;
 
 // Follows the same steps as the IndexedDB value serialization code.
 void SerializeV8Value(v8::Local<v8::Value> value,
@@ -165,8 +165,9 @@
 
   ASSERT_EQ(static_cast<unsigned char>(kVersionTag),
             wire_data[kSSVHeaderV8VersionTagOffset]);
-  ASSERT_EQ(v8::ValueSerializer::GetCurrentDataFormatVersion(),
-            wire_data[kSSVHeaderV8VersionOffset]);
+  // TODO(jbroman): Use the compile-time constant for V8 data format version.
+  // ASSERT_EQ(v8::ValueSerializer::GetCurrentDataFormatVersion(),
+  //           wire_data[kSSVHeaderV8VersionOffset]);
 }
 
 PassRefPtr<IDBValue> CreateIDBValue(v8::Isolate* isolate,
diff --git a/third_party/WebKit/Source/bindings/templates/callback_interface.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/callback_interface.cpp.tmpl
index c417aaa..e308643 100644
--- a/third_party/WebKit/Source/bindings/templates/callback_interface.cpp.tmpl
+++ b/third_party/WebKit/Source/bindings/templates/callback_interface.cpp.tmpl
@@ -26,8 +26,8 @@
          if method.idl_type == 'boolean' else 'return' %}{# void #}
   ExecutionContext* executionContext =
       ExecutionContext::From(m_scriptState.Get());
-  if (!executionContext || executionContext->IsContextSuspended() ||
-      executionContext->IsContextDestroyed())
+  DCHECK(!executionContext->IsContextSuspended());
+  if (!executionContext || executionContext->IsContextDestroyed())
     {{return_default}};
   if (!m_scriptState->ContextIsValid())
     {{return_default}};
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestCallbackInterface.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestCallbackInterface.cpp
index de0cb82..adcf84e 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestCallbackInterface.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestCallbackInterface.cpp
@@ -37,8 +37,8 @@
 void V8TestCallbackInterface::voidMethod() {
   ExecutionContext* executionContext =
       ExecutionContext::From(m_scriptState.Get());
-  if (!executionContext || executionContext->IsContextSuspended() ||
-      executionContext->IsContextDestroyed())
+  DCHECK(!executionContext->IsContextSuspended());
+  if (!executionContext || executionContext->IsContextDestroyed())
     return;
   if (!m_scriptState->ContextIsValid())
     return;
@@ -59,8 +59,8 @@
 bool V8TestCallbackInterface::booleanMethod() {
   ExecutionContext* executionContext =
       ExecutionContext::From(m_scriptState.Get());
-  if (!executionContext || executionContext->IsContextSuspended() ||
-      executionContext->IsContextDestroyed())
+  DCHECK(!executionContext->IsContextSuspended());
+  if (!executionContext || executionContext->IsContextDestroyed())
     return true;
   if (!m_scriptState->ContextIsValid())
     return true;
@@ -84,8 +84,8 @@
 void V8TestCallbackInterface::voidMethodBooleanArg(bool boolArg) {
   ExecutionContext* executionContext =
       ExecutionContext::From(m_scriptState.Get());
-  if (!executionContext || executionContext->IsContextSuspended() ||
-      executionContext->IsContextDestroyed())
+  DCHECK(!executionContext->IsContextSuspended());
+  if (!executionContext || executionContext->IsContextDestroyed())
     return;
   if (!m_scriptState->ContextIsValid())
     return;
@@ -107,8 +107,8 @@
 void V8TestCallbackInterface::voidMethodSequenceArg(const HeapVector<Member<TestInterfaceEmpty>>& sequenceArg) {
   ExecutionContext* executionContext =
       ExecutionContext::From(m_scriptState.Get());
-  if (!executionContext || executionContext->IsContextSuspended() ||
-      executionContext->IsContextDestroyed())
+  DCHECK(!executionContext->IsContextSuspended());
+  if (!executionContext || executionContext->IsContextDestroyed())
     return;
   if (!m_scriptState->ContextIsValid())
     return;
@@ -130,8 +130,8 @@
 void V8TestCallbackInterface::voidMethodFloatArg(float floatArg) {
   ExecutionContext* executionContext =
       ExecutionContext::From(m_scriptState.Get());
-  if (!executionContext || executionContext->IsContextSuspended() ||
-      executionContext->IsContextDestroyed())
+  DCHECK(!executionContext->IsContextSuspended());
+  if (!executionContext || executionContext->IsContextDestroyed())
     return;
   if (!m_scriptState->ContextIsValid())
     return;
@@ -153,8 +153,8 @@
 void V8TestCallbackInterface::voidMethodTestInterfaceEmptyArg(TestInterfaceEmpty* testInterfaceEmptyArg) {
   ExecutionContext* executionContext =
       ExecutionContext::From(m_scriptState.Get());
-  if (!executionContext || executionContext->IsContextSuspended() ||
-      executionContext->IsContextDestroyed())
+  DCHECK(!executionContext->IsContextSuspended());
+  if (!executionContext || executionContext->IsContextDestroyed())
     return;
   if (!m_scriptState->ContextIsValid())
     return;
@@ -176,8 +176,8 @@
 void V8TestCallbackInterface::voidMethodTestInterfaceEmptyStringArg(TestInterfaceEmpty* testInterfaceEmptyArg, const String& stringArg) {
   ExecutionContext* executionContext =
       ExecutionContext::From(m_scriptState.Get());
-  if (!executionContext || executionContext->IsContextSuspended() ||
-      executionContext->IsContextDestroyed())
+  DCHECK(!executionContext->IsContextSuspended());
+  if (!executionContext || executionContext->IsContextDestroyed())
     return;
   if (!m_scriptState->ContextIsValid())
     return;
@@ -200,8 +200,8 @@
 void V8TestCallbackInterface::callbackWithThisValueVoidMethodStringArg(ScriptValue thisValue, const String& stringArg) {
   ExecutionContext* executionContext =
       ExecutionContext::From(m_scriptState.Get());
-  if (!executionContext || executionContext->IsContextSuspended() ||
-      executionContext->IsContextDestroyed())
+  DCHECK(!executionContext->IsContextSuspended());
+  if (!executionContext || executionContext->IsContextDestroyed())
     return;
   if (!m_scriptState->ContextIsValid())
     return;
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZoom.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZoom.cpp
index a1abb7e..2d94b6fb 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZoom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZoom.cpp
@@ -17,8 +17,7 @@
   const CSSParserToken& token = range.Peek();
   CSSValue* zoom = nullptr;
   if (token.GetType() == kIdentToken) {
-    zoom = CSSPropertyParserHelpers::ConsumeIdent<CSSValueNormal, CSSValueReset,
-                                                  CSSValueDocument>(range);
+    zoom = CSSPropertyParserHelpers::ConsumeIdent<CSSValueNormal>(range);
   } else {
     zoom =
         CSSPropertyParserHelpers::ConsumePercent(range, kValueRangeNonNegative);
@@ -34,10 +33,6 @@
           (token.GetType() == kPercentageToken &&
            ToCSSPrimitiveValue(zoom)->GetDoubleValue() == 100)))
       context.Count(UseCounter::kCSSZoomNotEqualToOne);
-    if (token.Id() == CSSValueReset)
-      context.CountDeprecation(UseCounter::kCSSZoomReset);
-    if (token.Id() == CSSValueDocument)
-      context.CountDeprecation(UseCounter::kCSSZoomDocument);
   }
   return zoom;
 }
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
index b44925b..d9a49cbf 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -552,15 +552,6 @@
     if (identifier_value.GetValueID() == CSSValueNormal) {
       ResetEffectiveZoom(state);
       state.SetZoom(ComputedStyle::InitialZoom());
-    } else if (identifier_value.GetValueID() == CSSValueReset) {
-      state.SetEffectiveZoom(ComputedStyle::InitialZoom());
-      state.SetZoom(ComputedStyle::InitialZoom());
-    } else if (identifier_value.GetValueID() == CSSValueDocument) {
-      float doc_zoom = state.RootElementStyle()
-                           ? state.RootElementStyle()->Zoom()
-                           : ComputedStyle::InitialZoom();
-      state.SetEffectiveZoom(doc_zoom);
-      state.SetZoom(doc_zoom);
     }
   } else if (value.IsPrimitiveValue()) {
     const CSSPrimitiveValue& primitive_value = ToCSSPrimitiveValue(value);
diff --git a/third_party/WebKit/Source/core/dom/DOMArrayBuffer.cpp b/third_party/WebKit/Source/core/dom/DOMArrayBuffer.cpp
index 3b7c5bc..0887f6b 100644
--- a/third_party/WebKit/Source/core/dom/DOMArrayBuffer.cpp
+++ b/third_party/WebKit/Source/core/dom/DOMArrayBuffer.cpp
@@ -5,10 +5,58 @@
 #include "core/dom/DOMArrayBuffer.h"
 
 #include "bindings/core/v8/DOMDataStore.h"
+#include "bindings/core/v8/DOMWrapperWorld.h"
 #include "platform/wtf/RefPtr.h"
+#include "platform/wtf/Vector.h"
 
 namespace blink {
 
+static void AccumulateArrayBuffersForAllWorlds(
+    v8::Isolate* isolate,
+    DOMArrayBuffer* object,
+    Vector<v8::Local<v8::ArrayBuffer>, 4>& buffers) {
+  Vector<RefPtr<DOMWrapperWorld>> worlds;
+  DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
+  for (const auto& world : worlds) {
+    v8::Local<v8::Object> wrapper = world->DomDataStore().Get(object, isolate);
+    if (!wrapper.IsEmpty())
+      buffers.push_back(v8::Local<v8::ArrayBuffer>::Cast(wrapper));
+  }
+}
+
+bool DOMArrayBuffer::IsNeuterable(v8::Isolate* isolate) {
+  Vector<v8::Local<v8::ArrayBuffer>, 4> buffer_handles;
+  v8::HandleScope handle_scope(isolate);
+  AccumulateArrayBuffersForAllWorlds(isolate, this, buffer_handles);
+
+  bool is_neuterable = true;
+  for (const auto& buffer_handle : buffer_handles)
+    is_neuterable &= buffer_handle->IsNeuterable();
+
+  return is_neuterable;
+}
+
+bool DOMArrayBuffer::Transfer(v8::Isolate* isolate,
+                              WTF::ArrayBufferContents& result) {
+  DOMArrayBuffer* to_transfer = this;
+  if (!IsNeuterable(isolate)) {
+    to_transfer =
+        DOMArrayBuffer::Create(Buffer()->Data(), Buffer()->ByteLength());
+  }
+
+  if (!to_transfer->Buffer()->Transfer(result))
+    return false;
+
+  Vector<v8::Local<v8::ArrayBuffer>, 4> buffer_handles;
+  v8::HandleScope handle_scope(isolate);
+  AccumulateArrayBuffersForAllWorlds(isolate, to_transfer, buffer_handles);
+
+  for (const auto& buffer_handle : buffer_handles)
+    buffer_handle->Neuter();
+
+  return true;
+}
+
 DOMArrayBuffer* DOMArrayBuffer::CreateUninitializedOrNull(
     unsigned num_elements,
     unsigned element_byte_size) {
diff --git a/third_party/WebKit/Source/core/dom/DOMArrayBuffer.h b/third_party/WebKit/Source/core/dom/DOMArrayBuffer.h
index 584eca4..7da02346 100644
--- a/third_party/WebKit/Source/core/dom/DOMArrayBuffer.h
+++ b/third_party/WebKit/Source/core/dom/DOMArrayBuffer.h
@@ -41,6 +41,12 @@
     return Create(Buffer()->Slice(begin));
   }
 
+  bool IsNeuterable(v8::Isolate*);
+
+  // Transfer the ArrayBuffer if it is neuterable, otherwise make a copy and
+  // transfer that.
+  bool Transfer(v8::Isolate*, WTF::ArrayBufferContents& result);
+
   v8::Local<v8::Object> Wrap(v8::Isolate*,
                              v8::Local<v8::Object> creation_context) override;
 
diff --git a/third_party/WebKit/Source/core/dom/DOMArrayBufferBase.h b/third_party/WebKit/Source/core/dom/DOMArrayBufferBase.h
index 57dbc97..9f060718 100644
--- a/third_party/WebKit/Source/core/dom/DOMArrayBufferBase.h
+++ b/third_party/WebKit/Source/core/dom/DOMArrayBufferBase.h
@@ -24,12 +24,6 @@
   const void* Data() const { return Buffer()->Data(); }
   void* Data() { return Buffer()->Data(); }
   unsigned ByteLength() const { return Buffer()->ByteLength(); }
-  bool Transfer(WTF::ArrayBufferContents& result) {
-    return Buffer()->Transfer(result);
-  }
-  bool ShareContentsWith(WTF::ArrayBufferContents& result) {
-    return Buffer()->ShareContentsWith(result);
-  }
   bool IsNeutered() const { return Buffer()->IsNeutered(); }
   bool IsShared() const { return Buffer()->IsShared(); }
 
diff --git a/third_party/WebKit/Source/core/dom/DOMSharedArrayBuffer.h b/third_party/WebKit/Source/core/dom/DOMSharedArrayBuffer.h
index 5c09421..96ce8db 100644
--- a/third_party/WebKit/Source/core/dom/DOMSharedArrayBuffer.h
+++ b/third_party/WebKit/Source/core/dom/DOMSharedArrayBuffer.h
@@ -33,6 +33,10 @@
     return Create(WTF::ArrayBuffer::Create(contents));
   }
 
+  bool ShareContentsWith(WTF::ArrayBufferContents& result) {
+    return Buffer()->ShareContentsWith(result);
+  }
+
   v8::Local<v8::Object> Wrap(v8::Isolate*,
                              v8::Local<v8::Object> creation_context) override;
 
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
index ef91e363..860f87fe 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -1935,8 +1935,10 @@
 
   EphemeralRange range(Position::FirstPositionInNode(scope),
                        p.ParentAnchoredEquivalent());
-  return TextIterator::RangeLength(range.StartPosition(), range.EndPosition(),
-                                   true);
+
+  return TextIterator::RangeLength(
+      range.StartPosition(), range.EndPosition(),
+      TextIteratorBehavior::AllVisiblePositionsRangeLengthBehavior());
 }
 
 EphemeralRange MakeRange(const VisiblePosition& start,
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp
index d5e93c8..ac77e75a 100644
--- a/third_party/WebKit/Source/core/editing/SelectionController.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -97,7 +97,9 @@
 
 static int TextDistance(const PositionInFlatTree& start,
                         const PositionInFlatTree& end) {
-  return TextIteratorInFlatTree::RangeLength(start, end, true);
+  return TextIteratorInFlatTree::RangeLength(
+      start, end,
+      TextIteratorBehavior::AllVisiblePositionsRangeLengthBehavior());
 }
 
 bool CanMouseDownStartSelect(Node* node) {
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
index e319cee6..a328886 100644
--- a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
@@ -266,10 +266,14 @@
   Range* end_range =
       Range::Create(GetDocument(), Position::FirstPositionInNode(&scope),
                     visible_end.DeepEquivalent().ParentAnchoredEquivalent());
-  int start_index = TextIterator::RangeLength(start_range->StartPosition(),
-                                              start_range->EndPosition(), true);
+
+  const TextIteratorBehavior behavior =
+      TextIteratorBehavior::AllVisiblePositionsRangeLengthBehavior();
+
+  int start_index = TextIterator::RangeLength(
+      start_range->StartPosition(), start_range->EndPosition(), behavior);
   int end_index = TextIterator::RangeLength(end_range->StartPosition(),
-                                            end_range->EndPosition(), true);
+                                            end_range->EndPosition(), behavior);
 
   VisiblePosition paragraph_start(StartOfParagraph(visible_start));
   VisiblePosition next_paragraph_start(
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
index 2e7e9656..285363d 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -1394,17 +1394,22 @@
       bool end_in_paragraph =
           ComparePositions(visible_end, end_of_paragraph_to_move) <= 0;
 
+      const TextIteratorBehavior behavior =
+          TextIteratorBehavior::AllVisiblePositionsRangeLengthBehavior();
+
       start_index = 0;
-      if (start_in_paragraph)
+      if (start_in_paragraph) {
         start_index = TextIterator::RangeLength(
             start_of_paragraph_to_move.ToParentAnchoredPosition(),
-            visible_start.ToParentAnchoredPosition(), true);
+            visible_start.ToParentAnchoredPosition(), behavior);
+      }
 
       end_index = 0;
-      if (end_in_paragraph)
+      if (end_in_paragraph) {
         end_index = TextIterator::RangeLength(
             start_of_paragraph_to_move.ToParentAnchoredPosition(),
-            visible_end.ToParentAnchoredPosition(), true);
+            visible_end.ToParentAnchoredPosition(), behavior);
+      }
     }
   }
 
@@ -1504,7 +1509,8 @@
 
   destination_index = TextIterator::RangeLength(
       Position::FirstPositionInNode(GetDocument().documentElement()),
-      destination.ToParentAnchoredPosition(), true);
+      destination.ToParentAnchoredPosition(),
+      TextIteratorBehavior::AllVisiblePositionsRangeLengthBehavior());
 
   const SelectionInDOMTree& destination_selection =
       SelectionInDOMTree::Builder()
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index d3bcf4e..b569a1f 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -1341,18 +1341,12 @@
 int TextIteratorAlgorithm<Strategy>::RangeLength(
     const PositionTemplate<Strategy>& start,
     const PositionTemplate<Strategy>& end,
-    bool for_selection_preservation) {
+    const TextIteratorBehavior& behavior) {
   DCHECK(start.GetDocument());
   DocumentLifecycle::DisallowTransitionScope disallow_transition(
       start.GetDocument()->Lifecycle());
 
   int length = 0;
-  const TextIteratorBehavior& behavior =
-      TextIteratorBehavior::Builder()
-          .SetEmitsObjectReplacementCharacter(true)
-          .SetEmitsCharactersBetweenAllVisiblePositions(
-              for_selection_preservation)
-          .Build();
   for (TextIteratorAlgorithm<Strategy> it(start, end, behavior); !it.AtEnd();
        it.Advance())
     length += it.length();
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
index efd5e98..4438f9e5 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
@@ -100,14 +100,14 @@
   // TODO(xiaochengh): Avoid default parameters.
   int CopyTextTo(ForwardsTextBuffer* output, int position = 0) const;
 
-  // Computes the length of the given range using a text iterator. The default
-  // iteration behavior is to always emit object replacement characters for
-  // replaced elements. When |forSelectionPreservation| is set to true, it
-  // also emits spaces for other non-text nodes using the
-  // |TextIteratorEmitsCharactersBetweenAllVisiblePosition| mode.
-  static int RangeLength(const PositionTemplate<Strategy>& start,
-                         const PositionTemplate<Strategy>& end,
-                         bool for_selection_preservation = false);
+  // Computes the length of the given range using a text iterator according to
+  // the specified iteration behavior. The default iteration behavior is to
+  // always emit object replacement characters for replaced elements.
+  static int RangeLength(
+      const PositionTemplate<Strategy>& start,
+      const PositionTemplate<Strategy>& end,
+      const TextIteratorBehavior& =
+          TextIteratorBehavior::DefaultRangeLengthBehavior());
 
   static bool ShouldEmitTabBeforeNode(Node*);
   static bool ShouldEmitNewlineBeforeNode(Node&);
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorBehavior.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorBehavior.cpp
index 7f6cd321..41909e90 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorBehavior.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorBehavior.cpp
@@ -170,4 +170,20 @@
       .Build();
 }
 
+// static
+TextIteratorBehavior TextIteratorBehavior::DefaultRangeLengthBehavior() {
+  return TextIteratorBehavior::Builder()
+      .SetEmitsObjectReplacementCharacter(true)
+      .Build();
+}
+
+// static
+TextIteratorBehavior
+TextIteratorBehavior::AllVisiblePositionsRangeLengthBehavior() {
+  return TextIteratorBehavior::Builder()
+      .SetEmitsObjectReplacementCharacter(true)
+      .SetEmitsCharactersBetweenAllVisiblePositions(true)
+      .Build();
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorBehavior.h b/third_party/WebKit/Source/core/editing/iterators/TextIteratorBehavior.h
index 28e58c4..fe4a712 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorBehavior.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorBehavior.h
@@ -45,6 +45,8 @@
 
   static TextIteratorBehavior EmitsObjectReplacementCharacterBehavior();
   static TextIteratorBehavior IgnoresStyleVisibilityBehavior();
+  static TextIteratorBehavior DefaultRangeLengthBehavior();
+  static TextIteratorBehavior AllVisiblePositionsRangeLengthBehavior();
 
  private:
   bool collapse_trailing_space_ : 1;
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index ab4370b6..2eb92b60e 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -383,12 +383,6 @@
           "-internal-media-controls-overlay-cast-button selector", M61,
           "5714245488476160");
 
-    case UseCounter::kCSSZoomReset:
-      return willBeRemoved("\"zoom: reset\"", M59, "4997605029314560");
-
-    case UseCounter::kCSSZoomDocument:
-      return willBeRemoved("\"zoom: document\"", M59, "4997605029314560");
-
     case UseCounter::kSelectionAddRangeIntersect:
       return "The behavior that Selection.addRange() merges existing Range and "
              "the specified Range was removed. See "
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 7ed3ec6e..c022b034 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1198,8 +1198,6 @@
     kPresentationConnectionListConnectionAvailableEventListener = 1555,
     kWebAudioAutoplayCrossOriginIframe = 1556,
     kVRGetDisplays = 1558,
-    kCSSZoomReset = 1578,
-    kCSSZoomDocument = 1579,
     kXSSAuditorBlockedScript = 1581,
     kXSSAuditorBlockedEntirePage = 1582,
     kXSSAuditorDisabled = 1583,
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index e8eb453d7..da142b1 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1548,7 +1548,7 @@
 
   // Insert the ancestors of the frame having the new target node to the entered
   // frame chain.
-  HeapVector<Member<LocalFrame>> entered_frame_chain;
+  HeapVector<Member<LocalFrame>, 2> entered_frame_chain;
   LocalFrame* entered_frame_in_document =
       targeted_event.GetHitTestResult().InnerNodeFrame();
   while (entered_frame_in_document) {
@@ -1561,7 +1561,7 @@
 
   size_t index_entered_frame_chain = entered_frame_chain.size();
   LocalFrame* exited_frame_in_document = frame_;
-  HeapVector<Member<LocalFrame>> exited_frame_chain;
+  HeapVector<Member<LocalFrame>, 2> exited_frame_chain;
   // Insert the frame from the disagreement between last frames and entered
   // frames.
   while (exited_frame_in_document) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
index 14dc866..de326cd 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
@@ -401,7 +401,7 @@
 
   LayoutSize offset = LayoutBlockFlow::OffsetFromContainer(o);
   if (Parent())
-    offset -= ParentBox()->LocationOffset();
+    offset -= ParentBox()->PhysicalLocationOffset();
 
   return offset;
 }
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index c0329ed..d7ba41c 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -798,8 +798,14 @@
   if (!frame_)
     return false;
 
-  // The Document has now been created.
-  frame_->GetDocument()->EnforceSandboxFlags(kSandboxAll);
+  // The MHTML page is loaded in full sandboxing mode with the only
+  // exception to open new top-level windows. Since the MHTML page stays in a
+  // unquie origin with script execution disabled, the risk to navigate to
+  // 'blob:'' and 'filesystem:'' URLs that allow code execution in the page's
+  // "real" origin is mitigated.
+  frame_->GetDocument()->EnforceSandboxFlags(
+      kSandboxAll &
+      ~(kSandboxPopups | kSandboxPropagatesToAuxiliaryBrowsingContexts));
 
   CommitData(main_resource->Data()->Data(), main_resource->Data()->size());
   return true;
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
index 25853dbe..51268fd 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
@@ -53,6 +53,7 @@
       this._canAddAttributes = true;
     this._searchQuery = null;
     this._expandedChildrenLimit = Elements.ElementsTreeElement.InitialChildrenLimit;
+    this._decorationsThrottler = new Common.Throttler(100);
   }
 
   /**
@@ -1086,10 +1087,21 @@
     if (this.isClosingTag())
       return;
 
-    var node = this._node;
-    if (node.nodeType() !== Node.ELEMENT_NODE)
+    if (this._node.nodeType() !== Node.ELEMENT_NODE)
       return;
 
+    this._decorationsThrottler.schedule(this._updateDecorationsInternal.bind(this));
+  }
+
+  /**
+   * @return {!Promise}
+   */
+  _updateDecorationsInternal() {
+    if (!this.treeOutline)
+      return Promise.resolve();
+
+    var node = this._node;
+
     if (!this.treeOutline._decoratorExtensions)
       /** @type {!Array.<!Runtime.Extension>} */
       this.treeOutline._decoratorExtensions = runtime.extensions(Components.DOMPresentationUtils.MarkerDecorator);
@@ -1127,7 +1139,7 @@
       (n === node ? decorations : descendantDecorations).push(decoration);
     }
 
-    Promise.all(promises).then(updateDecorationsUI.bind(this));
+    return Promise.all(promises).then(updateDecorationsUI.bind(this));
 
     /**
      * @this {Elements.ElementsTreeElement}
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DOMDebuggerModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DOMDebuggerModel.js
index 069e2c861..fc3010b 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/DOMDebuggerModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/DOMDebuggerModel.js
@@ -182,18 +182,24 @@
 
     var currentURL = this._currentURL();
     for (var breakpoint of this._domBreakpointsSetting.get()) {
-      if (breakpoint.url !== currentURL)
-        continue;
-      this._domModel.pushNodeByPathToFrontend(breakpoint.path, nodeId => {
-        var node = nodeId ? this._domModel.nodeForId(nodeId) : null;
-        if (!node)
-          return;
-        var domBreakpoint = new SDK.DOMDebuggerModel.DOMBreakpoint(this, node, breakpoint.type, breakpoint.enabled);
-        this._domBreakpoints.push(domBreakpoint);
-        if (breakpoint.enabled)
-          this._enableDOMBreakpoint(domBreakpoint);
-        this.dispatchEventToListeners(SDK.DOMDebuggerModel.Events.DOMBreakpointAdded, domBreakpoint);
-      });
+      if (breakpoint.url === currentURL)
+        this._domModel.pushNodeByPathToFrontend(breakpoint.path, appendBreakpoint.bind(this, breakpoint));
+    }
+
+    /**
+     * @param {!{type: !SDK.DOMDebuggerModel.DOMBreakpoint.Type, enabled: boolean}} breakpoint
+     * @param {?number} nodeId
+     * @this {SDK.DOMDebuggerModel}
+     */
+    function appendBreakpoint(breakpoint, nodeId) {
+      var node = nodeId ? this._domModel.nodeForId(nodeId) : null;
+      if (!node)
+        return;
+      var domBreakpoint = new SDK.DOMDebuggerModel.DOMBreakpoint(this, node, breakpoint.type, breakpoint.enabled);
+      this._domBreakpoints.push(domBreakpoint);
+      if (breakpoint.enabled)
+        this._enableDOMBreakpoint(domBreakpoint);
+      this.dispatchEventToListeners(SDK.DOMDebuggerModel.Events.DOMBreakpointAdded, domBreakpoint);
     }
   }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
index 3b44d912..1a40a205 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
@@ -303,8 +303,19 @@
 
   DCHECK_GT(rate, 0);
 
-  if (audio_data->IsNeutered()) {
-    // If audioData is detached (neutered) we need to reject the
+  v8::Isolate* isolate = script_state->GetIsolate();
+  WTF::ArrayBufferContents buffer_contents;
+  // Detach the audio array buffer from the main thread and start
+  // async decoding of the data.
+  if (audio_data->IsNeuterable(isolate) &&
+      audio_data->Transfer(isolate, buffer_contents)) {
+    DOMArrayBuffer* audio = DOMArrayBuffer::Create(buffer_contents);
+
+    decode_audio_resolvers_.insert(resolver);
+    audio_decoder_.DecodeAsync(audio, rate, success_callback, error_callback,
+                               resolver, this);
+  } else {
+    // If audioData is already detached (neutered) we need to reject the
     // promise with an error.
     DOMException* error = DOMException::Create(
         kDataCloneError, "Cannot decode detached ArrayBuffer");
@@ -312,16 +323,6 @@
     if (error_callback) {
       error_callback->call(this, error);
     }
-  } else {
-    // Detach the audio array buffer from the main thread and start
-    // async decoding of the data.
-    WTF::ArrayBufferContents buffer_contents;
-    audio_data->Transfer(buffer_contents);
-    DOMArrayBuffer* audio = DOMArrayBuffer::Create(buffer_contents);
-
-    decode_audio_resolvers_.insert(resolver);
-    audio_decoder_.DecodeAsync(audio, rate, success_callback, error_callback,
-                               resolver, this);
   }
 
   return promise;
diff --git a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
index b208f25..a50faac2 100644
--- a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
@@ -52,21 +52,13 @@
 
 DecodingImageGenerator::~DecodingImageGenerator() {}
 
-SkData* DecodingImageGenerator::onRefEncodedData(GrContext* ctx) {
+SkData* DecodingImageGenerator::onRefEncodedData() {
   TRACE_EVENT0("blink", "DecodingImageGenerator::refEncodedData");
 
-  // The GPU only wants the data if it has all been received, since the GPU
-  // only wants a complete texture. getAsSkData() may require copying, so
-  // skip it and just return nullptr to avoid a slowdown. (See
-  // crbug.com/568016 for details about such a slowdown.)
-  // TODO (scroggo): Stop relying on the internal knowledge of how Skia uses
-  // this. skbug.com/5485
-  if (ctx && !all_data_received_)
-    return nullptr;
-
-  // Other clients are serializers, which want the data even if it requires
-  // copying, and even if the data is incomplete. (Otherwise they would
-  // potentially need to decode the partial image in order to re-encode it.)
+  // getAsSkData() may require copying, but the clients of this function are
+  // serializers, which want the data even if it requires copying, and even
+  // if the data is incomplete. (Otherwise they would potentially need to
+  // decode the partial image in order to re-encode it.)
   return data_->GetAsSkData().release();
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h
index 408fd74..5c5f703 100644
--- a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h
+++ b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.h
@@ -65,7 +65,7 @@
   void SetCanYUVDecode(bool yes) { can_yuv_decode_ = yes; }
 
  protected:
-  SkData* onRefEncodedData(GrContext* ctx) override;
+  SkData* onRefEncodedData() override;
 
   bool onGetPixels(const SkImageInfo&,
                    void* pixels,
diff --git a/third_party/WebKit/Source/web/tests/MHTMLTest.cpp b/third_party/WebKit/Source/web/tests/MHTMLTest.cpp
index e303756..33f9e9ed 100644
--- a/third_party/WebKit/Source/web/tests/MHTMLTest.cpp
+++ b/third_party/WebKit/Source/web/tests/MHTMLTest.cpp
@@ -289,8 +289,11 @@
   Document* document = frame->GetDocument();
   ASSERT_TRUE(document);
 
-  // Full sandboxing should be turned on.
-  EXPECT_TRUE(document->IsSandboxed(kSandboxAll));
+  // Full sandboxing with the exception to new top-level windows should be
+  // turned on.
+  EXPECT_EQ(kSandboxAll & ~(kSandboxPopups |
+                            kSandboxPropagatesToAuxiliaryBrowsingContexts),
+            document->GetSandboxFlags());
 
   // MHTML document should be loaded into unique origin.
   EXPECT_TRUE(document->GetSecurityOrigin()->IsUnique());
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py
index ed15115..d0c6bbd 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py
@@ -188,6 +188,7 @@
             _log.warn('xdpyinfo check failed with exit code %s while starting Xvfb on "%s".', exit_code, display)
             self.host.sleep(0.1)
         _log.fatal('Failed to start Xvfb on display "%s" (xdpyinfo check failed).', display)
+        self._stop_xvfb()
 
     def _find_display(self):
         """Tries to find a free X display, looping if necessary."""
@@ -219,8 +220,7 @@
             for line in self.host.filesystem.read_text_file(self._xvfb_stderr.name).splitlines():
                 _log.warn('Xvfb stderr:  %s', line)
             self.host.filesystem.remove(self._xvfb_stderr.name)
-
-
+        self._xvfb_stdout = self._xvfb_stderr = self._xvfb_process = None
 
     def _path_to_driver(self, target=None):
         binary_name = self.driver_name()
diff --git a/third_party/boringssl/BUILD.generated.gni b/third_party/boringssl/BUILD.generated.gni
index 982aa13..000a3be 100644
--- a/third_party/boringssl/BUILD.generated.gni
+++ b/third_party/boringssl/BUILD.generated.gni
@@ -158,17 +158,12 @@
   "src/crypto/fipsmodule/digest/internal.h",
   "src/crypto/fipsmodule/digest/md32_common.h",
   "src/crypto/fipsmodule/is_fips.c",
+  "src/crypto/fipsmodule/modes/internal.h",
+  "src/crypto/fipsmodule/rand/internal.h",
   "src/crypto/hkdf/hkdf.c",
   "src/crypto/internal.h",
   "src/crypto/lhash/lhash.c",
   "src/crypto/mem.c",
-  "src/crypto/modes/cbc.c",
-  "src/crypto/modes/cfb.c",
-  "src/crypto/modes/ctr.c",
-  "src/crypto/modes/gcm.c",
-  "src/crypto/modes/internal.h",
-  "src/crypto/modes/ofb.c",
-  "src/crypto/modes/polyval.c",
   "src/crypto/obj/obj.c",
   "src/crypto/obj/obj_dat.h",
   "src/crypto/obj/obj_xref.c",
@@ -193,14 +188,11 @@
   "src/crypto/poly1305/poly1305_vec.c",
   "src/crypto/pool/internal.h",
   "src/crypto/pool/pool.c",
-  "src/crypto/rand/ctrdrbg.c",
-  "src/crypto/rand/deterministic.c",
-  "src/crypto/rand/forkunsafe.c",
-  "src/crypto/rand/fuchsia.c",
-  "src/crypto/rand/internal.h",
-  "src/crypto/rand/rand.c",
-  "src/crypto/rand/urandom.c",
-  "src/crypto/rand/windows.c",
+  "src/crypto/rand_extra/deterministic.c",
+  "src/crypto/rand_extra/forkunsafe.c",
+  "src/crypto/rand_extra/fuchsia.c",
+  "src/crypto/rand_extra/rand_extra.c",
+  "src/crypto/rand_extra/windows.c",
   "src/crypto/rc4/rc4.c",
   "src/crypto/refcount_c11.c",
   "src/crypto/refcount_lock.c",
@@ -420,10 +412,10 @@
   "linux-aarch64/crypto/bn/armv8-mont.S",
   "linux-aarch64/crypto/chacha/chacha-armv8.S",
   "linux-aarch64/crypto/fipsmodule/aesv8-armx64.S",
+  "linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S",
   "linux-aarch64/crypto/fipsmodule/sha1-armv8.S",
   "linux-aarch64/crypto/fipsmodule/sha256-armv8.S",
   "linux-aarch64/crypto/fipsmodule/sha512-armv8.S",
-  "linux-aarch64/crypto/modes/ghashv8-armx64.S",
 ]
 
 crypto_sources_linux_arm = [
@@ -432,18 +424,18 @@
   "linux-arm/crypto/fipsmodule/aes-armv4.S",
   "linux-arm/crypto/fipsmodule/aesv8-armx32.S",
   "linux-arm/crypto/fipsmodule/bsaes-armv7.S",
+  "linux-arm/crypto/fipsmodule/ghash-armv4.S",
+  "linux-arm/crypto/fipsmodule/ghashv8-armx32.S",
   "linux-arm/crypto/fipsmodule/sha1-armv4-large.S",
   "linux-arm/crypto/fipsmodule/sha256-armv4.S",
   "linux-arm/crypto/fipsmodule/sha512-armv4.S",
-  "linux-arm/crypto/modes/ghash-armv4.S",
-  "linux-arm/crypto/modes/ghashv8-armx32.S",
   "src/crypto/curve25519/asm/x25519-asm-arm.S",
   "src/crypto/poly1305/poly1305_arm_asm.S",
 ]
 
 crypto_sources_linux_ppc64le = [
   "linux-ppc64le/crypto/fipsmodule/aesp8-ppc.S",
-  "linux-ppc64le/crypto/modes/ghashp8-ppc.S",
+  "linux-ppc64le/crypto/fipsmodule/ghashp8-ppc.S",
 ]
 
 crypto_sources_linux_x86 = [
@@ -453,12 +445,12 @@
   "linux-x86/crypto/chacha/chacha-x86.S",
   "linux-x86/crypto/fipsmodule/aes-586.S",
   "linux-x86/crypto/fipsmodule/aesni-x86.S",
+  "linux-x86/crypto/fipsmodule/ghash-x86.S",
   "linux-x86/crypto/fipsmodule/md5-586.S",
   "linux-x86/crypto/fipsmodule/sha1-586.S",
   "linux-x86/crypto/fipsmodule/sha256-586.S",
   "linux-x86/crypto/fipsmodule/sha512-586.S",
   "linux-x86/crypto/fipsmodule/vpaes-x86.S",
-  "linux-x86/crypto/modes/ghash-x86.S",
 ]
 
 crypto_sources_linux_x86_64 = [
@@ -469,16 +461,16 @@
   "linux-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S",
   "linux-x86_64/crypto/ec/p256-x86_64-asm.S",
   "linux-x86_64/crypto/fipsmodule/aes-x86_64.S",
+  "linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S",
   "linux-x86_64/crypto/fipsmodule/aesni-x86_64.S",
   "linux-x86_64/crypto/fipsmodule/bsaes-x86_64.S",
+  "linux-x86_64/crypto/fipsmodule/ghash-x86_64.S",
   "linux-x86_64/crypto/fipsmodule/md5-x86_64.S",
+  "linux-x86_64/crypto/fipsmodule/rdrand-x86_64.S",
   "linux-x86_64/crypto/fipsmodule/sha1-x86_64.S",
   "linux-x86_64/crypto/fipsmodule/sha256-x86_64.S",
   "linux-x86_64/crypto/fipsmodule/sha512-x86_64.S",
   "linux-x86_64/crypto/fipsmodule/vpaes-x86_64.S",
-  "linux-x86_64/crypto/modes/aesni-gcm-x86_64.S",
-  "linux-x86_64/crypto/modes/ghash-x86_64.S",
-  "linux-x86_64/crypto/rand/rdrand-x86_64.S",
   "src/crypto/curve25519/asm/x25519-asm-x86_64.S",
 ]
 
@@ -489,12 +481,12 @@
   "mac-x86/crypto/chacha/chacha-x86.S",
   "mac-x86/crypto/fipsmodule/aes-586.S",
   "mac-x86/crypto/fipsmodule/aesni-x86.S",
+  "mac-x86/crypto/fipsmodule/ghash-x86.S",
   "mac-x86/crypto/fipsmodule/md5-586.S",
   "mac-x86/crypto/fipsmodule/sha1-586.S",
   "mac-x86/crypto/fipsmodule/sha256-586.S",
   "mac-x86/crypto/fipsmodule/sha512-586.S",
   "mac-x86/crypto/fipsmodule/vpaes-x86.S",
-  "mac-x86/crypto/modes/ghash-x86.S",
 ]
 
 crypto_sources_mac_x86_64 = [
@@ -505,16 +497,16 @@
   "mac-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S",
   "mac-x86_64/crypto/ec/p256-x86_64-asm.S",
   "mac-x86_64/crypto/fipsmodule/aes-x86_64.S",
+  "mac-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S",
   "mac-x86_64/crypto/fipsmodule/aesni-x86_64.S",
   "mac-x86_64/crypto/fipsmodule/bsaes-x86_64.S",
+  "mac-x86_64/crypto/fipsmodule/ghash-x86_64.S",
   "mac-x86_64/crypto/fipsmodule/md5-x86_64.S",
+  "mac-x86_64/crypto/fipsmodule/rdrand-x86_64.S",
   "mac-x86_64/crypto/fipsmodule/sha1-x86_64.S",
   "mac-x86_64/crypto/fipsmodule/sha256-x86_64.S",
   "mac-x86_64/crypto/fipsmodule/sha512-x86_64.S",
   "mac-x86_64/crypto/fipsmodule/vpaes-x86_64.S",
-  "mac-x86_64/crypto/modes/aesni-gcm-x86_64.S",
-  "mac-x86_64/crypto/modes/ghash-x86_64.S",
-  "mac-x86_64/crypto/rand/rdrand-x86_64.S",
   "src/crypto/curve25519/asm/x25519-asm-x86_64.S",
 ]
 
@@ -525,12 +517,12 @@
   "win-x86/crypto/chacha/chacha-x86.asm",
   "win-x86/crypto/fipsmodule/aes-586.asm",
   "win-x86/crypto/fipsmodule/aesni-x86.asm",
+  "win-x86/crypto/fipsmodule/ghash-x86.asm",
   "win-x86/crypto/fipsmodule/md5-586.asm",
   "win-x86/crypto/fipsmodule/sha1-586.asm",
   "win-x86/crypto/fipsmodule/sha256-586.asm",
   "win-x86/crypto/fipsmodule/sha512-586.asm",
   "win-x86/crypto/fipsmodule/vpaes-x86.asm",
-  "win-x86/crypto/modes/ghash-x86.asm",
 ]
 
 crypto_sources_win_x86_64 = [
@@ -541,16 +533,16 @@
   "win-x86_64/crypto/cipher/chacha20_poly1305_x86_64.asm",
   "win-x86_64/crypto/ec/p256-x86_64-asm.asm",
   "win-x86_64/crypto/fipsmodule/aes-x86_64.asm",
+  "win-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.asm",
   "win-x86_64/crypto/fipsmodule/aesni-x86_64.asm",
   "win-x86_64/crypto/fipsmodule/bsaes-x86_64.asm",
+  "win-x86_64/crypto/fipsmodule/ghash-x86_64.asm",
   "win-x86_64/crypto/fipsmodule/md5-x86_64.asm",
+  "win-x86_64/crypto/fipsmodule/rdrand-x86_64.asm",
   "win-x86_64/crypto/fipsmodule/sha1-x86_64.asm",
   "win-x86_64/crypto/fipsmodule/sha256-x86_64.asm",
   "win-x86_64/crypto/fipsmodule/sha512-x86_64.asm",
   "win-x86_64/crypto/fipsmodule/vpaes-x86_64.asm",
-  "win-x86_64/crypto/modes/aesni-gcm-x86_64.asm",
-  "win-x86_64/crypto/modes/ghash-x86_64.asm",
-  "win-x86_64/crypto/rand/rdrand-x86_64.asm",
 ]
 
 fuzzers = [
diff --git a/third_party/boringssl/BUILD.generated_tests.gni b/third_party/boringssl/BUILD.generated_tests.gni
index 4197e37..6602508 100644
--- a/third_party/boringssl/BUILD.generated_tests.gni
+++ b/third_party/boringssl/BUILD.generated_tests.gni
@@ -7,6 +7,7 @@
 test_support_sources = [
   "src/crypto/test/file_test.cc",
   "src/crypto/test/file_test.h",
+  "src/crypto/test/gtest_main.h",
   "src/crypto/test/malloc.cc",
   "src/crypto/test/test_util.cc",
   "src/crypto/test/test_util.h",
@@ -21,14 +22,17 @@
   "src/crypto/bio/bio_test.cc",
   "src/crypto/bytestring/bytestring_test.cc",
   "src/crypto/chacha/chacha_test.cc",
+  "src/crypto/cmac/cmac_test.cc",
+  "src/crypto/compiler_test.cc",
   "src/crypto/constant_time_test.cc",
+  "src/crypto/curve25519/spake25519_test.cc",
   "src/crypto/curve25519/x25519_test.cc",
   "src/crypto/dh/dh_test.cc",
   "src/crypto/dsa/dsa_test.cc",
   "src/crypto/ec/ec_test.cc",
   "src/crypto/err/err_test.cc",
   "src/crypto/evp/evp_extra_test.cc",
-  "src/crypto/rand/ctrdrbg_test.cc",
+  "src/crypto/fipsmodule/rand/ctrdrbg_test.cc",
   "src/crypto/rsa/rsa_test.cc",
   "src/crypto/test/gtest_main.cc",
 ]
@@ -75,18 +79,6 @@
     deps = invoker.deps
   }
 
-  executable("boringssl_cmac_test") {
-    sources = [
-      "src/crypto/cmac/cmac_test.cc",
-    ]
-    sources += test_support_sources
-    if (defined(invoker.configs_exclude)) {
-      configs -= invoker.configs_exclude
-    }
-    configs += invoker.configs
-    deps = invoker.deps
-  }
-
   executable("boringssl_ed25519_test") {
     sources = [
       "src/crypto/curve25519/ed25519_test.cc",
@@ -99,18 +91,6 @@
     deps = invoker.deps
   }
 
-  executable("boringssl_spake25519_test") {
-    sources = [
-      "src/crypto/curve25519/spake25519_test.cc",
-    ]
-    sources += test_support_sources
-    if (defined(invoker.configs_exclude)) {
-      configs -= invoker.configs_exclude
-    }
-    configs += invoker.configs
-    deps = invoker.deps
-  }
-
   executable("boringssl_digest_test") {
     sources = [
       "src/crypto/digest_extra/digest_test.cc",
@@ -231,6 +211,30 @@
     deps = invoker.deps
   }
 
+  executable("boringssl_gcm_test") {
+    sources = [
+      "src/crypto/fipsmodule/modes/gcm_test.cc",
+    ]
+    sources += test_support_sources
+    if (defined(invoker.configs_exclude)) {
+      configs -= invoker.configs_exclude
+    }
+    configs += invoker.configs
+    deps = invoker.deps
+  }
+
+  executable("boringssl_ctrdrbg_vector_test") {
+    sources = [
+      "src/crypto/fipsmodule/rand/ctrdrbg_vector_test.cc",
+    ]
+    sources += test_support_sources
+    if (defined(invoker.configs_exclude)) {
+      configs -= invoker.configs_exclude
+    }
+    configs += invoker.configs
+    deps = invoker.deps
+  }
+
   executable("boringssl_hkdf_test") {
     sources = [
       "src/crypto/hkdf/hkdf_test.cc",
@@ -267,18 +271,6 @@
     deps = invoker.deps
   }
 
-  executable("boringssl_gcm_test") {
-    sources = [
-      "src/crypto/modes/gcm_test.cc",
-    ]
-    sources += test_support_sources
-    if (defined(invoker.configs_exclude)) {
-      configs -= invoker.configs_exclude
-    }
-    configs += invoker.configs
-    deps = invoker.deps
-  }
-
   executable("boringssl_obj_test") {
     sources = [
       "src/crypto/obj/obj_test.cc",
@@ -351,18 +343,6 @@
     deps = invoker.deps
   }
 
-  executable("boringssl_ctrdrbg_vector_test") {
-    sources = [
-      "src/crypto/rand/ctrdrbg_vector_test.cc",
-    ]
-    sources += test_support_sources
-    if (defined(invoker.configs_exclude)) {
-      configs -= invoker.configs_exclude
-    }
-    configs += invoker.configs
-    deps = invoker.deps
-  }
-
   executable("boringssl_refcount_test") {
     sources = [
       "src/crypto/refcount_test.cc",
@@ -429,7 +409,6 @@
       ":boringssl_aes_test",
       ":boringssl_bn_test",
       ":boringssl_cipher_test",
-      ":boringssl_cmac_test",
       ":boringssl_ctrdrbg_vector_test",
       ":boringssl_digest_test",
       ":boringssl_ecdh_test",
@@ -452,7 +431,6 @@
       ":boringssl_poly1305_test",
       ":boringssl_pool_test",
       ":boringssl_refcount_test",
-      ":boringssl_spake25519_test",
       ":boringssl_tab_test",
       ":boringssl_thread_test",
       ":boringssl_v3name_test",
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn
index abe39b2..ef900bc 100644
--- a/third_party/boringssl/BUILD.gn
+++ b/third_party/boringssl/BUILD.gn
@@ -139,6 +139,18 @@
     ":internal_config",
     "//build/config/compiler:no_chromium_code",
   ]
+
+  # Chromium infrastructure does not support GTest, only the //base wrapper.
+  if (build_with_chromium) {
+    sources -= [
+      "src/crypto/test/gtest_main.cc",
+
+      # //base includes its own conflicting malloc shim.
+      "src/crypto/test/malloc.cc",
+    ]
+    sources += [ "gtest_main_chromium.cc" ]
+    deps += [ "//base/test:test_support" ]
+  }
 }
 
 test("boringssl_ssl_tests") {
@@ -153,6 +165,18 @@
     ":internal_config",
     "//build/config/compiler:no_chromium_code",
   ]
+
+  # Chromium infrastructure does not support GTest, only the //base wrapper.
+  if (build_with_chromium) {
+    sources -= [
+      "src/crypto/test/gtest_main.cc",
+
+      # //base includes its own conflicting malloc shim.
+      "src/crypto/test/malloc.cc",
+    ]
+    sources += [ "gtest_main_chromium.cc" ]
+    deps += [ "//base/test:test_support" ]
+  }
 }
 
 if (build_with_chromium) {
diff --git a/third_party/boringssl/DEPS b/third_party/boringssl/DEPS
index dda2d7c..d2e250f 100644
--- a/third_party/boringssl/DEPS
+++ b/third_party/boringssl/DEPS
@@ -3,4 +3,8 @@
     "+base",
     "+testing",
   ],
+  "gtest_main_chromium\.cc": [
+    "+base",
+    "+testing",
+  ],
 }
diff --git a/third_party/boringssl/err_data.c b/third_party/boringssl/err_data.c
index a420f72..af0895401 100644
--- a/third_party/boringssl/err_data.c
+++ b/third_party/boringssl/err_data.c
@@ -62,162 +62,163 @@
     0xc348899,
     0xc3508a5,
     0xc3588c2,
-    0xc3608d4,
-    0xc3688e2,
-    0xc3708f2,
-    0xc3788ff,
-    0xc38090f,
-    0xc38891a,
-    0xc390930,
-    0xc39893f,
-    0xc3a0953,
+    0xc3608e2,
+    0xc3688f0,
+    0xc370900,
+    0xc37890d,
+    0xc38091d,
+    0xc388928,
+    0xc39093e,
+    0xc39894d,
+    0xc3a0961,
     0xc3a8845,
     0xc3b00ea,
+    0xc3b88d4,
     0x10320845,
-    0x103294ce,
-    0x103314da,
-    0x103394f3,
-    0x10341506,
-    0x10348ed1,
-    0x10350c42,
-    0x10359519,
-    0x1036152e,
-    0x10369541,
-    0x10371560,
-    0x10379579,
-    0x1038158e,
-    0x103895ac,
-    0x103915bb,
-    0x103995d7,
-    0x103a15f2,
-    0x103a9601,
-    0x103b161d,
-    0x103b9638,
-    0x103c164f,
+    0x103294dc,
+    0x103314e8,
+    0x10339501,
+    0x10341514,
+    0x10348edf,
+    0x10350c50,
+    0x10359527,
+    0x1036153c,
+    0x1036954f,
+    0x1037156e,
+    0x10379587,
+    0x1038159c,
+    0x103895ba,
+    0x103915c9,
+    0x103995e5,
+    0x103a1600,
+    0x103a960f,
+    0x103b162b,
+    0x103b9646,
+    0x103c165d,
     0x103c80ea,
-    0x103d1660,
-    0x103d9674,
-    0x103e1693,
-    0x103e96a2,
-    0x103f16b9,
-    0x103f96cc,
-    0x10400c06,
-    0x104096df,
-    0x104116fd,
-    0x10419710,
-    0x1042172a,
-    0x1042973a,
-    0x1043174e,
-    0x10439764,
-    0x1044177c,
-    0x10449791,
-    0x104517a5,
-    0x104597b7,
+    0x103d166e,
+    0x103d9682,
+    0x103e16a1,
+    0x103e96b0,
+    0x103f16c7,
+    0x103f96da,
+    0x10400c14,
+    0x104096ed,
+    0x1041170b,
+    0x1041971e,
+    0x10421738,
+    0x10429748,
+    0x1043175c,
+    0x10439772,
+    0x1044178a,
+    0x1044979f,
+    0x104517b3,
+    0x104597c5,
     0x104605fb,
-    0x1046893f,
-    0x104717cc,
-    0x104797e3,
-    0x104817f8,
-    0x10489806,
-    0x10490e33,
-    0x14320be9,
-    0x14328bf7,
-    0x14330c06,
-    0x14338c18,
+    0x1046894d,
+    0x104717da,
+    0x104797f1,
+    0x10481806,
+    0x10489814,
+    0x10490e41,
+    0x14320bf7,
+    0x14328c05,
+    0x14330c14,
+    0x14338c26,
     0x143400ac,
     0x143480ea,
     0x18320083,
-    0x18328f27,
+    0x18328f35,
     0x183300ac,
-    0x18338f3d,
-    0x18340f51,
+    0x18338f4b,
+    0x18340f5f,
     0x183480ea,
-    0x18350f66,
-    0x18358f7e,
-    0x18360f93,
-    0x18368fa7,
-    0x18370fcb,
-    0x18378fe1,
-    0x18380ff5,
-    0x18389005,
-    0x18390a57,
-    0x18399015,
-    0x183a102a,
-    0x183a9050,
-    0x183b0c4e,
-    0x183b906f,
-    0x183c1081,
-    0x183c908c,
-    0x183d109c,
-    0x183d90ad,
-    0x183e10be,
-    0x183e90d0,
-    0x183f10f9,
-    0x183f9112,
-    0x1840112a,
+    0x18350f74,
+    0x18358f8c,
+    0x18360fa1,
+    0x18368fb5,
+    0x18370fd9,
+    0x18378fef,
+    0x18381003,
+    0x18389013,
+    0x18390a65,
+    0x18399023,
+    0x183a1038,
+    0x183a905e,
+    0x183b0c5c,
+    0x183b907d,
+    0x183c108f,
+    0x183c909a,
+    0x183d10aa,
+    0x183d90bb,
+    0x183e10cc,
+    0x183e90de,
+    0x183f1107,
+    0x183f9120,
+    0x18401138,
     0x184086d3,
-    0x1841105d,
-    0x1841903e,
-    0x20321151,
-    0x2432115d,
-    0x24328985,
-    0x2433116f,
-    0x2433917c,
-    0x24341189,
-    0x2434919b,
-    0x243511aa,
-    0x243591c7,
-    0x243611d4,
-    0x243691e2,
-    0x243711f0,
-    0x243791fe,
-    0x24381207,
-    0x24389214,
-    0x24391227,
-    0x28320c36,
-    0x28328c4e,
-    0x28330c06,
-    0x28338c61,
-    0x28340c42,
+    0x1841106b,
+    0x1841904c,
+    0x2032115f,
+    0x2432116b,
+    0x24328993,
+    0x2433117d,
+    0x2433918a,
+    0x24341197,
+    0x243491a9,
+    0x243511b8,
+    0x243591d5,
+    0x243611e2,
+    0x243691f0,
+    0x243711fe,
+    0x2437920c,
+    0x24381215,
+    0x24389222,
+    0x24391235,
+    0x28320c44,
+    0x28328c5c,
+    0x28330c14,
+    0x28338c6f,
+    0x28340c50,
     0x283480ac,
     0x283500ea,
-    0x2c322bbb,
-    0x2c32923e,
-    0x2c332bc9,
-    0x2c33abdb,
-    0x2c342bef,
-    0x2c34ac01,
-    0x2c352c1c,
-    0x2c35ac2e,
-    0x2c362c41,
+    0x2c322bc9,
+    0x2c32924c,
+    0x2c332bd7,
+    0x2c33abe9,
+    0x2c342bfd,
+    0x2c34ac0f,
+    0x2c352c2a,
+    0x2c35ac3c,
+    0x2c362c4f,
     0x2c36832d,
-    0x2c372c4e,
-    0x2c37ac60,
-    0x2c382c85,
-    0x2c38ac9c,
-    0x2c392caa,
-    0x2c39acba,
-    0x2c3a2ccc,
-    0x2c3aace0,
-    0x2c3b2cf1,
-    0x2c3bad10,
-    0x2c3c1250,
-    0x2c3c9266,
-    0x2c3d2d24,
-    0x2c3d927f,
-    0x2c3e2d41,
-    0x2c3ead4f,
-    0x2c3f2d67,
-    0x2c3fad7f,
-    0x2c402d8c,
-    0x2c409151,
-    0x2c412d9d,
-    0x2c41adb0,
-    0x2c42112a,
-    0x2c42adc1,
+    0x2c372c5c,
+    0x2c37ac6e,
+    0x2c382c93,
+    0x2c38acaa,
+    0x2c392cb8,
+    0x2c39acc8,
+    0x2c3a2cda,
+    0x2c3aacee,
+    0x2c3b2cff,
+    0x2c3bad1e,
+    0x2c3c125e,
+    0x2c3c9274,
+    0x2c3d2d32,
+    0x2c3d928d,
+    0x2c3e2d4f,
+    0x2c3ead5d,
+    0x2c3f2d75,
+    0x2c3fad8d,
+    0x2c402d9a,
+    0x2c40915f,
+    0x2c412dab,
+    0x2c41adbe,
+    0x2c421138,
+    0x2c42adcf,
     0x2c430720,
-    0x2c43ad02,
-    0x2c442c73,
+    0x2c43ad10,
+    0x2c442c81,
     0x30320000,
     0x30328015,
     0x3033001f,
@@ -310,259 +311,259 @@
     0x305e8700,
     0x305f0716,
     0x305f8720,
-    0x34320b47,
-    0x34328b5b,
-    0x34330b78,
-    0x34338b8b,
-    0x34340b9a,
-    0x34348bd3,
-    0x34350bb7,
+    0x34320b55,
+    0x34328b69,
+    0x34330b86,
+    0x34338b99,
+    0x34340ba8,
+    0x34348be1,
+    0x34350bc5,
     0x3c320083,
-    0x3c328c8b,
-    0x3c330ca4,
-    0x3c338cbf,
-    0x3c340cdc,
-    0x3c348d06,
-    0x3c350d21,
-    0x3c358d47,
-    0x3c360d60,
-    0x3c368d78,
-    0x3c370d89,
-    0x3c378d97,
-    0x3c380da4,
-    0x3c388db8,
-    0x3c390c4e,
-    0x3c398dcc,
-    0x3c3a0de0,
-    0x3c3a88ff,
-    0x3c3b0df0,
-    0x3c3b8e0b,
-    0x3c3c0e1d,
-    0x3c3c8e50,
-    0x3c3d0e5a,
-    0x3c3d8e6e,
-    0x3c3e0e7c,
-    0x3c3e8ea1,
-    0x3c3f0c77,
-    0x3c3f8e8a,
+    0x3c328c99,
+    0x3c330cb2,
+    0x3c338ccd,
+    0x3c340cea,
+    0x3c348d14,
+    0x3c350d2f,
+    0x3c358d55,
+    0x3c360d6e,
+    0x3c368d86,
+    0x3c370d97,
+    0x3c378da5,
+    0x3c380db2,
+    0x3c388dc6,
+    0x3c390c5c,
+    0x3c398dda,
+    0x3c3a0dee,
+    0x3c3a890d,
+    0x3c3b0dfe,
+    0x3c3b8e19,
+    0x3c3c0e2b,
+    0x3c3c8e5e,
+    0x3c3d0e68,
+    0x3c3d8e7c,
+    0x3c3e0e8a,
+    0x3c3e8eaf,
+    0x3c3f0c85,
+    0x3c3f8e98,
     0x3c4000ac,
     0x3c4080ea,
-    0x3c410cf7,
-    0x3c418d36,
-    0x3c420e33,
-    0x40321839,
-    0x4032984f,
-    0x4033187d,
-    0x40339887,
-    0x4034189e,
-    0x403498bc,
-    0x403518cc,
-    0x403598de,
-    0x403618eb,
-    0x403698f7,
-    0x4037190c,
-    0x4037991e,
-    0x40381929,
-    0x4038993b,
-    0x40390ed1,
-    0x4039994b,
-    0x403a195e,
-    0x403a997f,
-    0x403b1990,
-    0x403b99a0,
+    0x3c410d05,
+    0x3c418d44,
+    0x3c420e41,
+    0x40321847,
+    0x4032985d,
+    0x4033188b,
+    0x40339895,
+    0x403418ac,
+    0x403498ca,
+    0x403518da,
+    0x403598ec,
+    0x403618f9,
+    0x40369905,
+    0x4037191a,
+    0x4037992c,
+    0x40381937,
+    0x40389949,
+    0x40390edf,
+    0x40399959,
+    0x403a196c,
+    0x403a998d,
+    0x403b199e,
+    0x403b99ae,
     0x403c0064,
     0x403c8083,
-    0x403d1a24,
-    0x403d9a3a,
-    0x403e1a49,
-    0x403e9a81,
-    0x403f1a9b,
-    0x403f9aa9,
-    0x40401abe,
-    0x40409aeb,
-    0x40411b08,
-    0x40419b23,
-    0x40421b3c,
-    0x40429b4f,
-    0x40431b63,
-    0x40439b7b,
-    0x40441b92,
+    0x403d1a32,
+    0x403d9a48,
+    0x403e1a57,
+    0x403e9a8f,
+    0x403f1aa9,
+    0x403f9ab7,
+    0x40401acc,
+    0x40409af9,
+    0x40411b16,
+    0x40419b31,
+    0x40421b4a,
+    0x40429b5d,
+    0x40431b71,
+    0x40439b89,
+    0x40441ba0,
     0x404480ac,
-    0x40451ba7,
-    0x40459bb9,
-    0x40461bdd,
-    0x40469bfd,
-    0x40471c0b,
-    0x40479c32,
-    0x40481c6f,
-    0x40489c88,
-    0x40491c9f,
-    0x40499cb9,
-    0x404a1cd0,
-    0x404a9cee,
-    0x404b1d06,
-    0x404b9d1d,
-    0x404c1d33,
-    0x404c9d45,
-    0x404d1d66,
-    0x404d9d88,
-    0x404e1d9c,
-    0x404e9da9,
-    0x404f1dd6,
-    0x404f9dff,
-    0x40501e3a,
-    0x40509e4e,
-    0x40511e69,
-    0x40521e79,
-    0x40529e9d,
-    0x40531eb5,
-    0x40539ec8,
-    0x40541edd,
-    0x40549f00,
-    0x40551f0e,
-    0x40559f2b,
-    0x40561f38,
-    0x40569f51,
-    0x40571f69,
-    0x40579f7c,
-    0x40581f91,
-    0x40589fb8,
-    0x40591fe7,
-    0x4059a014,
-    0x405a2028,
-    0x405aa038,
-    0x405b2050,
-    0x405ba061,
-    0x405c2074,
-    0x405ca0b3,
-    0x405d20c0,
-    0x405da0d7,
-    0x405e2115,
-    0x405e8a95,
-    0x405f2136,
-    0x405fa143,
-    0x40602151,
-    0x4060a173,
-    0x406121b7,
-    0x4061a1ef,
-    0x40622206,
-    0x4062a217,
-    0x40632228,
-    0x4063a23d,
-    0x40642254,
-    0x4064a280,
-    0x4065229b,
-    0x4065a2b2,
-    0x406622ca,
-    0x4066a2f4,
-    0x4067231f,
-    0x4067a340,
-    0x40682367,
-    0x4068a388,
-    0x406923ba,
-    0x4069a3e8,
-    0x406a2409,
-    0x406aa429,
-    0x406b25b1,
-    0x406ba5d4,
-    0x406c25ea,
-    0x406ca865,
-    0x406d2894,
-    0x406da8bc,
-    0x406e28ea,
-    0x406ea91e,
-    0x406f293d,
-    0x406fa952,
-    0x40702965,
-    0x4070a982,
+    0x40451bb5,
+    0x40459bc7,
+    0x40461beb,
+    0x40469c0b,
+    0x40471c19,
+    0x40479c40,
+    0x40481c7d,
+    0x40489c96,
+    0x40491cad,
+    0x40499cc7,
+    0x404a1cde,
+    0x404a9cfc,
+    0x404b1d14,
+    0x404b9d2b,
+    0x404c1d41,
+    0x404c9d53,
+    0x404d1d74,
+    0x404d9d96,
+    0x404e1daa,
+    0x404e9db7,
+    0x404f1de4,
+    0x404f9e0d,
+    0x40501e48,
+    0x40509e5c,
+    0x40511e77,
+    0x40521e87,
+    0x40529eab,
+    0x40531ec3,
+    0x40539ed6,
+    0x40541eeb,
+    0x40549f0e,
+    0x40551f1c,
+    0x40559f39,
+    0x40561f46,
+    0x40569f5f,
+    0x40571f77,
+    0x40579f8a,
+    0x40581f9f,
+    0x40589fc6,
+    0x40591ff5,
+    0x4059a022,
+    0x405a2036,
+    0x405aa046,
+    0x405b205e,
+    0x405ba06f,
+    0x405c2082,
+    0x405ca0c1,
+    0x405d20ce,
+    0x405da0e5,
+    0x405e2123,
+    0x405e8aa3,
+    0x405f2144,
+    0x405fa151,
+    0x4060215f,
+    0x4060a181,
+    0x406121c5,
+    0x4061a1fd,
+    0x40622214,
+    0x4062a225,
+    0x40632236,
+    0x4063a24b,
+    0x40642262,
+    0x4064a28e,
+    0x406522a9,
+    0x4065a2c0,
+    0x406622d8,
+    0x4066a302,
+    0x4067232d,
+    0x4067a34e,
+    0x40682375,
+    0x4068a396,
+    0x406923c8,
+    0x4069a3f6,
+    0x406a2417,
+    0x406aa437,
+    0x406b25bf,
+    0x406ba5e2,
+    0x406c25f8,
+    0x406ca873,
+    0x406d28a2,
+    0x406da8ca,
+    0x406e28f8,
+    0x406ea92c,
+    0x406f294b,
+    0x406fa960,
+    0x40702973,
+    0x4070a990,
     0x40710800,
-    0x4071a994,
-    0x407229a7,
-    0x4072a9c0,
-    0x407329d8,
-    0x4073943d,
-    0x407429ec,
-    0x4074aa06,
-    0x40752a17,
-    0x4075aa2b,
-    0x40762a39,
-    0x40769214,
-    0x40772a5e,
-    0x4077aa80,
-    0x40782a9b,
-    0x4078aad4,
-    0x40792aeb,
-    0x4079ab01,
-    0x407a2b0d,
-    0x407aab20,
-    0x407b2b35,
-    0x407bab47,
-    0x407c2b78,
-    0x407cab81,
-    0x407d23a3,
-    0x407d9e0f,
-    0x407e2ab0,
-    0x407e9fc8,
-    0x407f1c1f,
-    0x407f99c6,
-    0x40801de6,
-    0x40809c47,
-    0x40811e8b,
-    0x40819dc0,
-    0x408228d5,
-    0x408299ac,
-    0x40831fa3,
-    0x4083a265,
-    0x40841c5b,
-    0x4084a000,
-    0x40852085,
-    0x4085a19b,
-    0x408620f7,
-    0x40869e29,
-    0x40872902,
-    0x4087a1cc,
-    0x40881a0d,
-    0x4088a353,
-    0x40891a5c,
-    0x408999e9,
-    0x408a260a,
-    0x408a981d,
-    0x408b2b5c,
-    0x408b9ad2,
-    0x408c2095,
-    0x41f424dc,
-    0x41f9256e,
-    0x41fe2461,
-    0x41fea656,
-    0x41ff2747,
-    0x420324f5,
-    0x42082517,
-    0x4208a553,
-    0x42092445,
-    0x4209a58d,
-    0x420a249c,
-    0x420aa47c,
-    0x420b24bc,
-    0x420ba535,
-    0x420c2763,
-    0x420ca623,
-    0x420d263d,
-    0x420da674,
-    0x4212268e,
-    0x4217272a,
-    0x4217a6d0,
-    0x421c26f2,
-    0x421f26ad,
-    0x4221277a,
-    0x4226270d,
-    0x422b2849,
-    0x422ba7f7,
-    0x422c2831,
-    0x422ca7b6,
-    0x422d2795,
-    0x422da816,
-    0x422e27dc,
-    0x422eaba2,
+    0x4071a9a2,
+    0x407229b5,
+    0x4072a9ce,
+    0x407329e6,
+    0x4073944b,
+    0x407429fa,
+    0x4074aa14,
+    0x40752a25,
+    0x4075aa39,
+    0x40762a47,
+    0x40769222,
+    0x40772a6c,
+    0x4077aa8e,
+    0x40782aa9,
+    0x4078aae2,
+    0x40792af9,
+    0x4079ab0f,
+    0x407a2b1b,
+    0x407aab2e,
+    0x407b2b43,
+    0x407bab55,
+    0x407c2b86,
+    0x407cab8f,
+    0x407d23b1,
+    0x407d9e1d,
+    0x407e2abe,
+    0x407e9fd6,
+    0x407f1c2d,
+    0x407f99d4,
+    0x40801df4,
+    0x40809c55,
+    0x40811e99,
+    0x40819dce,
+    0x408228e3,
+    0x408299ba,
+    0x40831fb1,
+    0x4083a273,
+    0x40841c69,
+    0x4084a00e,
+    0x40852093,
+    0x4085a1a9,
+    0x40862105,
+    0x40869e37,
+    0x40872910,
+    0x4087a1da,
+    0x40881a1b,
+    0x4088a361,
+    0x40891a6a,
+    0x408999f7,
+    0x408a2618,
+    0x408a982b,
+    0x408b2b6a,
+    0x408b9ae0,
+    0x408c20a3,
+    0x41f424ea,
+    0x41f9257c,
+    0x41fe246f,
+    0x41fea664,
+    0x41ff2755,
+    0x42032503,
+    0x42082525,
+    0x4208a561,
+    0x42092453,
+    0x4209a59b,
+    0x420a24aa,
+    0x420aa48a,
+    0x420b24ca,
+    0x420ba543,
+    0x420c2771,
+    0x420ca631,
+    0x420d264b,
+    0x420da682,
+    0x4212269c,
+    0x42172738,
+    0x4217a6de,
+    0x421c2700,
+    0x421f26bb,
+    0x42212788,
+    0x4226271b,
+    0x422b2857,
+    0x422ba805,
+    0x422c283f,
+    0x422ca7c4,
+    0x422d27a3,
+    0x422da824,
+    0x422e27ea,
+    0x422eabb0,
     0x4432072b,
     0x4432873a,
     0x44330746,
@@ -580,143 +581,143 @@
     0x44390800,
     0x4439880e,
     0x443a0821,
-    0x4832123e,
-    0x48329250,
-    0x48331266,
-    0x4833927f,
-    0x4c3212a4,
-    0x4c3292b4,
-    0x4c3312c7,
-    0x4c3392e7,
+    0x4832124c,
+    0x4832925e,
+    0x48331274,
+    0x4833928d,
+    0x4c3212b2,
+    0x4c3292c2,
+    0x4c3312d5,
+    0x4c3392f5,
     0x4c3400ac,
     0x4c3480ea,
-    0x4c3512f3,
-    0x4c359301,
-    0x4c36131d,
-    0x4c369330,
-    0x4c37133f,
-    0x4c37934d,
-    0x4c381362,
-    0x4c38936e,
-    0x4c39138e,
-    0x4c3993b8,
-    0x4c3a13d1,
-    0x4c3a93ea,
+    0x4c351301,
+    0x4c35930f,
+    0x4c36132b,
+    0x4c36933e,
+    0x4c37134d,
+    0x4c37935b,
+    0x4c381370,
+    0x4c38937c,
+    0x4c39139c,
+    0x4c3993c6,
+    0x4c3a13df,
+    0x4c3a93f8,
     0x4c3b05fb,
-    0x4c3b9403,
-    0x4c3c1415,
-    0x4c3c9424,
-    0x4c3d143d,
-    0x4c3d8c29,
-    0x4c3e1496,
-    0x4c3e944c,
-    0x4c3f14b8,
-    0x4c3f9214,
-    0x4c401462,
-    0x4c409290,
-    0x4c411486,
-    0x50322dd3,
-    0x5032ade2,
-    0x50332ded,
-    0x5033adfd,
-    0x50342e16,
-    0x5034ae30,
-    0x50352e3e,
-    0x5035ae54,
-    0x50362e66,
-    0x5036ae7c,
-    0x50372e95,
-    0x5037aea8,
-    0x50382ec0,
-    0x5038aed1,
-    0x50392ee6,
-    0x5039aefa,
-    0x503a2f1a,
-    0x503aaf30,
-    0x503b2f48,
-    0x503baf5a,
-    0x503c2f76,
-    0x503caf8d,
-    0x503d2fa6,
-    0x503dafbc,
-    0x503e2fc9,
-    0x503eafdf,
-    0x503f2ff1,
+    0x4c3b9411,
+    0x4c3c1423,
+    0x4c3c9432,
+    0x4c3d144b,
+    0x4c3d8c37,
+    0x4c3e14a4,
+    0x4c3e945a,
+    0x4c3f14c6,
+    0x4c3f9222,
+    0x4c401470,
+    0x4c40929e,
+    0x4c411494,
+    0x50322de1,
+    0x5032adf0,
+    0x50332dfb,
+    0x5033ae0b,
+    0x50342e24,
+    0x5034ae3e,
+    0x50352e4c,
+    0x5035ae62,
+    0x50362e74,
+    0x5036ae8a,
+    0x50372ea3,
+    0x5037aeb6,
+    0x50382ece,
+    0x5038aedf,
+    0x50392ef4,
+    0x5039af08,
+    0x503a2f28,
+    0x503aaf3e,
+    0x503b2f56,
+    0x503baf68,
+    0x503c2f84,
+    0x503caf9b,
+    0x503d2fb4,
+    0x503dafca,
+    0x503e2fd7,
+    0x503eafed,
+    0x503f2fff,
     0x503f8382,
-    0x50403004,
-    0x5040b014,
-    0x5041302e,
-    0x5041b03d,
-    0x50423057,
-    0x5042b074,
-    0x50433084,
-    0x5043b094,
-    0x504430a3,
+    0x50403012,
+    0x5040b022,
+    0x5041303c,
+    0x5041b04b,
+    0x50423065,
+    0x5042b082,
+    0x50433092,
+    0x5043b0a2,
+    0x504430b1,
     0x5044843f,
-    0x504530b7,
-    0x5045b0d5,
-    0x504630e8,
-    0x5046b0fe,
-    0x50473110,
-    0x5047b125,
-    0x5048314b,
-    0x5048b159,
-    0x5049316c,
-    0x5049b181,
-    0x504a3197,
-    0x504ab1a7,
-    0x504b31c7,
-    0x504bb1da,
-    0x504c31fd,
-    0x504cb22b,
-    0x504d323d,
-    0x504db25a,
-    0x504e3275,
-    0x504eb291,
-    0x504f32a3,
-    0x504fb2ba,
-    0x505032c9,
+    0x504530c5,
+    0x5045b0e3,
+    0x504630f6,
+    0x5046b10c,
+    0x5047311e,
+    0x5047b133,
+    0x50483159,
+    0x5048b167,
+    0x5049317a,
+    0x5049b18f,
+    0x504a31a5,
+    0x504ab1b5,
+    0x504b31d5,
+    0x504bb1e8,
+    0x504c320b,
+    0x504cb239,
+    0x504d324b,
+    0x504db268,
+    0x504e3283,
+    0x504eb29f,
+    0x504f32b1,
+    0x504fb2c8,
+    0x505032d7,
     0x505086ef,
-    0x505132dc,
-    0x58320f0f,
-    0x68320ed1,
-    0x68328c4e,
-    0x68330c61,
-    0x68338edf,
-    0x68340eef,
+    0x505132ea,
+    0x58320f1d,
+    0x68320edf,
+    0x68328c5c,
+    0x68330c6f,
+    0x68338eed,
+    0x68340efd,
     0x683480ea,
-    0x6c320ead,
-    0x6c328c18,
-    0x6c330eb8,
-    0x74320a0b,
+    0x6c320ebb,
+    0x6c328c26,
+    0x6c330ec6,
+    0x74320a19,
     0x743280ac,
-    0x74330c29,
-    0x78320970,
-    0x78328985,
-    0x78330991,
+    0x74330c37,
+    0x7832097e,
+    0x78328993,
+    0x7833099f,
     0x78338083,
-    0x783409a0,
-    0x783489b5,
-    0x783509d4,
-    0x783589f6,
-    0x78360a0b,
-    0x78368a21,
-    0x78370a31,
-    0x78378a44,
-    0x78380a57,
-    0x78388a69,
-    0x78390a76,
-    0x78398a95,
-    0x783a0aaa,
-    0x783a8ab8,
-    0x783b0ac2,
-    0x783b8ad6,
-    0x783c0aed,
-    0x783c8b02,
-    0x783d0b19,
-    0x783d8b2e,
-    0x783e0a84,
-    0x7c321140,
+    0x783409ae,
+    0x783489c3,
+    0x783509e2,
+    0x78358a04,
+    0x78360a19,
+    0x78368a2f,
+    0x78370a3f,
+    0x78378a52,
+    0x78380a65,
+    0x78388a77,
+    0x78390a84,
+    0x78398aa3,
+    0x783a0ab8,
+    0x783a8ac6,
+    0x783b0ad0,
+    0x783b8ae4,
+    0x783c0afb,
+    0x783c8b10,
+    0x783d0b27,
+    0x783d8b3c,
+    0x783e0a92,
+    0x7c32114e,
 };
 
 const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]);
@@ -840,6 +841,7 @@
     "DIV_BY_ZERO\0"
     "EXPAND_ON_STATIC_BIGNUM_DATA\0"
     "INPUT_NOT_REDUCED\0"
+    "INVALID_INPUT\0"
     "INVALID_RANGE\0"
     "NEGATIVE_NUMBER\0"
     "NOT_A_SQUARE\0"
diff --git a/third_party/boringssl/gtest_main_chromium.cc b/third_party/boringssl/gtest_main_chromium.cc
new file mode 100644
index 0000000..128c9be
--- /dev/null
+++ b/third_party/boringssl/gtest_main_chromium.cc
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/boringssl/src/crypto/test/gtest_main.h"
+
+namespace {
+
+class BoringSSLTestSuite : public base::TestSuite {
+ public:
+  BoringSSLTestSuite(int argc, char** argv) : TestSuite(argc, argv) {}
+
+  void Initialize() override {
+    TestSuite::Initialize();
+    bssl::SetupGoogleTest();
+  }
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  BoringSSLTestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc, argv,
+      base::Bind(&BoringSSLTestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/third_party/boringssl/linux-aarch64/crypto/modes/ghashv8-armx64.S b/third_party/boringssl/linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S
similarity index 100%
rename from third_party/boringssl/linux-aarch64/crypto/modes/ghashv8-armx64.S
rename to third_party/boringssl/linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S
diff --git a/third_party/boringssl/linux-arm/crypto/modes/ghash-armv4.S b/third_party/boringssl/linux-arm/crypto/fipsmodule/ghash-armv4.S
similarity index 100%
rename from third_party/boringssl/linux-arm/crypto/modes/ghash-armv4.S
rename to third_party/boringssl/linux-arm/crypto/fipsmodule/ghash-armv4.S
diff --git a/third_party/boringssl/linux-arm/crypto/modes/ghashv8-armx32.S b/third_party/boringssl/linux-arm/crypto/fipsmodule/ghashv8-armx32.S
similarity index 100%
rename from third_party/boringssl/linux-arm/crypto/modes/ghashv8-armx32.S
rename to third_party/boringssl/linux-arm/crypto/fipsmodule/ghashv8-armx32.S
diff --git a/third_party/boringssl/linux-ppc64le/crypto/modes/ghashp8-ppc.S b/third_party/boringssl/linux-ppc64le/crypto/fipsmodule/ghashp8-ppc.S
similarity index 100%
rename from third_party/boringssl/linux-ppc64le/crypto/modes/ghashp8-ppc.S
rename to third_party/boringssl/linux-ppc64le/crypto/fipsmodule/ghashp8-ppc.S
diff --git a/third_party/boringssl/linux-x86/crypto/modes/ghash-x86.S b/third_party/boringssl/linux-x86/crypto/fipsmodule/ghash-x86.S
similarity index 100%
rename from third_party/boringssl/linux-x86/crypto/modes/ghash-x86.S
rename to third_party/boringssl/linux-x86/crypto/fipsmodule/ghash-x86.S
diff --git a/third_party/boringssl/linux-x86_64/crypto/modes/aesni-gcm-x86_64.S b/third_party/boringssl/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
similarity index 100%
rename from third_party/boringssl/linux-x86_64/crypto/modes/aesni-gcm-x86_64.S
rename to third_party/boringssl/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
diff --git a/third_party/boringssl/linux-x86_64/crypto/modes/ghash-x86_64.S b/third_party/boringssl/linux-x86_64/crypto/fipsmodule/ghash-x86_64.S
similarity index 99%
rename from third_party/boringssl/linux-x86_64/crypto/modes/ghash-x86_64.S
rename to third_party/boringssl/linux-x86_64/crypto/fipsmodule/ghash-x86_64.S
index 4afbc52f8b..7b563e1 100644
--- a/third_party/boringssl/linux-x86_64/crypto/modes/ghash-x86_64.S
+++ b/third_party/boringssl/linux-x86_64/crypto/fipsmodule/ghash-x86_64.S
@@ -1,7 +1,7 @@
 #if defined(__x86_64__) && !defined(OPENSSL_NO_ASM)
 .text	
-.extern	OPENSSL_ia32cap_P
-.hidden OPENSSL_ia32cap_P
+.extern	OPENSSL_ia32cap_addr
+.hidden OPENSSL_ia32cap_addr
 
 .globl	gcm_gmult_4bit
 .hidden gcm_gmult_4bit
@@ -890,7 +890,8 @@
 	jz	.Lodd_tail
 
 	movdqu	16(%rsi),%xmm6
-	movl	OPENSSL_ia32cap_P+4(%rip),%eax
+	movq	OPENSSL_ia32cap_addr(%rip),%rax
+	movl	4(%rax),%eax
 	cmpq	$0x30,%rcx
 	jb	.Lskip4x
 
diff --git a/third_party/boringssl/linux-x86_64/crypto/rand/rdrand-x86_64.S b/third_party/boringssl/linux-x86_64/crypto/fipsmodule/rdrand-x86_64.S
similarity index 100%
rename from third_party/boringssl/linux-x86_64/crypto/rand/rdrand-x86_64.S
rename to third_party/boringssl/linux-x86_64/crypto/fipsmodule/rdrand-x86_64.S
diff --git a/third_party/boringssl/mac-x86/crypto/modes/ghash-x86.S b/third_party/boringssl/mac-x86/crypto/fipsmodule/ghash-x86.S
similarity index 100%
rename from third_party/boringssl/mac-x86/crypto/modes/ghash-x86.S
rename to third_party/boringssl/mac-x86/crypto/fipsmodule/ghash-x86.S
diff --git a/third_party/boringssl/mac-x86_64/crypto/modes/aesni-gcm-x86_64.S b/third_party/boringssl/mac-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
similarity index 100%
rename from third_party/boringssl/mac-x86_64/crypto/modes/aesni-gcm-x86_64.S
rename to third_party/boringssl/mac-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S
diff --git a/third_party/boringssl/mac-x86_64/crypto/modes/ghash-x86_64.S b/third_party/boringssl/mac-x86_64/crypto/fipsmodule/ghash-x86_64.S
similarity index 99%
rename from third_party/boringssl/mac-x86_64/crypto/modes/ghash-x86_64.S
rename to third_party/boringssl/mac-x86_64/crypto/fipsmodule/ghash-x86_64.S
index 4c98a93..d47f061 100644
--- a/third_party/boringssl/mac-x86_64/crypto/modes/ghash-x86_64.S
+++ b/third_party/boringssl/mac-x86_64/crypto/fipsmodule/ghash-x86_64.S
@@ -889,7 +889,8 @@
 	jz	L$odd_tail
 
 	movdqu	16(%rsi),%xmm6
-	movl	_OPENSSL_ia32cap_P+4(%rip),%eax
+	movq	_OPENSSL_ia32cap_addr(%rip),%rax
+	movl	4(%rax),%eax
 	cmpq	$0x30,%rcx
 	jb	L$skip4x
 
diff --git a/third_party/boringssl/mac-x86_64/crypto/rand/rdrand-x86_64.S b/third_party/boringssl/mac-x86_64/crypto/fipsmodule/rdrand-x86_64.S
similarity index 100%
rename from third_party/boringssl/mac-x86_64/crypto/rand/rdrand-x86_64.S
rename to third_party/boringssl/mac-x86_64/crypto/fipsmodule/rdrand-x86_64.S
diff --git a/third_party/boringssl/win-x86/crypto/modes/ghash-x86.asm b/third_party/boringssl/win-x86/crypto/fipsmodule/ghash-x86.asm
similarity index 100%
rename from third_party/boringssl/win-x86/crypto/modes/ghash-x86.asm
rename to third_party/boringssl/win-x86/crypto/fipsmodule/ghash-x86.asm
diff --git a/third_party/boringssl/win-x86_64/crypto/modes/aesni-gcm-x86_64.asm b/third_party/boringssl/win-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.asm
similarity index 100%
rename from third_party/boringssl/win-x86_64/crypto/modes/aesni-gcm-x86_64.asm
rename to third_party/boringssl/win-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.asm
diff --git a/third_party/boringssl/win-x86_64/crypto/modes/ghash-x86_64.asm b/third_party/boringssl/win-x86_64/crypto/fipsmodule/ghash-x86_64.asm
similarity index 99%
rename from third_party/boringssl/win-x86_64/crypto/modes/ghash-x86_64.asm
rename to third_party/boringssl/win-x86_64/crypto/fipsmodule/ghash-x86_64.asm
index b01f98c..cfccae5b 100644
--- a/third_party/boringssl/win-x86_64/crypto/modes/ghash-x86_64.asm
+++ b/third_party/boringssl/win-x86_64/crypto/fipsmodule/ghash-x86_64.asm
@@ -4,7 +4,7 @@
 %define ZMMWORD
 section	.text code align=64
 
-EXTERN	OPENSSL_ia32cap_P
+EXTERN	OPENSSL_ia32cap_addr
 
 global	gcm_gmult_4bit
 
@@ -931,7 +931,8 @@
 	jz	NEAR $L$odd_tail
 
 	movdqu	xmm6,XMMWORD[16+rdx]
-	mov	eax,DWORD[((OPENSSL_ia32cap_P+4))]
+	mov	rax,QWORD[OPENSSL_ia32cap_addr]
+	mov	eax,DWORD[4+rax]
 	cmp	r9,0x30
 	jb	NEAR $L$skip4x
 
diff --git a/third_party/boringssl/win-x86_64/crypto/rand/rdrand-x86_64.asm b/third_party/boringssl/win-x86_64/crypto/fipsmodule/rdrand-x86_64.asm
similarity index 100%
rename from third_party/boringssl/win-x86_64/crypto/rand/rdrand-x86_64.asm
rename to third_party/boringssl/win-x86_64/crypto/fipsmodule/rdrand-x86_64.asm
diff --git a/third_party/gvr-android-sdk/BUILD.gn b/third_party/gvr-android-sdk/BUILD.gn
index 4540008..37067797 100644
--- a/third_party/gvr-android-sdk/BUILD.gn
+++ b/third_party/gvr-android-sdk/BUILD.gn
@@ -4,6 +4,11 @@
 
 import("//build/config/android/rules.gni")
 
+android_aar_prebuilt("controller_test_api_java") {
+  aar_path = "test-libraries/controller_test_api.aar"
+  proguard_configs = [ "test-libraries/proguard.txt" ]
+}
+
 android_aar_prebuilt("gvr_common_java") {
   aar_path = "common_library.aar"
   proguard_configs = [ "src/proguard-gvr.txt" ]
diff --git a/third_party/gvr-android-sdk/README.chromium b/third_party/gvr-android-sdk/README.chromium
index be951d95..1ba339e 100644
--- a/third_party/gvr-android-sdk/README.chromium
+++ b/third_party/gvr-android-sdk/README.chromium
@@ -33,3 +33,9 @@
 are downloaded into test-apks/vr_services and test-apks/daydream_home,
 respectively. The downloaded APKs are the release APKs that are or were
 publicly available via the Play Store.
+In order to run automated end-to-end tests that involve a Daydream controller,
+controller_test_api.aar needs to be present. This allows us to send controller
+events using broadcasts like a real controller sends them over Bluetooth. The
+library is open-sourced similar to the other .aars, but since it's only useful
+for Chromium at the moment, it is uploaded to storage instead of to GitHub like
+the GVR SDK.
diff --git a/third_party/gvr-android-sdk/test-libraries/controller_test_api.aar.sha1 b/third_party/gvr-android-sdk/test-libraries/controller_test_api.aar.sha1
new file mode 100644
index 0000000..8fd6fe8
--- /dev/null
+++ b/third_party/gvr-android-sdk/test-libraries/controller_test_api.aar.sha1
@@ -0,0 +1 @@
+2ef2878590caee4101008b2e4092133c69659c8e
\ No newline at end of file
diff --git a/third_party/gvr-android-sdk/test-libraries/proguard.txt b/third_party/gvr-android-sdk/test-libraries/proguard.txt
new file mode 100644
index 0000000..9c85a88
--- /dev/null
+++ b/third_party/gvr-android-sdk/test-libraries/proguard.txt
@@ -0,0 +1,4 @@
+# Suppress some warnings that block compilation in release builds, but don't
+# actually affect anything
+-dontwarn java.awt.**
+-dontwarn javax.lang.model.element.Modifier
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index d476b29..aca4835 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -22540,6 +22540,16 @@
   </summary>
 </histogram>
 
+<histogram name="Histogram.BadConstructionArguments" enum="HistogramNameHash">
+  <owner>asvitkine@chromium.org</owner>
+  <owner>bcwhite@chromium.org</owner>
+  <summary>
+    The hash codes of histograms that were found to have bad construction
+    arguments. These would be DCHECK exceptions in debug builds but have simply
+    been logged and corrected as best as possible rather than crash.
+  </summary>
+</histogram>
+
 <histogram name="Histogram.InconsistenciesBrowser" enum="Inconsistencies">
   <owner>asvitkine@chromium.org</owner>
   <summary>
@@ -99889,6 +99899,13 @@
   <int value="10" label="Persistent histograms created"/>
 </enum>
 
+<enum name="HistogramNameHash" type="int">
+  <summary>
+    These numbers are the lower 32 bits of the hash of the metric name.
+  </summary>
+  <int value="0" label="Missing hash value"/>
+</enum>
+
 <enum name="HistoryFaviconsRecoveryEnum" type="int">
   <summary>Error states noted in thumbnail_database.cc recovery code.</summary>
   <obsolete>
diff --git a/tools/perf/benchmarks/blink_perf.js b/tools/perf/benchmarks/blink_perf.js
index 465e1ff..bb764cf 100644
--- a/tools/perf/benchmarks/blink_perf.js
+++ b/tools/perf/benchmarks/blink_perf.js
@@ -12,6 +12,24 @@
   this.isDone = true;
 };
 
+testRunner.supportTracing = true;
+
+// If this is true, blink_perf tests is put on paused waiting for tracing to
+// be started. |scheduleTestRun| should be invoked after tracing is started
+// to continue blink perf test.
+testRunner.isWaitingForTracingStart = false;
+
+testRunner.startTracing = function(tracingCategories, scheduleTestRun) {
+  this.tracingCategories = tracingCategories;
+  this.scheduleTestRun = scheduleTestRun;
+  this.isWaitingForTracingStart = true;
+}
+
+testRunner.stopTracingAndMeasure = function(traceEventsToMeasure, callback) {
+  testRunner.traceEventsToMeasure = traceEventsToMeasure;
+  callback();
+}
+
 window.GCController = {};
 
 GCController.collect = function() {
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 64a55a45..5bc5efc9 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -12,8 +12,14 @@
 from telemetry.page import legacy_page_test
 from telemetry.page import shared_page_state
 from telemetry import story
+from telemetry.timeline import bounds
+from telemetry.timeline import model as model_module
+from telemetry.timeline import tracing_config
+
 from telemetry.value import list_of_scalar_values
 from telemetry.value import scalar
+from telemetry.value import trace
+
 
 from benchmarks import pywebsocket_server
 from measurements import timeline_controller
@@ -73,6 +79,53 @@
   return ps
 
 
+def _ComputeTraceEventsThreadTimeForBlinkPerf(
+    renderer_thread, trace_events_to_measure):
+  """ Compute the CPU duration for each of |trace_events_to_measure| during
+  blink_perf test.
+
+  Args:
+    renderer_thread: the renderer thread which run blink_perf test.
+    trace_events_to_measure: a list of string names of trace events to measure
+    CPU duration for.
+
+  Returns:
+    a dictionary in which each key is a trace event' name (from
+    |trace_events_to_measure| list), and value is a list of numbers that
+    represents to total cpu time of that trace events in each blink_perf test.
+  """
+  trace_cpu_time_metrics = {}
+
+  # Collect the bounds of "blink_perf.runTest" events.
+  test_runs_bounds = []
+  for event in renderer_thread.async_slices:
+    if event.name == "blink_perf.runTest":
+      test_runs_bounds.append(bounds.Bounds.CreateFromEvent(event))
+  test_runs_bounds.sort(key=lambda b: b.min)
+
+  for t in trace_events_to_measure:
+    trace_cpu_time_metrics[t] = [0.0] * len(test_runs_bounds)
+
+  for event_name in trace_events_to_measure:
+    curr_test_runs_bound_index = 0
+    for event in renderer_thread.IterAllSlicesOfName(event_name):
+      while (curr_test_runs_bound_index < len(test_runs_bounds) and
+             event.start > test_runs_bounds[curr_test_runs_bound_index].max):
+        curr_test_runs_bound_index += 1
+      if curr_test_runs_bound_index >= len(test_runs_bounds):
+        break
+      curr_test_bound = test_runs_bounds[curr_test_runs_bound_index]
+      intersect_wall_time = bounds.Bounds.GetOverlapBetweenBounds(
+          curr_test_bound, bounds.Bounds.CreateFromEvent(event))
+      intersect_cpu_time = (
+          intersect_wall_time * event.thread_duration / event.duration)
+      trace_cpu_time_metrics[event_name][curr_test_runs_bound_index] += (
+          intersect_cpu_time)
+
+  return trace_cpu_time_metrics
+
+
+
 class _BlinkPerfMeasurement(legacy_page_test.LegacyPageTest):
   """Tuns a blink performance test and reports the results."""
 
@@ -98,8 +151,53 @@
     if 'content-shell' in options.browser_type:
       options.AppendExtraBrowserArgs('--expose-internals-for-testing')
 
+  def _ContinueTestRunWithTracing(self, tab):
+    tracing_categories = tab.EvaluateJavaScript(
+        'testRunner.tracingCategories')
+    config = tracing_config.TracingConfig()
+    config.enable_chrome_trace = True
+    config.chrome_trace_config.category_filter.AddFilterString(
+        'blink.console')  # This is always required for js land trace event
+    config.chrome_trace_config.category_filter.AddFilterString(
+        tracing_categories)
+    tab.browser.platform.tracing_controller.StartTracing(config)
+    tab.EvaluateJavaScript('testRunner.scheduleTestRun()')
+    tab.WaitForJavaScriptCondition('testRunner.isDone')
+    return tab.browser.platform.tracing_controller.StopTracing()
+
+
+  def PrintAndCollectTraceEventMetrics(self, trace_cpu_time_metrics, results):
+    unit = 'ms'
+    print
+    for trace_event_name, cpu_times in trace_cpu_time_metrics.iteritems():
+      print 'CPU times of trace event "%s":' % trace_event_name
+      cpu_times_string = ', '.join(['{0:.10f}'.format(t) for t in cpu_times])
+      print 'values %s %s' % (cpu_times_string, unit)
+      avg = 0.0
+      if cpu_times:
+        avg = sum(cpu_times)/len(cpu_times)
+      print 'avg', '{0:.10f}'.format(avg), unit
+      results.AddValue(list_of_scalar_values.ListOfScalarValues(
+          results.current_page, name=trace_event_name, units=unit,
+          values=cpu_times))
+      print
+    print '\n'
+
   def ValidateAndMeasurePage(self, page, tab, results):
-    tab.WaitForJavaScriptCondition('testRunner.isDone', timeout=600)
+    tab.WaitForJavaScriptCondition(
+        'testRunner.isDone || testRunner.isWaitingForTracingStart', timeout=600)
+    trace_cpu_time_metrics = {}
+    if tab.EvaluateJavaScript('testRunner.isWaitingForTracingStart'):
+      trace_data = self._ContinueTestRunWithTracing(tab)
+      trace_value = trace.TraceValue(page, trace_data)
+      results.AddValue(trace_value)
+
+      trace_events_to_measure = tab.EvaluateJavaScript(
+          'window.testRunner.traceEventsToMeasure')
+      model = model_module.TimelineModel(trace_data)
+      renderer_thread = model.GetRendererThreadFromTabId(tab.id)
+      trace_cpu_time_metrics = _ComputeTraceEventsThreadTimeForBlinkPerf(
+          renderer_thread, trace_events_to_measure)
 
     log = tab.EvaluateJavaScript('document.getElementById("log").innerHTML')
 
@@ -120,6 +218,8 @@
 
     print log
 
+    self.PrintAndCollectTraceEventMetrics(trace_cpu_time_metrics, results)
+
 
 # TODO(wangxianzhu): Convert the paint benchmarks to use the new blink_perf
 # tracing once it's ready.
diff --git a/tools/perf/benchmarks/blink_perf_unittest.py b/tools/perf/benchmarks/blink_perf_unittest.py
new file mode 100644
index 0000000..cff0eeb
--- /dev/null
+++ b/tools/perf/benchmarks/blink_perf_unittest.py
@@ -0,0 +1,156 @@
+# 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 os
+import unittest
+
+from telemetry import decorators
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.testing import options_for_unittests
+from telemetry.testing import page_test_test_case
+from telemetry.timeline import async_slice
+from telemetry.timeline import model as model_module
+
+
+from benchmarks import blink_perf
+
+
+class BlinkPerfTest(page_test_test_case.PageTestTestCase):
+  _BLINK_PERF_TEST_DATA_DIR = os.path.join(os.path.dirname(__file__),
+      '..', '..', '..', 'third_party', 'WebKit', 'PerformanceTests',
+      'TestData')
+
+  _BLINK_PERF_RESOURCES_DIR = os.path.join(os.path.dirname(__file__),
+      '..', '..', '..', 'third_party', 'WebKit', 'PerformanceTests',
+      'resources')
+  def setUp(self):
+    self._options = options_for_unittests.GetCopy()
+    # pylint: disable=protected-access
+    self._measurement = blink_perf._BlinkPerfMeasurement()
+    # pylint: enable=protected-access
+
+  def _CreateStorySetForTestFile(self, test_file_name):
+    story_set = story.StorySet(base_dir=self._BLINK_PERF_TEST_DATA_DIR,
+        serving_dirs={self._BLINK_PERF_TEST_DATA_DIR,
+                      self._BLINK_PERF_RESOURCES_DIR})
+    page = page_module.Page('file://' + test_file_name, story_set,
+        base_dir=story_set.base_dir)
+    story_set.AddStory(page)
+    return story_set
+
+  def testBlinkPerfTracingMetricsForMeasureTime(self):
+    results = self.RunMeasurement(measurement=self._measurement,
+        ps=self._CreateStorySetForTestFile('append-child-measure-time.html'),
+        options=self._options)
+    self.assertFalse(results.failures)
+    self.assertEquals(len(results.FindAllTraceValues()), 1)
+
+    frame_view_layouts = results.FindAllPageSpecificValuesNamed(
+        'FrameView::layout')
+    self.assertEquals(len(frame_view_layouts), 1)
+    self.assertGreater(frame_view_layouts[0].GetRepresentativeNumber, 0.1)
+
+    update_layout_trees = results.FindAllPageSpecificValuesNamed(
+        'UpdateLayoutTree')
+    self.assertEquals(len(update_layout_trees), 1)
+    self.assertGreater(update_layout_trees[0].GetRepresentativeNumber, 0.1)
+
+  @decorators.Disabled('android')  # crbug.com/715685
+  def testBlinkPerfTracingMetricsForMeasureFrameTime(self):
+    results = self.RunMeasurement(measurement=self._measurement,
+        ps=self._CreateStorySetForTestFile(
+            'color-changes-measure-frame-time.html'),
+        options=self._options)
+    self.assertFalse(results.failures)
+    self.assertEquals(len(results.FindAllTraceValues()), 1)
+
+    frame_view_prepaints = results.FindAllPageSpecificValuesNamed(
+        'FrameView::prePaint')
+    self.assertEquals(len(frame_view_prepaints), 1)
+    self.assertGreater(frame_view_prepaints[0].GetRepresentativeNumber, 0.1)
+
+    frame_view_painttrees = results.FindAllPageSpecificValuesNamed(
+        'FrameView::paintTree')
+    self.assertEquals(len(frame_view_painttrees), 1)
+    self.assertGreater(frame_view_painttrees[0].GetRepresentativeNumber, 0.1)
+
+
+# pylint: disable=protected-access
+# This is needed for testing _ComputeTraceEventsThreadTimeForBlinkPerf method.
+class ComputeTraceEventsMetricsForBlinkPerfTest(unittest.TestCase):
+
+  def _AddBlinkTestSlice(self, renderer_thread, start, end):
+    s = async_slice.AsyncSlice(
+        'blink', 'blink_perf.runTest',
+        timestamp=start, duration=end - start, start_thread=renderer_thread,
+        end_thread=renderer_thread)
+    renderer_thread.AddAsyncSlice(s)
+
+  def testTraceEventMetricsSingleBlinkTest(self):
+    model = model_module.TimelineModel()
+    renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2)
+    renderer_main.name = 'CrRendererMain'
+
+    # Set up a main thread model that looks like:
+    #   [          blink_perf.run_test                ]
+    #   |     [ foo ]          [  bar ]      [        baz     ]
+    #   |     |     |          |      |      |        |       |
+    #   100   120   140        400    420    500      550     600
+    #             |                |                  |
+    # CPU dur:    15               18                 70
+    #
+    self._AddBlinkTestSlice(renderer_main, 100, 550)
+
+    renderer_main.BeginSlice('blink', 'foo', 120, 122)
+    renderer_main.EndSlice(140, 137)
+
+    renderer_main.BeginSlice('blink', 'bar', 400, 402)
+    renderer_main.EndSlice(420, 420)
+
+    # Since this "baz" slice has CPU duration = 70ms, wall-time duration = 100ms
+    # & its overalapped wall-time with "blink_perf.run_test" is 50 ms, its
+    # overlapped CPU time with "blink_perf.run_test" is
+    # 50 * 70 / 100 = 35ms.
+    renderer_main.BeginSlice('blink', 'baz', 500, 520)
+    renderer_main.EndSlice(600, 590)
+
+    self.assertEquals(
+        blink_perf._ComputeTraceEventsThreadTimeForBlinkPerf(
+            renderer_main, ['foo', 'bar', 'baz']),
+        {'foo': [15], 'bar': [18], 'baz': [35]})
+
+
+  def testTraceEventMetricsMultiBlinkTest(self):
+    model = model_module.TimelineModel()
+    renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2)
+    renderer_main.name = 'CrRendererMain'
+
+    # Set up a main thread model that looks like:
+    #   [          blink_perf.run_test    ]         [ blink_perf.run_test  ]
+    #   |     [ foo ]          [  bar ]   |     [   |    foo         ]     |
+    #   |     |     |          |      |   |     |   |     |          |     |
+    #   100   120   140        400    420 440   500 520              600   640
+    #             |                |                      |
+    # CPU dur:    15               18                     40
+    #
+    self._AddBlinkTestSlice(renderer_main, 100, 440)
+    self._AddBlinkTestSlice(renderer_main, 520, 640)
+
+    renderer_main.BeginSlice('blink', 'foo', 120, 122)
+    renderer_main.EndSlice(140, 137)
+
+    renderer_main.BeginSlice('blink', 'bar', 400, 402)
+    renderer_main.EndSlice(420, 420)
+
+    # Since this "foo" slice has CPU duration = 40ms, wall-time duration = 100ms
+    # & its overalapped wall-time with "blink_perf.run_test" is 80 ms, its
+    # overlapped CPU time with "blink_perf.run_test" is
+    # 80 * 40 / 100 = 32ms.
+    renderer_main.BeginSlice('blink', 'foo', 500, 520)
+    renderer_main.EndSlice(600, 560)
+
+    self.assertEquals(
+        blink_perf._ComputeTraceEventsThreadTimeForBlinkPerf(
+            renderer_main, ['foo', 'bar', 'baz']),
+        {'foo': [15, 32], 'bar': [18, 0], 'baz': [0, 0]})
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py
index f37ce44..32a408f9 100644
--- a/tools/perf/benchmarks/media.py
+++ b/tools/perf/benchmarks/media.py
@@ -41,6 +41,8 @@
 
 # android: See media.android.tough_video_cases below
 # crbug.com/565180: Only include cases that report time_to_play
+@benchmark.Owner(emails=['crouleau@chromium.org'],
+                 component='Internals>Media')
 @benchmark.Disabled('android')
 class MediaToughVideoCases(perf_benchmark.PerfBenchmark):
   """Obtains media metrics for key user scenarios."""
@@ -85,7 +87,8 @@
 
 # crbug.com/565180: Only include cases that don't report time_to_play
 @benchmark.Disabled('android')
-@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'])
+@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'],
+                 component='Internals>Media')
 class MediaExtra(perf_benchmark.PerfBenchmark):
   """Obtains extra media metrics for key user scenarios."""
   test = media.Media
@@ -96,8 +99,9 @@
     return 'media.tough_video_cases_extra'
 
 
-@benchmark.Disabled('android', 'mac')
-@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'])
+@benchmark.Disabled('all')  # crbug/676345
+@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'],
+                 component='Internals>Media')
 class MediaNetworkSimulation(perf_benchmark.PerfBenchmark):
   """Obtains media metrics under different network simulations."""
   test = media.Media
@@ -109,6 +113,8 @@
 
 
 @benchmark.Disabled('l', 'android-webview')  # WebView: crbug.com/419689.
+@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'],
+                 component='Internals>Media')
 class MediaAndroidToughVideoCases(perf_benchmark.PerfBenchmark):
   """Obtains media metrics for key user scenarios on Android."""
   test = media.Media
@@ -154,7 +160,10 @@
         ['--disable-gesture-requirement-for-media-playback'])
 
 
+# This isn't running anywhere. See crbug/709161.
 @benchmark.Enabled('chromeos')
+@benchmark.Owner(emails=['crouleau@chromium.org'],
+                 component='Internals>Media')
 class MediaChromeOS4kOnly(perf_benchmark.PerfBenchmark):
   """Benchmark for media performance on ChromeOS using only is_4k test content.
   """
@@ -172,7 +181,10 @@
     return 'media.chromeOS4kOnly.tough_video_cases'
 
 
+# This isn't running anywhere. See crbug/709161.
 @benchmark.Enabled('chromeos')
+@benchmark.Owner(emails=['crouleau@chromium.org'],
+                 component='Internals>Media')
 class MediaChromeOS(perf_benchmark.PerfBenchmark):
   """Benchmark for media performance on all ChromeOS platforms.
 
@@ -191,7 +203,8 @@
 
 
 @benchmark.Disabled('android-webview')  # crbug.com/419689
-@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'])
+@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'],
+                 component='Internals>Media>Source')
 class MediaSourceExtensions(perf_benchmark.PerfBenchmark):
   """Obtains media metrics for key media source extensions functions."""
   test = _MSEMeasurement
diff --git a/tools/perf/benchmarks/webrtc.py b/tools/perf/benchmarks/webrtc.py
index de21783..ea1e127 100644
--- a/tools/perf/benchmarks/webrtc.py
+++ b/tools/perf/benchmarks/webrtc.py
@@ -51,6 +51,7 @@
     return 'webrtc.datachannel'
 
 
+@benchmark.Disabled('win')
 @benchmark.Owner(emails=['ehmaldonado@chromium.org', 'phoglund@chromium.org'])
 class WebrtcStressTest(perf_benchmark.PerfBenchmark):
   """Measures WebRtc CPU and GPU usage with multiple peer connections."""
diff --git a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
index 77189db2..152e5b92 100644
--- a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
+++ b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
@@ -148,10 +148,11 @@
                 || eventAction == MotionEvent.ACTION_POINTER_UP;
     }
 
-    @TargetApi(Build.VERSION_CODES.M)
     public boolean onMouseEvent(MotionEvent event) {
         TraceEvent.begin("sendMouseEvent");
 
+        assert mNativeEventForwarder != 0;
+
         MotionEvent offsetEvent = createOffsetMotionEvent(event);
         try {
             int eventAction = event.getActionMasked();
@@ -167,10 +168,10 @@
             // behaving device, so mLastMouseButtonState is only nonzero on a buggy one.
             if (eventAction == MotionEvent.ACTION_HOVER_ENTER) {
                 if (mLastMouseButtonState == MotionEvent.BUTTON_PRIMARY) {
-                    sendMouseEvent(event.getEventTime(), MotionEvent.ACTION_BUTTON_RELEASE,
-                            offsetEvent.getX(), offsetEvent.getY(), event.getPointerId(0),
-                            event.getPressure(0), event.getOrientation(0),
-                            event.getAxisValue(MotionEvent.AXIS_TILT, 0),
+                    nativeOnMouseEvent(mNativeEventForwarder, event.getEventTime(),
+                            MotionEvent.ACTION_BUTTON_RELEASE, offsetEvent.getX(),
+                            offsetEvent.getY(), event.getPointerId(0), event.getPressure(0),
+                            event.getOrientation(0), event.getAxisValue(MotionEvent.AXIS_TILT, 0),
                             MotionEvent.BUTTON_PRIMARY, event.getButtonState(),
                             event.getMetaState(), event.getToolType(0));
                 }
@@ -192,11 +193,11 @@
                 return false;
             }
 
-            sendMouseEvent(event.getEventTime(), eventAction, offsetEvent.getX(),
-                    offsetEvent.getY(), event.getPointerId(0), event.getPressure(0),
-                    event.getOrientation(0), event.getAxisValue(MotionEvent.AXIS_TILT, 0),
-                    event.getActionButton(), event.getButtonState(), event.getMetaState(),
-                    event.getToolType(0));
+            nativeOnMouseEvent(mNativeEventForwarder, event.getEventTime(), eventAction,
+                    offsetEvent.getX(), offsetEvent.getY(), event.getPointerId(0),
+                    event.getPressure(0), event.getOrientation(0),
+                    event.getAxisValue(MotionEvent.AXIS_TILT, 0), getMouseEventActionButton(event),
+                    event.getButtonState(), event.getMetaState(), event.getToolType(0));
             return true;
         } finally {
             offsetEvent.recycle();
@@ -205,12 +206,11 @@
     }
 
     @TargetApi(Build.VERSION_CODES.M)
-    public void sendMouseEvent(long timeMs, int action, float x, float y, int pointerId,
-            float pressure, float orientation, float tilt, int actionButton, int buttonState,
-            int metaState, int toolType) {
-        assert mNativeEventForwarder != 0;
-        nativeOnMouseEvent(mNativeEventForwarder, timeMs, action, x, y, pointerId, pressure,
-                orientation, tilt, actionButton, buttonState, metaState, toolType);
+    private int getMouseEventActionButton(MotionEvent event) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) return event.getActionButton();
+
+        // On <M, the only mice events sent are hover events, which cannot have a button.
+        return 0;
     }
 
     public boolean onMouseWheelEvent(
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index ebc27076..a9fbea5 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -1116,16 +1116,18 @@
   WaitForDraw();
 }
 
-static void EmptyReleaseCallback(const gpu::SyncToken& sync_token,
-                                 bool is_lost) {}
-
 // Checks that the damage rect for a TextureLayer is empty after a commit.
 TEST_F(LayerWithNullDelegateTest, EmptyDamagedRect) {
+  base::RunLoop run_loop;
+  cc::ReleaseCallback callback =
+      base::Bind([](base::RunLoop* run_loop, const gpu::SyncToken& sync_token,
+                    bool is_lost) { run_loop->Quit(); },
+                 base::Unretained(&run_loop));
+
   std::unique_ptr<Layer> root(CreateLayer(LAYER_SOLID_COLOR));
   cc::TextureMailbox mailbox(gpu::Mailbox::Generate(), gpu::SyncToken(),
                              GL_TEXTURE_2D);
-  root->SetTextureMailbox(mailbox, cc::SingleReleaseCallback::Create(
-                                       base::Bind(EmptyReleaseCallback)),
+  root->SetTextureMailbox(mailbox, cc::SingleReleaseCallback::Create(callback),
                           gfx::Size(10, 10));
   compositor()->SetRootLayer(root.get());
 
@@ -1139,9 +1141,14 @@
   WaitForCommit();
   EXPECT_TRUE(root->damaged_region_for_testing().IsEmpty());
 
-  compositor()->SetRootLayer(nullptr);
-  root.reset();
-  WaitForCommit();
+  // The texture mailbox has a reference from an in-flight texture layer.
+  // We clear the texture mailbox from the root layer and draw a new frame
+  // to ensure that the texture mailbox is released.
+  root->SetShowSolidColorContent();
+  Draw();
+
+  // Wait for texture mailbox release to avoid DCHECKs.
+  run_loop.Run();
 }
 
 void ExpectRgba(int x, int y, SkColor expected_color, SkColor actual_color) {
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index c603352..f99ac41 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -155,6 +155,7 @@
 DrmDisplayHostManager::~DrmDisplayHostManager() {
   device_manager_->RemoveObserver(this);
   proxy_->UnRegisterHandlerForDrmDisplayHostManager();
+  proxy_->RemoveGpuThreadObserver(this);
 }
 
 DrmDisplayHost* DrmDisplayHostManager::GetDisplay(int64_t display_id) {
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
index 58c83ab..f94f1c8 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -239,6 +239,9 @@
   bool using_mojo_;
   bool single_process_;
 
+  // Bridges the DRM, GPU and main threads in mus. This must be destroyed last.
+  std::unique_ptr<MusThreadProxy> mus_thread_proxy_;
+
   // Objects in the GPU process.
   std::unique_ptr<DrmThreadProxy> drm_thread_proxy_;
   std::unique_ptr<GlApiLoader> gl_api_loader_;
@@ -257,9 +260,6 @@
   std::unique_ptr<DrmDisplayHostManager> display_manager_;
   std::unique_ptr<DrmOverlayManager> overlay_manager_;
 
-  // Bridges the DRM, GPU and main threads in mus.
-  std::unique_ptr<MusThreadProxy> mus_thread_proxy_;
-
 #if BUILDFLAG(USE_XKBCOMMON)
   XkbEvdevCodes xkb_evdev_code_converter_;
 #endif