diff --git a/BUILD.gn b/BUILD.gn
index 94469d3..8dee958a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -74,6 +74,7 @@
     "//skia:skia_unittests",
     "//sql:sql_unittests",
     "//tools/ipc_fuzzer:ipc_fuzzer_all",
+    "//ui/base:ui_base_unittests",
     "//url:url_unittests",
   ]
 
@@ -90,7 +91,6 @@
       "//services:services_unittests",
       "//services/service_manager/public/cpp",
       "//tools/metrics:metrics_metadata",
-      "//ui/base:ui_base_unittests",
       "//ui/gfx:gfx_unittests",
     ]
   }
@@ -155,6 +155,17 @@
     ]
   }
 
+  if (!is_ios) {
+    deps += [
+      "//mojo",
+      "//mojo/common:mojo_common_unittests",
+      "//mojo/edk/system:mojo_system_unittests",
+      "//mojo/edk/test:mojo_public_bindings_unittests",
+      "//mojo/edk/test:mojo_public_system_unittests",
+      "//ui/gl:gl_unittests",
+    ]
+  }
+
   if (!is_ios && !is_fuchsia) {
     deps += [
       "//cc:cc_unittests",
@@ -198,7 +209,6 @@
       "//tools/imagediff($host_toolchain)",
       "//ui/display:display_unittests",
       "//ui/events:events_unittests",
-      "//ui/gl:gl_unittests",
       "//ui/latency:latency_unittests",
       "//ui/touch_selection:ui_touch_selection_unittests",
       "//url/ipc:url_ipc_unittests",
diff --git a/DEPS b/DEPS
index 237fcda..70a8c0d 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': '04380e42329bc32fab5ac14ff330050bcf3d501f',
+  'skia_revision': 'ee3e0bacc8bedd1e3ebfb52fbc8b1cc3ccdad358',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -56,7 +56,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
-  'buildtools_revision': 'c2827ae578be603fb41a141631c27c3c09191dca',
+  'buildtools_revision': '5ad14542a6a74dd914f067b948c5d3e8d170396b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # 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': '00c3cfdbae074a379cab4edad0e4fa75d6127797',
+  'pdfium_revision': '2b918c8d05c922287efbc8858f029026cee31442',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '6daeed6d73113135b1c6bcd662c0e974a5b7cf7c',
+  'catapult_revision': '90038eee6f25a6153b827eb9fcd6a7dea8486b73',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -205,7 +205,7 @@
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '4e16f7070354fa91c1a617ee18335e580a0b8c8c',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'b578d59623ddb0f3f76efe5e160aff253b40d19b',
 
   'src/third_party/ffmpeg':
     Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'f82eb1989c0cdd5ed179ee4979ffb18a8030c78a',
diff --git a/android_webview/browser/aw_form_database_service.cc b/android_webview/browser/aw_form_database_service.cc
index 8fde67fd..f24adf6 100644
--- a/android_webview/browser/aw_form_database_service.cc
+++ b/android_webview/browser/aw_form_database_service.cc
@@ -124,9 +124,12 @@
     LOG(WARNING) << "Received unexpected callback from web data service";
     return;
   }
+
+  WaitableEvent* completion = it->second.completion;
   *(it->second.result) = has_form_data;
-  it->second.completion->Signal();
   result_map_.erase(h);
+
+  completion->Signal();
 }
 
 }  // namespace android_webview
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
index 5331ff8..b7cc9f72 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
@@ -29,9 +29,9 @@
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.ProcessInitException;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.components.minidump_uploader.CrashFileManager;
 import org.chromium.content.browser.BrowserStartupController;
+import org.chromium.content.browser.ChildProcessCreationParams;
 import org.chromium.content.browser.ChildProcessLauncherHelper;
 import org.chromium.policy.CombinedPolicyProvider;
 
diff --git a/apps/app_restore_service_browsertest.cc b/apps/app_restore_service_browsertest.cc
index 28788566..7174f8d9 100644
--- a/apps/app_restore_service_browsertest.cc
+++ b/apps/app_restore_service_browsertest.cc
@@ -7,10 +7,10 @@
 #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"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 #include "extensions/browser/api/file_system/saved_file_entry.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/notification_types.h"
diff --git a/ash/login/ui/lock_debug_view.cc b/ash/login/ui/lock_debug_view.cc
index 9be97e2..36e0711 100644
--- a/ash/login/ui/lock_debug_view.cc
+++ b/ash/login/ui/lock_debug_view.cc
@@ -74,8 +74,13 @@
       const ash::mojom::UserInfoPtr& root_user =
           root_users_[i % root_users_.size()];
       users.push_back(root_user->Clone());
+      if (i >= root_users_.size()) {
+        users[i]->account_id = AccountId::FromUserEmailGaiaId(
+            users[i]->account_id.GetUserEmail() + std::to_string(i),
+            users[i]->account_id.GetGaiaId() + std::to_string(i));
+      }
       if (i >= debug_users_.size())
-        debug_users_.push_back(UserMetadata(root_user));
+        debug_users_.push_back(UserMetadata(users[i]));
     }
 
     // Set debug user names. Useful for the stub user, which does not have a
diff --git a/ash/public/interfaces/night_light_controller.mojom b/ash/public/interfaces/night_light_controller.mojom
index 2da100f..c1bc817 100644
--- a/ash/public/interfaces/night_light_controller.mojom
+++ b/ash/public/interfaces/night_light_controller.mojom
@@ -19,6 +19,8 @@
 
 // Used by a client (e.g. Chrome) to provide the current user's geoposition.
 interface NightLightController {
+  // These values are written to logs. New enum values can be added, but
+  // existing enums must never be renumbered or deleted and reused.
   enum ScheduleType {
     // Automatic toggling of NightLight is turned off.
     kNone = 0,
@@ -30,6 +32,9 @@
     // Toggled automatically based on the custom set start and end times
     // selected by the user from the system settings.
     kCustom = 2,
+
+    // Must be the last item, used for UMA histograms.
+    kLast = kCustom,
   };
 
   // Sets the client that will be notified of changes in the Night Light
diff --git a/ash/session/session_controller.h b/ash/session/session_controller.h
index 12d009e..9dd039b 100644
--- a/ash/session/session_controller.h
+++ b/ash/session/session_controller.h
@@ -28,7 +28,7 @@
 
 // Implements mojom::SessionController to cache session related info such as
 // session state, meta data about user sessions to support synchronous
-// queries for ash. It is targeted as a replacement for SessionStateDelegate.
+// queries for ash.
 class ASH_EXPORT SessionController
     : NON_EXPORTED_BASE(public mojom::SessionController) {
  public:
diff --git a/ash/shell.cc b/ash/shell.cc
index 776300f..f8d53ea 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -857,7 +857,7 @@
     auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
     Shell::RegisterPrefs(pref_registry.get());
     prefs::ConnectToPrefService(
-        shell_delegate_->GetShellConnector(), std::move(pref_registry), {},
+        shell_delegate_->GetShellConnector(), std::move(pref_registry),
         base::Bind(&Shell::OnPrefServiceInitialized, base::Unretained(this)),
         prefs::mojom::kForwarderServiceName);
   }
diff --git a/ash/system/night_light/night_light_controller.cc b/ash/system/night_light/night_light_controller.cc
index 8578c8c1..1744604d 100644
--- a/ash/system/night_light/night_light_controller.cc
+++ b/ash/system/night_light/night_light_controller.cc
@@ -4,11 +4,14 @@
 
 #include "ash/system/night_light/night_light_controller.h"
 
+#include <cmath>
+
 #include "ash/ash_switches.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "base/command_line.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -78,6 +81,17 @@
   DISALLOW_COPY_AND_ASSIGN(NightLightControllerDelegateImpl);
 };
 
+// Returns the color temperature range bucket in which |temperature| resides.
+// The range buckets are:
+// 0 => Range [0 : 20) (least warm).
+// 1 => Range [20 : 40).
+// 2 => Range [40 : 60).
+// 3 => Range [60 : 80).
+// 4 => Range [80 : 100) (most warm).
+int GetTemperatureRange(float temperature) {
+  return std::floor(5 * temperature);
+}
+
 // Applies the given |layer_temperature| to all the layers of the root windows
 // with the given |animation_duration|.
 // |layer_temperature| is the ui::Layer floating-point value in the range of
@@ -94,6 +108,10 @@
 
     layer->SetLayerTemperature(layer_temperature);
   }
+
+  UMA_HISTOGRAM_EXACT_LINEAR(
+      "Ash.NightLight.Temperature", GetTemperatureRange(layer_temperature),
+      5 /* number of buckets defined in GetTemperatureRange() */);
 }
 
 }  // namespace
@@ -337,6 +355,10 @@
   DCHECK(active_user_pref_service_);
   NotifyClientWithScheduleChange();
   Refresh(true /* did_schedule_change */);
+
+  // TODO(https://crbug.com/742517).
+  UMA_HISTOGRAM_ENUMERATION("Ash.NightLight.ScheduleType", GetScheduleType(),
+                            static_cast<int>(ScheduleType::kLast) + 1);
 }
 
 void NightLightController::OnCustomSchedulePrefsChanged() {
diff --git a/ash/wm/system_modal_container_layout_manager.cc b/ash/wm/system_modal_container_layout_manager.cc
index 7651921..c536787 100644
--- a/ash/wm/system_modal_container_layout_manager.cc
+++ b/ash/wm/system_modal_container_layout_manager.cc
@@ -79,12 +79,8 @@
     aura::Window* child) {
   DCHECK(child->type() == aura::client::WINDOW_TYPE_NORMAL ||
          child->type() == aura::client::WINDOW_TYPE_POPUP);
-  // TODO(mash): IsUserSessionBlocked() depends on knowing the login state. We
-  // need a non-stub version of SessionStateDelegate. crbug.com/648964
-  if (Shell::GetAshConfig() != Config::MASH) {
-    DCHECK(container_->id() != kShellWindowId_LockSystemModalContainer ||
-           Shell::Get()->session_controller()->IsUserSessionBlocked());
-  }
+  DCHECK(container_->id() != kShellWindowId_LockSystemModalContainer ||
+         Shell::Get()->session_controller()->IsUserSessionBlocked());
   // Since this is for SystemModal, there is no good reason to add windows
   // other than MODAL_TYPE_NONE or MODAL_TYPE_SYSTEM. DCHECK to avoid simple
   // mistake.
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 4357e62..9a62e82 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -339,6 +339,7 @@
     "files/memory_mapped_file.h",
     "files/memory_mapped_file_posix.cc",
     "files/memory_mapped_file_win.cc",
+    "files/platform_file.h",
     "files/scoped_file.cc",
     "files/scoped_file.h",
     "files/scoped_temp_dir.cc",
@@ -2392,6 +2393,11 @@
     deps += [ "//base/third_party/libevent" ]
   }
 
+  if (is_fuchsia) {
+    # Fuchsia doesn't support file locking.
+    sources -= [ "files/file_locking_unittest.cc" ]
+  }
+
   if (is_android) {
     deps += [ "//testing/android/native_test:native_test_native_code" ]
     set_sources_assignment_filter([])
@@ -2615,7 +2621,6 @@
       "android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java",
       "android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java",
       "android/java/src/org/chromium/base/process_launcher/ChildProcessConstants.java",
-      "android/java/src/org/chromium/base/process_launcher/ChildProcessCreationParams.java",
       "android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java",
       "android/java/src/org/chromium/base/process_launcher/ChildProcessService.java",
       "android/java/src/org/chromium/base/process_launcher/ChildProcessServiceImpl.java",
diff --git a/base/OWNERS b/base/OWNERS
index 28043c42..51da1f5 100644
--- a/base/OWNERS
+++ b/base/OWNERS
@@ -32,6 +32,9 @@
 per-file *android*=file://base/android/OWNERS
 per-file BUILD.gn=file://base/android/OWNERS
 
+# For Fuchsia-specific changes:
+per-file *_fuchsia*=file://build/fuchsia/OWNERS
+
 # For FeatureList API:
 per-file feature_list*=asvitkine@chromium.org
 per-file feature_list*=isherman@chromium.org
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java b/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
index f21c46cf..08161f90 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
+++ b/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
@@ -42,18 +42,16 @@
     @VisibleForTesting
     public interface ConnectionFactory {
         ChildProcessConnection createConnection(Context context, ComponentName serviceName,
-                boolean bindAsExternalService, Bundle serviceBundle,
-                ChildProcessCreationParams creationParams);
+                boolean bindToCaller, boolean bindAsExternalService, Bundle serviceBundle);
     }
 
     /** Default implementation of the ConnectionFactory that creates actual connections. */
     private static class ConnectionFactoryImpl implements ConnectionFactory {
         @Override
         public ChildProcessConnection createConnection(Context context, ComponentName serviceName,
-                boolean bindAsExternalService, Bundle serviceBundle,
-                ChildProcessCreationParams creationParams) {
+                boolean bindToCaller, boolean bindAsExternalService, Bundle serviceBundle) {
             return new ChildProcessConnection(
-                    context, serviceName, bindAsExternalService, serviceBundle, creationParams);
+                    context, serviceName, bindToCaller, bindAsExternalService, serviceBundle);
         }
     }
 
@@ -68,9 +66,9 @@
 
     private final String mPackageName;
     private final String mServiceClassName;
+    private final boolean mBindToCaller;
     private final boolean mBindAsExternalService;
     private final boolean mUseStrongBinding;
-    private final ChildProcessCreationParams mCreationParams;
 
     // The list of free (not bound) service indices.
     private final ArrayList<Integer> mFreeConnectionIndices;
@@ -84,9 +82,9 @@
      * AndroidManifest.xml.
      */
     public static ChildConnectionAllocator create(Context context, Handler launcherHandler,
-            ChildProcessCreationParams creationParams, String packageName,
-            String serviceClassNameManifestKey, String numChildServicesManifestKey,
-            boolean bindAsExternalService, boolean useStrongBinding) {
+            String packageName, String serviceClassNameManifestKey,
+            String numChildServicesManifestKey, boolean bindToCaller, boolean bindAsExternalService,
+            boolean useStrongBinding) {
         String serviceClassName = null;
         int numServices = -1;
         PackageManager packageManager = context.getPackageManager();
@@ -114,8 +112,8 @@
             throw new RuntimeException("Illegal meta data value: the child service doesn't exist");
         }
 
-        return new ChildConnectionAllocator(launcherHandler, creationParams, packageName,
-                serviceClassName, bindAsExternalService, useStrongBinding, numServices);
+        return new ChildConnectionAllocator(launcherHandler, packageName, serviceClassName,
+                bindToCaller, bindAsExternalService, useStrongBinding, numServices);
     }
 
     // TODO(jcivelli): remove this method once crbug.com/693484 has been addressed.
@@ -143,21 +141,21 @@
      * instead of being retrieved from the AndroidManifest.xml.
      */
     @VisibleForTesting
-    public static ChildConnectionAllocator createForTest(ChildProcessCreationParams creationParams,
-            String packageName, String serviceClassName, int serviceCount,
+    public static ChildConnectionAllocator createForTest(String packageName,
+            String serviceClassName, int serviceCount, boolean bindToCaller,
             boolean bindAsExternalService, boolean useStrongBinding) {
-        return new ChildConnectionAllocator(new Handler(), creationParams, packageName,
-                serviceClassName, bindAsExternalService, useStrongBinding, serviceCount);
+        return new ChildConnectionAllocator(new Handler(), packageName, serviceClassName,
+                bindToCaller, bindAsExternalService, useStrongBinding, serviceCount);
     }
 
-    private ChildConnectionAllocator(Handler launcherHandler,
-            ChildProcessCreationParams creationParams, String packageName, String serviceClassName,
-            boolean bindAsExternalService, boolean useStrongBinding, int numChildServices) {
+    private ChildConnectionAllocator(Handler launcherHandler, String packageName,
+            String serviceClassName, boolean bindToCaller, boolean bindAsExternalService,
+            boolean useStrongBinding, int numChildServices) {
         mLauncherHandler = launcherHandler;
         assert isRunningOnLauncherThread();
-        mCreationParams = creationParams;
         mPackageName = packageName;
         mServiceClassName = serviceClassName;
+        mBindToCaller = bindToCaller;
         mBindAsExternalService = bindAsExternalService;
         mUseStrongBinding = useStrongBinding;
         mChildProcessConnections = new ChildProcessConnection[numChildServices];
@@ -240,7 +238,7 @@
                 };
 
         ChildProcessConnection connection = mConnectionFactory.createConnection(
-                context, serviceName, mBindAsExternalService, serviceBundle, mCreationParams);
+                context, serviceName, mBindToCaller, mBindAsExternalService, serviceBundle);
         mChildProcessConnections[slot] = connection;
 
         for (Listener listener : mListeners) {
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
index 0154363..431f5b32 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
+++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
@@ -84,15 +84,6 @@
         private final int mBindFlags;
         private boolean mBound;
 
-        private Intent createServiceBindIntent() {
-            Intent intent = new Intent();
-            if (mCreationParams != null) {
-                mCreationParams.addIntentExtras(intent);
-            }
-            intent.setComponent(mServiceName);
-            return intent;
-        }
-
         private ChildServiceConnectionImpl(int bindFlags) {
             mBindFlags = bindFlags;
         }
@@ -102,7 +93,8 @@
             if (!mBound) {
                 try {
                     TraceEvent.begin("ChildProcessConnection.ChildServiceConnectionImpl.bind");
-                    Intent intent = createServiceBindIntent();
+                    Intent intent = new Intent();
+                    intent.setComponent(mServiceName);
                     if (mServiceBundle != null) {
                         intent.putExtras(mServiceBundle);
                     }
@@ -168,7 +160,9 @@
     // should be common to all processes of that type.
     private final Bundle mServiceBundle;
 
-    private final ChildProcessCreationParams mCreationParams;
+    // Whether bindToCaller should be called on the service after setup to check that only one
+    // process is bound to the service.
+    private final boolean mBindToCaller;
 
     private static class ConnectionParams {
         final Bundle mConnectionBundle;
@@ -241,35 +235,21 @@
     // Timestamp when watchdog was last reset, which is equivalent to when start was called.
     private long mLastWatchdogResetTimestamp;
 
-    public ChildProcessConnection(Context context, ComponentName serviceName,
-            boolean bindAsExternalService, Bundle serviceBundle,
-            ChildProcessCreationParams creationParams) {
-        this(context, serviceName, bindAsExternalService, serviceBundle, creationParams,
-                true /* doBind */);
-    }
-
-    private ChildProcessConnection(Context context, ComponentName serviceName,
-            boolean bindAsExternalService, Bundle serviceBundle,
-            ChildProcessCreationParams creationParams, boolean doBind) {
+    public ChildProcessConnection(Context context, ComponentName serviceName, boolean bindToCaller,
+            boolean bindAsExternalService, Bundle serviceBundle) {
         mLauncherHandler = new Handler();
         mContext = context;
-        mCreationParams = creationParams;
         mServiceName = serviceName;
-        mServiceBundle = serviceBundle;
+        mServiceBundle = serviceBundle != null ? serviceBundle : new Bundle();
+        mServiceBundle.putBoolean(ChildProcessConstants.EXTRA_BIND_TO_CALLER, bindToCaller);
+        mBindToCaller = bindToCaller;
 
-        if (doBind) {
-            int defaultFlags = Context.BIND_AUTO_CREATE
-                    | (bindAsExternalService ? Context.BIND_EXTERNAL_SERVICE : 0);
-            mInitialBinding = createServiceConnection(defaultFlags);
-            mModerateBinding = createServiceConnection(defaultFlags);
-            mStrongBinding = createServiceConnection(defaultFlags | Context.BIND_IMPORTANT);
-            mWaivedBinding = createServiceConnection(defaultFlags | Context.BIND_WAIVE_PRIORITY);
-        } else {
-            mInitialBinding = null;
-            mModerateBinding = null;
-            mStrongBinding = null;
-            mWaivedBinding = null;
-        }
+        int defaultFlags = Context.BIND_AUTO_CREATE
+                | (bindAsExternalService ? Context.BIND_EXTERNAL_SERVICE : 0);
+        mInitialBinding = createServiceConnection(defaultFlags);
+        mModerateBinding = createServiceConnection(defaultFlags);
+        mStrongBinding = createServiceConnection(defaultFlags | Context.BIND_IMPORTANT);
+        mWaivedBinding = createServiceConnection(defaultFlags | Context.BIND_WAIVE_PRIORITY);
     }
 
     public final Context getContext() {
@@ -400,28 +380,24 @@
             mDidOnServiceConnected = true;
             mService = IChildProcessService.Stub.asInterface(service);
 
-            boolean boundToUs = false;
-            try {
-                boolean bindCheck =
-                        mCreationParams != null && mCreationParams.getBindToCallerCheck();
-                boundToUs = bindCheck ? mService.bindToCaller() : true;
-            } catch (RemoteException ex) {
-                // Do not trigger the StartCallback here, since the service is already
-                // dead and the onChildStopped callback will run from onServiceDisconnected().
-                Log.e(TAG, "Failed to bind service to connection.", ex);
-                return;
-            }
-
-            if (mServiceCallback != null) {
-                if (boundToUs) {
-                    mServiceCallback.onChildStarted();
-                } else {
-                    mServiceCallback.onChildStartFailed();
+            if (mBindToCaller) {
+                try {
+                    if (!mService.bindToCaller()) {
+                        if (mServiceCallback != null) {
+                            mServiceCallback.onChildStartFailed();
+                        }
+                        return;
+                    }
+                } catch (RemoteException ex) {
+                    // Do not trigger the StartCallback here, since the service is already
+                    // dead and the onChildStopped callback will run from onServiceDisconnected().
+                    Log.e(TAG, "Failed to bind service to connection.", ex);
+                    return;
                 }
             }
 
-            if (!boundToUs) {
-                return;
+            if (mServiceCallback != null) {
+                mServiceCallback.onChildStarted();
             }
 
             mServiceConnectComplete = true;
@@ -684,15 +660,6 @@
         mService.crashIntentionallyForTesting();
     }
 
-    /** Creates a connection with no service bindings. */
-    @VisibleForTesting
-    static ChildProcessConnection createUnboundConnectionForTesting(Context context,
-            ComponentName serviceName, boolean bindAsExternalService, Bundle serviceBundle,
-            ChildProcessCreationParams creationParams) {
-        return new ChildProcessConnection(context, serviceName, bindAsExternalService,
-                serviceBundle, creationParams, false /* doBind */);
-    }
-
     @VisibleForTesting
     public boolean didOnServiceConnectedForTesting() {
         return mDidOnServiceConnected;
diff --git a/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java b/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
index 633da541..50c3eb2 100644
--- a/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
+++ b/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
@@ -57,8 +57,7 @@
 
         @Override
         public ChildProcessConnection createConnection(Context context, ComponentName serviceName,
-                boolean bindAsExternalService, Bundle serviceBundle,
-                ChildProcessCreationParams creationParams) {
+                boolean bindToCaller, boolean bindAsExternalService, Bundle serviceBundle) {
             mLastServiceName = serviceName;
             if (mConnection == null) {
                 mConnection = mock(ChildProcessConnection.class);
@@ -119,20 +118,14 @@
 
     private final TestConnectionFactory mTestConnectionFactory = new TestConnectionFactory();
 
-    // For some reason creating ChildProcessCreationParams from a static context makes the launcher
-    // unhappy. (some Dalvik native library is not found when initializing a SparseArray)
-    private final ChildProcessCreationParams mCreationParams =
-            new ChildProcessCreationParams(TEST_PACKAGE_NAME, false /* isExternalService */,
-                    0 /* libraryProcessType */, true /* bindToCallerCheck */);
-
     private ChildConnectionAllocator mAllocator;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mAllocator = ChildConnectionAllocator.createForTest(mCreationParams, TEST_PACKAGE_NAME,
-                "AllocatorTest", MAX_CONNECTION_NUMBER, false /* bindAsExternalService */,
+        mAllocator = ChildConnectionAllocator.createForTest(TEST_PACKAGE_NAME, "AllocatorTest",
+                MAX_CONNECTION_NUMBER, true /* bindToCaller */, false /* bindAsExternalService */,
                 false /* useStrongBinding */);
         mAllocator.setConnectionFactoryForTesting(mTestConnectionFactory);
     }
@@ -185,8 +178,8 @@
     public void testStrongBindingParam() {
         for (boolean useStrongBinding : new boolean[] {true, false}) {
             ChildConnectionAllocator allocator = ChildConnectionAllocator.createForTest(
-                    mCreationParams, TEST_PACKAGE_NAME, "AllocatorTest", MAX_CONNECTION_NUMBER,
-                    false /* bindAsExternalService */, useStrongBinding);
+                    TEST_PACKAGE_NAME, "AllocatorTest", MAX_CONNECTION_NUMBER,
+                    true /* bindToCaller */, false /* bindAsExternalService */, useStrongBinding);
             allocator.setConnectionFactoryForTesting(mTestConnectionFactory);
             ChildProcessConnection connection = allocator.allocate(
                     null /* context */, null /* serviceBundle */, mServiceCallback);
diff --git a/base/files/file.h b/base/files/file.h
index 0155c7c..de5fe0d1 100644
--- a/base/files/file.h
+++ b/base/files/file.h
@@ -12,36 +12,23 @@
 #include "base/base_export.h"
 #include "base/files/file_path.h"
 #include "base/files/file_tracing.h"
+#include "base/files/platform_file.h"
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 
-#if defined(OS_WIN)
-#include <windows.h>
-#include "base/win/scoped_handle.h"
-#endif
-
 #if defined(OS_POSIX)
 #include <sys/stat.h>
 #endif
 
 namespace base {
 
-#if defined(OS_WIN)
-using PlatformFile = HANDLE;
-
-const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE;
-#elif defined(OS_POSIX)
-using PlatformFile = int;
-
-const PlatformFile kInvalidPlatformFile = -1;
 #if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
 typedef struct stat stat_wrapper_t;
-#else
+#elif defined(OS_POSIX)
 typedef struct stat64 stat_wrapper_t;
 #endif
-#endif  // defined(OS_POSIX)
 
 // Thin wrapper around an OS-level file.
 // Note that this class does not provide any support for asynchronous IO, other
@@ -273,6 +260,8 @@
   // Returns some basic information for the given file.
   bool GetInfo(Info* info);
 
+#if !defined(OS_FUCHSIA)  // Fuchsia's POSIX API does not support file locking.
+
   // Attempts to take an exclusive write lock on the file. Returns immediately
   // (i.e. does not wait for another process to unlock the file). If the lock
   // was obtained, the result will be FILE_OK. A lock only guarantees
@@ -298,6 +287,8 @@
   // Unlock a file previously locked.
   Error Unlock();
 
+#endif  // !defined(OS_FUCHSIA)
+
   // Returns a new object referencing this file for use within the current
   // process. Handling of FLAG_DELETE_ON_CLOSE varies by OS. On POSIX, the File
   // object that was created or initialized with this flag will have unlinked
@@ -355,11 +346,7 @@
 
   void SetPlatformFile(PlatformFile file);
 
-#if defined(OS_WIN)
-  win::ScopedHandle file_;
-#elif defined(OS_POSIX)
-  ScopedFD file_;
-#endif
+  ScopedPlatformFile file_;
 
   // A path to use for tracing purposes. Set if file tracing is enabled during
   // |Initialize()|.
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc
index e280bbc5..9945007 100644
--- a/base/files/file_path_watcher_unittest.cc
+++ b/base/files/file_path_watcher_unittest.cc
@@ -539,15 +539,14 @@
   ASSERT_TRUE(WaitForEvents());
 }
 
-#if defined(OS_POSIX)
-#if defined(OS_ANDROID)
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
 // Apps cannot create symlinks on Android in /sdcard as /sdcard uses the
 // "fuse" file system, while /data uses "ext4".  Running these tests in /data
 // would be preferable and allow testing file attributes and symlinks.
 // TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
 // the |temp_dir_| in /data.
-#define RecursiveWithSymLink DISABLED_RecursiveWithSymLink
-#endif  // defined(OS_ANDROID)
+//
+// This test is disabled on Fuchsia since it doesn't support symlinking.
 TEST_F(FilePathWatcherTest, RecursiveWithSymLink) {
   if (!FilePathWatcher::RecursiveWatchAvailable())
     return;
@@ -585,7 +584,7 @@
   ASSERT_TRUE(WriteFile(target2_file, "content"));
   ASSERT_TRUE(WaitForEvents());
 }
-#endif  // OS_POSIX
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
 
 TEST_F(FilePathWatcherTest, MoveChild) {
   FilePathWatcher file_watcher;
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index 46dd647f..dc127e5 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -70,6 +70,7 @@
 #endif
 }
 
+#if !defined(OS_FUCHSIA)
 File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
   struct flock lock;
   lock.l_type = do_lock ? F_WRLCK : F_UNLCK;
@@ -80,6 +81,8 @@
     return File::OSErrorToFileError(errno);
   return File::FILE_OK;
 }
+#endif
+
 #else   // defined(OS_NACL) && !defined(OS_AIX)
 
 bool IsOpenAppend(PlatformFile file) {
@@ -360,6 +363,7 @@
   return true;
 }
 
+#if !defined(OS_FUCHSIA)
 File::Error File::Lock() {
   SCOPED_FILE_TRACE("Lock");
   return CallFcntlFlock(file_.get(), true);
@@ -369,6 +373,7 @@
   SCOPED_FILE_TRACE("Unlock");
   return CallFcntlFlock(file_.get(), false);
 }
+#endif
 
 File File::Duplicate() const {
   if (!IsValid())
diff --git a/base/files/file_util.h b/base/files/file_util.h
index 27d5ff3..fac14d3 100644
--- a/base/files/file_util.h
+++ b/base/files/file_util.h
@@ -165,6 +165,10 @@
 // Returns true iff |bytes| bytes have been successfully read from |fd|.
 BASE_EXPORT bool ReadFromFD(int fd, char* buffer, size_t bytes);
 
+// The following functions use POSIX functionality that isn't supported by
+// Fuchsia.
+#if !defined(OS_FUCHSIA)
+
 // Creates a symbolic link at |symlink| pointing to |target|.  Returns
 // false on failure.
 BASE_EXPORT bool CreateSymbolicLink(const FilePath& target,
@@ -205,6 +209,7 @@
 BASE_EXPORT bool ExecutableExistsInPath(Environment* env,
                                         const FilePath::StringType& executable);
 
+#endif  // !OS_FUCHSIA
 #endif  // OS_POSIX
 
 // Returns true if the given directory is empty
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index 018592a..de9da50 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -438,6 +438,8 @@
 }
 
 #if !defined(OS_NACL_NONSFI)
+
+#if !defined(OS_FUCHSIA)
 bool CreateSymbolicLink(const FilePath& target_path,
                         const FilePath& symlink_path) {
   DCHECK(!symlink_path.empty());
@@ -514,6 +516,8 @@
   return false;
 }
 
+#endif  // !OS_FUCHSIA
+
 #if !defined(OS_MACOSX)
 // This is implemented in file_util_mac.mm for Mac.
 bool GetTempDir(FilePath* path) {
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index ed7adf91..8f3ffbf2 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -163,6 +163,8 @@
 
 #endif
 
+// Fuchsia doesn't support file permissions.
+#if !defined(OS_FUCHSIA)
 #if defined(OS_POSIX)
 // Provide a simple way to change the permissions bits on |path| in tests.
 // ASSERT failures will return, but not stop the test.  Caller should wrap
@@ -181,6 +183,48 @@
 }
 #endif  // defined(OS_POSIX)
 
+// Sets the source file to read-only.
+void SetReadOnly(const FilePath& path, bool read_only) {
+#if defined(OS_WIN)
+  // On Windows, it involves setting/removing the 'readonly' bit.
+  DWORD attrs = GetFileAttributes(path.value().c_str());
+  ASSERT_NE(INVALID_FILE_ATTRIBUTES, attrs);
+  ASSERT_TRUE(SetFileAttributes(
+      path.value().c_str(), read_only ? (attrs | FILE_ATTRIBUTE_READONLY)
+                                      : (attrs & ~FILE_ATTRIBUTE_READONLY)));
+
+  DWORD expected =
+      read_only
+          ? ((attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY)) |
+             FILE_ATTRIBUTE_READONLY)
+          : (attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY));
+
+  // Ignore FILE_ATTRIBUTE_NOT_CONTENT_INDEXED if present.
+  attrs = GetFileAttributes(path.value().c_str()) &
+          ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+  ASSERT_EQ(expected, attrs);
+#else
+  // On all other platforms, it involves removing/setting the write bit.
+  mode_t mode = read_only ? S_IRUSR : (S_IRUSR | S_IWUSR);
+  EXPECT_TRUE(SetPosixFilePermissions(
+      path, DirectoryExists(path) ? (mode | S_IXUSR) : mode));
+#endif  // defined(OS_WIN)
+}
+
+bool IsReadOnly(const FilePath& path) {
+#if defined(OS_WIN)
+  DWORD attrs = GetFileAttributes(path.value().c_str());
+  EXPECT_NE(INVALID_FILE_ATTRIBUTES, attrs);
+  return attrs & FILE_ATTRIBUTE_READONLY;
+#else
+  int mode = 0;
+  EXPECT_TRUE(GetPosixFilePermissions(path, &mode));
+  return !(mode & S_IWUSR);
+#endif  // defined(OS_WIN)
+}
+
+#endif  // defined(OS_FUCHSIA)
+
 const wchar_t bogus_content[] = L"I'm cannon fodder.";
 
 const int FILES_AND_DIRECTORIES =
@@ -575,7 +619,7 @@
 
 #endif  // defined(OS_WIN)
 
-#if defined(OS_POSIX)
+#if !defined(OS_FUCHSIA) && defined(OS_POSIX)
 
 TEST_F(FileUtilTest, CreateAndReadSymlinks) {
   FilePath link_from = temp_dir_.GetPath().Append(FPL("from_file"));
@@ -650,51 +694,7 @@
   // Infinite loop!
   EXPECT_FALSE(NormalizeFilePath(link_from, &normalized_path));
 }
-#endif  // defined(OS_POSIX)
 
-TEST_F(FileUtilTest, DeleteNonExistent) {
-  FilePath non_existent =
-      temp_dir_.GetPath().AppendASCII("bogus_file_dne.foobar");
-  ASSERT_FALSE(PathExists(non_existent));
-
-  EXPECT_TRUE(DeleteFile(non_existent, false));
-  ASSERT_FALSE(PathExists(non_existent));
-  EXPECT_TRUE(DeleteFile(non_existent, true));
-  ASSERT_FALSE(PathExists(non_existent));
-}
-
-TEST_F(FileUtilTest, DeleteNonExistentWithNonExistentParent) {
-  FilePath non_existent = temp_dir_.GetPath().AppendASCII("bogus_topdir");
-  non_existent = non_existent.AppendASCII("bogus_subdir");
-  ASSERT_FALSE(PathExists(non_existent));
-
-  EXPECT_TRUE(DeleteFile(non_existent, false));
-  ASSERT_FALSE(PathExists(non_existent));
-  EXPECT_TRUE(DeleteFile(non_existent, true));
-  ASSERT_FALSE(PathExists(non_existent));
-}
-
-TEST_F(FileUtilTest, DeleteFile) {
-  // Create a file
-  FilePath file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 1.txt"));
-  CreateTextFile(file_name, bogus_content);
-  ASSERT_TRUE(PathExists(file_name));
-
-  // Make sure it's deleted
-  EXPECT_TRUE(DeleteFile(file_name, false));
-  EXPECT_FALSE(PathExists(file_name));
-
-  // Test recursive case, create a new file
-  file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 2.txt"));
-  CreateTextFile(file_name, bogus_content);
-  ASSERT_TRUE(PathExists(file_name));
-
-  // Make sure it's deleted
-  EXPECT_TRUE(DeleteFile(file_name, true));
-  EXPECT_FALSE(PathExists(file_name));
-}
-
-#if defined(OS_POSIX)
 TEST_F(FileUtilTest, DeleteSymlinkToExistentFile) {
   // Create a file.
   FilePath file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 2.txt"));
@@ -907,7 +907,105 @@
   EXPECT_FALSE(ExecutableExistsInPath(env.get(), kDneFileName));
 }
 
-#endif  // defined(OS_POSIX)
+#endif  // !defined(OS_FUCHSIA) && defined(OS_POSIX)
+
+#if !defined(OS_FUCHSIA)
+
+TEST_F(FileUtilTest, CopyFileACL) {
+  // While FileUtilTest.CopyFile asserts the content is correctly copied over,
+  // this test case asserts the access control bits are meeting expectations in
+  // CopyFile().
+  FilePath src = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("src.txt"));
+  const std::wstring file_contents(L"Gooooooooooooooooooooogle");
+  CreateTextFile(src, file_contents);
+
+  // Set the source file to read-only.
+  ASSERT_FALSE(IsReadOnly(src));
+  SetReadOnly(src, true);
+  ASSERT_TRUE(IsReadOnly(src));
+
+  // Copy the file.
+  FilePath dst = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dst.txt"));
+  ASSERT_TRUE(CopyFile(src, dst));
+  EXPECT_EQ(file_contents, ReadTextFile(dst));
+
+  ASSERT_FALSE(IsReadOnly(dst));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryACL) {
+  // Create source directories.
+  FilePath src = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("src"));
+  FilePath src_subdir = src.Append(FILE_PATH_LITERAL("subdir"));
+  CreateDirectory(src_subdir);
+  ASSERT_TRUE(PathExists(src_subdir));
+
+  // Create a file under the directory.
+  FilePath src_file = src.Append(FILE_PATH_LITERAL("src.txt"));
+  CreateTextFile(src_file, L"Gooooooooooooooooooooogle");
+  SetReadOnly(src_file, true);
+  ASSERT_TRUE(IsReadOnly(src_file));
+
+  // Make directory read-only.
+  SetReadOnly(src_subdir, true);
+  ASSERT_TRUE(IsReadOnly(src_subdir));
+
+  // Copy the directory recursively.
+  FilePath dst = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dst"));
+  FilePath dst_file = dst.Append(FILE_PATH_LITERAL("src.txt"));
+  EXPECT_TRUE(CopyDirectory(src, dst, true));
+
+  FilePath dst_subdir = dst.Append(FILE_PATH_LITERAL("subdir"));
+  ASSERT_FALSE(IsReadOnly(dst_subdir));
+  ASSERT_FALSE(IsReadOnly(dst_file));
+
+  // Give write permissions to allow deletion.
+  SetReadOnly(src_subdir, false);
+  ASSERT_FALSE(IsReadOnly(src_subdir));
+}
+
+#endif  // !defined(OS_FUCHSIA)
+
+TEST_F(FileUtilTest, DeleteNonExistent) {
+  FilePath non_existent =
+      temp_dir_.GetPath().AppendASCII("bogus_file_dne.foobar");
+  ASSERT_FALSE(PathExists(non_existent));
+
+  EXPECT_TRUE(DeleteFile(non_existent, false));
+  ASSERT_FALSE(PathExists(non_existent));
+  EXPECT_TRUE(DeleteFile(non_existent, true));
+  ASSERT_FALSE(PathExists(non_existent));
+}
+
+TEST_F(FileUtilTest, DeleteNonExistentWithNonExistentParent) {
+  FilePath non_existent = temp_dir_.GetPath().AppendASCII("bogus_topdir");
+  non_existent = non_existent.AppendASCII("bogus_subdir");
+  ASSERT_FALSE(PathExists(non_existent));
+
+  EXPECT_TRUE(DeleteFile(non_existent, false));
+  ASSERT_FALSE(PathExists(non_existent));
+  EXPECT_TRUE(DeleteFile(non_existent, true));
+  ASSERT_FALSE(PathExists(non_existent));
+}
+
+TEST_F(FileUtilTest, DeleteFile) {
+  // Create a file
+  FilePath file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 1.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  // Make sure it's deleted
+  EXPECT_TRUE(DeleteFile(file_name, false));
+  EXPECT_FALSE(PathExists(file_name));
+
+  // Test recursive case, create a new file
+  file_name = temp_dir_.GetPath().Append(FPL("Test DeleteFile 2.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  // Make sure it's deleted
+  EXPECT_TRUE(DeleteFile(file_name, true));
+  EXPECT_FALSE(PathExists(file_name));
+}
 
 #if defined(OS_WIN)
 // Tests that the Delete function works for wild cards, especially
@@ -1452,77 +1550,6 @@
   EXPECT_TRUE(PathExists(file_name_to));
 }
 
-// Sets the source file to read-only.
-void SetReadOnly(const FilePath& path, bool read_only) {
-#if defined(OS_WIN)
-  // On Windows, it involves setting/removing the 'readonly' bit.
-  DWORD attrs = GetFileAttributes(path.value().c_str());
-  ASSERT_NE(INVALID_FILE_ATTRIBUTES, attrs);
-  ASSERT_TRUE(SetFileAttributes(
-      path.value().c_str(),
-      read_only ? (attrs | FILE_ATTRIBUTE_READONLY) :
-          (attrs & ~FILE_ATTRIBUTE_READONLY)));
-
-  DWORD expected = read_only ?
-      ((attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY)) |
-          FILE_ATTRIBUTE_READONLY) :
-      (attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY));
-
-  // Ignore FILE_ATTRIBUTE_NOT_CONTENT_INDEXED if present.
-  attrs = GetFileAttributes(path.value().c_str()) &
-          ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
-  ASSERT_EQ(expected, attrs);
-#else
-  // On all other platforms, it involves removing/setting the write bit.
-  mode_t mode = read_only ? S_IRUSR : (S_IRUSR | S_IWUSR);
-  EXPECT_TRUE(SetPosixFilePermissions(
-      path, DirectoryExists(path) ? (mode | S_IXUSR) : mode));
-#endif
-}
-
-bool IsReadOnly(const FilePath& path) {
-#if defined(OS_WIN)
-  DWORD attrs = GetFileAttributes(path.value().c_str());
-  EXPECT_NE(INVALID_FILE_ATTRIBUTES, attrs);
-  return attrs & FILE_ATTRIBUTE_READONLY;
-#else
-  int mode = 0;
-  EXPECT_TRUE(GetPosixFilePermissions(path, &mode));
-  return !(mode & S_IWUSR);
-#endif
-}
-
-TEST_F(FileUtilTest, CopyDirectoryACL) {
-  // Create source directories.
-  FilePath src = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("src"));
-  FilePath src_subdir = src.Append(FILE_PATH_LITERAL("subdir"));
-  CreateDirectory(src_subdir);
-  ASSERT_TRUE(PathExists(src_subdir));
-
-  // Create a file under the directory.
-  FilePath src_file = src.Append(FILE_PATH_LITERAL("src.txt"));
-  CreateTextFile(src_file, L"Gooooooooooooooooooooogle");
-  SetReadOnly(src_file, true);
-  ASSERT_TRUE(IsReadOnly(src_file));
-
-  // Make directory read-only.
-  SetReadOnly(src_subdir, true);
-  ASSERT_TRUE(IsReadOnly(src_subdir));
-
-  // Copy the directory recursively.
-  FilePath dst = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dst"));
-  FilePath dst_file = dst.Append(FILE_PATH_LITERAL("src.txt"));
-  EXPECT_TRUE(CopyDirectory(src, dst, true));
-
-  FilePath dst_subdir = dst.Append(FILE_PATH_LITERAL("subdir"));
-  ASSERT_FALSE(IsReadOnly(dst_subdir));
-  ASSERT_FALSE(IsReadOnly(dst_file));
-
-  // Give write permissions to allow deletion.
-  SetReadOnly(src_subdir, false);
-  ASSERT_FALSE(IsReadOnly(src_subdir));
-}
-
 TEST_F(FileUtilTest, CopyFile) {
   // Create a directory
   FilePath dir_name_from =
@@ -1560,27 +1587,6 @@
   EXPECT_FALSE(PathExists(dest_file2));
 }
 
-TEST_F(FileUtilTest, CopyFileACL) {
-  // While FileUtilTest.CopyFile asserts the content is correctly copied over,
-  // this test case asserts the access control bits are meeting expectations in
-  // CopyFile().
-  FilePath src = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("src.txt"));
-  const std::wstring file_contents(L"Gooooooooooooooooooooogle");
-  CreateTextFile(src, file_contents);
-
-  // Set the source file to read-only.
-  ASSERT_FALSE(IsReadOnly(src));
-  SetReadOnly(src, true);
-  ASSERT_TRUE(IsReadOnly(src));
-
-  // Copy the file.
-  FilePath dst = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dst.txt"));
-  ASSERT_TRUE(CopyFile(src, dst));
-  EXPECT_EQ(file_contents, ReadTextFile(dst));
-
-  ASSERT_FALSE(IsReadOnly(dst));
-}
-
 // file_util winds up using autoreleased objects on the Mac, so this needs
 // to be a PlatformTest.
 typedef PlatformTest ReadOnlyFileUtilTest;
@@ -2255,6 +2261,7 @@
 }
 
 #if defined(OS_POSIX)
+
 TEST_F(FileUtilTest, SetNonBlocking) {
   const int kInvalidFd = 99999;
   EXPECT_FALSE(SetNonBlocking(kInvalidFd));
@@ -2279,6 +2286,10 @@
   EXPECT_TRUE(SetCloseOnExec(fd.get()));
 }
 
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_FUCHSIA)
+
 // Testing VerifyPathControlledByAdmin() is hard, because there is no
 // way a test can make a file owned by root, or change file paths
 // at the root of the file system.  VerifyPathControlledByAdmin()
@@ -2561,6 +2572,8 @@
   EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 }
 
+#endif  // defined(OS_POSIX) && !defined(OS_FUCHSIA)
+
 #if defined(OS_ANDROID)
 TEST_F(FileUtilTest, ValidContentUriTest) {
   // Get the test image path.
@@ -2606,6 +2619,8 @@
 }
 #endif
 
+#if defined(OS_POSIX)
+
 TEST(ScopedFD, ScopedFDDoesClose) {
   int fds[2];
   char c = 0;
diff --git a/base/files/platform_file.h b/base/files/platform_file.h
new file mode 100644
index 0000000..6b4a0c21
--- /dev/null
+++ b/base/files/platform_file.h
@@ -0,0 +1,43 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_PLATFORM_FILE_H_
+#define BASE_FILES_PLATFORM_FILE_H_
+
+#include "base/files/scoped_file.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include "base/win/scoped_handle.h"
+#endif
+
+// This file defines platform-independent types for dealing with
+// platform-dependent files. If possible, use the higher-level base::File class
+// rather than these primitives.
+
+namespace base {
+
+#if defined(OS_WIN)
+
+using PlatformFile = HANDLE;
+using ScopedPlatformFile = ::base::win::ScopedHandle;
+
+// It would be nice to make this constexpr but INVALID_HANDLE_VALUE is a
+// ((void*)(-1)) which Clang rejects since reinterpret_cast is technically
+// disallowed in constexpr. Visual Studio accepts this, however.
+const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE;
+
+#elif defined(OS_POSIX)
+
+using PlatformFile = int;
+using ScopedPlatformFile = ::base::ScopedFD;
+
+constexpr PlatformFile kInvalidPlatformFile = -1;
+
+#endif
+
+}  // namespace
+
+#endif  // BASE_FILES_PLATFORM_FILE_H_
diff --git a/base/numerics/clamped_math.h b/base/numerics/clamped_math.h
index d2c4f298..799043a 100644
--- a/base/numerics/clamped_math.h
+++ b/base/numerics/clamped_math.h
@@ -108,7 +108,7 @@
       const U rhs) const {
     using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type;
     return ClampedNumeric<result_type>(
-        ClampedMaxOp<T, U>(value_, Wrapper<U>::value(rhs)));
+        ClampedMaxOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
   }
 
   template <typename U>
@@ -116,7 +116,7 @@
       const U rhs) const {
     using result_type = typename MathWrapper<ClampedMinOp, T, U>::type;
     return ClampedNumeric<result_type>(
-        ClampedMinOp<T, U>(value_, Wrapper<U>::value(rhs)));
+        ClampedMinOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
   }
 
   // This function is available only for integral types. It returns an unsigned
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc
index d124f13f..ef3bb09 100644
--- a/base/numerics/safe_numerics_unittest.cc
+++ b/base/numerics/safe_numerics_unittest.cc
@@ -877,6 +877,20 @@
   EXPECT_EQ(DstLimits::max(), CheckMax(MakeStrictNum(1), MakeCheckedNum(0),
                                        DstLimits::max(), SrcLimits::lowest())
                                   .ValueOrDie());
+
+  EXPECT_EQ(SrcLimits::max(),
+            MakeClampedNum(SrcLimits::max()).Max(DstLimits::lowest()));
+  EXPECT_EQ(DstLimits::max(),
+            MakeClampedNum(SrcLimits::lowest()).Max(DstLimits::max()));
+  EXPECT_EQ(DstLimits::lowest(),
+            MakeClampedNum(SrcLimits::max()).Min(DstLimits::lowest()));
+  EXPECT_EQ(SrcLimits::lowest(),
+            MakeClampedNum(SrcLimits::lowest()).Min(DstLimits::max()));
+  EXPECT_EQ(SrcLimits::lowest(),
+            ClampMin(MakeStrictNum(1), MakeClampedNum(0), DstLimits::max(),
+                     SrcLimits::lowest()));
+  EXPECT_EQ(DstLimits::max(), ClampMax(MakeStrictNum(1), MakeClampedNum(0),
+                                       DstLimits::max(), SrcLimits::lowest()));
 }
 
 template <typename Dst, typename Src>
diff --git a/build/config/c++/c++.gni b/build/config/c++/c++.gni
index 4ab97d8..362595d5 100644
--- a/build/config/c++/c++.gni
+++ b/build/config/c++/c++.gni
@@ -10,4 +10,9 @@
   # library.
   use_custom_libcxx = (is_linux && !is_chromeos &&
                        (!is_chromecast || is_cast_desktop_build)) || is_msan
+
+  # Sanitizer builds need to override operator new, operator delete, and
+  # some exception handling symbols, so libc++ must be a shared library
+  # to prevent duplicate symbol errors when linking.
+  libcpp_is_static = !is_component_build && !using_sanitizer
 }
diff --git a/build/fuchsia/OWNERS b/build/fuchsia/OWNERS
new file mode 100644
index 0000000..22e1b69
--- /dev/null
+++ b/build/fuchsia/OWNERS
@@ -0,0 +1,9 @@
+jamesr@chromium.org
+kmarshall@chromium.org
+scottmg@chromium.org
+sergeyu@chromium.org
+thakis@chromium.org
+wez@chromium.org
+
+# TEAM: cr-fuchsia@chromium.org
+# COMPONENT: Internals>PlatformIntegration
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 606d9fe..d9ac8bd 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -471,7 +471,7 @@
     "//base",
     "//base/third_party/dynamic_annotations",
     "//cc/paint",
-    "//cc/surfaces:surface_id",
+    "//components/viz/common",
     "//gpu",
     "//gpu/command_buffer/client:gles2_implementation",
     "//gpu/command_buffer/client:gles2_interface",
@@ -666,7 +666,6 @@
     "//base/third_party/dynamic_annotations",
     "//cc/paint",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
     "//components/viz/common",
     "//components/viz/service",
     "//components/viz/test:test_support",
@@ -869,7 +868,6 @@
     "//cc/ipc:test_interfaces",
     "//cc/paint",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
     "//cc/surfaces:surfaces",
     "//components/viz/common",
     "//components/viz/service",
@@ -926,7 +924,7 @@
     "//cc/ipc:interfaces",
     "//cc/paint",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
+    "//components/viz/common",
     "//components/viz/test:test_support",
     "//gpu",
     "//gpu:test_support",
diff --git a/cc/ipc/cc_param_traits_macros.h b/cc/ipc/cc_param_traits_macros.h
index 659543fd..ba065ea 100644
--- a/cc/ipc/cc_param_traits_macros.h
+++ b/cc/ipc/cc_param_traits_macros.h
@@ -20,10 +20,10 @@
 #include "cc/quads/yuv_video_draw_quad.h"
 #include "cc/resources/returned_resource.h"
 #include "cc/resources/transferable_resource.h"
-#include "cc/surfaces/surface_sequence.h"
 #include "components/viz/common/quads/resource_format.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "ui/gfx/ipc/color/gfx_param_traits.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
 #include "ui/gfx/ipc/skia/gfx_skia_param_traits.h"
@@ -44,7 +44,7 @@
 IPC_ENUM_TRAITS_MAX_VALUE(cc::SurfaceDrawQuadType,
                           cc::SurfaceDrawQuadType::LAST)
 
-IPC_STRUCT_TRAITS_BEGIN(cc::SurfaceSequence)
+IPC_STRUCT_TRAITS_BEGIN(viz::SurfaceSequence)
   IPC_STRUCT_TRAITS_MEMBER(frame_sink_id)
   IPC_STRUCT_TRAITS_MEMBER(sequence)
 IPC_STRUCT_TRAITS_END()
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index b93dc49..5bffa458 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -107,7 +107,7 @@
     std::move(callback).Run(s);
   }
 
-  void EchoSurfaceSequence(const SurfaceSequence& s,
+  void EchoSurfaceSequence(const viz::SurfaceSequence& s,
                            EchoSurfaceSequenceCallback callback) override {
     std::move(callback).Run(s);
   }
@@ -1031,9 +1031,9 @@
 TEST_F(StructTraitsTest, SurfaceSequence) {
   const viz::FrameSinkId frame_sink_id(2016, 1234);
   const uint32_t sequence = 0xfbadbeef;
-  SurfaceSequence input(frame_sink_id, sequence);
+  viz::SurfaceSequence input(frame_sink_id, sequence);
   mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
-  SurfaceSequence output;
+  viz::SurfaceSequence output;
   proxy->EchoSurfaceSequence(input, &output);
   EXPECT_EQ(frame_sink_id, output.frame_sink_id);
   EXPECT_EQ(sequence, output.sequence);
diff --git a/cc/ipc/surface_sequence.typemap b/cc/ipc/surface_sequence.typemap
index 7492d60a..e05d72e 100644
--- a/cc/ipc/surface_sequence.typemap
+++ b/cc/ipc/surface_sequence.typemap
@@ -3,7 +3,9 @@
 # found in the LICENSE file.
 
 mojom = "//cc/ipc/surface_sequence.mojom"
-public_headers = [ "//cc/surfaces/surface_sequence.h" ]
+public_headers = [ "//components/viz/common/surfaces/surface_sequence.h" ]
 traits_headers = [ "//cc/ipc/surface_sequence_struct_traits.h" ]
-deps = [ "//cc/surfaces:surface_id", ]
-type_mappings = [ "cc.mojom.SurfaceSequence=cc::SurfaceSequence" ]
+deps = [
+  "//components/viz/common",
+]
+type_mappings = [ "cc.mojom.SurfaceSequence=viz::SurfaceSequence" ]
diff --git a/cc/ipc/surface_sequence_struct_traits.h b/cc/ipc/surface_sequence_struct_traits.h
index 1b30ee0..ead28b37 100644
--- a/cc/ipc/surface_sequence_struct_traits.h
+++ b/cc/ipc/surface_sequence_struct_traits.h
@@ -6,26 +6,26 @@
 #define CC_IPC_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
 
 #include "cc/ipc/surface_sequence.mojom-shared.h"
-#include "cc/surfaces/surface_sequence.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 
 namespace mojo {
 
 template <>
-struct StructTraits<cc::mojom::SurfaceSequenceDataView, cc::SurfaceSequence> {
-  static const viz::FrameSinkId& frame_sink_id(const cc::SurfaceSequence& id) {
+struct StructTraits<cc::mojom::SurfaceSequenceDataView, viz::SurfaceSequence> {
+  static const viz::FrameSinkId& frame_sink_id(const viz::SurfaceSequence& id) {
     return id.frame_sink_id;
   }
 
-  static uint32_t sequence(const cc::SurfaceSequence& id) {
+  static uint32_t sequence(const viz::SurfaceSequence& id) {
     return id.sequence;
   }
 
   static bool Read(cc::mojom::SurfaceSequenceDataView data,
-                   cc::SurfaceSequence* out) {
+                   viz::SurfaceSequence* out) {
     viz::FrameSinkId frame_sink_id;
     if (!data.ReadFrameSinkId(&frame_sink_id))
       return false;
-    *out = cc::SurfaceSequence(frame_sink_id, data.sequence());
+    *out = viz::SurfaceSequence(frame_sink_id, data.sequence());
     return true;
   }
 };
diff --git a/cc/layers/recording_source.cc b/cc/layers/recording_source.cc
index 11033363..0177d35 100644
--- a/cc/layers/recording_source.cc
+++ b/cc/layers/recording_source.cc
@@ -24,6 +24,10 @@
 const bool kDefaultClearCanvasSetting = true;
 #endif
 
+// We don't perform per-layer solid color analysis when there are too many skia
+// operations.
+const int kMaxOpsToAnalyzeForLayer = 10;
+
 }  // namespace
 
 namespace cc {
@@ -141,14 +145,13 @@
   is_solid_color_ = false;
   solid_color_ = SK_ColorTRANSPARENT;
 
-  // TODO(vmpstr): We can probably remove this check.
-  if (!display_list_->ShouldBeAnalyzedForSolidColor())
+  if (display_list_->op_count() > kMaxOpsToAnalyzeForLayer)
     return;
 
   TRACE_EVENT1("cc", "RecordingSource::DetermineIfSolidColor", "opcount",
                display_list_->op_count());
-  is_solid_color_ =
-      display_list_->GetColorIfSolidInRect(gfx::Rect(GetSize()), &solid_color_);
+  is_solid_color_ = display_list_->GetColorIfSolidInRect(
+      gfx::Rect(GetSize()), &solid_color_, kMaxOpsToAnalyzeForLayer);
 }
 
 }  // namespace cc
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc
index 506b3396..ec81333 100644
--- a/cc/layers/surface_layer.cc
+++ b/cc/layers/surface_layer.cc
@@ -12,10 +12,10 @@
 #include "base/trace_event/trace_event.h"
 #include "cc/layers/surface_layer_impl.h"
 #include "cc/output/swap_promise.h"
-#include "cc/surfaces/surface_sequence_generator.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/swap_promise_manager.h"
 #include "cc/trees/task_runner_provider.h"
+#include "components/viz/common/surfaces/surface_sequence_generator.h"
 
 namespace cc {
 
@@ -52,11 +52,12 @@
 };
 
 scoped_refptr<SurfaceLayer> SurfaceLayer::Create(
-    scoped_refptr<SurfaceReferenceFactory> ref_factory) {
+    scoped_refptr<viz::SurfaceReferenceFactory> ref_factory) {
   return make_scoped_refptr(new SurfaceLayer(std::move(ref_factory)));
 }
 
-SurfaceLayer::SurfaceLayer(scoped_refptr<SurfaceReferenceFactory> ref_factory)
+SurfaceLayer::SurfaceLayer(
+    scoped_refptr<viz::SurfaceReferenceFactory> ref_factory)
     : ref_factory_(std::move(ref_factory)) {}
 
 SurfaceLayer::~SurfaceLayer() {
diff --git a/cc/layers/surface_layer.h b/cc/layers/surface_layer.h
index 565b712..e43fcb3 100644
--- a/cc/layers/surface_layer.h
+++ b/cc/layers/surface_layer.h
@@ -8,8 +8,8 @@
 #include "base/macros.h"
 #include "cc/cc_export.h"
 #include "cc/layers/layer.h"
-#include "cc/surfaces/surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace cc {
@@ -19,7 +19,7 @@
 class CC_EXPORT SurfaceLayer : public Layer {
  public:
   static scoped_refptr<SurfaceLayer> Create(
-      scoped_refptr<SurfaceReferenceFactory> ref_factory);
+      scoped_refptr<viz::SurfaceReferenceFactory> ref_factory);
 
   void SetPrimarySurfaceInfo(const viz::SurfaceInfo& surface_info);
   void SetFallbackSurfaceInfo(const viz::SurfaceInfo& surface_info);
@@ -33,7 +33,8 @@
   void SetLayerTreeHost(LayerTreeHost* host) override;
   void PushPropertiesTo(LayerImpl* layer) override;
 
-  scoped_refptr<SurfaceReferenceFactory> surface_reference_factory() const {
+  scoped_refptr<viz::SurfaceReferenceFactory> surface_reference_factory()
+      const {
     return ref_factory_;
   }
 
@@ -46,7 +47,8 @@
   }
 
  protected:
-  explicit SurfaceLayer(scoped_refptr<SurfaceReferenceFactory> ref_factory);
+  explicit SurfaceLayer(
+      scoped_refptr<viz::SurfaceReferenceFactory> ref_factory);
   bool HasDrawableContent() const override;
 
  private:
@@ -57,7 +59,7 @@
   viz::SurfaceInfo fallback_surface_info_;
   base::Closure fallback_reference_returner_;
 
-  scoped_refptr<SurfaceReferenceFactory> ref_factory_;
+  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory_;
   bool stretch_content_to_fill_bounds_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(SurfaceLayer);
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index 6e0d408..f5fa3bb 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -16,7 +16,6 @@
 #include "cc/layers/surface_layer.h"
 #include "cc/layers/surface_layer_impl.h"
 #include "cc/output/compositor_frame.h"
-#include "cc/surfaces/sequence_surface_reference_factory.h"
 #include "cc/test/fake_impl_task_runner_provider.h"
 #include "cc/test/fake_layer_tree_host.h"
 #include "cc/test/fake_layer_tree_host_client.h"
@@ -25,6 +24,7 @@
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_host.h"
+#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_info.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -75,14 +75,15 @@
   FakeLayerTreeHostImpl host_impl_;
 };
 
-class MockSurfaceReferenceFactory : public SequenceSurfaceReferenceFactory {
+class MockSurfaceReferenceFactory
+    : public viz::SequenceSurfaceReferenceFactory {
  public:
   MockSurfaceReferenceFactory() {}
 
   // SequenceSurfaceReferenceFactory implementation.
-  MOCK_CONST_METHOD1(SatisfySequence, void(const SurfaceSequence&));
+  MOCK_CONST_METHOD1(SatisfySequence, void(const viz::SurfaceSequence&));
   MOCK_CONST_METHOD2(RequireSequence,
-                     void(const viz::SurfaceId&, const SurfaceSequence&));
+                     void(const viz::SurfaceId&, const viz::SurfaceSequence&));
 
  protected:
   ~MockSurfaceReferenceFactory() override = default;
@@ -92,7 +93,8 @@
 };
 
 // Check that one surface can be referenced by multiple LayerTreeHosts, and
-// each will create its own SurfaceSequence that's satisfied on destruction.
+// each will create its own viz::SurfaceSequence that's satisfied on
+// destruction.
 TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) {
   const base::UnguessableToken kArbitraryToken =
       base::UnguessableToken::Create();
@@ -100,8 +102,8 @@
       viz::SurfaceId(kArbitraryFrameSinkId,
                      viz::LocalSurfaceId(1, kArbitraryToken)),
       1.f, gfx::Size(1, 1));
-  const SurfaceSequence expected_seq1(viz::FrameSinkId(1, 1), 1u);
-  const SurfaceSequence expected_seq2(viz::FrameSinkId(2, 2), 1u);
+  const viz::SurfaceSequence expected_seq1(viz::FrameSinkId(1, 1), 1u);
+  const viz::SurfaceSequence expected_seq2(viz::FrameSinkId(2, 2), 1u);
   const viz::SurfaceId expected_id(kArbitraryFrameSinkId,
                                    viz::LocalSurfaceId(1, kArbitraryToken));
 
@@ -160,7 +162,7 @@
 TEST_F(SurfaceLayerTest, SurfaceInfoPushProperties) {
   // We use a nice mock here because we are not really interested in calls to
   // MockSurfaceReferenceFactory and we don't want warnings printed.
-  scoped_refptr<SurfaceReferenceFactory> ref_factory =
+  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory =
       new testing::NiceMock<MockSurfaceReferenceFactory>();
 
   scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create(ref_factory);
@@ -222,7 +224,7 @@
 TEST_F(SurfaceLayerTest, CheckSurfaceReferencesForClonedLayer) {
   // We use a nice mock here because we are not really interested in calls to
   // MockSurfaceReferenceFactory and we don't want warnings printed.
-  scoped_refptr<SurfaceReferenceFactory> ref_factory =
+  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory =
       new testing::NiceMock<MockSurfaceReferenceFactory>();
 
   const viz::SurfaceId old_surface_id(
@@ -292,7 +294,7 @@
 TEST_F(SurfaceLayerTest, CheckNeedsSurfaceIdsSyncForClonedLayers) {
   // We use a nice mock here because we are not really interested in calls to
   // MockSurfaceReferenceFactory and we don't want warnings printed.
-  scoped_refptr<SurfaceReferenceFactory> ref_factory =
+  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory =
       new testing::NiceMock<MockSurfaceReferenceFactory>();
 
   const viz::SurfaceInfo surface_info(
@@ -349,7 +351,7 @@
   EXPECT_THAT(layer_tree_host_->SurfaceLayerIds(), SizeIs(0));
 }
 
-// Check that SurfaceSequence is sent through swap promise.
+// Check that viz::SurfaceSequence is sent through swap promise.
 class SurfaceLayerSwapPromise : public LayerTreeTest {
  public:
   SurfaceLayerSwapPromise()
@@ -374,7 +376,7 @@
     testing::Mock::VerifyAndClearExpectations(ref_factory_.get());
 
     // Add the layer to the tree. A sequence must be required.
-    SurfaceSequence expected_seq(kArbitraryFrameSinkId, 1u);
+    viz::SurfaceSequence expected_seq(kArbitraryFrameSinkId, 1u);
     viz::SurfaceId expected_id(kArbitraryFrameSinkId,
                                viz::LocalSurfaceId(1, kArbitraryToken));
     EXPECT_CALL(*ref_factory_, SatisfySequence(_)).Times(0);
@@ -420,7 +422,7 @@
       base::UnguessableToken::Create();
 };
 
-// Check that SurfaceSequence is sent through swap promise.
+// Check that viz::SurfaceSequence is sent through swap promise.
 class SurfaceLayerSwapPromiseWithDraw : public SurfaceLayerSwapPromise {
  public:
   void ChangeTree() override {
@@ -442,8 +444,8 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithDraw);
 
-// Check that SurfaceSequence is sent through swap promise and resolved when
-// swap fails.
+// Check that viz::SurfaceSequence is sent through swap promise and resolved
+// when swap fails.
 class SurfaceLayerSwapPromiseWithoutDraw : public SurfaceLayerSwapPromise {
  public:
   SurfaceLayerSwapPromiseWithoutDraw() : SurfaceLayerSwapPromise() {}
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc
index 3fb69bb..93da499a 100644
--- a/cc/paint/display_item_list.cc
+++ b/cc/paint/display_item_list.cc
@@ -26,10 +26,6 @@
 
 namespace {
 
-// We don't perform per-layer solid color analysis when there are too many skia
-// operations.
-const int kOpCountThatIsOkToAnalyze = 10;
-
 bool GetCanvasClipBounds(SkCanvas* canvas, gfx::Rect* clip_bounds) {
   SkRect canvas_clip_bounds;
   if (!canvas->getLocalClipBounds(&canvas_clip_bounds))
@@ -86,10 +82,6 @@
   return sizeof(*this) + paint_op_buffer_.bytes_used();
 }
 
-bool DisplayItemList::ShouldBeAnalyzedForSolidColor() const {
-  return op_count() <= kOpCountThatIsOkToAnalyze;
-}
-
 void DisplayItemList::EmitTraceSnapshot() const {
   bool include_items;
   TRACE_EVENT_CATEGORY_GROUP_ENABLED(
@@ -196,7 +188,8 @@
 }
 
 bool DisplayItemList::GetColorIfSolidInRect(const gfx::Rect& rect,
-                                            SkColor* color) {
+                                            SkColor* color,
+                                            int max_ops_to_analyze) {
   std::vector<size_t>* indices_to_use = nullptr;
   std::vector<size_t> indices;
   if (!rect.Contains(rtree_.GetBounds())) {
@@ -205,8 +198,8 @@
   }
 
   base::Optional<SkColor> solid_color =
-      SolidColorAnalyzer::DetermineIfSolidColor(&paint_op_buffer_, rect,
-                                                indices_to_use);
+      SolidColorAnalyzer::DetermineIfSolidColor(
+          &paint_op_buffer_, rect, max_ops_to_analyze, indices_to_use);
   if (solid_color) {
     *color = *solid_color;
     return true;
diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h
index 46cc3291..4801bb9 100644
--- a/cc/paint/display_item_list.h
+++ b/cc/paint/display_item_list.h
@@ -113,7 +113,6 @@
   // This gives the total number of PaintOps.
   size_t op_count() const { return paint_op_buffer_.size(); }
   size_t BytesUsed() const;
-  bool ShouldBeAnalyzedForSolidColor() const;
 
   void EmitTraceSnapshot() const;
 
@@ -138,7 +137,12 @@
   // an empty state.
   sk_sp<PaintRecord> ReleaseAsRecord();
 
-  bool GetColorIfSolidInRect(const gfx::Rect& rect, SkColor* color);
+  // If a rectangle is solid color, returns that color. |max_ops_to_analyze|
+  // indicates the maximum number of draw ops we consider when determining if a
+  // rectangle is solid color.
+  bool GetColorIfSolidInRect(const gfx::Rect& rect,
+                             SkColor* color,
+                             int max_ops_to_analyze = 1);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithNoOps);
diff --git a/cc/paint/solid_color_analyzer.cc b/cc/paint/solid_color_analyzer.cc
index 9aac466a..89c3baf 100644
--- a/cc/paint/solid_color_analyzer.cc
+++ b/cc/paint/solid_color_analyzer.cc
@@ -10,8 +10,6 @@
 
 namespace cc {
 namespace {
-const int kMaxOpsToAnalyze = 1;
-
 bool ActsLikeClear(SkBlendMode mode, unsigned src_alpha) {
   switch (mode) {
     case SkBlendMode::kClear:
@@ -133,6 +131,7 @@
 base::Optional<SkColor> SolidColorAnalyzer::DetermineIfSolidColor(
     const PaintOpBuffer* buffer,
     const gfx::Rect& rect,
+    int max_ops_to_analyze,
     const std::vector<size_t>* indices) {
   if (buffer->size() == 0 || (indices && indices->empty()))
     return SK_ColorTRANSPARENT;
@@ -212,7 +211,7 @@
         return base::nullopt;
 
       case PaintOpType::DrawRect: {
-        if (++num_ops > kMaxOpsToAnalyze)
+        if (++num_ops > max_ops_to_analyze)
           return base::nullopt;
         const DrawRectOp* rect_op = static_cast<const DrawRectOp*>(op);
         CheckIfSolidRect(canvas, rect_op->rect, rect_op->flags, &is_solid,
@@ -220,7 +219,7 @@
         break;
       }
       case PaintOpType::DrawColor: {
-        if (++num_ops > kMaxOpsToAnalyze)
+        if (++num_ops > max_ops_to_analyze)
           return base::nullopt;
         const DrawColorOp* color_op = static_cast<const DrawColorOp*>(op);
         CheckIfSolidColor(canvas, color_op->color, color_op->mode, &is_solid,
diff --git a/cc/paint/solid_color_analyzer.h b/cc/paint/solid_color_analyzer.h
index f0d9f26..2c77c14 100644
--- a/cc/paint/solid_color_analyzer.h
+++ b/cc/paint/solid_color_analyzer.h
@@ -22,6 +22,7 @@
   static base::Optional<SkColor> DetermineIfSolidColor(
       const PaintOpBuffer* buffer,
       const gfx::Rect& rect,
+      int max_ops_to_analyze,
       const std::vector<size_t>* indices = nullptr);
 };
 
diff --git a/cc/paint/solid_color_analyzer_unittest.cc b/cc/paint/solid_color_analyzer_unittest.cc
index a56d107..ce5d112 100644
--- a/cc/paint/solid_color_analyzer_unittest.cc
+++ b/cc/paint/solid_color_analyzer_unittest.cc
@@ -30,13 +30,13 @@
 
   bool IsSolidColor() {
     auto color =
-        SolidColorAnalyzer::DetermineIfSolidColor(&buffer_, rect_, nullptr);
+        SolidColorAnalyzer::DetermineIfSolidColor(&buffer_, rect_, 1, nullptr);
     return !!color;
   }
 
   SkColor GetColor() const {
     auto color =
-        SolidColorAnalyzer::DetermineIfSolidColor(&buffer_, rect_, nullptr);
+        SolidColorAnalyzer::DetermineIfSolidColor(&buffer_, rect_, 1, nullptr);
     EXPECT_TRUE(color);
     return color ? *color : SK_ColorTRANSPARENT;
   }
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index e5eed8cd..604fd1c 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -12,6 +12,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/base/devtools_instrumentation.h"
@@ -270,6 +271,10 @@
 bool Scheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) {
   TRACE_EVENT1("cc,benchmark", "Scheduler::BeginFrame", "args", args.AsValue());
 
+  // TEMPORARY: Compositor state for debugging BeginMainFrame renderer hang.
+  // TODO(sunnyps): Remove after fixing https://crbug.com/622080
+  debug_begin_frame_received_at_ = Now();
+
   if (!state_machine_.BeginFrameNeeded()) {
     TRACE_EVENT_INSTANT0("cc", "Scheduler::BeginFrameDropped",
                          TRACE_EVENT_SCOPE_THREAD);
@@ -690,6 +695,12 @@
         break;
       }
     }
+
+    // TEMPORARY: Compositor state for debugging BeginMainFrame renderer hang.
+    // TODO(sunnyps): Remove after fixing https://crbug.com/622080
+    if (action != SchedulerStateMachine::ACTION_NONE) {
+      debug_actions_.SaveToBuffer(action);
+    }
   } while (action != SchedulerStateMachine::ACTION_NONE);
 
   ScheduleBeginImplFrameDeadlineIfNeeded();
@@ -697,9 +708,16 @@
 
   // TEMPORARY: Compositor state for debugging BeginMainFrame renderer hang.
   // TODO(sunnyps): Remove after fixing https://crbug.com/622080
-  base::debug::SetCrashKeyValue(
-      kBeginMainFrameHangCompositorState,
-      state_machine_.CrashKeyValueForBeginMainFrameHang());
+  std::string state_dump = state_machine_.CrashKeyValueForBeginMainFrameHang();
+  base::StringAppendF(
+      &state_dump, ",%f,%d,%d,%d",
+      (Now() - debug_begin_frame_received_at_).InMillisecondsF(),
+      skipped_last_frame_to_reduce_latency_,
+      skipped_last_frame_missed_exceeded_deadline_, stopped_);
+  for (auto it = debug_actions_.Begin(); it; ++it)
+    base::StringAppendF(&state_dump, ",%d", **it);
+
+  base::debug::SetCrashKeyValue(kBeginMainFrameHangCompositorState, state_dump);
 }
 
 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index aa1aad6a..97ba607b 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -12,6 +12,7 @@
 #include "base/cancelable_callback.h"
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "cc/base/ring_buffer.h"
 #include "cc/cc_export.h"
 #include "cc/output/begin_frame_args.h"
 #include "cc/scheduler/begin_frame_source.h"
@@ -198,6 +199,11 @@
   SchedulerStateMachine::Action inside_action_ =
       SchedulerStateMachine::ACTION_NONE;
 
+  // TEMPORARY: Compositor state for debugging BeginMainFrame renderer hang.
+  // TODO(sunnyps): Remove after fixing https://crbug.com/622080
+  base::TimeTicks debug_begin_frame_received_at_;
+  RingBuffer<SchedulerStateMachine::Action, 10> debug_actions_;
+
   bool stopped_ = false;
 
  private:
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 6cbaf386..96695c6 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -241,11 +241,12 @@
 // TODO(sunnyps): Remove after fixing https://crbug.com/622080
 std::string SchedulerStateMachine::CrashKeyValueForBeginMainFrameHang() const {
   return base::StringPrintf(
-      "%d,%d,%d,%d,%d,%d,%d,%d,%d", begin_impl_frame_state_,
+      "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", begin_impl_frame_state_,
       begin_main_frame_state_, layer_tree_frame_sink_state_,
       pending_submit_frames_, visible_, has_pending_tree_,
       pending_tree_is_ready_for_activation_, active_tree_needs_first_draw_,
-      begin_frame_source_paused_);
+      begin_frame_source_paused_, needs_redraw_, needs_prepare_tiles_,
+      needs_one_begin_impl_frame_);
 }
 
 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
diff --git a/cc/surfaces/BUILD.gn b/cc/surfaces/BUILD.gn
index 4dfcc177..4301ca1 100644
--- a/cc/surfaces/BUILD.gn
+++ b/cc/surfaces/BUILD.gn
@@ -4,25 +4,6 @@
 
 import("//cc/cc.gni")
 
-cc_source_set("surface_id") {
-  sources = [
-    "surface_reference.cc",
-    "surface_reference.h",
-    "surface_reference_factory.h",
-    "surface_reference_owner.h",
-    "surface_sequence.h",
-    "surface_sequence_generator.cc",
-    "surface_sequence_generator.h",
-  ]
-
-  deps = [
-    "//base",
-    "//components/viz/common",
-    "//mojo/public/cpp/bindings:struct_traits",
-    "//ui/gfx/geometry:geometry",
-  ]
-}
-
 cc_component("surfaces") {
   output_name = "cc_surfaces"
   sources = [
@@ -32,8 +13,6 @@
     "primary_begin_frame_source.h",
     "referenced_surface_tracker.cc",
     "referenced_surface_tracker.h",
-    "sequence_surface_reference_factory.cc",
-    "sequence_surface_reference_factory.h",
     "stub_surface_reference_factory.cc",
     "stub_surface_reference_factory.h",
     "surface.cc",
@@ -49,6 +28,8 @@
     "surface_hittest_delegate.h",
     "surface_manager.cc",
     "surface_manager.h",
+    "surface_reference.cc",
+    "surface_reference.h",
     "surface_resource_holder.cc",
     "surface_resource_holder.h",
     "surface_resource_holder_client.h",
@@ -58,14 +39,13 @@
   defines = [ "CC_SURFACES_IMPLEMENTATION=1" ]
 
   public_deps = [
-    ":surface_id",
+    "//components/viz/common",
   ]
 
   deps = [
     "//base",
     "//base/third_party/dynamic_annotations",
     "//cc",
-    "//components/viz/common",
     "//gpu/command_buffer/client:gles2_interface",
     "//gpu/command_buffer/common",
     "//gpu/vulkan:features",
diff --git a/cc/surfaces/direct_surface_reference_factory.cc b/cc/surfaces/direct_surface_reference_factory.cc
index d107925..ef8be5c 100644
--- a/cc/surfaces/direct_surface_reference_factory.cc
+++ b/cc/surfaces/direct_surface_reference_factory.cc
@@ -16,7 +16,7 @@
 
 DirectSurfaceReferenceFactory::~DirectSurfaceReferenceFactory() = default;
 void DirectSurfaceReferenceFactory::SatisfySequence(
-    const SurfaceSequence& sequence) const {
+    const viz::SurfaceSequence& sequence) const {
   if (!manager_)
     return;
   manager_->SatisfySequence(sequence);
@@ -24,7 +24,7 @@
 
 void DirectSurfaceReferenceFactory::RequireSequence(
     const viz::SurfaceId& surface_id,
-    const SurfaceSequence& sequence) const {
+    const viz::SurfaceSequence& sequence) const {
   manager_->RequireSequence(surface_id, sequence);
 }
 
diff --git a/cc/surfaces/direct_surface_reference_factory.h b/cc/surfaces/direct_surface_reference_factory.h
index d3da125..2cc52ce 100644
--- a/cc/surfaces/direct_surface_reference_factory.h
+++ b/cc/surfaces/direct_surface_reference_factory.h
@@ -5,10 +5,11 @@
 #ifndef CC_SURFACES_DIRECT_SURFACE_REFERENCE_FACTORY_H_
 #define CC_SURFACES_DIRECT_SURFACE_REFERENCE_FACTORY_H_
 
-#include "cc/surfaces/sequence_surface_reference_factory.h"
+#include "base/compiler_specific.h"
 #include "cc/surfaces/surface_manager.h"
-#include "cc/surfaces/surface_sequence.h"
+#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 
 namespace cc {
 
@@ -18,7 +19,7 @@
 // You probably don't need to instantiate this class directly.
 // Use SurfaceManager::reference_factory() instead.
 class CC_SURFACES_EXPORT DirectSurfaceReferenceFactory final
-    : public SequenceSurfaceReferenceFactory {
+    : public NON_EXPORTED_BASE(viz::SequenceSurfaceReferenceFactory) {
  public:
   explicit DirectSurfaceReferenceFactory(base::WeakPtr<SurfaceManager> manager);
 
@@ -26,9 +27,9 @@
   ~DirectSurfaceReferenceFactory() override;
 
   // SequenceSurfaceReferenceFactory implementation:
-  void SatisfySequence(const SurfaceSequence& sequence) const override;
+  void SatisfySequence(const viz::SurfaceSequence& sequence) const override;
   void RequireSequence(const viz::SurfaceId& surface_id,
-                       const SurfaceSequence& sequence) const override;
+                       const viz::SurfaceSequence& sequence) const override;
 
   base::WeakPtr<SurfaceManager> manager_;
 
diff --git a/cc/surfaces/sequence_surface_reference_factory.h b/cc/surfaces/sequence_surface_reference_factory.h
deleted file mode 100644
index 1ad6f8f..0000000
--- a/cc/surfaces/sequence_surface_reference_factory.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_SURFACES_SEQUENCE_SURFACE_REFERENCE_FACTORY_H_
-#define CC_SURFACES_SEQUENCE_SURFACE_REFERENCE_FACTORY_H_
-
-#include "cc/surfaces/surface_reference_factory.h"
-#include "cc/surfaces/surface_sequence.h"
-#include "cc/surfaces/surfaces_export.h"
-
-namespace cc {
-
-// A surface reference factory that uses SurfaceSequence.
-class CC_SURFACES_EXPORT SequenceSurfaceReferenceFactory
-    : public NON_EXPORTED_BASE(SurfaceReferenceFactory) {
- public:
-  SequenceSurfaceReferenceFactory() = default;
-
-  // SurfaceReferenceFactory implementation:
-  base::Closure CreateReference(
-      SurfaceReferenceOwner* owner,
-      const viz::SurfaceId& surface_id) const override;
-
- protected:
-  ~SequenceSurfaceReferenceFactory() override = default;
-
- private:
-  virtual void RequireSequence(const viz::SurfaceId& surface_id,
-                               const SurfaceSequence& sequence) const = 0;
-  virtual void SatisfySequence(const SurfaceSequence& sequence) const = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(SequenceSurfaceReferenceFactory);
-};
-
-}  // namespace cc
-
-#endif  // CC_SURFACES_SEQUENCE_SURFACE_REFERENCE_FACTORY_H_
diff --git a/cc/surfaces/stub_surface_reference_factory.cc b/cc/surfaces/stub_surface_reference_factory.cc
index 29b6313..31d5617 100644
--- a/cc/surfaces/stub_surface_reference_factory.cc
+++ b/cc/surfaces/stub_surface_reference_factory.cc
@@ -9,7 +9,7 @@
 namespace cc {
 
 base::Closure StubSurfaceReferenceFactory::CreateReference(
-    SurfaceReferenceOwner* owner,
+    viz::SurfaceReferenceOwner* owner,
     const viz::SurfaceId& surface_id) const {
   return base::Closure();
 }
diff --git a/cc/surfaces/stub_surface_reference_factory.h b/cc/surfaces/stub_surface_reference_factory.h
index 62ff788..9eb67c0 100644
--- a/cc/surfaces/stub_surface_reference_factory.h
+++ b/cc/surfaces/stub_surface_reference_factory.h
@@ -6,22 +6,22 @@
 #define CC_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
 
 #include "base/compiler_specific.h"
-#include "cc/surfaces/surface_reference_factory.h"
 #include "cc/surfaces/surfaces_export.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
 
 namespace cc {
 
 // A stub implementation that creates a closure which does nothing.
-// TODO(kylechar): Delete this class and all usage of SurfaceReferenceFactory
-// when surface references are enabled by default.
+// TODO(kylechar): Delete this class and all usage of
+// viz::SurfaceReferenceFactory when surface references are enabled by default.
 class CC_SURFACES_EXPORT StubSurfaceReferenceFactory
-    : public NON_EXPORTED_BASE(SurfaceReferenceFactory) {
+    : public NON_EXPORTED_BASE(viz::SurfaceReferenceFactory) {
  public:
   StubSurfaceReferenceFactory() = default;
 
-  // SurfaceReferenceFactory:
+  // viz::SurfaceReferenceFactory:
   base::Closure CreateReference(
-      SurfaceReferenceOwner* owner,
+      viz::SurfaceReferenceOwner* owner,
       const viz::SurfaceId& surface_id) const override;
 
  protected:
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index 5cf26f3e..6e1b1aa2 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -355,15 +355,15 @@
                                              damage_rect);
 }
 
-void Surface::AddDestructionDependency(SurfaceSequence sequence) {
+void Surface::AddDestructionDependency(viz::SurfaceSequence sequence) {
   destruction_dependencies_.push_back(sequence);
 }
 
 void Surface::SatisfyDestructionDependencies(
-    base::flat_set<SurfaceSequence>* sequences,
+    base::flat_set<viz::SurfaceSequence>* sequences,
     base::flat_set<viz::FrameSinkId>* valid_frame_sink_ids) {
   base::EraseIf(destruction_dependencies_,
-                [sequences, valid_frame_sink_ids](SurfaceSequence seq) {
+                [sequences, valid_frame_sink_ids](viz::SurfaceSequence seq) {
                   return (!!sequences->erase(seq) ||
                           !valid_frame_sink_ids->count(seq.frame_sink_id));
                 });
diff --git a/cc/surfaces/surface.h b/cc/surfaces/surface.h
index 4bfd8a0..da2712d6 100644
--- a/cc/surfaces/surface.h
+++ b/cc/surfaces/surface.h
@@ -21,10 +21,10 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/surfaces/surface_dependency_deadline.h"
-#include "cc/surfaces/surface_sequence.h"
 #include "cc/surfaces/surfaces_export.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace ui {
@@ -121,14 +121,14 @@
   void RunDrawCallback();
   void RunWillDrawCallback(const gfx::Rect& damage_rect);
 
-  // Add a SurfaceSequence that must be satisfied before the Surface is
+  // Add a viz::SurfaceSequence that must be satisfied before the Surface is
   // destroyed.
-  void AddDestructionDependency(SurfaceSequence sequence);
+  void AddDestructionDependency(viz::SurfaceSequence sequence);
 
   // Satisfy all destruction dependencies that are contained in sequences, and
   // remove them from sequences.
   void SatisfyDestructionDependencies(
-      base::flat_set<SurfaceSequence>* sequences,
+      base::flat_set<viz::SurfaceSequence>* sequences,
       base::flat_set<viz::FrameSinkId>* valid_id_namespaces);
   size_t GetDestructionDependencyCount() const {
     return destruction_dependencies_.size();
@@ -215,7 +215,7 @@
   int frame_index_;
   bool closed_ = false;
   const bool needs_sync_tokens_;
-  std::vector<SurfaceSequence> destruction_dependencies_;
+  std::vector<viz::SurfaceSequence> destruction_dependencies_;
 
   base::flat_set<viz::SurfaceId> activation_dependencies_;
   base::flat_set<viz::SurfaceId> late_activation_dependencies_;
diff --git a/cc/surfaces/surface_manager.cc b/cc/surfaces/surface_manager.cc
index ee007a04..f6a0c35c 100644
--- a/cc/surfaces/surface_manager.cc
+++ b/cc/surfaces/surface_manager.cc
@@ -114,7 +114,7 @@
 }
 
 void SurfaceManager::RequireSequence(const viz::SurfaceId& surface_id,
-                                     const SurfaceSequence& sequence) {
+                                     const viz::SurfaceSequence& sequence) {
   auto* surface = GetSurfaceForId(surface_id);
   if (!surface) {
     DLOG(ERROR) << "Attempting to require callback on nonexistent surface";
@@ -123,7 +123,7 @@
   surface->AddDestructionDependency(sequence);
 }
 
-void SurfaceManager::SatisfySequence(const SurfaceSequence& sequence) {
+void SurfaceManager::SatisfySequence(const viz::SurfaceSequence& sequence) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(lifetime_type_, LifetimeType::SEQUENCES);
   satisfied_sequences_.insert(sequence);
diff --git a/cc/surfaces/surface_manager.h b/cc/surfaces/surface_manager.h
index 75034fd..c8c2ca2 100644
--- a/cc/surfaces/surface_manager.h
+++ b/cc/surfaces/surface_manager.h
@@ -22,11 +22,11 @@
 #include "cc/surfaces/surface_dependency_tracker.h"
 #include "cc/surfaces/surface_observer.h"
 #include "cc/surfaces/surface_reference.h"
-#include "cc/surfaces/surface_reference_factory.h"
-#include "cc/surfaces/surface_sequence.h"
 #include "cc/surfaces/surfaces_export.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 
 #if DCHECK_IS_ON()
 #include <iosfwd>
@@ -118,11 +118,11 @@
   // Require that the given sequence number must be satisfied (using
   // SatisfySequence) before the given surface can be destroyed.
   void RequireSequence(const viz::SurfaceId& surface_id,
-                       const SurfaceSequence& sequence);
+                       const viz::SurfaceSequence& sequence);
 
   // Satisfies the given sequence number. Once all sequence numbers that
   // a surface depends on are satisfied, the surface can be destroyed.
-  void SatisfySequence(const SurfaceSequence& sequence);
+  void SatisfySequence(const viz::SurfaceSequence& sequence);
 
   void RegisterFrameSinkId(const viz::FrameSinkId& frame_sink_id);
 
@@ -175,7 +175,7 @@
   const base::flat_set<viz::SurfaceId>& GetSurfacesThatReferenceChild(
       const viz::SurfaceId& surface_id) const;
 
-  const scoped_refptr<SurfaceReferenceFactory>& reference_factory() {
+  const scoped_refptr<viz::SurfaceReferenceFactory>& reference_factory() {
     return reference_factory_;
   }
 
@@ -266,7 +266,7 @@
 
   // Set of SurfaceSequences that have been satisfied by a frame but not yet
   // waited on.
-  base::flat_set<SurfaceSequence> satisfied_sequences_;
+  base::flat_set<viz::SurfaceSequence> satisfied_sequences_;
 
   // Set of valid FrameSinkIds. When a viz::FrameSinkId is removed from
   // this set, any remaining (surface) sequences with that viz::FrameSinkId are
@@ -283,7 +283,7 @@
 
   // The DirectSurfaceReferenceFactory that uses this manager to create surface
   // references.
-  scoped_refptr<SurfaceReferenceFactory> reference_factory_;
+  scoped_refptr<viz::SurfaceReferenceFactory> reference_factory_;
 
   // Keeps track of surface references for a surface. The graph of references is
   // stored in both directions, so we know the parents and children for each
diff --git a/cc/surfaces/surface_reference.h b/cc/surfaces/surface_reference.h
index b381a20..7630b43 100644
--- a/cc/surfaces/surface_reference.h
+++ b/cc/surfaces/surface_reference.h
@@ -8,12 +8,13 @@
 #include <string>
 
 #include "base/hash.h"
+#include "cc/surfaces/surfaces_export.h"
 #include "components/viz/common/surfaces/surface_id.h"
 
 namespace cc {
 
 // Hold a reference from an embedding (parent) to embedded (child) surface.
-class SurfaceReference {
+class CC_SURFACES_EXPORT SurfaceReference {
  public:
   SurfaceReference();
   SurfaceReference(const viz::SurfaceId& parent_id,
diff --git a/cc/surfaces/surface_reference_owner.h b/cc/surfaces/surface_reference_owner.h
deleted file mode 100644
index 8aa791c..0000000
--- a/cc/surfaces/surface_reference_owner.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_SURFACES_SURFACE_REFERENCE_OWNER_H_
-#define CC_SURFACES_SURFACE_REFERENCE_OWNER_H_
-
-#include "cc/surfaces/surface_sequence_generator.h"
-
-namespace cc {
-
-// Implementations of this interface can be passed to
-// SurfaceReferenceFactory::CreateReference as the reference owner.
-class SurfaceReferenceOwner {
- public:
-  virtual ~SurfaceReferenceOwner() {}
-
-  virtual SurfaceSequenceGenerator* GetSurfaceSequenceGenerator() = 0;
-};
-
-}  // namespace cc
-
-#endif  // CC_SURFACES_SURFACE_REFERENCE_OWNER_H_
diff --git a/cc/surfaces/surface_sequence_generator_unittest.cc b/cc/surfaces/surface_sequence_generator_unittest.cc
index 18cbbca..828a38a76 100644
--- a/cc/surfaces/surface_sequence_generator_unittest.cc
+++ b/cc/surfaces/surface_sequence_generator_unittest.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/surfaces/surface_sequence_generator.h"
+#include "components/viz/common/surfaces/surface_sequence_generator.h"
 
-#include "cc/surfaces/surface_sequence.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
@@ -13,10 +13,10 @@
 static constexpr viz::FrameSinkId kArbitraryFrameSinkId(1, 1);
 
 TEST(SurfaceSequenceGeneratorTest, Basic) {
-  SurfaceSequenceGenerator generator;
+  viz::SurfaceSequenceGenerator generator;
   generator.set_frame_sink_id(kArbitraryFrameSinkId);
-  SurfaceSequence sequence1 = generator.CreateSurfaceSequence();
-  SurfaceSequence sequence2 = generator.CreateSurfaceSequence();
+  viz::SurfaceSequence sequence1 = generator.CreateSurfaceSequence();
+  viz::SurfaceSequence sequence2 = generator.CreateSurfaceSequence();
   EXPECT_NE(sequence1, sequence2);
 }
 
diff --git a/cc/trees/blocking_task_runner.cc b/cc/trees/blocking_task_runner.cc
index 78ef04e..b6c8a49 100644
--- a/cc/trees/blocking_task_runner.cc
+++ b/cc/trees/blocking_task_runner.cc
@@ -34,19 +34,19 @@
 }
 
 bool BlockingTaskRunner::PostTask(const tracked_objects::Location& from_here,
-                                  const base::Closure& task) {
+                                  base::OnceClosure task) {
   base::AutoLock lock(lock_);
   DCHECK(task_runner_.get() || capture_);
   if (!capture_)
-    return task_runner_->PostTask(from_here, task);
-  captured_tasks_.push_back(task);
+    return task_runner_->PostTask(from_here, std::move(task));
+  captured_tasks_.push_back(std::move(task));
   return true;
 }
 
 void BlockingTaskRunner::SetCapture(bool capture) {
   DCHECK(BelongsToCurrentThread());
 
-  std::vector<base::Closure> tasks;
+  std::vector<base::OnceClosure> tasks;
 
   {
     base::AutoLock lock(lock_);
@@ -60,7 +60,7 @@
     tasks.swap(captured_tasks_);
   }
   for (size_t i = 0; i < tasks.size(); ++i)
-    tasks[i].Run();
+    std::move(tasks[i]).Run();
 }
 
 BlockingTaskRunner::CapturePostTasks::CapturePostTasks(
diff --git a/cc/trees/blocking_task_runner.h b/cc/trees/blocking_task_runner.h
index d34e2f20..25d227a6 100644
--- a/cc/trees/blocking_task_runner.h
+++ b/cc/trees/blocking_task_runner.h
@@ -76,7 +76,7 @@
   // until the capturing stops. At that time the tasks will be run directly
   // instead of being posted to the SingleThreadTaskRunner.
   bool PostTask(const tracked_objects::Location& from_here,
-                const base::Closure& task);
+                base::OnceClosure task);
 
  private:
   explicit BlockingTaskRunner(
@@ -89,7 +89,7 @@
 
   base::Lock lock_;
   int capture_;
-  std::vector<base::Closure> captured_tasks_;
+  std::vector<base::OnceClosure> captured_tasks_;
 
   DISALLOW_COPY_AND_ASSIGN(BlockingTaskRunner);
 };
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 39c74932..cf65cad 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -250,8 +250,7 @@
   swap_promise_manager_.QueueSwapPromise(std::move(swap_promise));
 }
 
-SurfaceSequenceGenerator*
-LayerTreeHost::GetSurfaceSequenceGenerator() {
+viz::SurfaceSequenceGenerator* LayerTreeHost::GetSurfaceSequenceGenerator() {
   return &surface_sequence_generator_;
 }
 
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index a253e3e..df5f9a4 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -35,8 +35,6 @@
 #include "cc/layers/layer_list_iterator.h"
 #include "cc/output/layer_tree_frame_sink.h"
 #include "cc/output/swap_promise.h"
-#include "cc/surfaces/surface_reference_owner.h"
-#include "cc/surfaces/surface_sequence_generator.h"
 #include "cc/trees/compositor_mode.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_settings.h"
@@ -45,6 +43,8 @@
 #include "cc/trees/swap_promise_manager.h"
 #include "cc/trees/target_property.h"
 #include "components/viz/common/quads/resource_format.h"
+#include "components/viz/common/surfaces/surface_reference_owner.h"
+#include "components/viz/common/surfaces/surface_sequence_generator.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -65,8 +65,9 @@
 struct RenderingStats;
 struct ScrollAndScaleSet;
 
-class CC_EXPORT LayerTreeHost : public NON_EXPORTED_BASE(SurfaceReferenceOwner),
-                                public NON_EXPORTED_BASE(MutatorHostClient) {
+class CC_EXPORT LayerTreeHost
+    : public NON_EXPORTED_BASE(viz::SurfaceReferenceOwner),
+      public NON_EXPORTED_BASE(MutatorHostClient) {
  public:
   struct CC_EXPORT InitParams {
     LayerTreeHostClient* client = nullptr;
@@ -457,8 +458,8 @@
   bool IsSingleThreaded() const;
   bool IsThreaded() const;
 
-  // SurfaceReferenceOwner implementation.
-  SurfaceSequenceGenerator* GetSurfaceSequenceGenerator() override;
+  // viz::SurfaceReferenceOwner implementation.
+  viz::SurfaceSequenceGenerator* GetSurfaceSequenceGenerator() override;
 
   // MutatorHostClient implementation.
   bool IsElementInList(ElementId element_id,
@@ -585,7 +586,7 @@
 
   TaskGraphRunner* task_graph_runner_;
 
-  SurfaceSequenceGenerator surface_sequence_generator_;
+  viz::SurfaceSequenceGenerator surface_sequence_generator_;
   uint32_t num_consecutive_frames_without_slow_paths_ = 0;
 
   scoped_refptr<Layer> root_layer_;
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index d31b85bd..9b35214 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -260,10 +260,7 @@
   return jitter;
 }
 
-enum PropertyTreeOption {
-  BUILD_PROPERTY_TREES_IF_NEEDED,
-  DONT_BUILD_PROPERTY_TREES
-};
+enum PropertyTreeOption { BUILD_PROPERTY_TREES, DONT_BUILD_PROPERTY_TREES };
 
 static void AddSurfaceToRenderSurfaceList(
     RenderSurfaceImpl* render_surface,
@@ -500,11 +497,11 @@
   inputs->render_surface_list->clear();
 
   const bool should_measure_property_tree_performance =
-      property_tree_option == BUILD_PROPERTY_TREES_IF_NEEDED;
+      property_tree_option == BUILD_PROPERTY_TREES;
 
   LayerImplList visible_layer_list;
   switch (property_tree_option) {
-    case BUILD_PROPERTY_TREES_IF_NEEDED: {
+    case BUILD_PROPERTY_TREES: {
       // The translation from layer to property trees is an intermediate
       // state. We will eventually get these data passed directly to the
       // compositor.
@@ -671,7 +668,9 @@
 
 void LayerTreeHostCommon::CalculateDrawPropertiesForTesting(
     CalcDrawPropsImplInputsForTesting* inputs) {
-  CalculateDrawPropertiesInternal(inputs, BUILD_PROPERTY_TREES_IF_NEEDED);
+  CalculateDrawPropertiesInternal(inputs, inputs->property_trees->needs_rebuild
+                                              ? BUILD_PROPERTY_TREES
+                                              : DONT_BUILD_PROPERTY_TREES);
 }
 
 PropertyTrees* GetPropertyTrees(Layer* layer) {
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index d488c7b..54bbaa91 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -248,20 +248,6 @@
         update_layer_list_impl(), property_trees);
   }
 
-  void ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(
-      LayerImpl* root_layer) {
-    gfx::Size device_viewport_size =
-        gfx::Size(root_layer->bounds().width(), root_layer->bounds().height());
-    render_surface_list_impl_.reset(new RenderSurfaceList);
-
-    DCHECK(!root_layer->bounds().IsEmpty());
-    LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root_layer, device_viewport_size, render_surface_list_impl_.get());
-    inputs.can_adjust_raster_scales = true;
-
-    LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
-  }
-
   void ExecuteCalculateDrawPropertiesWithoutAdjustingRasterScales(
       LayerImpl* root_layer) {
     gfx::Size device_viewport_size =
@@ -10191,5 +10177,63 @@
   EXPECT_EQ(gfx::Rect(10, 10), child->drawable_content_rect());
 }
 
+TEST_F(LayerTreeHostCommonTest, SurfaceContentsScaleChangeWithCopyRequestTest) {
+  LayerImpl* root = root_layer_for_testing();
+  LayerImpl* scale_layer = AddChild<LayerImpl>(root);
+  LayerImpl* copy_layer = AddChild<LayerImpl>(scale_layer);
+  LayerImpl* clip_layer = AddChild<LayerImpl>(copy_layer);
+  LayerImpl* test_layer = AddChild<LayerImpl>(clip_layer);
+
+  root->SetBounds(gfx::Size(150, 150));
+
+  scale_layer->SetBounds(gfx::Size(30, 30));
+  gfx::Transform transform;
+  transform.Scale(5.f, 5.f);
+  scale_layer->test_properties()->transform = transform;
+
+  // Need to persist the render surface after copy request is cleared.
+  copy_layer->test_properties()->force_render_surface = true;
+  copy_layer->test_properties()->copy_requests.push_back(
+      CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+
+  clip_layer->SetDrawsContent(true);
+  clip_layer->SetMasksToBounds(true);
+  clip_layer->SetBounds(gfx::Size(10, 10));
+
+  test_layer->SetDrawsContent(true);
+  test_layer->SetMasksToBounds(true);
+  test_layer->SetBounds(gfx::Size(20, 20));
+
+  ExecuteCalculateDrawPropertiesWithoutAdjustingRasterScales(root);
+
+  // Check surface with copy request draw properties.
+  EXPECT_EQ(gfx::Rect(50, 50), GetRenderSurface(copy_layer)->content_rect());
+  EXPECT_EQ(gfx::Transform(), GetRenderSurface(copy_layer)->draw_transform());
+  EXPECT_EQ(gfx::RectF(50.0f, 50.0f),
+            GetRenderSurface(copy_layer)->DrawableContentRect());
+
+  // Check test layer draw properties.
+  EXPECT_EQ(gfx::Rect(10, 10), test_layer->visible_layer_rect());
+  EXPECT_EQ(transform, test_layer->DrawTransform());
+  EXPECT_EQ(gfx::Rect(50, 50), test_layer->clip_rect());
+  EXPECT_EQ(gfx::Rect(50, 50), test_layer->drawable_content_rect());
+
+  // Clear the copy request and call UpdateSurfaceContentsScale.
+  host_impl()->active_tree()->property_trees()->effect_tree.ClearCopyRequests();
+  ExecuteCalculateDrawPropertiesWithoutAdjustingRasterScales(root);
+
+  // Check surface draw properties without copy request.
+  EXPECT_EQ(gfx::Rect(10, 10), GetRenderSurface(copy_layer)->content_rect());
+  EXPECT_EQ(transform, GetRenderSurface(copy_layer)->draw_transform());
+  EXPECT_EQ(gfx::RectF(50.0f, 50.0f),
+            GetRenderSurface(copy_layer)->DrawableContentRect());
+
+  // Check test layer draw properties without copy request.
+  EXPECT_EQ(gfx::Rect(10, 10), test_layer->visible_layer_rect());
+  EXPECT_EQ(gfx::Transform(), test_layer->DrawTransform());
+  EXPECT_EQ(gfx::Rect(10, 10), test_layer->clip_rect());
+  EXPECT_EQ(gfx::Rect(10, 10), test_layer->drawable_content_rect());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index d6325ba..4f9792c1 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -856,11 +856,19 @@
   bool use_transform_for_contents_scale =
       property_trees()->can_adjust_raster_scales ||
       effect_node->has_copy_request;
+  const gfx::Vector2dF old_scale = effect_node->surface_contents_scale;
   effect_node->surface_contents_scale =
       use_transform_for_contents_scale
           ? MathUtil::ComputeTransform2dScaleComponents(
                 transform_tree.ToScreen(transform_node->id), layer_scale_factor)
           : gfx::Vector2dF(layer_scale_factor, layer_scale_factor);
+
+  // If surface contents scale changes, draw transforms are no longer valid.
+  // Invalidates the draw transform cache and updates the clip for the surface.
+  if (old_scale != effect_node->surface_contents_scale) {
+    property_trees()->clip_tree.set_needs_update(true);
+    property_trees()->UpdateTransformTreeUpdateNumber();
+  }
 }
 
 EffectNode* EffectTree::FindNodeFromElementId(ElementId id) {
diff --git a/chrome/VERSION b/chrome/VERSION
index be1962727..b7399b3 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=61
 MINOR=0
-BUILD=3157
+BUILD=3158
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 779807b5..44c68f41 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -197,7 +197,6 @@
     public static final String NTP_OFFLINE_PAGES_FEATURE_NAME = "NTPOfflinePages";
     public static final String NTP_SHOW_GOOGLE_G_IN_OMNIBOX = "NTPShowGoogleGInOmnibox";
     public static final String NTP_SNIPPETS_INCREASED_VISIBILITY = "NTPSnippetsIncreasedVisibility";
-    public static final String OMNIBOX_SPARE_RENDERER = "OmniboxSpareRenderer";
     public static final String PAY_WITH_GOOGLE_V1 = "PayWithGoogleV1";
     public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps";
     public static final String SITE_NOTIFICATION_CHANNELS = "SiteNotificationChannels";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
index 87a8b12..fddb44e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
@@ -8,7 +8,7 @@
 
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
+import org.chromium.content.browser.ChildProcessCreationParams;
 
 /**
  * This is Application class for Monochrome.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
index e1e839f8..5dbfe443 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
@@ -255,27 +255,6 @@
     }
 
     /**
-     * Warms up a spare, empty RenderProcessHost that may be used for subsequent navigations.
-     *
-     * The spare RenderProcessHost will be used automatically in subsequent navigations.
-     * There is nothing further the WarmupManager needs to do to enable that use.
-     *
-     * This uses a different mechanism than createSpareWebContents, below, and is subject
-     * to fewer restrictions.
-     *
-     * This must be called from the UI thread.
-     */
-    public void createSpareRenderProcessHost(Profile profile) {
-        ThreadUtils.assertOnUiThread();
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_SPARE_RENDERER)) {
-            // Spare WebContents should not be used with spare RenderProcessHosts, but if one
-            // has been created, destroy it in order not to consume too many processes.
-            destroySpareWebContents();
-            nativeWarmupSpareRenderer(profile);
-        }
-    }
-
-    /**
      * Creates and initializes a spare WebContents, to be used in a subsequent navigation.
      *
      * This creates a renderer that is suitable for any navigation. It can be picked up by any tab.
@@ -341,5 +320,4 @@
     }
 
     private static native void nativePreconnectUrlAndSubresources(Profile profile, String url);
-    private static native void nativeWarmupSpareRenderer(Profile profile);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
index 7746751..68905ab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
@@ -565,7 +565,7 @@
                 .apply();
         RecordHistogram.recordBooleanHistogram(
                 "Android.DownloadManager.ShowStorageInfo", mShouldShowStorageInfoHeader);
-        filter(mFilter);
+        if (mLoadingDelegate.isLoaded()) filter(mFilter);
     }
 
     private DownloadDelegate getDownloadDelegate() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
index 3cb91bd..fb977ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
@@ -32,8 +32,7 @@
         mCategoryInfo = section.getCategoryInfo();
         mParentSection = section;
         mSuggestionsRanker = ranker;
-        setVisibilityInternal(
-                mCategoryInfo.getAdditionalAction() != ContentSuggestionsAdditionalAction.NONE);
+        setVisible(mCategoryInfo.getAdditionalAction() != ContentSuggestionsAdditionalAction.NONE);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java
index a07a2292..1809b653 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/AllDismissedItem.java
@@ -40,10 +40,6 @@
         visitor.visitAllDismissedItem();
     }
 
-    public void setVisible(boolean visible) {
-        setVisibilityInternal(visible);
-    }
-
     /**
      * ViewHolder for an item of type {@link ItemViewType#ALL_DISMISSED}.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/Footer.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/Footer.java
index 07d1a3d..dd851e9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/Footer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/Footer.java
@@ -37,10 +37,6 @@
         visitor.visitFooter();
     }
 
-    public void setVisible(boolean visible) {
-        setVisibilityInternal(visible);
-    }
-
     /**
      * The {@code ViewHolder} for the {@link Footer}.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index 6d44e90..88530ed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -15,14 +15,9 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder.PartialBindCallback;
-import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
-import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
 import org.chromium.chrome.browser.ntp.snippets.SectionHeaderViewHolder;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder;
-import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
-import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.browser.suggestions.TileGrid;
@@ -108,9 +103,6 @@
             mRoot.addChild(mBottomSpacer);
         }
 
-        RemoteSuggestionsStatusObserver suggestionsObserver = new RemoteSuggestionsStatusObserver();
-        mUiDelegate.addDestructionObserver(suggestionsObserver);
-
         updateAllDismissedVisibility();
         mRoot.setParent(this);
     }
@@ -230,8 +222,7 @@
     }
 
     private void updateAllDismissedVisibility() {
-        boolean showAllDismissed = hasAllBeenDismissed()
-                && mUiDelegate.getSuggestionsSource().areRemoteSuggestionsEnabled();
+        boolean showAllDismissed = hasAllBeenDismissed();
         mAllDismissed.setVisible(showAllDismissed);
         mFooter.setVisible(!showAllDismissed);
     }
@@ -318,24 +309,4 @@
     InnerNode getRootForTesting() {
         return mRoot;
     }
-
-    private class RemoteSuggestionsStatusObserver
-            extends SuggestionsSource.EmptyObserver implements DestructionObserver {
-        public RemoteSuggestionsStatusObserver() {
-            mUiDelegate.getSuggestionsSource().addObserver(this);
-        }
-
-        @Override
-        public void onCategoryStatusChanged(
-                @CategoryInt int category, @CategoryStatus int newStatus) {
-            if (!SnippetsBridge.isCategoryRemote(category)) return;
-
-            updateAllDismissedVisibility();
-        }
-
-        @Override
-        public void onDestroy() {
-            mUiDelegate.getSuggestionsSource().removeObserver(this);
-        }
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/OptionalLeaf.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/OptionalLeaf.java
index 26174cc7..19af66a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/OptionalLeaf.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/OptionalLeaf.java
@@ -67,7 +67,7 @@
      * initially considered hidden.
      */
     @CallSuper
-    protected void setVisibilityInternal(boolean visible) {
+    public void setVisible(boolean visible) {
         if (mVisible == visible) return;
         mVisible = visible;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java
index b1b39f0c..50e89fc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ProgressItem.java
@@ -28,8 +28,4 @@
     protected void visitOptionalItem(NodeVisitor visitor) {
         visitor.visitProgressItem();
     }
-
-    public void setVisible(boolean visible) {
-        setVisibilityInternal(visible);
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
index 4cc059122..cf3437a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
@@ -43,7 +43,7 @@
 
     public SectionList(SuggestionsUiDelegate uiDelegate, OfflinePageBridge offlinePageBridge) {
         mUiDelegate = uiDelegate;
-        mUiDelegate.getSuggestionsSource().addObserver(this);
+        mUiDelegate.getSuggestionsSource().setObserver(this);
         mOfflinePageBridge = offlinePageBridge;
 
         mUiDelegate.addDestructionObserver(new DestructionObserver() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
index 857c604..1a53583 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
@@ -15,10 +15,6 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
-import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
-import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
-import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
-import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.signin.AccountSigninActivity;
 import org.chromium.chrome.browser.signin.SigninAccessPoint;
@@ -43,37 +39,23 @@
      */
     private boolean mDismissed;
 
-    /**
-     * Whether the signin status means that the user has the possibility to sign in.
-     */
-    private boolean mCanSignIn;
-
-    /**
-     * Whether personalized suggestions can be shown. If it's not the case, we have no reason to
-     * offer the user to sign in.
-     */
-    private boolean mCanShowPersonalizedSuggestions;
-
     private final ImpressionTracker mImpressionTracker = new ImpressionTracker(null, this);
 
     @Nullable
-    private final SigninObserver mSigninObserver;
+    private final SigninObserver mObserver;
 
     public SignInPromo(SuggestionsUiDelegate uiDelegate) {
         mDismissed = ChromePreferenceManager.getInstance().getNewTabPageSigninPromoDismissed();
 
-        SuggestionsSource suggestionsSource = uiDelegate.getSuggestionsSource();
         SigninManager signinManager = SigninManager.get(ContextUtils.getApplicationContext());
         if (mDismissed) {
-            mSigninObserver = null;
+            mObserver = null;
         } else {
-            mSigninObserver = new SigninObserver(signinManager, suggestionsSource);
-            uiDelegate.addDestructionObserver(mSigninObserver);
+            mObserver = new SigninObserver(signinManager);
+            uiDelegate.addDestructionObserver(mObserver);
         }
 
-        mCanSignIn = signinManager.isSignInAllowed() && !signinManager.isSignedInOnNative();
-        mCanShowPersonalizedSuggestions = suggestionsSource.areRemoteSuggestionsEnabled();
-        updateVisibility();
+        setVisible(signinManager.isSignInAllowed() && !signinManager.isSignedInOnNative());
     }
 
     @Override
@@ -88,7 +70,7 @@
      */
     @Nullable
     public DestructionObserver getObserver() {
-        return mSigninObserver;
+        return mObserver;
     }
 
     @Override
@@ -132,8 +114,9 @@
         mImpressionTracker.reset(null);
     }
 
-    private void updateVisibility() {
-        setVisibilityInternal(!mDismissed && mCanSignIn && mCanShowPersonalizedSuggestions);
+    @Override
+    public void setVisible(boolean visible) {
+        super.setVisible(!mDismissed && visible);
     }
 
     @Override
@@ -144,31 +127,26 @@
     /** Hides the sign in promo and sets a preference to make sure it is not shown again. */
     @Override
     public void dismiss(Callback<String> itemRemovedCallback) {
-        assert mSigninObserver != null;
         mDismissed = true;
-        updateVisibility();
+        setVisible(false);
 
         ChromePreferenceManager.getInstance().setNewTabPageSigninPromoDismissed(true);
-        mSigninObserver.unregister();
+        mObserver.unregister();
         itemRemovedCallback.onResult(ContextUtils.getApplicationContext().getString(getHeader()));
     }
 
     @VisibleForTesting
-    class SigninObserver extends SuggestionsSource.EmptyObserver
+    class SigninObserver
             implements SignInStateObserver, SignInAllowedObserver, DestructionObserver {
         private final SigninManager mSigninManager;
-        private final SuggestionsSource mSuggestionsSource;
 
         /** Guards {@link #unregister()}, which can be called multiple times. */
         private boolean mUnregistered;
 
-        private SigninObserver(SigninManager signinManager, SuggestionsSource suggestionsSource) {
+        private SigninObserver(SigninManager signinManager) {
             mSigninManager = signinManager;
             mSigninManager.addSignInAllowedObserver(this);
             mSigninManager.addSignInStateObserver(this);
-
-            mSuggestionsSource = suggestionsSource;
-            mSuggestionsSource.addObserver(this);
         }
 
         private void unregister() {
@@ -177,8 +155,6 @@
 
             mSigninManager.removeSignInAllowedObserver(this);
             mSigninManager.removeSignInStateObserver(this);
-
-            mSuggestionsSource.removeObserver(this);
         }
 
         @Override
@@ -191,31 +167,17 @@
             // Listening to onSignInAllowedChanged is important for the FRE. Sign in is not allowed
             // until it is completed, but the NTP is initialised before the FRE is even shown. By
             // implementing this we can show the promo if the user did not sign in during the FRE.
-            mCanSignIn = mSigninManager.isSignInAllowed();
-            updateVisibility();
+            setVisible(mSigninManager.isSignInAllowed());
         }
 
         @Override
         public void onSignedIn() {
-            mCanSignIn = false;
-            updateVisibility();
+            setVisible(false);
         }
 
         @Override
         public void onSignedOut() {
-            mCanSignIn = mSigninManager.isSignInAllowed();
-            updateVisibility();
-        }
-
-        @Override
-        public void onCategoryStatusChanged(
-                @CategoryInt int category, @CategoryStatus int newStatus) {
-            if (!SnippetsBridge.isCategoryRemote(category)) return;
-
-            // Checks whether the category is enabled first to avoid unnecessary calls across JNI.
-            mCanShowPersonalizedSuggestions = SnippetsBridge.isCategoryEnabled(category)
-                    || mSuggestionsSource.areRemoteSuggestionsEnabled();
-            updateVisibility();
+            setVisible(true);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java
index f359a848..e603b04 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusItem.java
@@ -63,8 +63,4 @@
         assert holder instanceof StatusCardViewHolder;
         ((StatusCardViewHolder) holder).onBindViewHolder(this);
     }
-
-    public void setVisible(boolean visible) {
-        setVisibilityInternal(visible);
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java
index 4cad997b..9f70931f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeader.java
@@ -18,7 +18,7 @@
 
     public SectionHeader(String headerText) {
         this.mHeaderText = headerText;
-        setVisibilityInternal(true);
+        setVisible(true);
     }
 
     @Override
@@ -41,8 +41,4 @@
     public void visitOptionalItem(NodeVisitor visitor) {
         visitor.visitHeader();
     }
-
-    public void setVisible(boolean visible) {
-        setVisibilityInternal(visible);
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
index 9ace85e..84642b82 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -7,7 +7,6 @@
 import android.graphics.Bitmap;
 
 import org.chromium.base.Callback;
-import org.chromium.base.ObserverList;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -23,17 +22,13 @@
     private static final String TAG = "SnippetsBridge";
 
     private long mNativeSnippetsBridge;
-    private final ObserverList<Observer> mObserverList = new ObserverList<>();
+    private SuggestionsSource.Observer mObserver;
 
     public static boolean isCategoryStatusAvailable(@CategoryStatus int status) {
-        // Note: This code is duplicated in category_status.cc.
+        // Note: This code is duplicated in content_suggestions_category_status.cc.
         return status == CategoryStatus.AVAILABLE_LOADING || status == CategoryStatus.AVAILABLE;
     }
 
-    public static boolean isCategoryRemote(@CategoryInt int category) {
-        return category > KnownCategories.REMOTE_CATEGORIES_OFFSET;
-    }
-
     /** Returns whether the category is considered "enabled", and can show content suggestions. */
     public static boolean isCategoryEnabled(@CategoryStatus int status) {
         switch (status) {
@@ -67,7 +62,7 @@
         assert mNativeSnippetsBridge != 0;
         nativeDestroy(mNativeSnippetsBridge);
         mNativeSnippetsBridge = 0;
-        mObserverList.clear();
+        mObserver = null;
     }
 
     /**
@@ -88,9 +83,8 @@
         nativeSetRemoteSuggestionsEnabled(enabled);
     }
 
-    @Override
-    public boolean areRemoteSuggestionsEnabled() {
-        return nativeAreRemoteSuggestionsEnabled(mNativeSnippetsBridge);
+    public static boolean areRemoteSuggestionsEnabled() {
+        return nativeAreRemoteSuggestionsEnabled();
     }
 
     public static boolean areRemoteSuggestionsManaged() {
@@ -180,14 +174,9 @@
     }
 
     @Override
-    public void addObserver(Observer observer) {
+    public void setObserver(Observer observer) {
         assert observer != null;
-        mObserverList.addObserver(observer);
-    }
-
-    @Override
-    public void removeObserver(Observer observer) {
-        mObserverList.removeObserver(observer);
+        mObserver = observer;
     }
 
     @Override
@@ -240,26 +229,22 @@
 
     @CalledByNative
     private void onNewSuggestions(@CategoryInt int category) {
-        for (Observer observer : mObserverList) observer.onNewSuggestions(category);
+        if (mObserver != null) mObserver.onNewSuggestions(category);
     }
 
     @CalledByNative
     private void onCategoryStatusChanged(@CategoryInt int category, @CategoryStatus int newStatus) {
-        for (Observer observer : mObserverList) {
-            observer.onCategoryStatusChanged(category, newStatus);
-        }
+        if (mObserver != null) mObserver.onCategoryStatusChanged(category, newStatus);
     }
 
     @CalledByNative
     private void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) {
-        for (Observer observer : mObserverList) {
-            observer.onSuggestionInvalidated(category, idWithinCategory);
-        }
+        if (mObserver != null) mObserver.onSuggestionInvalidated(category, idWithinCategory);
     }
 
     @CalledByNative
     private void onFullRefreshRequired() {
-        for (Observer observer : mObserverList) observer.onFullRefreshRequired();
+        if (mObserver != null) mObserver.onFullRefreshRequired();
     }
 
     private native long nativeInit(Profile profile);
@@ -268,7 +253,7 @@
     private static native void nativeRemoteSuggestionsSchedulerOnPersistentSchedulerWakeUp();
     private static native void nativeRemoteSuggestionsSchedulerOnBrowserUpgraded();
     private static native void nativeSetRemoteSuggestionsEnabled(boolean enabled);
-    private native boolean nativeAreRemoteSuggestionsEnabled(long nativeNTPSnippetsBridge);
+    private static native boolean nativeAreRemoteSuggestionsEnabled();
     private static native boolean nativeAreRemoteSuggestionsManaged();
     private static native boolean nativeAreRemoteSuggestionsManagedByCustodian();
     private static native void nativeSetContentSuggestionsNotificationsEnabled(boolean enabled);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
index 8d36eca..b20d676 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
@@ -43,11 +43,6 @@
     void fetchRemoteSuggestions();
 
     /**
-     * @return Whether remote suggestions are enabled.
-     */
-    boolean areRemoteSuggestionsEnabled();
-
-    /**
      * Gets the categories in the order in which they should be displayed.
      * @return The categories.
      */
@@ -125,26 +120,5 @@
     /**
      * Sets the recipient for update events from the source.
      */
-    void addObserver(Observer observer);
-
-    /**
-     * Removes an observer. Is no-op if the observer was not already registered.
-     */
-    void removeObserver(Observer observer);
-
-    /** No-op implementation of {@link SuggestionsSource.Observer}. */
-    class EmptyObserver implements Observer {
-        @Override
-        public void onNewSuggestions(@CategoryInt int category) {}
-
-        @Override
-        public void onCategoryStatusChanged(
-                @CategoryInt int category, @CategoryStatus int newStatus) {}
-
-        @Override
-        public void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) {}
-
-        @Override
-        public void onFullRefreshRequired() {}
-    }
+    void setObserver(Observer observer);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java
index 83f6394..12ecd35f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java
@@ -9,8 +9,6 @@
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
-import org.chromium.chrome.browser.WarmupManager;
-import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestion.MatchClassification;
 import org.chromium.chrome.browser.omnibox.VoiceSuggestionProvider.VoiceResult;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -161,12 +159,6 @@
     public void startZeroSuggest(Profile profile, String omniboxText, String url,
             boolean focusedFromFakebox) {
         if (profile == null || TextUtils.isEmpty(url)) return;
-
-        if (!NewTabPage.isNTPUrl(url)) {
-            // Proactively start up a renderer, to reduce the time to display search results,
-            // especially if a Service Worker is used.
-            WarmupManager.getInstance().createSpareRenderProcessHost(profile);
-        }
         mNativeAutocompleteControllerAndroid = nativeInit(profile);
         if (mNativeAutocompleteControllerAndroid != 0) {
             if (mUseCachedZeroSuggestResults) mWaitingForSuggestionsToCache = true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContentSuggestionsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContentSuggestionsPreferences.java
index b264fd4..529a5d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContentSuggestionsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContentSuggestionsPreferences.java
@@ -23,9 +23,7 @@
 import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationAction;
 import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsNotificationOptOut;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
-import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.suggestions.SuggestionsDependencyFactory;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -76,12 +74,7 @@
         setHasOptionsMenu(true);
         finishSwitchInitialisation();
 
-        SuggestionsSource suggestionsSource =
-                SuggestionsDependencyFactory.getInstance().createSuggestionSource(
-                        Profile.getLastUsedProfile());
-        boolean isEnabled = suggestionsSource.areRemoteSuggestionsEnabled();
-        suggestionsSource.onDestroy();
-
+        boolean isEnabled = SnippetsBridge.areRemoteSuggestionsEnabled();
         mIsEnabled = !isEnabled; // Opposite so that we trigger side effects below.
         updatePreferences(isEnabled);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
index 2d040ff7..c74fd56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
@@ -540,7 +540,7 @@
         if (wipeData) {
             wipeProfileData(wipeDataHooks);
         } else {
-            onSignOutDone();
+            wipeGoogleServiceWorkerCaches(wipeDataHooks);
         }
 
         AccountTrackerService.get().invalidateAccountSeedStatus(true);
@@ -592,6 +592,12 @@
         nativeWipeProfileData(mNativeSigninManagerAndroid, hooks);
     }
 
+    private void wipeGoogleServiceWorkerCaches(WipeDataHooks hooks) {
+        if (hooks != null) hooks.preWipeData();
+        // This will call back to onProfileDataWiped().
+        nativeWipeGoogleServiceWorkerCaches(mNativeSigninManagerAndroid, hooks);
+    }
+
     /**
      * Convenience method to return a Promise to be fulfilled when the user's sync data has been
      * wiped if the parameter is true, or an already fulfilled Promise if the parameter is false.
@@ -679,6 +685,8 @@
     private native void nativeSignOut(long nativeSigninManagerAndroid);
     private native String nativeGetManagementDomain(long nativeSigninManagerAndroid);
     private native void nativeWipeProfileData(long nativeSigninManagerAndroid, WipeDataHooks hooks);
+    private native void nativeWipeGoogleServiceWorkerCaches(
+            long nativeSigninManagerAndroid, WipeDataHooks hooks);
     private native void nativeClearLastSignedInUser(long nativeSigninManagerAndroid);
     private native void nativeLogInSignedInUser(long nativeSigninManagerAndroid);
     private native boolean nativeIsSignedInOnNative(long nativeSigninManagerAndroid);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
index 146072c6..87cd6b2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
@@ -66,7 +66,7 @@
 
     @Override
     public void onTileDataChanged() {
-        setVisibilityInternal(mTileGroup.getTiles().length != 0);
+        setVisible(mTileGroup.getTiles().length != 0);
         if (isVisible()) notifyItemChanged(0, new ViewHolder.UpdateTilesCallback(mTileGroup));
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
index 7aef3da4..00302bf1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -709,6 +709,14 @@
                 mToolbarButtonsContainer.setVisibility(View.VISIBLE);
                 mToolbarButtonsContainer.setTranslationX(0);
 
+                mToggleTabStackButton.setAlpha(1.f);
+                mToggleTabStackButton.setVisibility(View.VISIBLE);
+
+                if (!mUseToolbarHandle) {
+                    if (mTabSwitcherState != ENTERING_TAB_SWITCHER) mExpandButton.setAlpha(1.f);
+                    mExpandButton.setVisibility(View.VISIBLE);
+                }
+
                 requestLayout();
             } else {
                 mToolbarButtonVisibilityPercent = 0.f;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 536d6516..c122c3d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -487,41 +487,39 @@
         private static final long NANOS_PER_SECOND = 1000000000;
 
         private static final long VSYNC_TIMEBASE_UPDATE_DELTA = 1 * NANOS_PER_SECOND;
-        private static final double VSYNC_DRIFT_THRESHOLD = 1.2;
+        private static final double MIN_VSYNC_INTERVAL_THRESHOLD = 1.2;
 
         // Estimates based on too few frames are unstable, probably anything above 2 is reasonable.
         // Higher numbers will reduce how frequently we update the native vsync base/interval.
         private static final int MIN_FRAME_COUNT = 5;
 
         private final long mReportedVSyncNanos;
-        private final long mMaxVSyncIntervalNanos;
         private final long mMinVSyncIntervalNanos;
 
         private long mVSyncTimebaseNanos;
         private long mVSyncIntervalNanos;
         private long mVSyncIntervalMicros;
 
+        private int mVSyncCount;
+
         private final FrameCallback mCallback = new FrameCallback() {
             @Override
             public void doFrame(long frameTimeNanos) {
                 if (mNativeVrShellDelegate == 0) return;
                 Choreographer.getInstance().postFrameCallback(this);
+                ++mVSyncCount;
                 if (mVSyncTimebaseNanos == 0) {
                     updateVSyncInterval(frameTimeNanos, mVSyncIntervalNanos);
                     return;
                 }
+                if (mVSyncCount < MIN_FRAME_COUNT) return;
                 long elapsed = frameTimeNanos - mVSyncTimebaseNanos;
                 // If you're hitting the assert below, you probably added the callback twice.
                 assert elapsed != 0;
-                long count = Math.round(elapsed / (double) mVSyncIntervalNanos);
-                if (count < MIN_FRAME_COUNT) return;
-                long vSyncIntervalNanos = elapsed / count;
-                if (vSyncIntervalNanos > mMaxVSyncIntervalNanos
-                        || vSyncIntervalNanos < mMinVSyncIntervalNanos) {
-                    // This algorithm for computing VSync becomes unstable if it drifts too far from
-                    // the real VSync, which shouldn't happen in practice. If this assert is getting
-                    // hit, something has gone very wrong, but we should probably do something
-                    // reasonable for release builds.
+                long vSyncIntervalNanos = elapsed / mVSyncCount;
+                if (vSyncIntervalNanos < mMinVSyncIntervalNanos) {
+                    // We may run slow, but we should never run fast. If the VSync interval is too
+                    // low, something is very wrong.
                     Log.v(TAG, "Error computing VSync interval. Resetting.");
                     assert false;
                     vSyncIntervalNanos = mReportedVSyncNanos;
@@ -535,8 +533,7 @@
                                       .getDefaultDisplay();
             mReportedVSyncNanos = (long) ((1.0d / display.getRefreshRate()) * NANOS_PER_SECOND);
             mVSyncIntervalNanos = mReportedVSyncNanos;
-            mMaxVSyncIntervalNanos = (long) (VSYNC_DRIFT_THRESHOLD * mReportedVSyncNanos);
-            mMinVSyncIntervalNanos = (long) (mReportedVSyncNanos / VSYNC_DRIFT_THRESHOLD);
+            mMinVSyncIntervalNanos = (long) (mReportedVSyncNanos / MIN_VSYNC_INTERVAL_THRESHOLD);
         }
 
         void updateVSyncInterval(long frameTimeNanos, long vSyncIntervalNanos) {
@@ -548,6 +545,7 @@
             }
             mVSyncIntervalMicros = vSyncIntervalMicros;
             mVSyncTimebaseNanos = frameTimeNanos;
+            mVSyncCount = 0;
 
             nativeUpdateVSyncInterval(
                     mNativeVrShellDelegate, mVSyncTimebaseNanos, mVSyncIntervalMicros);
@@ -558,6 +556,8 @@
         }
 
         public void resume() {
+            mVSyncTimebaseNanos = 0;
+            mVSyncCount = 0;
             Choreographer.getInstance().postFrameCallback(mCallback);
         }
     }
@@ -882,7 +882,7 @@
         mRequestedWebVr = true;
         switch (enterVrInternal()) {
             case ENTER_VR_NOT_NECESSARY:
-                mVrShell.setWebVrModeEnabled(true, true);
+                mVrShell.setWebVrModeEnabled(true, !mAutopresentWebVr);
                 maybeSetPresentResult(true, true);
                 break;
             case ENTER_VR_CANCELLED:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
index a7fc0d0..4338078 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -16,7 +16,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationParams;
 import org.chromium.chrome.browser.metrics.WebApkUma;
 import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
@@ -26,6 +25,7 @@
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.util.UrlUtilities;
 import org.chromium.components.navigation_interception.NavigationParams;
+import org.chromium.content.browser.ChildProcessCreationParams;
 import org.chromium.net.NetError;
 import org.chromium.net.NetworkChangeNotifier;
 import org.chromium.webapk.lib.client.WebApkServiceConnectionManager;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/widget/OWNERS
index 87d040abf..8042524 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/OWNERS
@@ -1,2 +1,3 @@
-per-file BottomSheet*=mdjones@chromium.org   
-per-file ToolbarProgressBar*=mdjones@chromium.org   
+twellington@chromium.org
+
+per-file ToolbarProgressBar*=mdjones@chromium.org
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 2f9684c..46e91dee 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1538,7 +1538,7 @@
   "javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentManifestParserTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java",
-  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBasicCardTest.java",
+  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentMethodIdentifierTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBlobUrlTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
index 859228e..f9ac32cec 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
@@ -361,6 +361,7 @@
     @Test
     @SmallTest
     @Restriction(ChromeRestriction.RESTRICTION_TYPE_TABLET)
+    @RetryOnFailure
     public void testOpenWindowFromUserGesture() throws InterruptedException {
         loadUrlAndWaitForIntentUrl(mTestServer.getURL(OPEN_WINDOW_FROM_USER_GESTURE_PAGE),
                 true, 1, true, null, true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBasicCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentMethodIdentifierTest.java
similarity index 96%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBasicCardTest.java
rename to chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentMethodIdentifierTest.java
index 92882c1..eeb5ff4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBasicCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentMethodIdentifierTest.java
@@ -18,11 +18,11 @@
 import java.util.concurrent.TimeoutException;
 
 /**
- * A payment integration test for "basic-card" payment method.
+ * A payment integration test for supported payment methods.
  */
-public class PaymentRequestBasicCardTest extends PaymentRequestTestBase {
-    public PaymentRequestBasicCardTest() {
-        super("payment_request_basic_card_test.html");
+public class PaymentRequestPaymentMethodIdentifierTest extends PaymentRequestTestBase {
+    public PaymentRequestPaymentMethodIdentifierTest() {
+        super("payment_request_payment_method_identifier_test.html");
         PaymentRequestImpl.setIsLocalCanMakePaymentQueryQuotaEnforcedForTest();
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
index 7cb9ae3..99b03b47 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -11,6 +11,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -62,7 +63,6 @@
 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
 import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
-import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.signin.SigninManager;
@@ -80,7 +80,6 @@
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -255,7 +254,10 @@
         mSource.setInfoForCategory(
                 TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).showIfEmpty().build());
 
-        resetUiDelegate();
+        when(mUiDelegate.getSuggestionsSource()).thenReturn(mSource);
+        when(mUiDelegate.getEventReporter()).thenReturn(mock(SuggestionsEventReporter.class));
+        when(mUiDelegate.getSuggestionsRanker()).thenReturn(mock(SuggestionsRanker.class));
+
         reloadNtp();
     }
 
@@ -890,26 +892,28 @@
     @Test
     @Feature({"Ntp"})
     public void testSigninPromo() {
-        @CategoryInt
-        final int remoteCategory = KnownCategories.REMOTE_CATEGORIES_OFFSET + TEST_CATEGORY;
-
         when(mMockSigninManager.isSignInAllowed()).thenReturn(true);
         when(mMockSigninManager.isSignedInOnNative()).thenReturn(false);
-        mSource.setRemoteSuggestionsEnabled(true);
-        resetUiDelegate();
-        reloadNtp();
+        ArgumentCaptor<DestructionObserver> observers =
+                ArgumentCaptor.forClass(DestructionObserver.class);
 
+        doNothing().when(mUiDelegate).addDestructionObserver(observers.capture());
+
+        reloadNtp();
         assertTrue(isSignInPromoVisible());
 
-        // Note: As currently implemented, these variables should point to the same object, a
+        // Note: As currently implemented, these two variables should point to the same object, a
         // SignInPromo.SigninObserver
-        List<DestructionObserver> observers = getDestructionObserver(mUiDelegate);
-        SignInStateObserver signInStateObserver =
-                findFirstInstanceOf(observers, SignInStateObserver.class);
-        SignInAllowedObserver signInAllowedObserver =
-                findFirstInstanceOf(observers, SignInAllowedObserver.class);
-        SuggestionsSource.Observer suggestionsObserver =
-                findFirstInstanceOf(observers, SuggestionsSource.Observer.class);
+        SignInStateObserver signInStateObserver = null;
+        SignInAllowedObserver signInAllowedObserver = null;
+        for (DestructionObserver observer : observers.getAllValues()) {
+            if (observer instanceof SignInStateObserver) {
+                signInStateObserver = (SignInStateObserver) observer;
+            }
+            if (observer instanceof SignInAllowedObserver) {
+                signInAllowedObserver = (SignInAllowedObserver) observer;
+            }
+        }
 
         signInStateObserver.onSignedIn();
         assertFalse(isSignInPromoVisible());
@@ -924,15 +928,6 @@
         when(mMockSigninManager.isSignInAllowed()).thenReturn(true);
         signInAllowedObserver.onSignInAllowedChanged();
         assertTrue(isSignInPromoVisible());
-
-        mSource.setRemoteSuggestionsEnabled(false);
-        suggestionsObserver.onCategoryStatusChanged(
-                remoteCategory, CategoryStatus.CATEGORY_EXPLICITLY_DISABLED);
-        assertFalse(isSignInPromoVisible());
-
-        mSource.setRemoteSuggestionsEnabled(true);
-        suggestionsObserver.onCategoryStatusChanged(remoteCategory, CategoryStatus.AVAILABLE);
-        assertTrue(isSignInPromoVisible());
     }
 
     @Test
@@ -965,8 +960,17 @@
     @Test
     @Feature({"Ntp"})
     public void testAllDismissedVisibility() {
-        SigninObserver signinObserver =
-                findFirstInstanceOf(getDestructionObserver(mUiDelegate), SigninObserver.class);
+        ArgumentCaptor<DestructionObserver> observers =
+                ArgumentCaptor.forClass(DestructionObserver.class);
+
+        verify(mUiDelegate, atLeastOnce()).addDestructionObserver(observers.capture());
+
+        SigninObserver signinObserver = null;
+        for (DestructionObserver observer : observers.getAllValues()) {
+            if (observer instanceof SigninObserver) {
+                signinObserver = (SigninObserver) observer;
+            }
+        }
 
         @SuppressWarnings("unchecked")
         Callback<String> itemDismissedCallback = mock(Callback.class);
@@ -1041,28 +1045,8 @@
         assertEquals(RecyclerView.NO_POSITION,
                 mAdapter.getFirstPositionForType(ItemViewType.ALL_DISMISSED));
 
-        // Disabling remote suggestions should remove both the promo and the AllDismissed item
-        mSource.setRemoteSuggestionsEnabled(false);
-        signinObserver.onCategoryStatusChanged(
-                KnownCategories.REMOTE_CATEGORIES_OFFSET + TEST_CATEGORY,
-                CategoryStatus.CATEGORY_EXPLICITLY_DISABLED);
-        // Adapter content:
-        // Idx | Item
-        // ----|--------------------
-        // 0   | Above-the-fold
-        // 1   | Footer
-        // 2   | Spacer
-        assertEquals(ItemViewType.FOOTER, mAdapter.getItemViewType(1));
-        assertEquals(RecyclerView.NO_POSITION,
-                mAdapter.getFirstPositionForType(ItemViewType.ALL_DISMISSED));
-        assertEquals(
-                RecyclerView.NO_POSITION, mAdapter.getFirstPositionForType(ItemViewType.PROMO));
-
         // Prepare some suggestions. They should not load because the category is dismissed on
         // the current NTP.
-        mSource.setRemoteSuggestionsEnabled(true);
-        signinObserver.onCategoryStatusChanged(
-                KnownCategories.REMOTE_CATEGORIES_OFFSET + TEST_CATEGORY, CategoryStatus.AVAILABLE);
         mSource.setStatusForCategory(TEST_CATEGORY, CategoryStatus.AVAILABLE);
         mSource.setSuggestionsForCategory(TEST_CATEGORY, createDummySuggestions(1, TEST_CATEGORY));
         mSource.setInfoForCategory(TEST_CATEGORY, new CategoryInfoBuilder(TEST_CATEGORY).build());
@@ -1153,13 +1137,6 @@
         return new SectionDescriptor(Collections.<SnippetArticle>emptyList());
     }
 
-    private void resetUiDelegate() {
-        reset(mUiDelegate);
-        when(mUiDelegate.getSuggestionsSource()).thenReturn(mSource);
-        when(mUiDelegate.getEventReporter()).thenReturn(mock(SuggestionsEventReporter.class));
-        when(mUiDelegate.getSuggestionsRanker()).thenReturn(mock(SuggestionsRanker.class));
-    }
-
     private void reloadNtp() {
         mAdapter = new NewTabPageAdapter(mUiDelegate, mock(View.class), makeUiConfig(),
                 mOfflinePageBridge, mock(ContextMenuManager.class), /* tileGroupDelegate =
@@ -1174,25 +1151,4 @@
     private int getCategory(TreeNode item) {
         return ((SuggestionsSection) item).getCategory();
     }
-
-    /**
-     * Note: Currently the observers need to be re-registered to be returned again if this method
-     * has been called, as it relies on argument captors that don't repeatedly capture individual
-     * calls.
-     * @return The currently registered destruction observers.
-     */
-    private List<DestructionObserver> getDestructionObserver(SuggestionsUiDelegate delegate) {
-        ArgumentCaptor<DestructionObserver> observers =
-                ArgumentCaptor.forClass(DestructionObserver.class);
-        verify(delegate, atLeastOnce()).addDestructionObserver(observers.capture());
-        return observers.getAllValues();
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T> T findFirstInstanceOf(Collection<?> collection, Class<T> clazz) {
-        for (Object item : collection) {
-            if (clazz.isAssignableFrom(item.getClass())) return (T) item;
-        }
-        return null;
-    }
 }
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index c362678..af4b7f4 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -3214,4 +3214,18 @@
       Open proxy settings
     </message>
   </if>
+
+  <!-- Multidevice Page -->
+  <if expr="chromeos">
+    <message name="IDS_SETTINGS_MULTIDEVICE" desc="Name of the settings page features the user's other devices connected to the Chromebook.">
+      Connected devices
+    </message>
+    <message name="IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT" desc="Title of the multi-device feature for displaying SMS notifications.">
+      SMS connect
+    </message>
+    <message name="IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT_SUMMARY" desc="Summary explaining what the SMS connect feature does.">
+      Get notifications for new text messages on your Chromebook
+    </message>
+  </if>
+
 </grit-part>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 721aa7b..4f6bd5ea 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -535,6 +535,8 @@
     "invalidation/profile_invalidation_provider_factory.h",
     "io_thread.cc",
     "io_thread.h",
+    "language/url_language_histogram_factory.cc",
+    "language/url_language_histogram_factory.h",
     "lifetime/application_lifetime.cc",
     "lifetime/application_lifetime.h",
     "lifetime/application_lifetime_mac.mm",
@@ -1020,6 +1022,8 @@
     "prefs/chrome_pref_model_associator_client.h",
     "prefs/chrome_pref_service_factory.cc",
     "prefs/chrome_pref_service_factory.h",
+    "prefs/in_process_service_factory_factory.cc",
+    "prefs/in_process_service_factory_factory.h",
     "prefs/incognito_mode_prefs.cc",
     "prefs/incognito_mode_prefs.h",
     "prefs/origin_trial_prefs.cc",
@@ -1379,8 +1383,6 @@
     "translate/android/translate_utils.h",
     "translate/chrome_translate_client.cc",
     "translate/chrome_translate_client.h",
-    "translate/language_model_factory.cc",
-    "translate/language_model_factory.h",
     "translate/translate_accept_languages_factory.cc",
     "translate/translate_accept_languages_factory.h",
     "translate/translate_ranker_factory.cc",
@@ -1530,6 +1532,7 @@
     "//components/infobars/core",
     "//components/invalidation/impl",
     "//components/keyed_service/content",
+    "//components/language/core/browser",
     "//components/metrics:call_stacks",
     "//components/metrics:gpu",
     "//components/metrics:net",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 3e9bb14..906f9d4 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -763,12 +763,14 @@
      switches::kEnableWebFontsInterventionV2SwitchValueDisabled},
 };
 
-const FeatureEntry::Choice kSSLVersionMaxChoices[] = {
+const FeatureEntry::Choice kTLS13VariantChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
-    {flag_descriptions::kSslVersionMaxTls12, switches::kSSLVersionMax,
-     "tls1.2"},
-    {flag_descriptions::kSslVersionMaxTls13, switches::kSSLVersionMax,
-     "tls1.3"},
+    {flag_descriptions::kTLS13VariantDisabled, switches::kTLS13Variant,
+     switches::kTLS13VariantDisabled},
+    {flag_descriptions::kTLS13VariantDraft, switches::kTLS13Variant,
+     switches::kTLS13VariantDraft},
+    {flag_descriptions::kTLS13VariantExperiment, switches::kTLS13Variant,
+     switches::kTLS13VariantExperiment},
 };
 
 #if !defined(OS_ANDROID)
@@ -2342,9 +2344,9 @@
      flag_descriptions::kEnableWebfontsInterventionTriggerName,
      flag_descriptions::kEnableWebfontsInterventionTriggerDescription, kOsAll,
      SINGLE_VALUE_TYPE(switches::kEnableWebFontsInterventionTrigger)},
-    {"ssl-version-max", flag_descriptions::kSslVersionMaxName,
-     flag_descriptions::kSslVersionMaxDescription, kOsAll,
-     MULTI_VALUE_TYPE(kSSLVersionMaxChoices)},
+    {"tls13-variant", flag_descriptions::kTLS13VariantName,
+     flag_descriptions::kTLS13VariantDescription, kOsAll,
+     MULTI_VALUE_TYPE(kTLS13VariantChoices)},
     {"enable-token-binding", flag_descriptions::kEnableTokenBindingName,
      flag_descriptions::kEnableTokenBindingDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kTokenBinding)},
@@ -3168,12 +3170,6 @@
      flag_descriptions::kResourceLoadSchedulerDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kResourceLoadScheduler)},
 
-#if defined(OS_ANDROID)
-    {"omnibox-spare-renderer", flag_descriptions::kOmniboxSpareRendererName,
-     flag_descriptions::kOmniboxSpareRendererDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kOmniboxSpareRenderer)},
-#endif
-
 #if defined(TOOLKIT_VIEWS)
     {"delay-reload-stop-button-change",
      flag_descriptions::kDelayReloadStopButtonChangeName,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index b2127e6..4315806 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -78,7 +78,6 @@
     &kNTPLaunchAfterInactivity,
     &kNTPOfflinePagesFeature,
     &NTPShowGoogleGInOmniboxFeature,
-    &kOmniboxSpareRenderer,
     &kPayWithGoogleV1,
     &kPhysicalWebFeature,
     &kPhysicalWebSharing,
@@ -219,9 +218,6 @@
 const base::Feature NTPShowGoogleGInOmniboxFeature{
     "NTPShowGoogleGInOmnibox", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kOmniboxSpareRenderer{"OmniboxSpareRenderer",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kPayWithGoogleV1{"PayWithGoogleV1",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 784ce00a..b2c5bd6 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -46,7 +46,6 @@
 extern const base::Feature kNTPLaunchAfterInactivity;
 extern const base::Feature kNTPOfflinePagesFeature;
 extern const base::Feature NTPShowGoogleGInOmniboxFeature;
-extern const base::Feature kOmniboxSpareRenderer;
 extern const base::Feature kPayWithGoogleV1;
 extern const base::Feature kPhysicalWebFeature;
 extern const base::Feature kPhysicalWebSharing;
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
index 88659629..1473982 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -160,6 +160,18 @@
   content_suggestions_service->SetRemoteSuggestionsEnabled(enabled);
 }
 
+static jboolean AreRemoteSuggestionsEnabled(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& caller) {
+  ntp_snippets::ContentSuggestionsService* content_suggestions_service =
+      ContentSuggestionsServiceFactory::GetForProfile(
+          ProfileManager::GetLastUsedProfile());
+  if (!content_suggestions_service)
+    return false;
+
+  return content_suggestions_service->AreRemoteSuggestionsEnabled();
+}
+
 // Returns true if the remote provider is managed by an adminstrator's policy.
 static jboolean AreRemoteSuggestionsManaged(
     JNIEnv* env,
@@ -273,12 +285,6 @@
       content_suggestions_service_->GetSuggestionsForCategory(category));
 }
 
-jboolean NTPSnippetsBridge::AreRemoteSuggestionsEnabled(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  return content_suggestions_service_->AreRemoteSuggestionsEnabled();
-}
-
 void NTPSnippetsBridge::FetchSuggestionImage(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.h b/chrome/browser/android/ntp/ntp_snippets_bridge.h
index 396ac80..0860da0 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.h
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.h
@@ -53,10 +53,6 @@
       const base::android::JavaParamRef<jobject>& obj,
       jint j_category_id);
 
-  jboolean AreRemoteSuggestionsEnabled(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-
   void FetchSuggestionImage(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc
index 5fd3e001..29e9ad8b 100644
--- a/chrome/browser/android/signin/signin_manager_android.cc
+++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
-
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
@@ -31,6 +30,7 @@
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/common/pref_names.h"
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "components/google/core/browser/google_util.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
@@ -42,6 +42,7 @@
 #include "components/signin/core/browser/signin_metrics.h"
 #include "components/signin/core/common/profile_management_switches.h"
 #include "components/signin/core/common/signin_pref_names.h"
+#include "content/public/browser/browsing_data_filter_builder.h"
 #include "content/public/browser/browsing_data_remover.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -53,19 +54,42 @@
 
 namespace {
 
-// A BrowsingDataRemover::Observer that clears all Profile data and then
-// invokes a callback and deletes itself.
+// A BrowsingDataRemover::Observer that clears Profile data and then invokes
+// a callback and deletes itself. It can be configured to delete all data
+// (for enterprise users) or only Google's service workers (for all users).
 class ProfileDataRemover : public content::BrowsingDataRemover::Observer {
  public:
-  ProfileDataRemover(Profile* profile, const base::Closure& callback)
+  ProfileDataRemover(Profile* profile,
+                     bool all_data,
+                     const base::Closure& callback)
       : callback_(callback),
         origin_runner_(base::ThreadTaskRunnerHandle::Get()),
         remover_(content::BrowserContext::GetBrowsingDataRemover(profile)) {
     remover_->AddObserver(this);
-    remover_->RemoveAndReply(
-        base::Time(), base::Time::Max(),
-        ChromeBrowsingDataRemoverDelegate::ALL_DATA_TYPES,
-        ChromeBrowsingDataRemoverDelegate::ALL_ORIGIN_TYPES, this);
+
+    if (all_data) {
+      remover_->RemoveAndReply(
+          base::Time(), base::Time::Max(),
+          ChromeBrowsingDataRemoverDelegate::ALL_DATA_TYPES,
+          ChromeBrowsingDataRemoverDelegate::ALL_ORIGIN_TYPES, this);
+    } else {
+      std::unique_ptr<content::BrowsingDataFilterBuilder> google_tld_filter =
+          content::BrowsingDataFilterBuilder::Create(
+              content::BrowsingDataFilterBuilder::WHITELIST);
+
+      // TODO(msramek): BrowsingDataFilterBuilder was not designed for
+      // large filters. Optimize it.
+      for (const std::string& domain :
+           google_util::GetGoogleRegistrableDomains()) {
+        google_tld_filter->AddRegisterableDomain(domain);
+      }
+
+      remover_->RemoveWithFilterAndReply(
+          base::Time(), base::Time::Max(),
+          content::BrowsingDataRemover::DATA_TYPE_CACHE_STORAGE,
+          ChromeBrowsingDataRemoverDelegate::ALL_ORIGIN_TYPES,
+          std::move(google_tld_filter), this);
+    }
   }
 
   ~ProfileDataRemover() override {}
@@ -199,10 +223,21 @@
   base::android::ScopedJavaGlobalRef<jobject> java_callback;
   java_callback.Reset(env, callback);
 
-  // The ProfileDataRemover deletes itself once done.
-  new ProfileDataRemover(
-      profile_, base::Bind(&SigninManagerAndroid::OnBrowsingDataRemoverDone,
-                           weak_factory_.GetWeakPtr(), java_callback));
+  WipeData(profile_, true /* all data */,
+           base::Bind(&SigninManagerAndroid::OnBrowsingDataRemoverDone,
+                      weak_factory_.GetWeakPtr(), java_callback));
+}
+
+void SigninManagerAndroid::WipeGoogleServiceWorkerCaches(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& callback) {
+  base::android::ScopedJavaGlobalRef<jobject> java_callback;
+  java_callback.Reset(env, callback);
+
+  WipeData(profile_, false /* only Google service worker caches */,
+           base::Bind(&SigninManagerAndroid::OnBrowsingDataRemoverDone,
+                      weak_factory_.GetWeakPtr(), java_callback));
 }
 
 void SigninManagerAndroid::OnPolicyRegisterDone(
@@ -315,6 +350,14 @@
       SigninManagerFactory::GetForProfile(profile_)->IsSigninAllowed());
 }
 
+// static
+void SigninManagerAndroid::WipeData(Profile* profile,
+                                    bool all_data,
+                                    const base::Closure& callback) {
+  // The ProfileDataRemover deletes itself once done.
+  new ProfileDataRemover(profile, all_data, callback);
+}
+
 static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   SigninManagerAndroid* signin_manager_android =
       new SigninManagerAndroid(env, obj);
diff --git a/chrome/browser/android/signin/signin_manager_android.h b/chrome/browser/android/signin/signin_manager_android.h
index 0faee77..e164336 100644
--- a/chrome/browser/android/signin/signin_manager_android.h
+++ b/chrome/browser/android/signin/signin_manager_android.h
@@ -57,10 +57,17 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
+  // Delete all data for this profile.
   void WipeProfileData(JNIEnv* env,
                        const base::android::JavaParamRef<jobject>& obj,
                        const base::android::JavaParamRef<jobject>& hooks);
 
+  // Delete service worker caches for google.<eTLD>.
+  void WipeGoogleServiceWorkerCaches(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& hooks);
+
   void LogInSignedInUser(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj);
 
@@ -90,6 +97,9 @@
                        const std::string& username) override;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(SigninManagerAndroidTest,
+                           DeleteGoogleServiceWorkerCaches);
+
   ~SigninManagerAndroid() override;
 
   void OnPolicyRegisterDone(const std::string& dm_token,
@@ -103,6 +113,10 @@
 
   void OnSigninAllowedPrefChanged();
 
+  static void WipeData(Profile* profile,
+                       bool all_data,
+                       const base::Closure& callback);
+
   Profile* profile_;
 
   // Java-side SigninManager object.
diff --git a/chrome/browser/android/signin/signin_manager_android_unittest.cc b/chrome/browser/android/signin/signin_manager_android_unittest.cc
new file mode 100644
index 0000000..6119fefb
--- /dev/null
+++ b/chrome/browser/android/signin/signin_manager_android_unittest.cc
@@ -0,0 +1,97 @@
+// 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 "signin_manager_android.h"
+
+#include <memory>
+#include <set>
+
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "chrome/browser/browsing_data/browsing_data_cache_storage_helper.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browsing_data_remover.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class SigninManagerAndroidTest : public ::testing::Test {
+ public:
+  SigninManagerAndroidTest()
+      : profile_manager_(TestingBrowserProcess::GetGlobal()) {}
+  ~SigninManagerAndroidTest() override{};
+
+  void SetUp() override {
+    ASSERT_TRUE(profile_manager_.SetUp());
+    profile_ = profile_manager_.CreateTestingProfile("Testing Profile");
+  }
+
+  TestingProfile* profile() { return profile_; }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  TestingProfileManager profile_manager_;
+  TestingProfile* profile_;  // Owned by |profile_manager_|.
+
+  DISALLOW_COPY_AND_ASSIGN(SigninManagerAndroidTest);
+};
+
+TEST_F(SigninManagerAndroidTest, DeleteGoogleServiceWorkerCaches) {
+  struct TestCase {
+    std::string worker_url;
+    bool should_be_deleted;
+  } kTestCases[] = {
+      // A Google domain.
+      {"https://google.com/foo/bar", true},
+
+      // A Google domain with long TLD.
+      {"https://plus.google.co.uk/?query_params", true},
+
+      // Youtube.
+      {"https://youtube.com", false},
+
+      // A random domain.
+      {"https://a.b.c.example.com", false},
+
+      // Another Google domain.
+      {"https://www.google.de/worker.html", true},
+
+      // Ports don't matter, only TLDs.
+      {"https://google.com:8444/worker.html", true},
+  };
+
+  // Add service workers.
+  scoped_refptr<CannedBrowsingDataCacheStorageHelper> helper(
+      new CannedBrowsingDataCacheStorageHelper(
+          content::BrowserContext::GetDefaultStoragePartition(profile())
+              ->GetCacheStorageContext()));
+
+  for (const TestCase& test_case : kTestCases)
+    helper->AddCacheStorage(GURL(test_case.worker_url));
+
+  ASSERT_EQ(arraysize(kTestCases), helper->GetCacheStorageCount());
+
+  // Delete service workers and wait for completion.
+  base::RunLoop run_loop;
+  SigninManagerAndroid::WipeData(profile(),
+                                 false /* only Google service worker caches */,
+                                 run_loop.QuitClosure());
+  run_loop.Run();
+
+  // Test whether the correct service worker caches were deleted.
+  std::set<std::string> remaining_cache_storages;
+  for (const auto& info : helper->GetCacheStorageUsageInfo())
+    remaining_cache_storages.insert(info.origin.spec());
+
+  for (const TestCase& test_case : kTestCases) {
+    EXPECT_EQ(test_case.should_be_deleted,
+              base::ContainsKey(remaining_cache_storages, test_case.worker_url))
+        << test_case.worker_url << " should "
+        << (test_case.should_be_deleted ? "" : "NOT ")
+        << "be deleted, but it was"
+        << (test_case.should_be_deleted ? "NOT" : "") << ".";
+  }
+}
diff --git a/chrome/browser/android/vr_shell/BUILD.gn b/chrome/browser/android/vr_shell/BUILD.gn
index bdb99e0..8875e9b 100644
--- a/chrome/browser/android/vr_shell/BUILD.gn
+++ b/chrome/browser/android/vr_shell/BUILD.gn
@@ -24,14 +24,10 @@
     "vr_compositor.h",
     "vr_controller.cc",
     "vr_controller.h",
-    "vr_controller_model.cc",
-    "vr_controller_model.h",
     "vr_core_info.cc",
     "vr_core_info.h",
     "vr_gl_thread.cc",
     "vr_gl_thread.h",
-    "vr_gl_util.cc",
-    "vr_gl_util.h",
     "vr_input_manager.cc",
     "vr_input_manager.h",
     "vr_metrics_util.cc",
@@ -42,8 +38,6 @@
     "vr_shell_delegate.h",
     "vr_shell_gl.cc",
     "vr_shell_gl.h",
-    "vr_shell_renderer.cc",
-    "vr_shell_renderer.h",
     "vr_usage_monitor.cc",
     "vr_usage_monitor.h",
     "vr_web_contents_observer.cc",
diff --git a/chrome/browser/android/vr_shell/gl_browser_interface.h b/chrome/browser/android/vr_shell/gl_browser_interface.h
index 6bfb21d..1a23816 100644
--- a/chrome/browser/android/vr_shell/gl_browser_interface.h
+++ b/chrome/browser/android/vr_shell/gl_browser_interface.h
@@ -41,6 +41,7 @@
   virtual void OnContentPaused(bool enabled) = 0;
   virtual void ToggleCardboardGamepad(bool enabled) = 0;
   virtual void OnGLInitialized() = 0;
+  virtual void OnWebVrFrameAvailable() = 0;
 };
 
 }  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/vr_controller.cc b/chrome/browser/android/vr_shell/vr_controller.cc
index 8a5e07f..4e5b1f9 100644
--- a/chrome/browser/android/vr_shell/vr_controller.cc
+++ b/chrome/browser/android/vr_shell/vr_controller.cc
@@ -186,14 +186,14 @@
          gfx::ScaleVector3d(pointer_direction, kLaserStartDisplacement);
 }
 
-VrControllerModel::State VrController::GetModelState() const {
+vr::VrControllerModel::State VrController::GetModelState() const {
   if (ButtonState(gvr::ControllerButton::GVR_CONTROLLER_BUTTON_CLICK))
-    return VrControllerModel::TOUCHPAD;
+    return vr::VrControllerModel::TOUCHPAD;
   if (ButtonState(gvr::ControllerButton::GVR_CONTROLLER_BUTTON_APP))
-    return VrControllerModel::APP;
+    return vr::VrControllerModel::APP;
   if (ButtonState(gvr::ControllerButton::GVR_CONTROLLER_BUTTON_HOME))
-    return VrControllerModel::SYSTEM;
-  return VrControllerModel::IDLE;
+    return vr::VrControllerModel::SYSTEM;
+  return vr::VrControllerModel::IDLE;
 }
 
 bool VrController::TouchDownHappened() {
diff --git a/chrome/browser/android/vr_shell/vr_controller.h b/chrome/browser/android/vr_shell/vr_controller.h
index 8bcc6c18..ffc3440 100644
--- a/chrome/browser/android/vr_shell/vr_controller.h
+++ b/chrome/browser/android/vr_shell/vr_controller.h
@@ -10,7 +10,7 @@
 
 #include "base/macros.h"
 #include "base/time/time.h"
-#include "chrome/browser/android/vr_shell/vr_controller_model.h"
+#include "chrome/browser/vr/vr_controller_model.h"
 #include "device/vr/android/gvr/gvr_gamepad_data_provider.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 #include "ui/gfx/geometry/point3_f.h"
@@ -69,7 +69,7 @@
   float GetOpacity() const;
   gfx::Point3F GetPointerStart() const;
 
-  VrControllerModel::State GetModelState() const;
+  vr::VrControllerModel::State GetModelState() const;
 
   bool TouchDownHappened();
 
diff --git a/chrome/browser/android/vr_shell/vr_gl_thread.cc b/chrome/browser/android/vr_shell/vr_gl_thread.cc
index 702182d..d7f3d3d2 100644
--- a/chrome/browser/android/vr_shell/vr_gl_thread.cc
+++ b/chrome/browser/android/vr_shell/vr_gl_thread.cc
@@ -247,6 +247,11 @@
                                      weak_scene_manager_, bitmap));
 }
 
+void VrGLThread::OnWebVrFrameAvailable() {
+  DCHECK(task_runner()->BelongsToCurrentThread());
+  scene_manager_->OnWebVrFrameAvailable();
+}
+
 void VrGLThread::CleanUp() {
   scene_manager_.reset();
   vr_shell_gl_.reset();
diff --git a/chrome/browser/android/vr_shell/vr_gl_thread.h b/chrome/browser/android/vr_shell/vr_gl_thread.h
index 75c5e77..88b917b9 100644
--- a/chrome/browser/android/vr_shell/vr_gl_thread.h
+++ b/chrome/browser/android/vr_shell/vr_gl_thread.h
@@ -62,6 +62,7 @@
   void OnContentPaused(bool enabled) override;
   void ToggleCardboardGamepad(bool enabled) override;
   void OnGLInitialized() override;
+  void OnWebVrFrameAvailable() override;
 
   // vr::UiBrowserInterface implementation (UI calling to VrShell).
   void ExitPresent() override;
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc
index a8279e0..b313ca4 100644
--- a/chrome/browser/android/vr_shell/vr_shell.cc
+++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/vr_shell/android_ui_gesture_target.h"
 #include "chrome/browser/android/vr_shell/vr_compositor.h"
-#include "chrome/browser/android/vr_shell/vr_controller_model.h"
 #include "chrome/browser/android/vr_shell/vr_gl_thread.h"
 #include "chrome/browser/android/vr_shell/vr_input_manager.h"
 #include "chrome/browser/android/vr_shell/vr_shell_delegate.h"
diff --git a/chrome/browser/android/vr_shell/vr_shell.h b/chrome/browser/android/vr_shell/vr_shell.h
index c92ea63..8a4a371 100644
--- a/chrome/browser/android/vr_shell/vr_shell.h
+++ b/chrome/browser/android/vr_shell/vr_shell.h
@@ -14,7 +14,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
-#include "chrome/browser/android/vr_shell/vr_controller_model.h"
 #include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
 #include "chrome/browser/vr/ui_interface.h"
 #include "chrome/browser/vr/ui_unsupported_mode.h"
@@ -173,7 +172,6 @@
   void ExitVrDueToUnsupportedMode(vr::UiUnsupportedMode mode);
 
   void ProcessContentGesture(std::unique_ptr<blink::WebInputEvent> event);
-  void SubmitControllerModel(std::unique_ptr<VrControllerModel> model);
 
   // device::GvrGamepadDataProvider implementation.
   void UpdateGamepadData(device::GvrGamepadData) override;
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index d620717..615e0a3 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -17,15 +17,15 @@
 #include "chrome/browser/android/vr_shell/gl_browser_interface.h"
 #include "chrome/browser/android/vr_shell/mailbox_to_surface_bridge.h"
 #include "chrome/browser/android/vr_shell/vr_controller.h"
-#include "chrome/browser/android/vr_shell/vr_gl_util.h"
 #include "chrome/browser/android/vr_shell/vr_metrics_util.h"
 #include "chrome/browser/android/vr_shell/vr_shell.h"
-#include "chrome/browser/android/vr_shell/vr_shell_renderer.h"
 #include "chrome/browser/android/vr_shell/vr_usage_monitor.h"
 #include "chrome/browser/vr/elements/ui_element.h"
 #include "chrome/browser/vr/fps_meter.h"
 #include "chrome/browser/vr/ui_interface.h"
 #include "chrome/browser/vr/ui_scene.h"
+#include "chrome/browser/vr/vr_gl_util.h"
+#include "chrome/browser/vr/vr_shell_renderer.h"
 #include "device/vr/android/gvr/gvr_delegate.h"
 #include "device/vr/android/gvr/gvr_device.h"
 #include "device/vr/android/gvr/gvr_gamepad_data_provider.h"
@@ -47,20 +47,6 @@
 // which requires fairly high precision to draw on top of elements correctly.
 static constexpr float kZFar = 100.0f;
 
-static constexpr float kReticleWidth = 0.025f;
-static constexpr float kReticleHeight = 0.025f;
-
-static constexpr float kLaserWidth = 0.01f;
-
-static constexpr gfx::Point3F kOrigin = {0.0f, 0.0f, 0.0f};
-
-// Fraction of the distance to the object the reticle is drawn at to avoid
-// rounding errors drawing the reticle behind the object.
-// TODO(mthiesse): Find a better approach for drawing the reticle on an object.
-// Right now we have to wedge it very precisely between the content window and
-// backplane to avoid rendering artifacts.
-static constexpr float kReticleOffset = 0.999f;
-
 // GVR buffer indices for use with viewport->SetSourceBufferIndex
 // or frame.BindBuffer. We use one for world content (with reprojection)
 // including main VrShell and WebVR content plus world-space UI.
@@ -99,8 +85,6 @@
 static constexpr base::TimeDelta kWebVRFenceCheckInterval =
     base::TimeDelta::FromMicroseconds(250);
 
-static constexpr float kEpsilon = 1e-6f;
-
 // Provides the direction the head is looking towards as a 3x1 unit vector.
 gfx::Vector3dF GetForwardVector(const gfx::Transform& head_pose) {
   // Same as multiplying the inverse of the rotation component of the matrix by
@@ -110,25 +94,6 @@
                         -head_pose.matrix().get(2, 2));
 }
 
-// Generate a quaternion representing the rotation from the negative Z axis
-// (0, 0, -1) to a specified vector. This is an optimized version of a more
-// general vector-to-vector calculation.
-gfx::Quaternion GetRotationFromZAxis(gfx::Vector3dF vec) {
-  vec.GetNormalized(&vec);
-  gfx::Quaternion quat;
-  quat.set_w(1.0f - vec.z());
-  if (quat.w() < kEpsilon) {
-    // Degenerate case: vectors are exactly opposite. Replace by an
-    // arbitrary 180 degree rotation to avoid invalid normalization.
-    return gfx::Quaternion(1, 0, 0, 0);
-  }
-
-  quat.set_x(vec.y());
-  quat.set_y(-vec.x());
-  quat.set_z(0.0);
-  return quat.Normalized();
-}
-
 gfx::Transform PerspectiveMatrixFromView(const gvr::Rectf& fov,
                                          float z_near,
                                          float z_far) {
@@ -194,7 +159,7 @@
 void LoadControllerModelTask(
     base::WeakPtr<VrShellGl> weak_vr_shell_gl,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  auto controller_model = VrControllerModel::LoadFromResources();
+  auto controller_model = vr::VrControllerModel::LoadFromResources();
   if (controller_model) {
     task_runner->PostTask(
         FROM_HERE, base::Bind(&VrShellGl::SetControllerModel, weak_vr_shell_gl,
@@ -309,6 +274,8 @@
   }
 
   input_manager_ = base::MakeUnique<vr::UiInputManager>(scene_, this);
+  ui_renderer_ = base::MakeUnique<vr::UiRenderer>(scene_, content_texture_id_,
+                                                  vr_shell_renderer_.get());
 }
 
 void VrShellGl::CreateContentSurface() {
@@ -356,6 +323,13 @@
   if (!submit_client_.get())
     return;
 
+  if (frame_index < 0 ||
+      !webvr_frame_oustanding_[frame_index % kPoseRingBufferSize]) {
+    mojo::ReportBadMessage("SubmitFrame called with an invalid frame_index");
+    binding_.Close();
+    return;
+  }
+
   webvr_time_js_submit_[frame_index % kPoseRingBufferSize] =
       base::TimeTicks::Now();
 
@@ -410,6 +384,8 @@
   TRACE_EVENT1("gpu", "VrShellGl::OnWebVRFrameAvailable", "frame", frame_index);
   pending_frames_.pop();
 
+  browser_->OnWebVrFrameAvailable();
+
   DrawFrame(frame_index);
 }
 
@@ -432,6 +408,7 @@
   device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose);
   webvr_head_pose_.assign(kPoseRingBufferSize, head_pose);
   webvr_time_pose_.assign(kPoseRingBufferSize, base::TimeTicks());
+  webvr_frame_oustanding_.assign(kPoseRingBufferSize, false);
   webvr_time_js_submit_.assign(kPoseRingBufferSize, base::TimeTicks());
 
   std::vector<gvr::BufferSpec> specs;
@@ -454,7 +431,7 @@
   swap_chain_ =
       base::MakeUnique<gvr::SwapChain>(gvr_api_->CreateSwapChain(specs));
 
-  vr_shell_renderer_ = base::MakeUnique<VrShellRenderer>();
+  vr_shell_renderer_ = base::MakeUnique<vr::VrShellRenderer>();
 
   // Allocate a buffer viewport for use in UI drawing. This isn't
   // initialized at this point, it'll be set from other viewport list
@@ -508,7 +485,7 @@
 
 void VrShellGl::UpdateController(const gfx::Vector3dF& head_direction) {
   controller_->UpdateState(head_direction);
-  pointer_start_ = controller_->GetPointerStart();
+  controller_info_.laser_origin = controller_->GetPointerStart();
 
   device::GvrGamepadData controller_data = controller_->GetGamepadData();
   browser_->UpdateGamepadData(controller_data);
@@ -529,7 +506,8 @@
     // 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(head_direction);
+    controller_quat_ =
+        gfx::Quaternion(gfx::Vector3dF(0.0f, 0.0f, -1.0f), head_direction);
   } else {
     ergo_neutral_pose = {0.0f, -sin(kErgoAngleOffset), -cos(kErgoAngleOffset)};
     controller_quat_ = controller_->Orientation();
@@ -544,22 +522,34 @@
   if (ShouldDrawWebVr())
     return;
 
+  controller_->GetTransform(&controller_info_.transform);
   std::unique_ptr<GestureList> gesture_list_ptr = controller_->DetectGestures();
   GestureList& gesture_list = *gesture_list_ptr;
-  vr::UiInputManager::ButtonState controller_button_state =
-      vr::UiInputManager::ButtonState::UP;
+  controller_info_.touchpad_button_state = vr::UiInputManager::ButtonState::UP;
   DCHECK(!(controller_->ButtonUpHappened(gvr::kControllerButtonClick) &&
            controller_->ButtonDownHappened(gvr::kControllerButtonClick)))
       << "Cannot handle a button down and up event within one frame.";
   if (touch_pending_) {
-    controller_button_state = vr::UiInputManager::ButtonState::CLICKED;
+    controller_info_.touchpad_button_state =
+        vr::UiInputManager::ButtonState::CLICKED;
     touch_pending_ = false;
   } else if (controller_->ButtonState(gvr::kControllerButtonClick)) {
-    controller_button_state = vr::UiInputManager::ButtonState::DOWN;
+    controller_info_.touchpad_button_state =
+        vr::UiInputManager::ButtonState::DOWN;
   }
-  input_manager_->HandleInput(controller_direction, pointer_start_,
-                              controller_button_state, gesture_list,
-                              &target_point_, &reticle_render_target_);
+  controller_info_.app_button_state =
+      controller_->ButtonState(gvr::kControllerButtonApp)
+          ? vr::UiInputManager::ButtonState::DOWN
+          : vr::UiInputManager::ButtonState::UP;
+  controller_info_.home_button_state =
+      controller_->ButtonState(gvr::kControllerButtonHome)
+          ? vr::UiInputManager::ButtonState::DOWN
+          : vr::UiInputManager::ButtonState::UP;
+  controller_info_.opacity = controller_->GetOpacity();
+  input_manager_->HandleInput(
+      controller_direction, controller_info_.laser_origin,
+      controller_info_.touchpad_button_state, gesture_list,
+      &controller_info_.target_point, &controller_info_.reticle_render_target);
 }
 
 void VrShellGl::HandleWebVrCompatibilityClick() {
@@ -790,27 +780,29 @@
                                              *webvr_left_viewport_);
     buffer_viewport_list_->SetBufferViewport(GVR_RIGHT_EYE,
                                              *webvr_right_viewport_);
-    if (render_size_primary_ != webvr_surface_size_) {
+    if (render_info_primary_.content_texture_size != webvr_surface_size_) {
       if (!webvr_surface_size_.width()) {
         // Don't try to resize to 0x0 pixels, drop frames until we get a
         // valid size.
         return;
       }
 
-      render_size_primary_ = webvr_surface_size_;
+      render_info_primary_.content_texture_size = webvr_surface_size_;
       DVLOG(1) << __FUNCTION__ << ": resize GVR to "
-               << render_size_primary_.width() << "x"
-               << render_size_primary_.height();
+               << render_info_primary_.content_texture_size.width() << "x"
+               << render_info_primary_.content_texture_size.height();
       swap_chain_->ResizeBuffer(
           kFramePrimaryBuffer,
-          {render_size_primary_.width(), render_size_primary_.height()});
+          {render_info_primary_.content_texture_size.width(),
+           render_info_primary_.content_texture_size.height()});
     }
   } else {
-    if (render_size_primary_ != render_size_vrshell_) {
-      render_size_primary_ = render_size_vrshell_;
+    if (render_info_primary_.content_texture_size != render_size_vrshell_) {
+      render_info_primary_.content_texture_size = render_size_vrshell_;
       swap_chain_->ResizeBuffer(
           kFramePrimaryBuffer,
-          {render_size_primary_.width(), render_size_primary_.height()});
+          {render_info_primary_.content_texture_size.width(),
+           render_info_primary_.content_texture_size.height()});
     }
   }
 
@@ -836,9 +828,12 @@
   if (ShouldDrawWebVr()) {
     static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize),
                   "kPoseRingBufferSize must be a power of 2");
-    head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize];
+    render_info_primary_.head_pose =
+        webvr_head_pose_[frame_index % kPoseRingBufferSize];
+    webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = false;
   } else {
-    device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose);
+    device::GvrDelegate::GetGvrPoseWithNeckModel(
+        gvr_api_.get(), &render_info_primary_.head_pose);
   }
 
   // Update the render position of all UI elements (including desktop).
@@ -858,15 +853,30 @@
   // textures.
   scene_->PrepareToDraw();
 
-  DrawWorldElements(head_pose);
-  DrawOverlayElements(head_pose);
+  UpdateEyeInfos(render_info_primary_.head_pose, kViewportListPrimaryOffset,
+                 render_info_primary_.content_texture_size,
+                 &render_info_primary_);
+  ui_renderer_->Draw(render_info_primary_, controller_info_, ShouldDrawWebVr());
 
   frame.Unbind();
 
   // Draw head-locked elements to a separate, non-reprojected buffer.
   if (scene_->HasVisibleHeadLockedElements()) {
     frame.BindBuffer(kFrameHeadlockedBuffer);
-    DrawHeadLockedElements();
+
+    // Add head-locked viewports. The list gets reset to just
+    // the recommended viewports (for the primary buffer) each frame.
+    buffer_viewport_list_->SetBufferViewport(
+        kViewportListHeadlockedOffset + GVR_LEFT_EYE,
+        *headlocked_left_viewport_);
+    buffer_viewport_list_->SetBufferViewport(
+        kViewportListHeadlockedOffset + GVR_RIGHT_EYE,
+        *headlocked_right_viewport_);
+
+    UpdateEyeInfos(render_info_headlocked_.head_pose,
+                   kViewportListHeadlockedOffset, render_size_headlocked_,
+                   &render_info_headlocked_);
+    ui_renderer_->DrawHeadLocked(render_info_headlocked_, controller_info_);
     frame.Unbind();
   }
 
@@ -878,11 +888,37 @@
         FROM_HERE,
         base::Bind(&VrShellGl::DrawFrameSubmitWhenReady,
                    weak_ptr_factory_.GetWeakPtr(), frame_index, frame.release(),
-                   head_pose, base::Passed(&fence)),
+                   render_info_primary_.head_pose, base::Passed(&fence)),
         kWebVRFenceCheckInterval);
   } else {
     // Continue with submit immediately.
-    DrawFrameSubmitWhenReady(frame_index, frame.release(), head_pose, nullptr);
+    DrawFrameSubmitWhenReady(frame_index, frame.release(),
+                             render_info_primary_.head_pose, nullptr);
+  }
+}
+
+void VrShellGl::UpdateEyeInfos(const gfx::Transform& head_pose,
+                               int viewport_offset,
+                               const gfx::Size& render_size,
+                               vr::RenderInfo* out_render_info) {
+  for (auto eye : {GVR_LEFT_EYE, GVR_RIGHT_EYE}) {
+    vr::RenderInfo::EyeInfo& eye_info = (eye == GVR_LEFT_EYE)
+                                            ? out_render_info->left_eye_info
+                                            : out_render_info->right_eye_info;
+
+    buffer_viewport_list_->GetBufferViewport(eye + viewport_offset,
+                                             buffer_viewport_.get());
+
+    gfx::Transform eye_matrix;
+    GvrMatToTransform(gvr_api_->GetEyeFromHeadMatrix(eye), &eye_matrix);
+    eye_info.view_matrix = eye_matrix * head_pose;
+
+    const gfx::RectF& rect = GfxRectFromUV(buffer_viewport_->GetSourceUv());
+    eye_info.viewport = vr::CalculatePixelSpaceRect(render_size, rect);
+
+    eye_info.proj_matrix = PerspectiveMatrixFromView(
+        buffer_viewport_->GetSourceFov(), kZNear, kZFar);
+    eye_info.view_proj_matrix = eye_info.proj_matrix * eye_info.view_matrix;
   }
 }
 
@@ -944,273 +980,6 @@
   TRACE_COUNTER1("gpu", "WebVR FPS", fps_meter_->GetFPS());
 }
 
-void VrShellGl::DrawWorldElements(const gfx::Transform& head_pose) {
-  TRACE_EVENT0("gpu", "VrShellGl::DrawWorldElements");
-
-  if (ShouldDrawWebVr()) {
-    // WebVR is incompatible with 3D world compositing since the
-    // depth buffer was already populated with unknown scaling - the
-    // WebVR app has full control over zNear/zFar. Just leave the
-    // existing content in place in the primary buffer without
-    // clearing. Currently, there aren't any world elements in WebVR
-    // mode, this will need further testing if those get added
-    // later.
-  } else {
-    // Non-WebVR mode, enable depth testing and clear the primary buffers.
-    glEnable(GL_CULL_FACE);
-    glEnable(GL_DEPTH_TEST);
-    glDepthMask(GL_TRUE);
-
-    const SkColor backgroundColor = scene_->GetWorldBackgroundColor();
-    glClearColor(SkColorGetR(backgroundColor) / 255.0,
-                 SkColorGetG(backgroundColor) / 255.0,
-                 SkColorGetB(backgroundColor) / 255.0,
-                 SkColorGetA(backgroundColor) / 255.0);
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-  }
-  std::vector<const vr::UiElement*> elements = scene_->GetWorldElements();
-  const bool draw_reticle =
-      !(scene_->is_exiting() || scene_->showing_splash_screen() ||
-        ShouldDrawWebVr());
-  DrawUiView(head_pose, elements, render_size_primary_,
-             kViewportListPrimaryOffset, draw_reticle);
-}
-
-void VrShellGl::DrawOverlayElements(const gfx::Transform& head_pose) {
-  std::vector<const vr::UiElement*> elements = scene_->GetOverlayElements();
-  if (elements.empty())
-    return;
-
-  glDisable(GL_CULL_FACE);
-  glDisable(GL_DEPTH_TEST);
-  glDepthMask(GL_FALSE);
-
-  const bool draw_reticle = false;
-  DrawUiView(head_pose, elements, render_size_primary_,
-             kViewportListPrimaryOffset, draw_reticle);
-}
-
-void VrShellGl::DrawHeadLockedElements() {
-  TRACE_EVENT0("gpu", "VrShellGl::DrawHeadLockedElements");
-  std::vector<const vr::UiElement*> elements = scene_->GetHeadLockedElements();
-
-  // Add head-locked viewports. The list gets reset to just
-  // the recommended viewports (for the primary buffer) each frame.
-  buffer_viewport_list_->SetBufferViewport(
-      kViewportListHeadlockedOffset + GVR_LEFT_EYE, *headlocked_left_viewport_);
-  buffer_viewport_list_->SetBufferViewport(
-      kViewportListHeadlockedOffset + GVR_RIGHT_EYE,
-      *headlocked_right_viewport_);
-
-  glEnable(GL_CULL_FACE);
-  glEnable(GL_DEPTH_TEST);
-  glDepthMask(GL_TRUE);
-
-  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-  gfx::Transform identity_matrix;
-  DrawUiView(identity_matrix, elements, render_size_headlocked_,
-             kViewportListHeadlockedOffset, false);
-}
-
-void VrShellGl::DrawUiView(const gfx::Transform& head_pose,
-                           const std::vector<const vr::UiElement*>& elements,
-                           const gfx::Size& render_size,
-                           int viewport_offset,
-                           bool draw_reticle) {
-  TRACE_EVENT0("gpu", "VrShellGl::DrawUiView");
-
-  auto sorted_elements = GetElementsInDrawOrder(head_pose, elements);
-
-  for (auto eye : {GVR_LEFT_EYE, GVR_RIGHT_EYE}) {
-    buffer_viewport_list_->GetBufferViewport(eye + viewport_offset,
-                                             buffer_viewport_.get());
-
-    gfx::Transform eye_matrix;
-    GvrMatToTransform(gvr_api_->GetEyeFromHeadMatrix(eye), &eye_matrix);
-    gfx::Transform eye_view_matrix = eye_matrix * head_pose;
-
-    const gfx::RectF& rect = GfxRectFromUV(buffer_viewport_->GetSourceUv());
-    const gfx::Rect& pixel_rect = CalculatePixelSpaceRect(render_size, rect);
-    glViewport(pixel_rect.x(), pixel_rect.y(), pixel_rect.width(),
-               pixel_rect.height());
-
-    gfx::Transform perspective_matrix = PerspectiveMatrixFromView(
-        buffer_viewport_->GetSourceFov(), kZNear, kZFar);
-    gfx::Transform view_proj_matrix = perspective_matrix * eye_view_matrix;
-
-    DrawElements(view_proj_matrix, sorted_elements, draw_reticle);
-    if (draw_reticle) {
-      DrawController(view_proj_matrix);
-      DrawLaser(view_proj_matrix);
-    }
-  }
-}
-
-void VrShellGl::DrawElements(const gfx::Transform& view_proj_matrix,
-                             const std::vector<const vr::UiElement*>& elements,
-                             bool draw_reticle) {
-  if (elements.empty())
-    return;
-  int initial_draw_phase = elements.front()->draw_phase();
-  bool drawn_reticle = false;
-  for (const auto* element : elements) {
-    // If we have no element to draw the reticle on, draw it after the
-    // background (the initial draw phase).
-    if (!reticle_render_target_ && draw_reticle && !drawn_reticle &&
-        element->draw_phase() > initial_draw_phase) {
-      DrawReticle(view_proj_matrix);
-      drawn_reticle = true;
-    }
-
-    DrawElement(view_proj_matrix, *element);
-
-    if (draw_reticle && (reticle_render_target_ == element)) {
-      DrawReticle(view_proj_matrix);
-    }
-  }
-  vr_shell_renderer_->Flush();
-}
-
-void VrShellGl::DrawElement(const gfx::Transform& view_proj_matrix,
-                            const vr::UiElement& element) {
-  gfx::Transform transform =
-      view_proj_matrix * element.screen_space_transform();
-
-  switch (element.fill()) {
-    case vr::Fill::OPAQUE_GRADIENT: {
-      vr_shell_renderer_->GetGradientQuadRenderer()->Draw(
-          transform, element.edge_color(), element.center_color(),
-          element.computed_opacity());
-      break;
-    }
-    case vr::Fill::GRID_GRADIENT: {
-      vr_shell_renderer_->GetGradientGridRenderer()->Draw(
-          transform, element.edge_color(), element.center_color(),
-          element.grid_color(), element.gridline_count(),
-          element.computed_opacity());
-      break;
-    }
-    case vr::Fill::CONTENT: {
-      vr_shell_renderer_->GetExternalTexturedQuadRenderer()->Draw(
-          content_texture_id_, transform, render_size_vrshell_,
-          gfx::SizeF(element.size().x(), element.size().y()),
-          element.computed_opacity(), element.corner_radius());
-      break;
-    }
-    case vr::Fill::SELF: {
-      element.Render(vr_shell_renderer_.get(), transform);
-      break;
-    }
-    default:
-      break;
-  }
-}
-
-std::vector<const vr::UiElement*> VrShellGl::GetElementsInDrawOrder(
-    const gfx::Transform& view_matrix,
-    const std::vector<const vr::UiElement*>& elements) {
-  std::vector<const vr::UiElement*> sorted_elements = elements;
-
-  // Sort elements primarily based on their draw phase (lower draw phase first)
-  // and secondarily based on their z-axis distance (more distant first).
-  // TODO(mthiesse, crbug.com/721356): This will not work well for elements not
-  // directly in front of the user, but works well enough for our initial
-  // release, and provides a consistent ordering that we can easily design
-  // around.
-  std::sort(sorted_elements.begin(), sorted_elements.end(),
-            [](const vr::UiElement* first, const vr::UiElement* second) {
-              if (first->draw_phase() != second->draw_phase()) {
-                return first->draw_phase() < second->draw_phase();
-              } else {
-                return first->screen_space_transform().matrix().get(2, 3) <
-                       second->screen_space_transform().matrix().get(2, 3);
-              }
-            });
-
-  return sorted_elements;
-}
-
-void VrShellGl::DrawReticle(const gfx::Transform& render_matrix) {
-  // Scale the reticle to have a fixed FOV size at any distance.
-  const float eye_to_target =
-      std::sqrt(target_point_.SquaredDistanceTo(kOrigin));
-
-  gfx::Transform mat;
-  mat.Scale3d(kReticleWidth * eye_to_target, kReticleHeight * eye_to_target, 1);
-
-  gfx::Quaternion rotation;
-  if (reticle_render_target_ != nullptr) {
-    // Make the reticle planar to the element it's hitting.
-    rotation = GetRotationFromZAxis(reticle_render_target_->GetNormal());
-  } else {
-    // Rotate the reticle to directly face the eyes.
-    rotation = GetRotationFromZAxis(target_point_ - kOrigin);
-  }
-  gfx::Transform rotation_mat(rotation);
-  mat = rotation_mat * mat;
-
-  gfx::Point3F target_point = ScalePoint(target_point_, kReticleOffset);
-  // Place the pointer slightly in front of the plane intersection point.
-  mat.matrix().postTranslate(target_point.x(), target_point.y(),
-                             target_point.z());
-
-  gfx::Transform transform = render_matrix * mat;
-  vr_shell_renderer_->GetReticleRenderer()->Draw(transform);
-}
-
-void VrShellGl::DrawLaser(const gfx::Transform& render_matrix) {
-  gfx::Point3F target_point = ScalePoint(target_point_, kReticleOffset);
-  // Find the length of the beam (from hand to target).
-  const float laser_length =
-      std::sqrt(pointer_start_.SquaredDistanceTo(target_point));
-
-  // Build a beam, originating from the origin.
-  gfx::Transform mat;
-
-  // Move the beam half its height so that its end sits on the origin.
-  mat.matrix().postTranslate(0.0f, 0.5f, 0.0f);
-  mat.matrix().postScale(kLaserWidth, laser_length, 1);
-
-  // Tip back 90 degrees to flat, pointing at the scene.
-  const gfx::Quaternion quat(gfx::Vector3dF(1.0f, 0.0f, 0.0f), -M_PI / 2);
-  gfx::Transform rotation_mat(quat);
-  mat = rotation_mat * mat;
-
-  const gfx::Vector3dF beam_direction = target_point_ - pointer_start_;
-
-  gfx::Transform beam_direction_mat(GetRotationFromZAxis(beam_direction));
-
-  float opacity = controller_->GetOpacity();
-  // Render multiple faces to make the laser appear cylindrical.
-  const int faces = 4;
-  gfx::Transform face_transform;
-  gfx::Transform transform;
-  for (int i = 0; i < faces; i++) {
-    // Rotate around Z.
-    const float angle = M_PI * 2 * i / faces;
-    const gfx::Quaternion rot({0.0f, 0.0f, 1.0f}, angle);
-    face_transform = beam_direction_mat * gfx::Transform(rot) * mat;
-
-    // Move the beam origin to the hand.
-    face_transform.matrix().postTranslate(
-        pointer_start_.x(), pointer_start_.y(), pointer_start_.z());
-    transform = render_matrix * face_transform;
-    vr_shell_renderer_->GetLaserRenderer()->Draw(opacity, transform);
-  }
-}
-
-void VrShellGl::DrawController(const gfx::Transform& view_proj_matrix) {
-  if (!vr_shell_renderer_->GetControllerRenderer()->IsSetUp())
-    return;
-  auto state = controller_->GetModelState();
-  auto opacity = controller_->GetOpacity();
-  gfx::Transform controller_transform;
-  controller_->GetTransform(&controller_transform);
-  gfx::Transform transform = view_proj_matrix * controller_transform;
-  vr_shell_renderer_->GetControllerRenderer()->Draw(state, opacity, transform);
-}
-
 bool VrShellGl::ShouldDrawWebVr() {
   return web_vr_mode_ && scene_->GetWebVrRenderingEnabled();
 }
@@ -1287,7 +1056,8 @@
   return weak_ptr_factory_.GetWeakPtr();
 }
 
-void VrShellGl::SetControllerModel(std::unique_ptr<VrControllerModel> model) {
+void VrShellGl::SetControllerModel(
+    std::unique_ptr<vr::VrControllerModel> model) {
   vr_shell_renderer_->GetControllerRenderer()->SetUp(std::move(model));
 }
 
@@ -1354,14 +1124,45 @@
   browser_->ForceExitVr();
 }
 
+namespace {
+bool ValidateRect(const gfx::RectF& bounds) {
+  // Bounds should be between 0 and 1, with positive width/height.
+  // We simply clamp to [0,1], but still validate that the bounds are not NAN.
+  return !std::isnan(bounds.width()) && !std::isnan(bounds.height()) &&
+         !std::isnan(bounds.x()) && !std::isnan(bounds.y());
+}
+
+gfx::RectF ClampRect(gfx::RectF bounds) {
+  bounds.AdjustToFit(gfx::RectF(0, 0, 1, 1));
+  return bounds;
+}
+
+}  // namespace
+
 void VrShellGl::UpdateLayerBounds(int16_t frame_index,
                                   const gfx::RectF& left_bounds,
                                   const gfx::RectF& right_bounds,
                                   const gfx::Size& source_size) {
+  if (!ValidateRect(left_bounds) || !ValidateRect(right_bounds)) {
+    mojo::ReportBadMessage("UpdateLayerBounds called with invalid bounds");
+    binding_.Close();
+    return;
+  }
+
+  if (frame_index >= 0 &&
+      !webvr_frame_oustanding_[frame_index % kPoseRingBufferSize]) {
+    mojo::ReportBadMessage("UpdateLayerBounds called with invalid frame_index");
+    binding_.Close();
+    return;
+  }
+
   if (frame_index < 0) {
-    webvr_left_viewport_->SetSourceUv(UVFromGfxRect(left_bounds));
-    webvr_right_viewport_->SetSourceUv(UVFromGfxRect(right_bounds));
+    webvr_left_viewport_->SetSourceUv(UVFromGfxRect(ClampRect(left_bounds)));
+    webvr_right_viewport_->SetSourceUv(UVFromGfxRect(ClampRect(right_bounds)));
     CreateOrResizeWebVRSurface(source_size);
+
+    // clear all pending bounds
+    pending_bounds_ = std::queue<std::pair<uint8_t, WebVrBounds>>();
   } else {
     pending_bounds_.emplace(
         frame_index, WebVrBounds(left_bounds, right_bounds, source_size));
@@ -1398,6 +1199,7 @@
                                                      prediction_nanos);
 
   webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat;
+  webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = true;
   webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now();
 
   std::move(callback).Run(
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.h b/chrome/browser/android/vr_shell/vr_shell_gl.h
index 8211ae8..2423a834 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.h
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.h
@@ -17,7 +17,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "chrome/browser/android/vr_shell/vr_controller.h"
-#include "chrome/browser/android/vr_shell/vr_controller_model.h"
+#include "chrome/browser/vr/ui_renderer.h"
+#include "chrome/browser/vr/vr_controller_model.h"
 #include "device/vr/vr_service.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
@@ -25,6 +26,7 @@
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 #include "ui/gfx/geometry/quaternion.h"
 #include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size_f.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace blink {
@@ -46,8 +48,8 @@
 namespace vr {
 class FPSMeter;
 class SlidingAverage;
-class UiElement;
 class UiScene;
+class VrShellRenderer;
 }  // namespace vr
 
 namespace vr_shell {
@@ -56,7 +58,6 @@
 class GlBrowserInterface;
 class VrController;
 class VrShell;
-class VrShellRenderer;
 
 struct WebVrBounds {
   WebVrBounds(const gfx::RectF& left,
@@ -101,7 +102,7 @@
   void UIPhysicalBoundsChanged(int width, int height);
   base::WeakPtr<VrShellGl> GetWeakPtr();
 
-  void SetControllerModel(std::unique_ptr<VrControllerModel> model);
+  void SetControllerModel(std::unique_ptr<vr::VrControllerModel> model);
 
   void UpdateVSyncInterval(base::TimeTicks vsync_timebase,
                            base::TimeDelta vsync_interval);
@@ -121,25 +122,6 @@
                                 gvr_frame* frame_ptr,
                                 const gfx::Transform& head_pose,
                                 std::unique_ptr<gl::GLFence> fence);
-  void DrawWorldElements(const gfx::Transform& head_pose);
-  void DrawOverlayElements(const gfx::Transform& head_pose);
-  void DrawHeadLockedElements();
-  void DrawUiView(const gfx::Transform& head_pose,
-                  const std::vector<const vr::UiElement*>& elements,
-                  const gfx::Size& render_size,
-                  int viewport_offset,
-                  bool draw_cursor);
-  void DrawElements(const gfx::Transform& view_proj_matrix,
-                    const std::vector<const vr::UiElement*>& elements,
-                    bool draw_cursor);
-  void DrawElement(const gfx::Transform& view_proj_matrix,
-                   const vr::UiElement& element);
-  std::vector<const vr::UiElement*> GetElementsInDrawOrder(
-      const gfx::Transform& view_matrix,
-      const std::vector<const vr::UiElement*>& elements);
-  void DrawReticle(const gfx::Transform& view_proj_matrix);
-  void DrawLaser(const gfx::Transform& view_proj_matrix);
-  void DrawController(const gfx::Transform& view_proj_matrix);
   bool ShouldDrawWebVr();
   void DrawWebVr();
   bool WebVrPoseByteIsValid(int pose_index_byte);
@@ -181,6 +163,11 @@
 
   void OnVSync();
 
+  void UpdateEyeInfos(const gfx::Transform& head_pose,
+                      int viewport_offset,
+                      const gfx::Size& render_size,
+                      vr::RenderInfo* out_render_info);
+
   // VRPresentationProvider
   void GetVSync(GetVSyncCallback callback) override;
   void SubmitFrame(int16_t frame_index,
@@ -229,15 +216,12 @@
   // can be restored after exiting WebVR mode.
   gfx::Size render_size_vrshell_;
 
-  std::unique_ptr<VrShellRenderer> vr_shell_renderer_;
+  std::unique_ptr<vr::VrShellRenderer> vr_shell_renderer_;
 
   bool cardboard_ = false;
   bool touch_pending_ = false;
   gfx::Quaternion controller_quat_;
 
-  gfx::Point3F target_point_;
-  vr::UiElement* reticle_render_target_ = nullptr;
-
   int content_tex_css_width_ = 0;
   int content_tex_css_height_ = 0;
   gfx::Size content_tex_physical_size_ = {0, 0};
@@ -245,7 +229,7 @@
 
   std::vector<base::TimeTicks> webvr_time_pose_;
   std::vector<base::TimeTicks> webvr_time_js_submit_;
-
+  std::vector<bool> webvr_frame_oustanding_;
   std::vector<gfx::Transform> webvr_head_pose_;
 
   bool web_vr_mode_;
@@ -285,6 +269,11 @@
   gfx::Point3F pointer_start_;
 
   std::unique_ptr<vr::UiInputManager> input_manager_;
+  std::unique_ptr<vr::UiRenderer> ui_renderer_;
+
+  vr::ControllerInfo controller_info_;
+  vr::RenderInfo render_info_primary_;
+  vr::RenderInfo render_info_headlocked_;
 
   base::WeakPtrFactory<VrShellGl> weak_ptr_factory_;
 
diff --git a/chrome/browser/android/warmup_manager.cc b/chrome/browser/android/warmup_manager.cc
index eb06a2e..e3271e3c 100644
--- a/chrome/browser/android/warmup_manager.cc
+++ b/chrome/browser/android/warmup_manager.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/net/predictor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
-#include "content/public/browser/render_process_host.h"
 #include "jni/WarmupManager_jni.h"
 #include "url/gurl.h"
 
@@ -28,14 +27,6 @@
   }
 }
 
-static void WarmupSpareRenderer(JNIEnv* env,
-                                const JavaParamRef<jclass>& clazz,
-                                const JavaParamRef<jobject>& jprofile) {
-  Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
-  if (profile) {
-    content::RenderProcessHost::WarmupSpareRenderProcessHost(profile);
-  }
-}
 
 // Register native methods.
 bool RegisterWarmupManager(JNIEnv* env) {
diff --git a/chrome/browser/browser_encoding_browsertest.cc b/chrome/browser/browser_encoding_browsertest.cc
index 79325655..9f39368 100644
--- a/chrome/browser/browser_encoding_browsertest.cc
+++ b/chrome/browser/browser_encoding_browsertest.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/download_test_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
 
@@ -68,37 +69,6 @@
   { "windows-1258.html", "windows-1258" }
 };
 
-class SavePackageFinishedObserver : public content::DownloadManager::Observer {
- public:
-  SavePackageFinishedObserver(content::DownloadManager* manager,
-                              const base::Closure& callback)
-      : download_manager_(manager),
-        callback_(callback) {
-    download_manager_->AddObserver(this);
-  }
-
-  ~SavePackageFinishedObserver() override {
-    if (download_manager_)
-      download_manager_->RemoveObserver(this);
-  }
-
-  // DownloadManager::Observer:
-  void OnSavePackageSuccessfullyFinished(content::DownloadManager* manager,
-                                         content::DownloadItem* item) override {
-    callback_.Run();
-  }
-  void ManagerGoingDown(content::DownloadManager* manager) override {
-    download_manager_->RemoveObserver(this);
-    download_manager_ = NULL;
-  }
-
- private:
-  content::DownloadManager* download_manager_;
-  base::Closure callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(SavePackageFinishedObserver);
-};
-
 }  // namespace
 
 using content::BrowserThread;
@@ -124,7 +94,7 @@
     // sub resources, but the directory name is still required.
     scoped_refptr<content::MessageLoopRunner> loop_runner(
         new content::MessageLoopRunner);
-    SavePackageFinishedObserver observer(
+    content::SavePackageFinishedObserver observer(
         content::BrowserContext::GetDownloadManager(browser()->profile()),
         loop_runner->QuitClosure());
     browser()->tab_strip_model()->GetActiveWebContents()->SavePage(
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 12ba413e..99bbf83 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -471,18 +471,12 @@
   ProfileManager* pm = profile_manager();
   std::vector<Profile*> profiles(pm->GetLoadedProfiles());
   scoped_refptr<RundownTaskCounter> rundown_counter(new RundownTaskCounter());
-  std::vector<scoped_refptr<base::SequencedTaskRunner>> profile_writer_runners;
   for (size_t i = 0; i < profiles.size(); ++i) {
     Profile* profile = profiles[i];
     profile->SetExitType(Profile::EXIT_SESSION_ENDED);
     if (profile->GetPrefs()) {
       profile->GetPrefs()->CommitPendingWrite();
-      if (profile->GetPrefServiceTaskRunner()) {
-        rundown_counter->Post(profile->GetPrefServiceTaskRunner().get());
-        profile_writer_runners.push_back(profile->GetIOTaskRunner());
-      } else {
-        rundown_counter->Post(profile->GetIOTaskRunner().get());
-      }
+      rundown_counter->Post(profile->GetIOTaskRunner().get());
     }
   }
 
@@ -524,15 +518,7 @@
   // processes to launch, this can result in a hang. See
   // http://crbug.com/318527.
   const base::TimeTicks end_time = base::TimeTicks::Now() + kEndSessionTimeout;
-  const bool timed_out = !rundown_counter->TimedWaitUntil(end_time);
-  if (timed_out || !base::FeatureList::IsEnabled(features::kPrefService))
-    return;
-
-  scoped_refptr<RundownTaskCounter> profile_write_rundown_counter(
-      new RundownTaskCounter());
-  for (auto& profile_writer_runner : profile_writer_runners)
-    profile_write_rundown_counter->Post(profile_writer_runner.get());
-  profile_write_rundown_counter->TimedWaitUntil(end_time);
+  rundown_counter->TimedWaitUntil(end_time);
 #else
   NOTIMPLEMENTED();
 #endif
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc
index 47e06b6..b779f69f 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.cc
+++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -257,7 +257,7 @@
     services->insert(std::make_pair(chromeos::kChromeServiceName, info));
   }
 
-  if (features::PrefServiceEnabled()) {
+  {
     service_manager::EmbeddedServiceInfo info;
     info.factory = base::Bind([] {
       return std::unique_ptr<service_manager::Service>(
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc
index d2bb713..af65c46 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc
@@ -16,11 +16,6 @@
 
 class CannedBrowsingDataIndexedDBHelperTest : public testing::Test {
  public:
-  void SetUp() override {
-    IndexedDBContext()->SetTaskRunnerForTesting(
-        base::ThreadTaskRunnerHandle::Get().get());
-  }
-
   content::IndexedDBContext* IndexedDBContext() {
     return content::BrowserContext::GetDefaultStoragePartition(&profile_)->
         GetIndexedDBContext();
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 38d453ed..060bf0c 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/web_history_service_factory.h"
 #include "chrome/browser/io_thread.h"
+#include "chrome/browser/language/url_language_histogram_factory.h"
 #include "chrome/browser/media/media_device_id_salt.h"
 #include "chrome/browser/media/media_engagement_service.h"
 #include "chrome/browser/net/nqe/ui_network_quality_estimator_service.h"
@@ -45,7 +46,6 @@
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
-#include "chrome/browser/translate/language_model_factory.h"
 #include "chrome/browser/web_data_service_factory.h"
 #include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
@@ -62,6 +62,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/domain_reliability/service.h"
 #include "components/history/core/browser/history_service.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/nacl/browser/nacl_browser.h"
 #include "components/nacl/browser/pnacl_host.h"
 #include "components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h"
@@ -73,7 +74,6 @@
 #include "components/previews/core/previews_ui_service.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/sessions/core/tab_restore_service.h"
-#include "components/translate/core/browser/language_model.h"
 #include "components/web_cache/browser/web_cache_manager.h"
 #include "content/public/browser/browsing_data_filter_builder.h"
 #include "content/public/browser/plugin_data_remover.h"
@@ -490,10 +490,11 @@
                                                   filter, bookmark_model);
     }
 
-    translate::LanguageModel* language_model =
-        LanguageModelFactory::GetInstance()->GetForBrowserContext(profile_);
-    if (language_model) {
-      language_model->ClearHistory(delete_begin_, delete_end_);
+    language::UrlLanguageHistogram* language_histogram =
+        UrlLanguageHistogramFactory::GetInstance()->GetForBrowserContext(
+            profile_);
+    if (language_histogram) {
+      language_histogram->ClearHistory(delete_begin_, delete_end_);
     }
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 3fe46b93..38ec2d9 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -24,11 +24,11 @@
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/language/url_language_histogram_factory.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/permissions/permission_decision_auto_blocker.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/storage/durable_storage_permission_context.h"
-#include "chrome/browser/translate/language_model_factory.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -50,6 +50,7 @@
 #include "components/domain_reliability/service.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/history/core/browser/history_service.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h"
 #include "components/omnibox/browser/omnibox_pref_names.h"
 #include "components/os_crypt/os_crypt_mocker.h"
@@ -57,7 +58,6 @@
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "components/prefs/testing_pref_service.h"
-#include "components/translate/core/browser/language_model.h"
 #include "content/public/browser/browsing_data_filter_builder.h"
 #include "content/public/browser/browsing_data_remover.h"
 #include "content/public/test/browsing_data_remover_test_util.h"
@@ -2072,18 +2072,19 @@
 }
 
 // Test that the remover clears language model data (normally added by the
-// ChromeTranslateClient).
+// LanguageDetectionDriver).
 TEST_F(ChromeBrowsingDataRemoverDelegateTest,
-       LanguageModelClearedOnClearingCompleteHistory) {
-  translate::LanguageModel* language_model =
-      LanguageModelFactory::GetInstance()->GetForBrowserContext(GetProfile());
+       LanguageHistogramClearedOnClearingCompleteHistory) {
+  language::UrlLanguageHistogram* language_histogram =
+      UrlLanguageHistogramFactory::GetInstance()->GetForBrowserContext(
+          GetProfile());
 
   // Simulate browsing.
   for (int i = 0; i < 100; i++) {
-    language_model->OnPageVisited("en");
-    language_model->OnPageVisited("en");
-    language_model->OnPageVisited("en");
-    language_model->OnPageVisited("es");
+    language_histogram->OnPageVisited("en");
+    language_histogram->OnPageVisited("en");
+    language_histogram->OnPageVisited("en");
+    language_histogram->OnPageVisited("es");
   }
 
   // Clearing a part of the history has no effect.
@@ -2091,18 +2092,18 @@
       AnHourAgo(), base::Time::Max(),
       ChromeBrowsingDataRemoverDelegate::DATA_TYPE_HISTORY, false);
 
-  EXPECT_THAT(language_model->GetTopLanguages(), SizeIs(2));
-  EXPECT_THAT(language_model->GetLanguageFrequency("en"), FloatEq(0.75));
-  EXPECT_THAT(language_model->GetLanguageFrequency("es"), FloatEq(0.25));
+  EXPECT_THAT(language_histogram->GetTopLanguages(), SizeIs(2));
+  EXPECT_THAT(language_histogram->GetLanguageFrequency("en"), FloatEq(0.75));
+  EXPECT_THAT(language_histogram->GetLanguageFrequency("es"), FloatEq(0.25));
 
   // Clearing the full history does the trick.
   BlockUntilBrowsingDataRemoved(
       base::Time(), base::Time::Max(),
       ChromeBrowsingDataRemoverDelegate::DATA_TYPE_HISTORY, false);
 
-  EXPECT_THAT(language_model->GetTopLanguages(), SizeIs(0));
-  EXPECT_THAT(language_model->GetLanguageFrequency("en"), FloatEq(0.0));
-  EXPECT_THAT(language_model->GetLanguageFrequency("es"), FloatEq(0.0));
+  EXPECT_THAT(language_histogram->GetTopLanguages(), SizeIs(0));
+  EXPECT_THAT(language_histogram->GetLanguageFrequency("en"), FloatEq(0.0));
+  EXPECT_THAT(language_histogram->GetLanguageFrequency("es"), FloatEq(0.0));
 }
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index c32c0c7..eb79a33e 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -609,14 +609,14 @@
  protected:
   void RunNavigationHintTest(
       const char* scope,
-      content::StartServiceWorkerForNavigationHintResult expeced_requst,
+      content::StartServiceWorkerForNavigationHintResult expected_result,
       bool expected_started) {
     base::RunLoop run_loop;
     GetServiceWorkerContext()->StartServiceWorkerForNavigationHint(
         embedded_test_server()->GetURL(scope),
         base::Bind(&ExpectResultAndRun<
                        content::StartServiceWorkerForNavigationHintResult>,
-                   expeced_requst, run_loop.QuitClosure()));
+                   expected_result, run_loop.QuitClosure()));
     run_loop.Run();
     if (expected_started) {
       histogram_tester_.ExpectBucketCount(
@@ -631,6 +631,9 @@
       histogram_tester_.ExpectTotalCount(
           "ServiceWorker.StartWorker.StatusByPurpose_NAVIGATION_HINT", 0);
     }
+    histogram_tester_.ExpectBucketCount(
+        "ServiceWorker.StartForNavigationHint.Result",
+        static_cast<int>(expected_result), 1);
   }
 
   base::HistogramTester histogram_tester_;
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
index c667b28c..393b26e 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -28,7 +28,7 @@
 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index ffd4c5d..fa207f3 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -56,6 +56,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/download_test_observer.h"
 #include "content/public/test/test_utils.h"
 #include "net/base/filename_util.h"
 #include "net/dns/mock_host_resolver.h"
@@ -273,37 +274,6 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadItemCreatedObserver);
 };
 
-class SavePackageFinishedObserver : public content::DownloadManager::Observer {
- public:
-  SavePackageFinishedObserver(content::DownloadManager* manager,
-                              const base::Closure& callback)
-      : download_manager_(manager),
-        callback_(callback) {
-    download_manager_->AddObserver(this);
-  }
-
-  ~SavePackageFinishedObserver() override {
-    if (download_manager_)
-      download_manager_->RemoveObserver(this);
-  }
-
-  // DownloadManager::Observer:
-  void OnSavePackageSuccessfullyFinished(content::DownloadManager* manager,
-                                         content::DownloadItem* item) override {
-    callback_.Run();
-  }
-  void ManagerGoingDown(content::DownloadManager* manager) override {
-    download_manager_->RemoveObserver(this);
-    download_manager_ = NULL;
-  }
-
- private:
-  content::DownloadManager* download_manager_;
-  base::Closure callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(SavePackageFinishedObserver);
-};
-
 class SavePageBrowserTest : public InProcessBrowserTest {
  public:
   SavePageBrowserTest() {}
@@ -387,11 +357,12 @@
         base::Bind(&DownloadStoredProperly, url, *main_file_name,
                    expected_number_of_files, history::DownloadState::COMPLETE));
     base::RunLoop run_loop;
-    SavePackageFinishedObserver observer(
+    content::SavePackageFinishedObserver observer(
         content::BrowserContext::GetDownloadManager(browser()->profile()),
         run_loop.QuitClosure());
     ASSERT_TRUE(GetCurrentTab(browser())
                     ->SavePage(*main_file_name, *output_dir, save_page_type));
+
     run_loop.Run();
     ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
     persisted.WaitForPersisted();
@@ -593,7 +564,7 @@
   GetDestinationPaths("b", &full_file_name, &dir);
   scoped_refptr<content::MessageLoopRunner> loop_runner(
       new content::MessageLoopRunner);
-  SavePackageFinishedObserver observer(
+  content::SavePackageFinishedObserver observer(
       content::BrowserContext::GetDownloadManager(incognito->profile()),
       loop_runner->QuitClosure());
   ASSERT_TRUE(GetCurrentTab(incognito)->SavePage(
@@ -626,7 +597,7 @@
       history::DownloadState::COMPLETE));
   scoped_refptr<content::MessageLoopRunner> loop_runner(
       new content::MessageLoopRunner);
-  SavePackageFinishedObserver observer(
+  content::SavePackageFinishedObserver observer(
       content::BrowserContext::GetDownloadManager(browser()->profile()),
       loop_runner->QuitClosure());
   ASSERT_TRUE(GetCurrentTab(browser())->SavePage(
@@ -691,7 +662,7 @@
   SavePackageFilePicker::SetShouldPromptUser(false);
   scoped_refptr<content::MessageLoopRunner> loop_runner(
       new content::MessageLoopRunner);
-  SavePackageFinishedObserver observer(
+  content::SavePackageFinishedObserver observer(
       content::BrowserContext::GetDownloadManager(browser()->profile()),
       loop_runner->QuitClosure());
   chrome::SavePage(browser());
@@ -732,7 +703,7 @@
       history::DownloadState::COMPLETE));
   scoped_refptr<content::MessageLoopRunner> loop_runner(
       new content::MessageLoopRunner);
-  SavePackageFinishedObserver observer(
+  content::SavePackageFinishedObserver observer(
       content::BrowserContext::GetDownloadManager(browser()->profile()),
       loop_runner->QuitClosure());
   chrome::SavePage(browser());
@@ -758,7 +729,7 @@
   ui_test_utils::NavigateToURL(browser(), url);
   scoped_refptr<content::MessageLoopRunner> loop_runner(
       new content::MessageLoopRunner);
-  SavePackageFinishedObserver observer(
+  content::SavePackageFinishedObserver observer(
       content::BrowserContext::GetDownloadManager(browser()->profile()),
       loop_runner->QuitClosure());
   chrome::SavePage(browser());
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index e8d901d..07509f3 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -192,10 +192,10 @@
     "api/feedback_private/feedback_service.h",
     "api/file_handlers/non_native_file_system_delegate_chromeos.cc",
     "api/file_handlers/non_native_file_system_delegate_chromeos.h",
+    "api/file_system/chrome_file_system_delegate.cc",
+    "api/file_system/chrome_file_system_delegate.h",
     "api/file_system/file_entry_picker.cc",
     "api/file_system/file_entry_picker.h",
-    "api/file_system/file_system_api.cc",
-    "api/file_system/file_system_api.h",
     "api/font_settings/font_settings_api.cc",
     "api/font_settings/font_settings_api.h",
     "api/gcm/gcm_api.cc",
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index 11c840f..a570d50 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/extensions/api/chrome_device_permissions_prompt.h"
 #include "chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h"
 #include "chrome/browser/extensions/api/declarative_content/default_content_predicate_evaluators.h"
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h"
 #include "chrome/browser/extensions/api/management/chrome_management_api_delegate.h"
 #include "chrome/browser/extensions/api/metrics_private/chrome_metrics_private_delegate.h"
 #include "chrome/browser/extensions/api/networking_cast_private/chrome_networking_cast_private_delegate.h"
@@ -179,6 +180,12 @@
   return networking_cast_private_delegate_.get();
 }
 
+FileSystemDelegate* ChromeExtensionsAPIClient::GetFileSystemDelegate() {
+  if (!file_system_delegate_)
+    file_system_delegate_ = base::MakeUnique<ChromeFileSystemDelegate>();
+  return file_system_delegate_.get();
+}
+
 #if defined(OS_CHROMEOS)
 NonNativeFileSystemDelegate*
 ChromeExtensionsAPIClient::GetNonNativeFileSystemDelegate() {
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chrome/browser/extensions/api/chrome_extensions_api_client.h
index 134df51..1b791b9 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -55,6 +55,7 @@
   ManagementAPIDelegate* CreateManagementAPIDelegate() const override;
   MetricsPrivateDelegate* GetMetricsPrivateDelegate() override;
   NetworkingCastPrivateDelegate* GetNetworkingCastPrivateDelegate() override;
+  FileSystemDelegate* GetFileSystemDelegate() override;
 
 #if defined(OS_CHROMEOS)
   NonNativeFileSystemDelegate* GetNonNativeFileSystemDelegate() override;
@@ -71,6 +72,7 @@
   std::unique_ptr<ChromeMetricsPrivateDelegate> metrics_private_delegate_;
   std::unique_ptr<NetworkingCastPrivateDelegate>
       networking_cast_private_delegate_;
+  std::unique_ptr<FileSystemDelegate> file_system_delegate_;
 
 #if defined(OS_CHROMEOS)
   std::unique_ptr<NonNativeFileSystemDelegate> non_native_file_system_delegate_;
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index 56dc506..7580156 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -13,7 +13,6 @@
 #include "base/scoped_observer.h"
 #include "chrome/browser/extensions/api/commands/command_service.h"
 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/error_console/error_console.h"
 #include "chrome/browser/extensions/extension_management.h"
@@ -22,6 +21,7 @@
 #include "chrome/common/extensions/api/developer_private.h"
 #include "chrome/common/extensions/webstore_install_result.h"
 #include "components/prefs/pref_change_registrar.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/event_router.h"
diff --git a/chrome/browser/extensions/api/file_system/DEPS b/chrome/browser/extensions/api/file_system/DEPS
index 2bb1dad..b9a9cec 100644
--- a/chrome/browser/extensions/api/file_system/DEPS
+++ b/chrome/browser/extensions/api/file_system/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "+chrome/browser/ui/views/extensions",
-  "+components/constrained_window",
 ]
 
 specific_include_rules = {
diff --git a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
new file mode 100644
index 0000000..2bad956
--- /dev/null
+++ b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
@@ -0,0 +1,398 @@
+// 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 "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h"
+
+#include <utility>
+#include <vector>
+
+#include "apps/saved_files_service.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/extensions/api/file_system/file_entry_picker.h"
+#include "chrome/browser/extensions/chrome_extension_function_details.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/apps/directory_access_confirmation_dialog.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
+#include "extensions/browser/api/file_system/saved_files_service_interface.h"
+#include "extensions/browser/app_window/app_window.h"
+#include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_util.h"
+#include "extensions/common/api/file_system.h"
+#include "extensions/common/extension.h"
+#include "storage/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/common/fileapi/file_system_types.h"
+#include "storage/common/fileapi/file_system_util.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#include "base/mac/foundation_util.h"
+#endif
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/file_manager/volume_manager.h"
+#include "chrome/browser/extensions/api/file_system/consent_provider.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/constants.h"
+#include "url/url_constants.h"
+#endif
+
+namespace extensions {
+
+namespace file_system = api::file_system;
+
+#if defined(OS_CHROMEOS)
+using file_system_api::ConsentProvider;
+using file_system_api::ConsentProviderDelegate;
+
+namespace {
+
+const char kConsentImpossible[] =
+    "Impossible to ask for user consent as there is no app window visible.";
+const char kNotSupportedOnNonKioskSessionError[] =
+    "Operation only supported for kiosk apps running in a kiosk session.";
+const char kRequiresFileSystemWriteError[] =
+    "Operation requires fileSystem.write permission";
+const char kSecurityError[] = "Security error.";
+const char kVolumeNotFoundError[] = "Volume not found.";
+
+// Fills a list of volumes mounted in the system.
+void FillVolumeList(content::BrowserContext* browser_context,
+                    std::vector<file_system::Volume>* result) {
+  file_manager::VolumeManager* const volume_manager =
+      file_manager::VolumeManager::Get(browser_context);
+  DCHECK(volume_manager);
+
+  const auto& volume_list = volume_manager->GetVolumeList();
+  // Convert volume_list to result_volume_list.
+  for (const auto& volume : volume_list) {
+    file_system::Volume result_volume;
+    result_volume.volume_id = volume->volume_id();
+    result_volume.writable = !volume->is_read_only();
+    result->push_back(std::move(result_volume));
+  }
+}
+
+// Callback called when consent is granted or denied.
+void OnConsentReceived(
+    content::BrowserContext* browser_context,
+    scoped_refptr<UIThreadExtensionFunction> requester,
+    const FileSystemDelegate::FileSystemCallback& success_callback,
+    const FileSystemDelegate::ErrorCallback& error_callback,
+    const std::string& extension_id,
+    const base::WeakPtr<file_manager::Volume>& volume,
+    bool writable,
+    ConsentProvider::Consent result) {
+  using file_manager::VolumeManager;
+  using file_manager::Volume;
+
+  // Render frame host can be gone before this callback method is executed.
+  if (!requester->render_frame_host()) {
+    error_callback.Run(std::string());
+    return;
+  }
+
+  switch (result) {
+    case ConsentProvider::CONSENT_REJECTED:
+      error_callback.Run(kSecurityError);
+      return;
+
+    case ConsentProvider::CONSENT_IMPOSSIBLE:
+      error_callback.Run(kConsentImpossible);
+      return;
+
+    case ConsentProvider::CONSENT_GRANTED:
+      break;
+  }
+
+  if (!volume.get()) {
+    error_callback.Run(kVolumeNotFoundError);
+    return;
+  }
+
+  const GURL site = util::GetSiteForExtensionId(extension_id, browser_context);
+  scoped_refptr<storage::FileSystemContext> file_system_context =
+      content::BrowserContext::GetStoragePartitionForSite(browser_context, site)
+          ->GetFileSystemContext();
+  storage::ExternalFileSystemBackend* const backend =
+      file_system_context->external_backend();
+  DCHECK(backend);
+
+  base::FilePath virtual_path;
+  if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) {
+    error_callback.Run(kSecurityError);
+    return;
+  }
+
+  storage::IsolatedContext* const isolated_context =
+      storage::IsolatedContext::GetInstance();
+  DCHECK(isolated_context);
+
+  const storage::FileSystemURL original_url =
+      file_system_context->CreateCrackedFileSystemURL(
+          GURL(std::string(kExtensionScheme) + url::kStandardSchemeSeparator +
+               extension_id),
+          storage::kFileSystemTypeExternal, virtual_path);
+
+  // Set a fixed register name, as the automatic one would leak the mount point
+  // directory.
+  std::string register_name = "fs";
+  const std::string file_system_id =
+      isolated_context->RegisterFileSystemForPath(
+          storage::kFileSystemTypeNativeForPlatformApp,
+          std::string() /* file_system_id */, original_url.path(),
+          &register_name);
+  if (file_system_id.empty()) {
+    error_callback.Run(kSecurityError);
+    return;
+  }
+
+  backend->GrantFileAccessToExtension(extension_id, virtual_path);
+
+  // Grant file permissions to the renderer hosting component.
+  content::ChildProcessSecurityPolicy* policy =
+      content::ChildProcessSecurityPolicy::GetInstance();
+  DCHECK(policy);
+
+  const auto process_id = requester->render_frame_host()->GetProcess()->GetID();
+  // Read-only permisisons.
+  policy->GrantReadFile(process_id, volume->mount_path());
+  policy->GrantReadFileSystem(process_id, file_system_id);
+
+  // Additional write permissions.
+  if (writable) {
+    policy->GrantCreateReadWriteFile(process_id, volume->mount_path());
+    policy->GrantCopyInto(process_id, volume->mount_path());
+    policy->GrantWriteFileSystem(process_id, file_system_id);
+    policy->GrantDeleteFromFileSystem(process_id, file_system_id);
+    policy->GrantCreateFileForFileSystem(process_id, file_system_id);
+  }
+
+  success_callback.Run(file_system_id, register_name);
+}
+
+}  // namespace
+
+namespace file_system_api {
+
+void DispatchVolumeListChangeEvent(content::BrowserContext* browser_context) {
+  DCHECK(browser_context);
+  EventRouter* const event_router = EventRouter::Get(browser_context);
+  if (!event_router)  // Possible on shutdown.
+    return;
+
+  ExtensionRegistry* const registry = ExtensionRegistry::Get(browser_context);
+  if (!registry)  // Possible on shutdown.
+    return;
+
+  ConsentProviderDelegate consent_provider_delegate(
+      Profile::FromBrowserContext(browser_context));
+  ConsentProvider consent_provider(&consent_provider_delegate);
+  file_system::VolumeListChangedEvent event_args;
+  FillVolumeList(browser_context, &event_args.volumes);
+  for (const auto& extension : registry->enabled_extensions()) {
+    if (!consent_provider.IsGrantable(*extension.get()))
+      continue;
+    event_router->DispatchEventToExtension(
+        extension->id(),
+        base::MakeUnique<Event>(
+            events::FILE_SYSTEM_ON_VOLUME_LIST_CHANGED,
+            file_system::OnVolumeListChanged::kEventName,
+            file_system::OnVolumeListChanged::Create(event_args)));
+  }
+}
+
+}  // namespace file_system_api
+#endif  // defined(OS_CHROMEOS)
+
+ChromeFileSystemDelegate::ChromeFileSystemDelegate() {}
+
+ChromeFileSystemDelegate::~ChromeFileSystemDelegate() {}
+
+base::FilePath ChromeFileSystemDelegate::GetDefaultDirectory() {
+  base::FilePath documents_dir;
+  PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir);
+  return documents_dir;
+}
+
+bool ChromeFileSystemDelegate::ShowSelectFileDialog(
+    scoped_refptr<UIThreadExtensionFunction> extension_function,
+    ui::SelectFileDialog::Type type,
+    const base::FilePath& default_path,
+    const ui::SelectFileDialog::FileTypeInfo* file_types,
+    FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+    base::OnceClosure file_selection_canceled_callback) {
+  const Extension* extension = extension_function->extension();
+  content::WebContents* web_contents = nullptr;
+
+  // TODO(asargent/benwells) - As a short term remediation for
+  // crbug.com/179010 we're adding the ability for a whitelisted extension to
+  // use this API since chrome.fileBrowserHandler.selectFile is ChromeOS-only.
+  // Eventually we'd like a better solution and likely this code will go back
+  // to being platform-app only.
+  if (extension->is_platform_app()) {
+    content::WebContents* candidate = content::WebContents::FromRenderFrameHost(
+        extension_function->render_frame_host());
+    // Make sure there is an app window associated with the web contents.
+    if (AppWindowRegistry::Get(extension_function->browser_context())
+            ->GetAppWindowForWebContents(candidate)) {
+      web_contents = candidate;
+    }
+  } else {
+    // TODO(michaelpg): As a workaround for crbug.com/736930, allow this to work
+    // from a background page by using the the extended GetAssociatedWebContents
+    // function provided by ChromeExtensionFunctionDetails. This is safe because
+    // only whitelisted extensions can access the chrome.fileSystem API;
+    // platform apps cannot open the file picker from a background page.
+    web_contents = ChromeExtensionFunctionDetails(extension_function.get())
+                       .GetAssociatedWebContents();
+  }
+
+  if (!web_contents)
+    return false;
+
+  // The file picker will hold a reference to the UIThreadExtensionFunction
+  // instance, preventing its destruction (and subsequent sending of the
+  // function response) until the user has selected a file or cancelled the
+  // picker. At that point, the picker will delete itself, which will also free
+  // the function instance.
+  new FileEntryPicker(web_contents, default_path, *file_types, type,
+                      std::move(files_selected_callback),
+                      std::move(file_selection_canceled_callback));
+  return true;
+}
+
+void ChromeFileSystemDelegate::ConfirmSensitiveDirectoryAccess(
+    bool has_write_permission,
+    const base::string16& app_name,
+    content::WebContents* web_contents,
+    const base::Closure& on_accept,
+    const base::Closure& on_cancel) {
+  CreateDirectoryAccessConfirmationDialog(has_write_permission, app_name,
+                                          web_contents, on_accept, on_cancel);
+}
+
+int ChromeFileSystemDelegate::GetDescriptionIdForAcceptType(
+    const std::string& accept_type) {
+  if (accept_type == "image/*")
+    return IDS_IMAGE_FILES;
+  if (accept_type == "audio/*")
+    return IDS_AUDIO_FILES;
+  if (accept_type == "video/*")
+    return IDS_VIDEO_FILES;
+  return 0;
+}
+
+#if defined(OS_CHROMEOS)
+bool ChromeFileSystemDelegate::IsGrantable(
+    content::BrowserContext* browser_context,
+    content::RenderFrameHost* render_frame_host,
+    const Extension& extension) {
+  // Only kiosk apps in kiosk sessions can use this API.
+  // Additionally it is enabled for whitelisted component extensions and apps.
+  ConsentProviderDelegate consent_provider_delegate(
+      Profile::FromBrowserContext(browser_context));
+  return ConsentProvider(&consent_provider_delegate).IsGrantable(extension);
+}
+
+void ChromeFileSystemDelegate::RequestFileSystem(
+    content::BrowserContext* browser_context,
+    scoped_refptr<UIThreadExtensionFunction> requester,
+    const Extension& extension,
+    std::string volume_id,
+    bool writable,
+    const FileSystemCallback& success_callback,
+    const ErrorCallback& error_callback) {
+  ConsentProviderDelegate consent_provider_delegate(
+      Profile::FromBrowserContext(browser_context));
+  ConsentProvider consent_provider(&consent_provider_delegate);
+
+  if (!consent_provider.IsGrantable(extension)) {
+    error_callback.Run(kNotSupportedOnNonKioskSessionError);
+    return;
+  }
+
+  using file_manager::VolumeManager;
+  using file_manager::Volume;
+  VolumeManager* const volume_manager = VolumeManager::Get(browser_context);
+  DCHECK(volume_manager);
+
+  if (writable &&
+      !app_file_handler_util::HasFileSystemWritePermission(&extension)) {
+    error_callback.Run(kRequiresFileSystemWriteError);
+    return;
+  }
+
+  base::WeakPtr<file_manager::Volume> volume =
+      volume_manager->FindVolumeById(volume_id);
+  if (!volume.get()) {
+    error_callback.Run(kVolumeNotFoundError);
+    return;
+  }
+
+  const GURL site =
+      util::GetSiteForExtensionId(extension.id(), browser_context);
+  scoped_refptr<storage::FileSystemContext> file_system_context =
+      content::BrowserContext::GetStoragePartitionForSite(browser_context, site)
+          ->GetFileSystemContext();
+  storage::ExternalFileSystemBackend* const backend =
+      file_system_context->external_backend();
+  DCHECK(backend);
+
+  base::FilePath virtual_path;
+  if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) {
+    error_callback.Run(kSecurityError);
+    return;
+  }
+
+  if (writable && (volume->is_read_only())) {
+    error_callback.Run(kSecurityError);
+    return;
+  }
+
+  const ConsentProvider::ConsentCallback& callback = base::Bind(
+      &OnConsentReceived, browser_context, requester, success_callback,
+      error_callback, extension.id(), volume, writable);
+
+  consent_provider.RequestConsent(extension, requester->render_frame_host(),
+                                  volume, writable, callback);
+}
+
+void ChromeFileSystemDelegate::GetVolumeList(
+    content::BrowserContext* browser_context,
+    const VolumeListCallback& success_callback,
+    const ErrorCallback& error_callback) {
+  std::vector<file_system::Volume> result_volume_list;
+  FillVolumeList(browser_context, &result_volume_list);
+
+  success_callback.Run(result_volume_list);
+}
+
+#endif  // defined(OS_CHROMEOS)
+
+SavedFilesServiceInterface* ChromeFileSystemDelegate::GetSavedFilesService(
+    content::BrowserContext* browser_context) {
+  return apps::SavedFilesService::Get(browser_context);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h
new file mode 100644
index 0000000..f827a68
--- /dev/null
+++ b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h
@@ -0,0 +1,71 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_H_
+#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_H_
+
+#include "extensions/browser/api/file_system/file_system_delegate.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+
+namespace extensions {
+
+#if defined(OS_CHROMEOS)
+namespace file_system_api {
+
+// Dispatches an event about a mounted or unmounted volume in the system to
+// each extension which can request it.
+void DispatchVolumeListChangeEvent(content::BrowserContext* browser_context);
+
+}  // namespace file_system_api
+#endif  // defined(OS_CHROMEOS)
+
+class ChromeFileSystemDelegate : public FileSystemDelegate {
+ public:
+  ChromeFileSystemDelegate();
+  ~ChromeFileSystemDelegate() override;
+
+  // FileSystemDelegate:
+  base::FilePath GetDefaultDirectory() override;
+  bool ShowSelectFileDialog(
+      scoped_refptr<UIThreadExtensionFunction> extension_function,
+      ui::SelectFileDialog::Type type,
+      const base::FilePath& default_path,
+      const ui::SelectFileDialog::FileTypeInfo* file_types,
+      FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+      base::OnceClosure file_selection_canceled_callback) override;
+  void ConfirmSensitiveDirectoryAccess(bool has_write_permission,
+                                       const base::string16& app_name,
+                                       content::WebContents* web_contents,
+                                       const base::Closure& on_accept,
+                                       const base::Closure& on_cancel) override;
+  int GetDescriptionIdForAcceptType(const std::string& accept_type) override;
+#if defined(OS_CHROMEOS)
+  bool IsGrantable(content::BrowserContext* browser_context,
+                   content::RenderFrameHost* render_frame_host,
+                   const Extension& extension) override;
+  void RequestFileSystem(content::BrowserContext* browser_context,
+                         scoped_refptr<UIThreadExtensionFunction> requester,
+                         const Extension& extension,
+                         std::string volume_id,
+                         bool writable,
+                         const FileSystemCallback& success_callback,
+                         const ErrorCallback& error_callback) override;
+  void GetVolumeList(content::BrowserContext* browser_context,
+                     const VolumeListCallback& success_callback,
+                     const ErrorCallback& error_callback) override;
+#endif  // defined(OS_CHROMEOS)
+  SavedFilesServiceInterface* GetSavedFilesService(
+      content::BrowserContext* browser_context) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ChromeFileSystemDelegate);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_H_
diff --git a/chrome/browser/extensions/api/file_system/consent_provider.cc b/chrome/browser/extensions/api/file_system/consent_provider.cc
index a6e087c..a9aac11 100644
--- a/chrome/browser/extensions/api/file_system/consent_provider.cc
+++ b/chrome/browser/extensions/api/file_system/consent_provider.cc
@@ -17,12 +17,12 @@
 #include "chrome/browser/extensions/api/file_system/request_file_system_notification.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/views/extensions/request_file_system_dialog_view.h"
-#include "chrome/common/extensions/api/file_system.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/common/api/file_system.h"
 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
 
 namespace extensions {
@@ -85,6 +85,7 @@
 
 void ConsentProvider::RequestConsent(
     const Extension& extension,
+    content::RenderFrameHost* host,
     const base::WeakPtr<file_manager::Volume>& volume,
     bool writable,
     const ConsentCallback& callback) {
@@ -111,7 +112,7 @@
   // the confirmation dialog.
   if (KioskModeInfo::IsKioskOnly(&extension) &&
       user_manager::UserManager::Get()->IsLoggedInAsKioskApp()) {
-    delegate_->ShowDialog(extension, volume, writable,
+    delegate_->ShowDialog(extension, host, volume, writable,
                           base::Bind(&DialogResultToConsent, callback));
     return;
   }
@@ -130,9 +131,8 @@
   return is_whitelisted_component || is_running_in_kiosk_session;
 }
 
-ConsentProviderDelegate::ConsentProviderDelegate(Profile* profile,
-                                                 content::RenderFrameHost* host)
-    : profile_(profile), host_(host) {
+ConsentProviderDelegate::ConsentProviderDelegate(Profile* profile)
+    : profile_(profile) {
   DCHECK(profile_);
 }
 
@@ -147,15 +147,16 @@
 
 void ConsentProviderDelegate::ShowDialog(
     const Extension& extension,
+    content::RenderFrameHost* host,
     const base::WeakPtr<file_manager::Volume>& volume,
     bool writable,
     const file_system_api::ConsentProvider::ShowDialogCallback& callback) {
-  DCHECK(host_);
+  DCHECK(host);
   content::WebContents* web_contents = nullptr;
 
   // Find an app window to host the dialog.
   content::WebContents* const foreground_contents =
-      content::WebContents::FromRenderFrameHost(host_);
+      content::WebContents::FromRenderFrameHost(host);
   if (AppWindowRegistry::Get(profile_)->GetAppWindowForWebContents(
           foreground_contents)) {
     web_contents = foreground_contents;
diff --git a/chrome/browser/extensions/api/file_system/consent_provider.h b/chrome/browser/extensions/api/file_system/consent_provider.h
index 3a517b6f..b789f87 100644
--- a/chrome/browser/extensions/api/file_system/consent_provider.h
+++ b/chrome/browser/extensions/api/file_system/consent_provider.h
@@ -31,6 +31,10 @@
 // Interaction with UI and environmental checks (kiosk mode, whitelist) are
 // provided by a delegate: ConsentProviderDelegate. For testing, it is
 // TestingConsentProviderDelegate.
+// This class may post callbacks given to it, but does not asynchronously call
+// itself. It is generally safe to use a temporary ConsentProvider.
+// TODO(michaelpg): Make this easier to use by replacing member functions with
+// static methods.
 class ConsentProvider {
  public:
   enum Consent { CONSENT_GRANTED, CONSENT_REJECTED, CONSENT_IMPOSSIBLE };
@@ -42,6 +46,7 @@
    public:
     // Shows a dialog for granting permissions.
     virtual void ShowDialog(const Extension& extension,
+                            content::RenderFrameHost* host,
                             const base::WeakPtr<file_manager::Volume>& volume,
                             bool writable,
                             const ShowDialogCallback& callback) = 0;
@@ -66,6 +71,7 @@
   // volume by the |extension|. Must be called only if the extension is
   // grantable, which can be checked with IsGrantable().
   void RequestConsent(const Extension& extension,
+                      content::RenderFrameHost* host,
                       const base::WeakPtr<file_manager::Volume>& volume,
                       bool writable,
                       const ConsentCallback& callback);
@@ -83,7 +89,7 @@
 // context of running extensions) for ConsentProvider.
 class ConsentProviderDelegate : public ConsentProvider::DelegateInterface {
  public:
-  ConsentProviderDelegate(Profile* profile, content::RenderFrameHost* host);
+  explicit ConsentProviderDelegate(Profile* profile);
   ~ConsentProviderDelegate();
 
  private:
@@ -95,6 +101,7 @@
 
   // ConsentProvider::DelegateInterface overrides:
   void ShowDialog(const Extension& extension,
+                  content::RenderFrameHost* host,
                   const base::WeakPtr<file_manager::Volume>& volume,
                   bool writable,
                   const file_system_api::ConsentProvider::ShowDialogCallback&
@@ -106,7 +113,6 @@
   bool IsWhitelistedComponent(const Extension& extension) override;
 
   Profile* const profile_;
-  content::RenderFrameHost* const host_;
 
   DISALLOW_COPY_AND_ASSIGN(ConsentProviderDelegate);
 };
diff --git a/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc b/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc
index 15769153..23782c4 100644
--- a/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc
+++ b/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc
@@ -60,6 +60,7 @@
   // ConsentProvider::DelegateInterface overrides:
   void ShowDialog(
       const extensions::Extension& extension,
+      content::RenderFrameHost* host,
       const base::WeakPtr<Volume>& volume,
       bool writable,
       const ConsentProvider::ShowDialogCallback& callback) override {
@@ -153,8 +154,8 @@
     EXPECT_TRUE(provider.IsGrantable(*whitelisted_component_extension));
 
     ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
-    provider.RequestConsent(*whitelisted_component_extension.get(), volume_,
-                            true /* writable */,
+    provider.RequestConsent(*whitelisted_component_extension.get(), nullptr,
+                            volume_, true /* writable */,
                             base::Bind(&OnConsentReceived, &result));
     base::RunLoop().RunUntilIdle();
 
@@ -196,7 +197,7 @@
     EXPECT_TRUE(provider.IsGrantable(*auto_launch_kiosk_app));
 
     ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
-    provider.RequestConsent(*auto_launch_kiosk_app.get(), volume_,
+    provider.RequestConsent(*auto_launch_kiosk_app.get(), nullptr, volume_,
                             true /* writable */,
                             base::Bind(&OnConsentReceived, &result));
     base::RunLoop().RunUntilIdle();
@@ -226,7 +227,7 @@
     EXPECT_TRUE(provider.IsGrantable(*manual_launch_kiosk_app));
 
     ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
-    provider.RequestConsent(*manual_launch_kiosk_app.get(), volume_,
+    provider.RequestConsent(*manual_launch_kiosk_app.get(), nullptr, volume_,
                             true /* writable */,
                             base::Bind(&OnConsentReceived, &result));
     base::RunLoop().RunUntilIdle();
@@ -245,7 +246,7 @@
     EXPECT_TRUE(provider.IsGrantable(*manual_launch_kiosk_app));
 
     ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
-    provider.RequestConsent(*manual_launch_kiosk_app.get(), volume_,
+    provider.RequestConsent(*manual_launch_kiosk_app.get(), nullptr, volume_,
                             true /* writable */,
                             base::Bind(&OnConsentReceived, &result));
     base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/extensions/api/file_system/file_entry_picker.cc b/chrome/browser/extensions/api/file_system/file_entry_picker.cc
index f9dac1f..c1ab2746 100644
--- a/chrome/browser/extensions/api/file_system/file_entry_picker.cc
+++ b/chrome/browser/extensions/api/file_system/file_entry_picker.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/file_system/file_system_delegate.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/shell_dialogs/selected_file_info.h"
 
@@ -23,7 +24,7 @@
     const base::FilePath& suggested_name,
     const ui::SelectFileDialog::FileTypeInfo& file_type_info,
     ui::SelectFileDialog::Type picker_type,
-    FilesSelectedCallback files_selected_callback,
+    FileSystemDelegate::FilesSelectedCallback files_selected_callback,
     base::OnceClosure file_selection_canceled_callback)
     : files_selected_callback_(std::move(files_selected_callback)),
       file_selection_canceled_callback_(
diff --git a/chrome/browser/extensions/api/file_system/file_entry_picker.h b/chrome/browser/extensions/api/file_system/file_entry_picker.h
index 43beff0..53a7dbf 100644
--- a/chrome/browser/extensions/api/file_system/file_entry_picker.h
+++ b/chrome/browser/extensions/api/file_system/file_entry_picker.h
@@ -9,6 +9,7 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
+#include "extensions/browser/api/file_system/file_system_delegate.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
 namespace base {
@@ -25,19 +26,17 @@
 // open. Deletes itself once the dialog is closed.
 class FileEntryPicker : public ui::SelectFileDialog::Listener {
  public:
-  using FilesSelectedCallback =
-      base::OnceCallback<void(const std::vector<base::FilePath>& paths)>;
-
   // Creates a file picker. After the user picks file(s) or cancels, the
   // relevant callback is called and this object deletes itself.
   // The dialog is modal to the |web_contents|'s window.
   // See SelectFileDialog::SelectFile for the other parameters.
-  FileEntryPicker(content::WebContents* web_contents,
-                  const base::FilePath& suggested_name,
-                  const ui::SelectFileDialog::FileTypeInfo& file_type_info,
-                  ui::SelectFileDialog::Type picker_type,
-                  FilesSelectedCallback files_selected_callback,
-                  base::OnceClosure file_selection_canceled_callback);
+  FileEntryPicker(
+      content::WebContents* web_contents,
+      const base::FilePath& suggested_name,
+      const ui::SelectFileDialog::FileTypeInfo& file_type_info,
+      ui::SelectFileDialog::Type picker_type,
+      FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+      base::OnceClosure file_selection_canceled_callback);
 
  private:
   ~FileEntryPicker() override;  // FileEntryPicker deletes itself.
@@ -56,7 +55,7 @@
       void* params) override;
   void FileSelectionCanceled(void* params) override;
 
-  FilesSelectedCallback files_selected_callback_;
+  FileSystemDelegate::FilesSelectedCallback files_selected_callback_;
   base::OnceClosure file_selection_canceled_callback_;
   scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
 
diff --git a/chrome/browser/extensions/api/file_system/file_system_api_unittest.cc b/chrome/browser/extensions/api/file_system/file_system_api_unittest.cc
index 1b8de48..30a2293 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api_unittest.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_api_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 
 #include <stddef.h>
 
@@ -16,6 +16,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
+// Tests static helper methods of chrome.fileSystem API functions.
+
 using extensions::FileSystemChooseEntryFunction;
 using extensions::api::file_system::AcceptOption;
 
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 abd1da1..fde936c0 100644
--- a/chrome/browser/extensions/api/file_system/file_system_apitest.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_apitest.cc
@@ -10,14 +10,16 @@
 #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"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_paths.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 #include "extensions/browser/api/file_system/saved_file_entry.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
 
+// TODO(michaelpg): Port these tests to app_shell: crbug.com/505926.
+
 namespace content {
 class BrowserContext;
 }
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
index 9e1a42db..103a946 100644
--- a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
-
 #include "base/callback.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -21,17 +19,20 @@
 #include "chrome/browser/extensions/api/file_system/consent_provider.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/api/file_system.h"
 #include "components/drive/chromeos/file_system_interface.h"
 #include "components/drive/service/fake_drive_service.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 #include "extensions/browser/event_router.h"
+#include "extensions/common/api/file_system.h"
 #include "google_apis/drive/base_requests.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "google_apis/drive/test_util.h"
 #include "storage/browser/fileapi/external_mount_points.h"
 #include "ui/base/ui_base_types.h"
 
+// TODO(michaelpg): Port these tests to app_shell: crbug.com/505926.
+
 using file_manager::VolumeManager;
 
 namespace extensions {
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
index 87c653dc7..6031be4 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
@@ -4,13 +4,13 @@
 
 #include "base/message_loop/message_loop.h"
 #include "build/build_config.h"
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/extensions/api/image_writer_private/operation.h"
 #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h"
 #include "chrome/browser/extensions/api/image_writer_private/test_utils.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/common/extensions/api/image_writer_private.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 
 namespace extensions {
 
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
index 65dac00..6a6a648 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
@@ -24,7 +24,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/extensions/chrome_extension_function_details.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/media_galleries/fileapi/safe_media_metadata_parser.h"
@@ -49,6 +48,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/blob_holder.h"
diff --git a/chrome/browser/extensions/app_data_migrator_unittest.cc b/chrome/browser/extensions/app_data_migrator_unittest.cc
index 2ed85f6..d0400b6 100644
--- a/chrome/browser/extensions/app_data_migrator_unittest.cc
+++ b/chrome/browser/extensions/app_data_migrator_unittest.cc
@@ -53,8 +53,6 @@
         content::BrowserContext::GetDefaultStoragePartition(profile_.get());
 
     idb_context_ = default_partition_->GetIndexedDBContext();
-    idb_context_->SetTaskRunnerForTesting(
-        base::ThreadTaskRunnerHandle::Get().get());
 
     default_fs_context_ = default_partition_->GetFileSystemContext();
 
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 189b8b41..12b0727 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -4622,14 +4622,14 @@
   EXPECT_TRUE(base::PathExists(lso_file_path));
 
   // Create indexed db. Similarly, it is enough to only simulate this by
-  // creating the directory on the disk.
+  // creating the directory on the disk, and resetting the caches of
+  // "known" origins.
   IndexedDBContext* idb_context = BrowserContext::GetDefaultStoragePartition(
                                       profile())->GetIndexedDBContext();
-  idb_context->SetTaskRunnerForTesting(
-      base::ThreadTaskRunnerHandle::Get().get());
   base::FilePath idb_path = idb_context->GetFilePathForTesting(ext_url);
   EXPECT_TRUE(base::CreateDirectory(idb_path));
   EXPECT_TRUE(base::DirectoryExists(idb_path));
+  idb_context->ResetCachesForTesting();
 
   // Uninstall the extension.
   base::RunLoop run_loop;
@@ -4743,14 +4743,14 @@
   EXPECT_TRUE(base::PathExists(lso_file_path));
 
   // Create indexed db. Similarly, it is enough to only simulate this by
-  // creating the directory on the disk.
+  // creating the directory on the disk, and resetting the caches of
+  // "known" origins.
   IndexedDBContext* idb_context = BrowserContext::GetDefaultStoragePartition(
                                       profile())->GetIndexedDBContext();
-  idb_context->SetTaskRunnerForTesting(
-      base::ThreadTaskRunnerHandle::Get().get());
   base::FilePath idb_path = idb_context->GetFilePathForTesting(origin1);
   EXPECT_TRUE(base::CreateDirectory(idb_path));
   EXPECT_TRUE(base::DirectoryExists(idb_path));
+  idb_context->ResetCachesForTesting();
 
   // Uninstall one of them, unlimited storage should still be granted
   // to the origin.
diff --git a/chrome/browser/extensions/extension_user_script_loader_unittest.cc b/chrome/browser/extensions/extension_user_script_loader_unittest.cc
index ffeb5de4..42463166 100644
--- a/chrome/browser/extensions/extension_user_script_loader_unittest.cc
+++ b/chrome/browser/extensions/extension_user_script_loader_unittest.cc
@@ -13,21 +13,19 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
+#include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/common/host_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using content::BrowserThread;
 using extensions::URLPatternSet;
 
 namespace {
@@ -42,7 +40,6 @@
 
 // Test bringing up a script loader on a specific directory, putting a script
 // in there, etc.
-
 class ExtensionUserScriptLoaderTest : public testing::Test,
                                       public content::NotificationObserver {
  public:
@@ -55,18 +52,6 @@
     registrar_.Add(this,
                    extensions::NOTIFICATION_USER_SCRIPTS_UPDATED,
                    content::NotificationService::AllSources());
-
-    // ExtensionUserScriptLoader posts tasks to the file thread so make the
-    // current thread look like one.
-    file_thread_.reset(new content::TestBrowserThread(
-        BrowserThread::FILE, base::MessageLoop::current()));
-    ui_thread_.reset(new content::TestBrowserThread(
-        BrowserThread::UI, base::MessageLoop::current()));
-  }
-
-  void TearDown() override {
-    file_thread_.reset();
-    ui_thread_.reset();
   }
 
   void Observe(int type,
@@ -75,23 +60,19 @@
     DCHECK(type == extensions::NOTIFICATION_USER_SCRIPTS_UPDATED);
 
     shared_memory_ = content::Details<base::SharedMemory>(details).ptr();
-    if (base::MessageLoop::current() == &message_loop_)
-      base::MessageLoop::current()->QuitWhenIdle();
   }
 
   // Directory containing user scripts.
   base::ScopedTempDir temp_dir_;
 
-  content::NotificationRegistrar registrar_;
-
-  // MessageLoop used in tests.
-  base::MessageLoopForUI message_loop_;
-
-  std::unique_ptr<content::TestBrowserThread> file_thread_;
-  std::unique_ptr<content::TestBrowserThread> ui_thread_;
-
   // Updated to the script shared memory when we get notified.
   base::SharedMemory* shared_memory_;
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  content::NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionUserScriptLoaderTest);
 };
 
 // Test that we get notified even when there are no scripts.
diff --git a/chrome/browser/extensions/native_bindings_apitest.cc b/chrome/browser/extensions/native_bindings_apitest.cc
index d0cb79c..c6f33e1 100644
--- a/chrome/browser/extensions/native_bindings_apitest.cc
+++ b/chrome/browser/extensions/native_bindings_apitest.cc
@@ -7,7 +7,6 @@
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -18,6 +17,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/common/switches.h"
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index 2e1740f8..12c9e8e 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -198,8 +198,7 @@
 PrefService* TestExtensionPrefs::CreateIncognitoPrefService() const {
   return CreateIncognitoPrefServiceSyncable(
       pref_service_.get(),
-      new ExtensionPrefStore(extension_pref_value_map_.get(), true),
-      std::set<PrefValueStore::PrefStoreType>(), nullptr, nullptr);
+      new ExtensionPrefStore(extension_pref_value_map_.get(), true), nullptr);
 }
 
 void TestExtensionPrefs::set_extensions_disabled(bool extensions_disabled) {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 9fe27a3..078c64a 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -823,12 +823,6 @@
     "Elides the path, query, and ref of suggested URLs in the Omnibox "
     "dropdown.";
 
-const char kOmniboxSpareRendererName[] =
-    "Start spare renderer on omnibox focus";
-const char kOmniboxSpareRendererDescription[] =
-    "When the omnibox is focused, start an empty spare renderer. This can "
-    "speed up the load of the navigation from the omnibox.";
-
 const char kOmniboxUIHideSuggestionUrlSchemeName[] =
     "Omnibox UI Hide Suggestion URL Scheme";
 const char kOmniboxUIHideSuggestionUrlSchemeDescription[] =
@@ -1133,11 +1127,6 @@
 const char kSpellingFeedbackFieldTrialDescription[] =
     "Enable the field trial for sending user feedback to spelling service.";
 
-const char kSslVersionMaxName[] = "Maximum TLS version enabled.";
-const char kSslVersionMaxDescription[] = "Set maximum enabled TLS version.";
-const char kSslVersionMaxTls12[] = "TLS 1.2";
-const char kSslVersionMaxTls13[] = "TLS 1.3";
-
 const char kSuggestionsWithSubStringMatchName[] =
     "Substring matching for Autofill suggestions";
 const char kSuggestionsWithSubStringMatchDescription[] =
@@ -1183,6 +1172,12 @@
     "this can dramatically hurt scrolling performance of most websites and is "
     "intended for testing purposes only.";
 
+const char kTLS13VariantName[] = "TLS 1.3";
+const char kTLS13VariantDescription[] = "Sets the TLS 1.3 variant used.";
+const char kTLS13VariantDisabled[] = "Disabled";
+const char kTLS13VariantDraft[] = "Enabled (Draft)";
+const char kTLS13VariantExperiment[] = "Enabled (Experiment)";
+
 const char kTopDocumentIsolationName[] = "Top document isolation";
 const char kTopDocumentIsolationDescription[] =
     "Highly experimental performance mode where cross-site iframes are kept in "
@@ -1354,6 +1349,492 @@
 const char kZeroCopyDescription[] =
     "Raster threads write directly to GPU memory associated with tiles.";
 
+// Android ---------------------------------------------------------------------
+
+#if defined(OS_ANDROID)
+
+const char kAiaFetchingName[] = "Intermediate Certificate Fetching";
+const char kAiaFetchingDescription[] =
+    "Enable intermediate certificate fetching when a server does not provide "
+    "sufficient certificates to build a chain to a trusted root.";
+
+const char kAccessibilityTabSwitcherName[] = "Accessibility Tab Switcher";
+const char kAccessibilityTabSwitcherDescription[] =
+    "Enable the accessibility tab switcher for Android.";
+
+const char kAndroidAutofillAccessibilityName[] = "Autofill Accessibility";
+const char kAndroidAutofillAccessibilityDescription[] =
+    "Enable accessibility for autofill popup.";
+
+const char kAndroidPaymentAppsName[] = "Android payment apps";
+const char kAndroidPaymentAppsDescription[] =
+    "Enable third party Android apps to integrate as payment apps";
+
+const char kAutofillAccessoryViewName[] =
+    "Autofill suggestions as keyboard accessory view";
+const char kAutofillAccessoryViewDescription[] =
+    "Shows Autofill suggestions on top of the keyboard rather than in a "
+    "dropdown.";
+
+const char kBackgroundLoaderForDownloadsName[] =
+    "Enables background downloading of pages.";
+const char kBackgroundLoaderForDownloadsDescription[] =
+    "Enables downloading pages in the background in case page is not yet "
+    "loaded in current tab.";
+
+const char kChromeHomeExpandButtonName[] = "Chrome Home Expand Button";
+const char kChromeHomeExpandButtonDescription[] =
+    "Enables the expand button for Chrome Home.";
+
+const char kChromeHomeSwipeLogicName[] = "Chrome Home Swipe Logic";
+const char kChromeHomeSwipeLogicDescription[] =
+    "Various swipe logic options for Chrome Home for sheet expansion.";
+const char kChromeHomeSwipeLogicRestrictArea[] = "Restrict swipable area";
+const char kChromeHomeSwipeLogicButtonOnly[] = "Swipe on expand button";
+
+const char kChromeHomeName[] = "Chrome Home";
+const char kChromeHomeDescription[] =
+    "Enables Chrome Home on Android. You must restart the browser"
+    " twice for changes to take effect.";
+
+const char kContentSuggestionsCategoryOrderName[] =
+    "Default content suggestions category order (e.g. on NTP)";
+const char kContentSuggestionsCategoryOrderDescription[] =
+    "Set default order of content suggestion categories (e.g. on the NTP).";
+
+const char kContentSuggestionsCategoryRankerName[] =
+    "Content suggestions category ranker (e.g. on NTP)";
+const char kContentSuggestionsCategoryRankerDescription[] =
+    "Set category ranker to order categories of content suggestions (e.g. on "
+    "the NTP).";
+
+const char kContextualSearchContextualCardsBarIntegration[] =
+    "Contextual Search - Contextual Cards Integration";
+const char kContextualSearchContextualCardsBarIntegrationDescription[] =
+    "Whether or not integration of Contextual Cards data in the Contextual "
+    "Search Bar is enabled.";
+
+const char kContextualSearchSingleActionsName[] =
+    "Contextual Search - Single Actions";
+const char kContextualSearchSingleActionsDescription[] =
+    "Whether or not single actions using Contextual Cards data in the "
+    "Contextual Search Bar is enabled.";
+
+const char kContextualSearchUrlActionsName[] =
+    "Contextual Search - URL Actions";
+const char kContextualSearchUrlActionsDescription[] =
+    "Whether or not URL actions using Contextual Cards data in the Contextual "
+    "Search Bar is enabled.";
+
+const char kContextualSearchName[] = "Contextual Search";
+const char kContextualSearchDescription[] =
+    "Whether or not Contextual Search is enabled.";
+
+const char kEnableAndroidPayIntegrationV1Name[] = "Enable Android Pay v1";
+const char kEnableAndroidPayIntegrationV1Description[] =
+    "Enable integration with Android Pay using the first version of the API";
+
+const char kEnableAndroidPayIntegrationV2Name[] = "Enable Android Pay v2";
+const char kEnableAndroidPayIntegrationV2Description[] =
+    "Enable integration with Android Pay using the second version of the API";
+
+const char kEnableAndroidSpellcheckerDescription[] =
+    "Enables use of the Android spellchecker.";
+const char kEnableAndroidSpellcheckerName[] = "Enable spell checking";
+
+const char kEnableConsistentOmniboxGeolocationName[] =
+    "Have consistent omnibox geolocation access.";
+const char kEnableConsistentOmniboxGeolocationDescription[] =
+    "Have consistent geolocation access between the omnibox and default search "
+    "engine.";
+
+const char kEnableContentSuggestionsNewFaviconServerName[] =
+    "Get favicons for content suggestions from a new server.";
+const char kEnableContentSuggestionsNewFaviconServerDescription[] =
+    "If enabled, the content suggestions (on the NTP) will get favicons from a "
+    "new favicon server.";
+
+const char kEnableContentSuggestionsLargeThumbnailName[] =
+    "Large thumbnails layout for content suggestions cards.";
+const char kEnableContentSuggestionsLargeThumbnailDescription[] =
+    "If enabled, the content suggestions cards will use large thumbnails and "
+    "some related adjustments.";
+
+const char kEnableContentSuggestionsVideoOverlayName[] =
+    "Video icon overlay on thumbnails for content suggestions cards.";
+const char kEnableContentSuggestionsVideoOverlayDescription[] =
+    "If enabled, the content suggestions cards for suggestions with a video "
+    "will show a video play icon overlay on the thumbnail.";
+
+const char kEnableContentSuggestionsSettingsName[] =
+    "Show content suggestions settings.";
+const char kEnableContentSuggestionsSettingsDescription[] =
+    "If enabled, the content suggestions settings will be available from the "
+    "main settings menu.";
+
+const char kEnableContentSuggestionsShowSummaryName[] =
+    "Show content suggestions summaries.";
+const char kEnableContentSuggestionsShowSummaryDescription[] =
+    "If enabled, the content suggestions summaries will be shown.";
+
+const char kEnableCopylessPasteName[] = "App Indexing (Copyless Paste)";
+const char kEnableCopylessPasteDescription[] =
+    "Provide suggestions for text input, based on your recent context. For "
+    "example, if you looked at a restaurant website and switched to the Maps "
+    "app, the keyboard would offer the name of that restaurant as a suggestion "
+    "to enter into the search bar. The data is indexed locally, and never sent "
+    "to the server. It's disabled in incognito mode.";
+
+const char kEnableCustomContextMenuName[] = "Enable custom context menu";
+const char kEnableCustomContextMenuDescription[] =
+    "Enables a new context menu when a link, image, or video is pressed within "
+    "Chrome.";
+
+const char kEnableCustomFeedbackUiName[] = "Enable Custom Feedback UI";
+const char kEnableCustomFeedbackUiDescription[] =
+    "Enables a custom feedback UI when submitting feedback through Google "
+    "Feedback. Works with Google Play Services v10.2+";
+
+const char kEnableDataReductionProxyMainMenuName[] =
+    "Enable Data Saver main menu footer";
+const char kEnableDataReductionProxyMainMenuDescription[] =
+    "Enables the Data Saver footer in the main menu";
+
+const char kEnableDataReductionProxySiteBreakdownName[] =
+    "Data Saver Site Breakdown";
+const char kEnableDataReductionProxySiteBreakdownDescription[] =
+    "Enable the site breakdown on the Data Saver settings page.";
+
+const char kEnableOmniboxClipboardProviderName[] =
+    "Omnibox clipboard URL suggestions";
+const char kEnableOmniboxClipboardProviderDescription[] =
+    "Provide a suggestion of the URL stored in the clipboard (if any) upon "
+    "focus in the omnibox.";
+
+const char kEnableExpandedAutofillCreditCardPopupLayoutName[] =
+    "Use expanded autofill credit card popup layout.";
+const char kEnableExpandedAutofillCreditCardPopupLayoutDescription[] =
+    "If enabled, displays autofill credit card popup using expanded layout.";
+
+const char kEnableFaviconsFromWebManifestName[] =
+    "Load favicons from Web Manifests";
+const char kEnableFaviconsFromWebManifestDescription[] =
+    "Fetch Web Manifests on page load to read favicons from them.";
+
+const char kEnableNtpAssetDownloadSuggestionsName[] =
+    "Show asset downloads on the New Tab page";
+const char kEnableNtpAssetDownloadSuggestionsDescription[] =
+    "If enabled, the list of content suggestions on the New Tab page will "
+    "contain assets (e.g. books, pictures, audio) that the user downloaded for "
+    "later use.";
+
+const char kEnableNtpBookmarkSuggestionsName[] =
+    "Show recently visited bookmarks on the New Tab page";
+const char kEnableNtpBookmarkSuggestionsDescription[] =
+    "If enabled, the list of content suggestions on the New Tab page will "
+    "contain recently visited bookmarks.";
+
+const char kEnableNtpForeignSessionsSuggestionsName[] =
+    "Show recent foreign tabs on the New Tab page";
+const char kEnableNtpForeignSessionsSuggestionsDescription[] =
+    "If enabled, the list of content suggestions on the New Tab page will "
+    "contain recent foreign tabs.";
+
+const char kEnableNtpMostLikelyFaviconsFromServerName[] =
+    "Download favicons for NTP tiles from Google.";
+const char kEnableNtpMostLikelyFaviconsFromServerDescription[] =
+    "If enabled, missing favicons for NTP tiles get downloaded from Google. "
+    "This only applies to tiles that originate from synced history.";
+
+const char kEnableNtpOfflinePageDownloadSuggestionsName[] =
+    "Show offline page downloads on the New Tab page";
+const char kEnableNtpOfflinePageDownloadSuggestionsDescription[] =
+    "If enabled, the list of content suggestions on the New Tab page will "
+    "contain pages that the user downloaded for later use.";
+
+const char kEnableNtpRemoteSuggestionsName[] =
+    "Show server-side suggestions on the New Tab page";
+const char kEnableNtpRemoteSuggestionsDescription[] =
+    "If enabled, the list of content suggestions on the New Tab page will "
+    "contain server-side suggestions (e.g., Articles for you). Furthermore, it "
+    "allows to override the source used to retrieve these server-side "
+    "suggestions.";
+
+const char kEnableNtpSnippetsVisibilityName[] =
+    "Make New Tab Page Snippets more visible.";
+const char kEnableNtpSnippetsVisibilityDescription[] =
+    "If enabled, the NTP snippets will become more discoverable with a larger "
+    "portion of the first card above the fold.";
+
+const char kEnableNtpSuggestionsNotificationsName[] =
+    "Notify about new content suggestions available at the New Tab page";
+const char kEnableNtpSuggestionsNotificationsDescription[] =
+    "If enabled, notifications will inform about new content suggestions on "
+    "the New Tab page.";
+
+const char kEnablePhysicalWebName[] = "Enable the Physical Web.";
+const char kEnablePhysicalWebDescription[] =
+    "Enable scanning for URLs from Physical Web objects.";
+
+const char kEnableOfflinePreviewsName[] = "Offline Page Previews";
+const char kEnableOfflinePreviewsDescription[] =
+    "Enable showing offline page previews on slow networks.";
+
+const char kEnableOskOverscrollName[] = "Enable OSK Overscroll";
+const char kEnableOskOverscrollDescription[] =
+    "Enable OSK overscroll support. With this flag on, the OSK will only "
+    "resize the visual viewport.";
+
+const char kEnableSpecialLocaleName[] =
+    "Enable custom logic for special locales.";
+const char kEnableSpecialLocaleDescription[] =
+    "Enable custom logic for special locales. In this mode, Chrome might "
+    "behave differently in some locales.";
+
+const char kEnableWebapk[] = "Enable improved add to Home screen";
+const char kEnableWebapkDescription[] =
+    R"*(Packages "Progressive Web Apps" so that they can integrate more )*"
+    R"*(deeply with Android. A Chrome server is used to package sites. In )*"
+    R"*(Chrome Canary and Chrome Dev, this requires “Untrusted )*"
+    R"*(sources” to be enabled in Android security settings.)*";
+
+const char kEnableWebNfcName[] = "WebNFC";
+const char kEnableWebNfcDescription[] = "Enable WebNFC support.";
+
+const char kEnableWebPaymentsSingleAppUiSkipName[] =
+    "Enable Web Payments single app UI skip";
+const char kEnableWebPaymentsSingleAppUiSkipDescription[] =
+    "Enable Web Payments to skip showing its UI if the developer specifies a "
+    "single app.";
+
+const char kHerbPrototypeChoicesName[] = "Switch preferred flavor of Herb";
+const char kHerbPrototypeChoicesDescription[] =
+    "Switching this option changes which tab management prototype is being "
+    "tested.";
+const char kHerbPrototypeFlavorElderberry[] =
+    "ELDERBERRY: All View Intents in CCT v2";
+
+const char kKeepPrefetchedContentSuggestionsName[] =
+    "Keep prefetched content suggestions";
+const char kKeepPrefetchedContentSuggestionsDescription[] =
+    "If enabled, some of prefetched content suggestions are not replaced by "
+    "the new fetched suggestions.";
+
+const char kLsdPermissionPromptName[] =
+    "Location Settings Dialog Permission Prompt";
+const char kLsdPermissionPromptDescription[] =
+    "Whether to use the Google Play Services Location Settings Dialog "
+    "permission dialog.";
+
+const char kMediaDocumentDownloadButtonName[] =
+    "Download button when opening a page with media url.";
+const char kMediaDocumentDownloadButtonDescription[] =
+    "Allow a download button to show up when opening a page with media url.";
+
+const char kMediaScreenCaptureName[] = "Experimental ScreenCapture.";
+const char kMediaScreenCaptureDescription[] =
+    "Enable this option for experimental ScreenCapture feature on Android.";
+
+const char kModalPermissionPromptsName[] = "Modal Permission Prompts";
+const char kModalPermissionPromptsDescription[] =
+    "Whether to use permission dialogs in place of permission infobars.";
+
+const char kNewBackgroundLoaderName[] =
+    "Use background loader instead of prerenderer to load pages.";
+const char kNewBackgroundLoaderDescription[] =
+    "Use background loader instead of prerenderer to asynchronously download "
+    "pages.";
+
+const char kNewPhotoPickerName[] = "Enable new Photopicker";
+const char kNewPhotoPickerDescription[] =
+    "Activates the new picker for selecting photos.";
+
+const char kNoCreditCardAbort[] = "No Credit Card Abort";
+const char kNoCreditCardAbortDescription[] =
+    "Whether or not the No Credit Card Abort is enabled.";
+
+const char kNtpCondensedLayoutName[] = "Condensed NTP layout";
+const char kNtpCondensedLayoutDescription[] =
+    "Show a condensed layout on the New Tab Page.";
+
+const char kNtpCondensedTileLayoutName[] = "Condensed NTP tile layout";
+const char kNtpCondensedTileLayoutDescription[] =
+    "Show a condensed tile layout on the New Tab Page.";
+
+const char kNtpGoogleGInOmniboxName[] = "Google G in New Tab Page omnibox";
+const char kNtpGoogleGInOmniboxDescription[] =
+    "Show a Google G in the omnibox on the New Tab Page.";
+
+const char kNtpOfflinePagesName[] = "Enable NTP offline pages";
+const char kNtpOfflinePagesDescription[] =
+    "Enables badging of offline pages on the New Tab page. Only relevant if "
+    "offline pages are enabled.";
+
+const char kNtpPopularSitesName[] = "Show popular sites on the New Tab page";
+const char kNtpPopularSitesDescription[] =
+    "Pre-populate the New Tab page with popular sites.";
+
+const char kNtpSwitchToExistingTabName[] =
+    "Switch to an existing tab for New Tab Page suggestions.";
+const char kNtpSwitchToExistingTabDescription[] =
+    "When opening a suggested webpage from the New Tab Page, if a tab is "
+    "already open for the suggestion, switch to that one instead of loading "
+    "the suggestion in the new tab.";
+const char kNtpSwitchToExistingTabMatchUrl[] = "Match by URL";
+const char kNtpSwitchToExistingTabMatchHost[] = "Match by Hostname";
+
+const char kOfflineBookmarksName[] = "Enable offline bookmarks";
+const char kOfflineBookmarksDescription[] =
+    "Enable saving bookmarked pages for offline viewing.";
+
+const char kOfflinePagesAsyncDownloadName[] =
+    R"*(Enables showing "DOWNLOAD WHEN ONLINE" button in error pages.)*";
+const char kOfflinePagesAsyncDownloadDescription[] =
+    R"*(Enables showing "DOWNLOAD WHEN ONLINE" button in error pages such )*"
+    R"*(that the user can click on it to download the page later.)*";
+
+const char kOfflinePagesCtName[] = "Enable Offline Pages CT features.";
+const char kOfflinePagesCtDescription[] = "Enable Offline Pages CT features.";
+
+const char kOfflinePagesCtV2Name[] = "Enable Offline Pages CT V2 features.";
+const char kOfflinePagesCtV2Description[] =
+    "V2 features include attributing pages to the app that initiated the "
+    "custom tabs, and being able to query for pages by page attribution.";
+
+const char kOfflinePagesLoadSignalCollectingName[] =
+    "Enables collecting load timing data for offline page snapshots.";
+const char kOfflinePagesLoadSignalCollectingDescription[] =
+    "Enables loading completeness data collection while writing an offline "
+    "page.  This data is collected in the snapshotted offline page to allow "
+    "data analysis to improve deciding when to make the offline snapshot.";
+
+const char kOfflinePagesPrefetchingName[] =
+    "Enables suggested offline pages to be prefetched.";
+const char kOfflinePagesPrefetchingDescription[] =
+    "Enables suggested offline pages to be prefetched, so useful content is "
+    "available while offline.";
+
+const char kOfflinePagesSharingName[] = "Enables offline pages to be shared.";
+const char kOfflinePagesSharingDescription[] =
+    "Enables the saved offline pages to be shared via other applications.";
+
+const char kOfflinePagesSvelteConcurrentLoadingName[] =
+    "Enables concurrent background loading on svelte.";
+const char kOfflinePagesSvelteConcurrentLoadingDescription[] =
+    "Enables concurrent background loading (or downloading) of pages on "
+    "Android svelte (512MB RAM) devices. Otherwise, background loading will "
+    "happen when the svelte device is idle.";
+
+const char kOffliningRecentPagesName[] =
+    "Enable offlining of recently visited pages";
+const char kOffliningRecentPagesDescription[] =
+    "Enable storing recently visited pages locally for offline use. Requires "
+    "Offline Pages to be enabled.";
+
+extern const char kPayWithGoogleV1Name[] = "Pay with Google v1";
+extern const char kPayWithGoogleV1Description[] =
+    "Enable Pay with Google integration into Web Payments with API version "
+    "'1'.";
+
+const char kProgressBarAnimationName[] =
+    "Android phone page loading progress bar animation";
+const char kProgressBarAnimationDescription[] =
+    "Configures Android phone page loading progress bar animation.";
+const char kProgressBarAnimationLinear[] = "Linear";
+const char kProgressBarAnimationSmooth[] = "Smooth";
+const char kProgressBarAnimationSmoothIndeterminate[] = "Smooth indeterminate";
+const char kProgressBarAnimationFastStart[] = "Fast start";
+
+const char kProgressBarCompletionName[] =
+    "Android phone page load progress bar completion time.";
+const char kProgressBarCompletionDescription[] =
+    "Configures Android phone page loading progress bar completion time.";
+const char kProgressBarCompletionLoadEvent[] =
+    R"*(Top loading frame's onload event ("everything" is done in the )*"
+    R"*(page, historical behavior).)*";
+const char kProgressBarCompletionResourcesBeforeDcl[] =
+    "Main frame's domContentLoaded and all resources loads started before "
+    "domContentLoaded (iframes ignored).";
+const char kProgressBarCompletionDomContentLoaded[] =
+    "Main frame's domContentLoaded (iframes ignored).";
+const char kProgressBarCompletionResourcesBeforeDclAndSameOriginIframes[] =
+    "domContentLoaded and all resources loads started before domContentLoaded "
+    "(main frame and same origin iframes).";
+
+const char kPullToRefreshEffectName[] = "The pull-to-refresh effect";
+const char kPullToRefreshEffectDescription[] =
+    "Page reloads triggered by vertically overscrolling content.";
+
+const char kReaderModeHeuristicsName[] = "Reader Mode triggering";
+const char kReaderModeHeuristicsDescription[] =
+    "Determines what pages the Reader Mode infobar is shown on.";
+const char kReaderModeHeuristicsMarkup[] = "With article structured markup";
+const char kReaderModeHeuristicsAdaboost[] = "Non-mobile-friendly articles";
+const char kReaderModeHeuristicsAllArticles[] = "All articles";
+const char kReaderModeHeuristicsAlwaysOff[] = "Never";
+const char kReaderModeHeuristicsAlwaysOn[] = "Always";
+
+const char kServiceWorkerPaymentAppsName[] = "Service Worker payment apps";
+const char kServiceWorkerPaymentAppsDescription[] =
+    "Enable Service Worker applications to integrate as payment apps";
+
+const char kSetMarketUrlForTestingName[] = "Set market URL for testing";
+const char kSetMarketUrlForTestingDescription[] =
+    "When enabled, sets the market URL for use in testing the update menu "
+    "item.";
+
+const char kSpannableInlineAutocompleteName[] = "Spannable inline autocomplete";
+const char kSpannableInlineAutocompleteDescription[] =
+    "A new type of inline autocomplete for the omnibox that works with "
+    "keyboards that compose text.";
+
+const char kTabsInCbdName[] = "Enable tabs for the Clear Browsing Data dialog.";
+const char kTabsInCbdDescription[] =
+    "Enables a basic and an advanced tab for the Clear Browsing Data dialog.";
+
+const char kTranslateCompactUIName[] = "New Translate Infobar";
+const char kTranslateCompactUIDescription[] =
+    "Enable the new Translate compact infobar UI.";
+
+const char kUpdateMenuBadgeName[] = "Force show update menu badge";
+const char kUpdateMenuBadgeDescription[] =
+    "When enabled, an update badge will be shown on the app menu button.";
+
+const char kUpdateMenuItemCustomSummaryDescription[] =
+    "When this flag and the force show update menu item flag are enabled, a "
+    "custom summary string will be displayed below the update menu item.";
+const char kUpdateMenuItemCustomSummaryName[] =
+    "Update menu item custom summary";
+
+const char kUpdateMenuItemName[] = "Force show update menu item";
+const char kUpdateMenuItemDescription[] =
+    R"*(When enabled, an "Update Chrome" item will be shown in the app )*"
+    R"*(menu.)*";
+
+const char kUseAndroidMidiApiName[] = "Use Android Midi API";
+const char kUseAndroidMidiApiDescription[] =
+    "Use Android Midi API for WebMIDI (effective only with Android M+ "
+    "devices).";
+
+const char kUseDdljsonApiName[] = "Use new ddljson API for Doodles";
+const char kUseDdljsonApiDescription[] =
+    "Enables the new ddljson API to fetch Doodles for the NTP.";
+
+const char kWebPaymentsModifiersName[] = "Enable web payment modifiers";
+const char kWebPaymentsModifiersDescription[] =
+    "If the website provides modifiers in the payment request, show the custom "
+    "total for each payment instrument, update the shopping cart when "
+    "instruments are switched, and send modified payment method specific data "
+    "to the payment app.";
+
+const char kXGEOVisibleNetworksName[] = "Enable XGEO Visible Networks";
+const char kXGEOVisibleNetworksDescription[] =
+    "If location permissions are granted, include visible networks in the XGEO "
+    "Header for omnibox queries. This will only happen if location is not "
+    "fresh or not available (for example, due to a cold start).";
+
+#endif  // OS_ANDROID
+
 #if !defined(DISABLE_NACL)
 
 const char kNaclName[] = "Native Client";
@@ -1395,25 +1876,6 @@
 
 #endif  // defined(OS_WIN)
 
-#if defined(OS_ANDROID)
-
-const char kAccessibilityTabSwitcherName[] = "Accessibility Tab Switcher";
-
-const char kAccessibilityTabSwitcherDescription[] =
-    "Enable the accessibility tab switcher for Android.";
-
-const char kAndroidAutofillAccessibilityName[] = "Autofill Accessibility";
-
-const char kAndroidAutofillAccessibilityDescription[] =
-    "Enable accessibility for autofill popup.";
-
-const char kEnablePhysicalWebName[] = "Enable the Physical Web.";
-
-const char kEnablePhysicalWebDescription[] =
-    "Enable scanning for URLs from Physical Web objects.";
-
-#endif  // defined(OS_ANDROID)
-
 const char kDelayReloadStopButtonChangeName[] =
     "Reduce stop/reload button flicker";
 
@@ -1421,45 +1883,6 @@
     "Delays display of stop button when page is loading such that short "
     "loads won't show the stop button at all.";
 
-#if defined(OS_ANDROID)
-
-const char kContextualSearchName[] = "Contextual Search";
-
-const char kContextualSearchDescription[] =
-    "Whether or not Contextual Search is enabled.";
-
-const char kContextualSearchContextualCardsBarIntegration[] =
-    "Contextual Search - Contextual Cards Integration";
-
-const char kContextualSearchContextualCardsBarIntegrationDescription[] =
-    "Whether or not integration of Contextual Cards data in the Contextual "
-    "Search Bar is enabled.";
-
-const char kContextualSearchSingleActionsName[] =
-    "Contextual Search - Single Actions";
-
-const char kContextualSearchSingleActionsDescription[] =
-    "Whether or not single actions using Contextual Cards data in the "
-    "Contextual Search Bar is enabled.";
-
-const char kContextualSearchUrlActionsName[] =
-    "Contextual Search - URL Actions";
-
-const char kContextualSearchUrlActionsDescription[] =
-    "Whether or not URL actions using Contextual Cards data in the Contextual "
-    "Search Bar is enabled.";
-
-#endif  // defined(OS_ANDROID)
-
-#if defined(OS_ANDROID)
-
-const char kMediaScreenCaptureName[] = "Experimental ScreenCapture.";
-
-const char kMediaScreenCaptureDescription[] =
-    "Enable this option for experimental ScreenCapture feature on Android.";
-
-#endif  // defined(OS_ANDROID)
-
 #if BUILDFLAG(ENABLE_WEBRTC)
 
 const char kWebrtcH264WithOpenh264FfmpegName[] =
@@ -1472,25 +1895,6 @@
 
 #endif  // BUILDFLAG(ENABLE_WEBRTC)
 
-#if defined(OS_ANDROID)
-
-const char kNewPhotoPickerName[] = "Enable new Photopicker";
-
-const char kNewPhotoPickerDescription[] =
-    "Activates the new picker for selecting photos.";
-
-#endif  // defined(OS_ANDROID)
-
-#if defined(OS_ANDROID)
-
-const char kEnableOskOverscrollName[] = "Enable OSK Overscroll";
-
-const char kEnableOskOverscrollDescription[] =
-    "Enable OSK overscroll support. With this flag on, the OSK will only "
-    "resize the visual viewport.";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(USE_ASH)
 
 const char kAshShelfColorName[] = "Shelf color in Chrome OS system UI";
@@ -1560,16 +1964,6 @@
 
 #endif  // defined(USE_ASH)
 
-#if defined(OS_ANDROID)
-
-const char kMediaDocumentDownloadButtonName[] =
-    "Download button when opening a page with media url.";
-
-const char kMediaDocumentDownloadButtonDescription[] =
-    "Allow a download button to show up when opening a page with media url.";
-
-#endif  // defined(OS_ANDROID)
-
 const char kForceGpuRasterization[] = "Force-enabled for all layers";
 
 #if defined(OS_CHROMEOS)
@@ -1608,27 +2002,6 @@
 
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID)
-
-const char kEnableDataReductionProxyMainMenuName[] =
-    "Enable Data Saver main menu footer";
-
-const char kEnableDataReductionProxyMainMenuDescription[] =
-    "Enables the Data Saver footer in the main menu";
-
-const char kEnableDataReductionProxySiteBreakdownName[] =
-    "Data Saver Site Breakdown";
-
-const char kEnableDataReductionProxySiteBreakdownDescription[] =
-    "Enable the site breakdown on the Data Saver settings page.";
-
-const char kEnableOfflinePreviewsName[] = "Offline Page Previews";
-
-const char kEnableOfflinePreviewsDescription[] =
-    "Enable showing offline page previews on slow networks.";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_CHROMEOS)
 
 const char kFirstRunUiTransitionsName[] =
@@ -1668,20 +2041,6 @@
 
 #endif  // defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
-
-const char kPullToRefreshEffectName[] = "The pull-to-refresh effect";
-
-const char kPullToRefreshEffectDescription[] =
-    "Page reloads triggered by vertically overscrolling content.";
-
-const char kTranslateCompactUIName[] = "New Translate Infobar";
-
-const char kTranslateCompactUIDescription[] =
-    "Enable the new Translate compact infobar UI.";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_MACOSX)
 
 const char kTranslateNewUxName[] = "New Translate UX";
@@ -1738,51 +2097,6 @@
 
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID)
-
-extern const char kPayWithGoogleV1Name[] = "Pay with Google v1";
-
-extern const char kPayWithGoogleV1Description[] =
-    "Enable Pay with Google integration into Web Payments with API version "
-    "'1'.";
-
-const char kProgressBarAnimationName[] =
-    "Android phone page loading progress bar animation";
-
-const char kProgressBarAnimationDescription[] =
-    "Configures Android phone page loading progress bar animation.";
-
-const char kProgressBarAnimationLinear[] = "Linear";
-
-const char kProgressBarAnimationSmooth[] = "Smooth";
-
-const char kProgressBarAnimationSmoothIndeterminate[] = "Smooth indeterminate";
-
-const char kProgressBarAnimationFastStart[] = "Fast start";
-
-const char kProgressBarCompletionName[] =
-    "Android phone page load progress bar completion time.";
-
-const char kProgressBarCompletionDescription[] =
-    "Configures Android phone page loading progress bar completion time.";
-
-const char kProgressBarCompletionLoadEvent[] =
-    R"*(Top loading frame's onload event ("everything" is done in the )*"
-    R"*(page, historical behavior).)*";
-
-const char kProgressBarCompletionResourcesBeforeDcl[] =
-    "Main frame's domContentLoaded and all resources loads started before "
-    "domContentLoaded (iframes ignored).";
-
-const char kProgressBarCompletionDomContentLoaded[] =
-    "Main frame's domContentLoaded (iframes ignored).";
-
-const char kProgressBarCompletionResourcesBeforeDclAndSameOriginIframes[] =
-    "domContentLoaded and all resources loads started before domContentLoaded "
-    "(main frame and same origin iframes).";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_WIN)
 
 const char kEnableAppcontainerName[] = "Enable AppContainer Lockdown.";
@@ -1823,24 +2137,6 @@
 
 #endif  // defined(OS_WIN) || defined(OS_LINUX)
 
-#if defined(OS_ANDROID)
-
-const char kTabsInCbdName[] = "Enable tabs for the Clear Browsing Data dialog.";
-
-const char kTabsInCbdDescription[] =
-    "Enables a basic and an advanced tab for the Clear Browsing Data dialog.";
-
-#endif  // defined(OS_ANDROID)
-
-#if defined(OS_ANDROID)
-
-const char kEnableAndroidSpellcheckerDescription[] =
-    "Enables use of the Android spellchecker.";
-
-const char kEnableAndroidSpellcheckerName[] = "Enable spell checking";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_CHROMEOS)
 
 const char kVirtualKeyboardName[] = "Virtual Keyboard";
@@ -1930,64 +2226,6 @@
 
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID)
-
-const char kAutofillAccessoryViewName[] =
-    "Autofill suggestions as keyboard accessory view";
-
-const char kAutofillAccessoryViewDescription[] =
-    "Shows Autofill suggestions on top of the keyboard rather than in a "
-    "dropdown.";
-
-#endif  // defined(OS_ANDROID)
-
-//  Reader mode experiment flags
-
-#if defined(OS_ANDROID)
-
-const char kReaderModeHeuristicsName[] = "Reader Mode triggering";
-
-const char kReaderModeHeuristicsDescription[] =
-    "Determines what pages the Reader Mode infobar is shown on.";
-
-const char kReaderModeHeuristicsMarkup[] = "With article structured markup";
-
-const char kReaderModeHeuristicsAdaboost[] = "Non-mobile-friendly articles";
-
-const char kReaderModeHeuristicsAllArticles[] = "All articles";
-
-const char kReaderModeHeuristicsAlwaysOff[] = "Never";
-
-const char kReaderModeHeuristicsAlwaysOn[] = "Always";
-
-#endif  // defined(OS_ANDROID)
-
-//  Chrome home flags
-
-#if defined(OS_ANDROID)
-
-const char kChromeHomeName[] = "Chrome Home";
-
-const char kChromeHomeDescription[] =
-    "Enables Chrome Home on Android. You must restart the browser"
-    " twice for changes to take effect.";
-
-const char kChromeHomeExpandButtonName[] = "Chrome Home Expand Button";
-
-const char kChromeHomeExpandButtonDescription[] =
-    "Enables the expand button for Chrome Home.";
-
-const char kChromeHomeSwipeLogicName[] = "Chrome Home Swipe Logic";
-
-const char kChromeHomeSwipeLogicDescription[] =
-    "Various swipe logic options for Chrome Home for sheet expansion.";
-
-const char kChromeHomeSwipeLogicRestrictArea[] = "Restrict swipable area";
-
-const char kChromeHomeSwipeLogicButtonOnly[] = "Swipe on expand button";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_WIN) || defined(OS_MACOSX)
 
 //  Tab discarding
@@ -2002,108 +2240,6 @@
 
 #endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
-
-const char kOfflineBookmarksName[] = "Enable offline bookmarks";
-
-const char kOfflineBookmarksDescription[] =
-    "Enable saving bookmarked pages for offline viewing.";
-
-const char kNtpOfflinePagesName[] = "Enable NTP offline pages";
-
-const char kNtpOfflinePagesDescription[] =
-    "Enables badging of offline pages on the New Tab page. Only relevant if "
-    "offline pages are enabled.";
-
-const char kOfflinePagesAsyncDownloadName[] =
-    R"*(Enables showing "DOWNLOAD WHEN ONLINE" button in error pages.)*";
-
-const char kOfflinePagesAsyncDownloadDescription[] =
-    R"*(Enables showing "DOWNLOAD WHEN ONLINE" button in error pages such )*"
-    R"*(that the user can click on it to download the page later.)*";
-
-const char kOfflinePagesSvelteConcurrentLoadingName[] =
-    "Enables concurrent background loading on svelte.";
-
-const char kOfflinePagesSvelteConcurrentLoadingDescription[] =
-    "Enables concurrent background loading (or downloading) of pages on "
-    "Android svelte (512MB RAM) devices. Otherwise, background loading will "
-    "happen when the svelte device is idle.";
-
-const char kOfflinePagesLoadSignalCollectingName[] =
-    "Enables collecting load timing data for offline page snapshots.";
-
-const char kOfflinePagesLoadSignalCollectingDescription[] =
-    "Enables loading completeness data collection while writing an offline "
-    "page.  This data is collected in the snapshotted offline page to allow "
-    "data analysis to improve deciding when to make the offline snapshot.";
-
-const char kOfflinePagesPrefetchingName[] =
-    "Enables suggested offline pages to be prefetched.";
-
-const char kOfflinePagesPrefetchingDescription[] =
-    "Enables suggested offline pages to be prefetched, so useful content is "
-    "available while offline.";
-
-const char kOfflinePagesSharingName[] = "Enables offline pages to be shared.";
-
-const char kOfflinePagesSharingDescription[] =
-    "Enables the saved offline pages to be shared via other applications.";
-
-const char kBackgroundLoaderForDownloadsName[] =
-    "Enables background downloading of pages.";
-
-const char kBackgroundLoaderForDownloadsDescription[] =
-    "Enables downloading pages in the background in case page is not yet "
-    "loaded in current tab.";
-
-const char kNewBackgroundLoaderName[] =
-    "Use background loader instead of prerenderer to load pages.";
-
-const char kNewBackgroundLoaderDescription[] =
-    "Use background loader instead of prerenderer to asynchronously download "
-    "pages.";
-
-const char kNtpPopularSitesName[] = "Show popular sites on the New Tab page";
-
-const char kNtpPopularSitesDescription[] =
-    "Pre-populate the New Tab page with popular sites.";
-
-const char kNtpSwitchToExistingTabName[] =
-    "Switch to an existing tab for New Tab Page suggestions.";
-
-const char kNtpSwitchToExistingTabDescription[] =
-    "When opening a suggested webpage from the New Tab Page, if a tab is "
-    "already open for the suggestion, switch to that one instead of loading "
-    "the suggestion in the new tab.";
-
-const char kNtpSwitchToExistingTabMatchUrl[] = "Match by URL";
-
-const char kNtpSwitchToExistingTabMatchHost[] = "Match by Hostname";
-
-const char kUseAndroidMidiApiName[] = "Use Android Midi API";
-
-const char kUseAndroidMidiApiDescription[] =
-    "Use Android Midi API for WebMIDI (effective only with Android M+ "
-    "devices).";
-
-const char kWebPaymentsModifiersName[] = "Enable web payment modifiers";
-
-const char kWebPaymentsModifiersDescription[] =
-    "If the website provides modifiers in the payment request, show the custom "
-    "total for each payment instrument, update the shopping cart when "
-    "instruments are switched, and send modified payment method specific data "
-    "to the payment app.";
-
-const char kXGEOVisibleNetworksName[] = "Enable XGEO Visible Networks";
-
-const char kXGEOVisibleNetworksDescription[] =
-    "If location permissions are granted, include visible networks in the XGEO "
-    "Header for omnibox queries. This will only happen if location is not "
-    "fresh or not available (for example, due to a cold start).";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_WIN)
 
 //  Exporting tracing events to ETW
@@ -2131,68 +2267,6 @@
 
 #endif  // defined(OS_WIN)
 
-#if defined(OS_ANDROID)
-
-//  Data Use
-
-//  Update Menu Item Flags
-
-const char kUpdateMenuItemName[] = "Force show update menu item";
-
-const char kUpdateMenuItemDescription[] =
-    R"*(When enabled, an "Update Chrome" item will be shown in the app )*"
-    R"*(menu.)*";
-
-const char kUpdateMenuItemCustomSummaryDescription[] =
-    "When this flag and the force show update menu item flag are enabled, a "
-    "custom summary string will be displayed below the update menu item.";
-
-const char kUpdateMenuItemCustomSummaryName[] =
-    "Update menu item custom summary";
-
-const char kUpdateMenuBadgeName[] = "Force show update menu badge";
-
-const char kUpdateMenuBadgeDescription[] =
-    "When enabled, an update badge will be shown on the app menu button.";
-
-const char kSetMarketUrlForTestingName[] = "Set market URL for testing";
-
-const char kSetMarketUrlForTestingDescription[] =
-    "When enabled, sets the market URL for use in testing the update menu "
-    "item.";
-
-#endif  // defined(OS_ANDROID)
-
-#if defined(OS_ANDROID)
-
-const char kHerbPrototypeChoicesName[] = "Switch preferred flavor of Herb";
-
-const char kHerbPrototypeChoicesDescription[] =
-    "Switching this option changes which tab management prototype is being "
-    "tested.";
-
-const char kHerbPrototypeFlavorElderberry[] =
-    "ELDERBERRY: All View Intents in CCT v2";
-
-const char kEnableSpecialLocaleName[] =
-    "Enable custom logic for special locales.";
-
-const char kEnableSpecialLocaleDescription[] =
-    "Enable custom logic for special locales. In this mode, Chrome might "
-    "behave differently in some locales.";
-
-//  WebApks
-
-const char kEnableWebapk[] = "Enable improved add to Home screen";
-
-const char kEnableWebapkDescription[] =
-    R"*(Packages "Progressive Web Apps" so that they can integrate more )*"
-    R"*(deeply with Android. A Chrome server is used to package sites. In )*"
-    R"*(Chrome Canary and Chrome Dev, this requires “Untrusted )*"
-    R"*(sources” to be enabled in Android security settings.)*";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_CHROMEOS)
 
 const char kDisableNativeCupsName[] = "Native CUPS";
@@ -2224,175 +2298,6 @@
 
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID)
-
-const char kKeepPrefetchedContentSuggestionsName[] =
-    "Keep prefetched content suggestions";
-
-const char kKeepPrefetchedContentSuggestionsDescription[] =
-    "If enabled, some of prefetched content suggestions are not replaced by "
-    "the new fetched suggestions.";
-
-const char kContentSuggestionsCategoryOrderName[] =
-    "Default content suggestions category order (e.g. on NTP)";
-
-const char kContentSuggestionsCategoryOrderDescription[] =
-    "Set default order of content suggestion categories (e.g. on the NTP).";
-
-const char kContentSuggestionsCategoryRankerName[] =
-    "Content suggestions category ranker (e.g. on NTP)";
-
-const char kContentSuggestionsCategoryRankerDescription[] =
-    "Set category ranker to order categories of content suggestions (e.g. on "
-    "the NTP).";
-
-const char kEnableNtpSnippetsVisibilityName[] =
-    "Make New Tab Page Snippets more visible.";
-
-const char kEnableNtpSnippetsVisibilityDescription[] =
-    "If enabled, the NTP snippets will become more discoverable with a larger "
-    "portion of the first card above the fold.";
-
-const char kEnableContentSuggestionsNewFaviconServerName[] =
-    "Get favicons for content suggestions from a new server.";
-
-const char kEnableContentSuggestionsNewFaviconServerDescription[] =
-    "If enabled, the content suggestions (on the NTP) will get favicons from a "
-    "new favicon server.";
-
-const char kEnableFaviconsFromWebManifestName[] =
-    "Load favicons from Web Manifests";
-
-const char kEnableFaviconsFromWebManifestDescription[] =
-    "Fetch Web Manifests on page load to read favicons from them.";
-
-const char kEnableNtpMostLikelyFaviconsFromServerName[] =
-    "Download favicons for NTP tiles from Google.";
-
-const char kEnableNtpMostLikelyFaviconsFromServerDescription[] =
-    "If enabled, missing favicons for NTP tiles get downloaded from Google. "
-    "This only applies to tiles that originate from synced history.";
-
-const char kEnableContentSuggestionsLargeThumbnailName[] =
-    "Large thumbnails layout for content suggestions cards.";
-
-const char kEnableContentSuggestionsLargeThumbnailDescription[] =
-    "If enabled, the content suggestions cards will use large thumbnails and "
-    "some related adjustments.";
-
-const char kEnableContentSuggestionsVideoOverlayName[] =
-    "Video icon overlay on thumbnails for content suggestions cards.";
-
-const char kEnableContentSuggestionsVideoOverlayDescription[] =
-    "If enabled, the content suggestions cards for suggestions with a video "
-    "will show a video play icon overlay on the thumbnail.";
-
-const char kEnableContentSuggestionsSettingsName[] =
-    "Show content suggestions settings.";
-
-const char kEnableContentSuggestionsSettingsDescription[] =
-    "If enabled, the content suggestions settings will be available from the "
-    "main settings menu.";
-
-const char kEnableContentSuggestionsShowSummaryName[] =
-    "Show content suggestions summaries.";
-
-const char kEnableContentSuggestionsShowSummaryDescription[] =
-    "If enabled, the content suggestions summaries will be shown.";
-
-const char kEnableNtpRemoteSuggestionsName[] =
-    "Show server-side suggestions on the New Tab page";
-
-const char kEnableNtpRemoteSuggestionsDescription[] =
-    "If enabled, the list of content suggestions on the New Tab page will "
-    "contain server-side suggestions (e.g., Articles for you). Furthermore, it "
-    "allows to override the source used to retrieve these server-side "
-    "suggestions.";
-
-const char kEnableNtpAssetDownloadSuggestionsName[] =
-    "Show asset downloads on the New Tab page";
-
-const char kEnableNtpAssetDownloadSuggestionsDescription[] =
-    "If enabled, the list of content suggestions on the New Tab page will "
-    "contain assets (e.g. books, pictures, audio) that the user downloaded for "
-    "later use.";
-
-const char kEnableNtpOfflinePageDownloadSuggestionsName[] =
-    "Show offline page downloads on the New Tab page";
-
-const char kEnableNtpOfflinePageDownloadSuggestionsDescription[] =
-    "If enabled, the list of content suggestions on the New Tab page will "
-    "contain pages that the user downloaded for later use.";
-
-const char kEnableNtpBookmarkSuggestionsName[] =
-    "Show recently visited bookmarks on the New Tab page";
-
-const char kEnableNtpBookmarkSuggestionsDescription[] =
-    "If enabled, the list of content suggestions on the New Tab page will "
-    "contain recently visited bookmarks.";
-
-const char kEnableNtpForeignSessionsSuggestionsName[] =
-    "Show recent foreign tabs on the New Tab page";
-
-const char kEnableNtpForeignSessionsSuggestionsDescription[] =
-    "If enabled, the list of content suggestions on the New Tab page will "
-    "contain recent foreign tabs.";
-
-const char kEnableNtpSuggestionsNotificationsName[] =
-    "Notify about new content suggestions available at the New Tab page";
-
-const char kEnableNtpSuggestionsNotificationsDescription[] =
-    "If enabled, notifications will inform about new content suggestions on "
-    "the New Tab page.";
-
-const char kNtpCondensedLayoutName[] = "Condensed NTP layout";
-
-const char kNtpCondensedLayoutDescription[] =
-    "Show a condensed layout on the New Tab Page.";
-
-const char kNtpCondensedTileLayoutName[] = "Condensed NTP tile layout";
-
-const char kNtpCondensedTileLayoutDescription[] =
-    "Show a condensed tile layout on the New Tab Page.";
-
-const char kNtpGoogleGInOmniboxName[] = "Google G in New Tab Page omnibox";
-
-const char kNtpGoogleGInOmniboxDescription[] =
-    "Show a Google G in the omnibox on the New Tab Page.";
-
-#endif  // defined(OS_ANDROID)
-
-#if defined(OS_ANDROID)
-
-const char kOffliningRecentPagesName[] =
-    "Enable offlining of recently visited pages";
-
-const char kOffliningRecentPagesDescription[] =
-    "Enable storing recently visited pages locally for offline use. Requires "
-    "Offline Pages to be enabled.";
-
-const char kOfflinePagesCtName[] = "Enable Offline Pages CT features.";
-
-const char kOfflinePagesCtDescription[] = "Enable Offline Pages CT features.";
-
-const char kOfflinePagesCtV2Name[] = "Enable Offline Pages CT V2 features.";
-
-const char kOfflinePagesCtV2Description[] =
-    "V2 features include attributing pages to the app that initiated the "
-    "custom tabs, and being able to query for pages by page attribution.";
-
-#endif  // defined(OS_ANDROID)
-
-#if defined(OS_ANDROID)
-
-const char kEnableExpandedAutofillCreditCardPopupLayoutName[] =
-    "Use expanded autofill credit card popup layout.";
-
-const char kEnableExpandedAutofillCreditCardPopupLayoutDescription[] =
-    "If enabled, displays autofill credit card popup using expanded layout.";
-
-#endif  // defined(OS_ANDROID)
-
 #if !defined(OS_ANDROID) && defined(GOOGLE_CHROME_BUILD)
 
 const char kGoogleBrandedContextMenuName[] =
@@ -2430,37 +2335,6 @@
 
 #endif  // BUILDFLAG(ENABLE_VR)
 
-#if defined(OS_ANDROID)
-
-const char kEnableAndroidPayIntegrationV1Name[] = "Enable Android Pay v1";
-
-const char kEnableAndroidPayIntegrationV1Description[] =
-    "Enable integration with Android Pay using the first version of the API";
-
-const char kEnableAndroidPayIntegrationV2Name[] = "Enable Android Pay v2";
-
-const char kEnableAndroidPayIntegrationV2Description[] =
-    "Enable integration with Android Pay using the second version of the API";
-
-const char kEnableWebPaymentsSingleAppUiSkipName[] =
-    "Enable Web Payments single app UI skip";
-
-const char kEnableWebPaymentsSingleAppUiSkipDescription[] =
-    "Enable Web Payments to skip showing its UI if the developer specifies a "
-    "single app.";
-
-const char kAndroidPaymentAppsName[] = "Android payment apps";
-
-const char kAndroidPaymentAppsDescription[] =
-    "Enable third party Android apps to integrate as payment apps";
-
-const char kServiceWorkerPaymentAppsName[] = "Service Worker payment apps";
-
-const char kServiceWorkerPaymentAppsDescription[] =
-    "Enable Service Worker applications to integrate as payment apps";
-
-#endif  // defined(OS_ANDROID)
-
 #if !defined(OS_ANDROID)
 
 const char kEnableAudioFocusName[] = "Manage audio focus across tabs";
@@ -2487,15 +2361,6 @@
 
 #endif  // defined(OS_WIN)
 
-#if defined(OS_ANDROID)
-
-const char kModalPermissionPromptsName[] = "Modal Permission Prompts";
-
-const char kModalPermissionPromptsDescription[] =
-    "Whether to use permission dialogs in place of permission infobars.";
-
-#endif  // defined(OS_ANDROID)
-
 #if !defined(OS_MACOSX)
 
 const char kPermissionPromptPersistenceToggleName[] =
@@ -2506,41 +2371,6 @@
 
 #endif  // !defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
-
-const char kNoCreditCardAbort[] = "No Credit Card Abort";
-
-const char kNoCreditCardAbortDescription[] =
-    "Whether or not the No Credit Card Abort is enabled.";
-
-#endif  // defined(OS_ANDROID)
-
-//  Consistent omnibox geolocation
-
-#if defined(OS_ANDROID)
-
-const char kEnableConsistentOmniboxGeolocationName[] =
-    "Have consistent omnibox geolocation access.";
-
-const char kEnableConsistentOmniboxGeolocationDescription[] =
-    "Have consistent geolocation access between the omnibox and default search "
-    "engine.";
-
-#endif  // defined(OS_ANDROID)
-
-//  Play Services LSD permission prompt chrome://flags strings
-
-#if defined(OS_ANDROID)
-
-const char kLsdPermissionPromptName[] =
-    "Location Settings Dialog Permission Prompt";
-
-const char kLsdPermissionPromptDescription[] =
-    "Whether to use the Google Play Services Location Settings Dialog "
-    "permission dialog.";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_WIN)
 
 //  Custom draw the Windows 10 titlebar. crbug.com/505013
@@ -2563,16 +2393,6 @@
 
 #endif  // defined(OS_WIN)
 
-#if defined(OS_ANDROID)
-
-const char kAiaFetchingName[] = "Intermediate Certificate Fetching";
-
-const char kAiaFetchingDescription[] =
-    "Enable intermediate certificate fetching when a server does not provide "
-    "sufficient certificates to build a chain to a trusted root.";
-
-#endif  // defined(OS_ANDROID)
-
 //  Desktop iOS promotion chrome://flags strings
 
 #if defined(OS_WIN)
@@ -2585,16 +2405,6 @@
 
 #endif  // defined(OS_WIN)
 
-#if defined(OS_ANDROID)
-
-const char kEnableCustomFeedbackUiName[] = "Enable Custom Feedback UI";
-
-const char kEnableCustomFeedbackUiDescription[] =
-    "Enables a custom feedback UI when submitting feedback through Google "
-    "Feedback. Works with Google Play Services v10.2+";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
     defined(OS_WIN)
 
@@ -2628,25 +2438,6 @@
 
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID)
-
-const char kUseDdljsonApiName[] = "Use new ddljson API for Doodles";
-
-const char kUseDdljsonApiDescription[] =
-    "Enables the new ddljson API to fetch Doodles for the NTP.";
-
-#endif  // defined(OS_ANDROID)
-
-#if defined(OS_ANDROID)
-
-const char kEnableCustomContextMenuName[] = "Enable custom context menu";
-
-const char kEnableCustomContextMenuDescription[] =
-    "Enables a new context menu when a link, image, or video is pressed within "
-    "Chrome.";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_CHROMEOS)
 
 //  File Manager
@@ -2845,34 +2636,6 @@
 
 #endif  // #if defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID)
-
-const char kEnableCopylessPasteName[] = "App Indexing (Copyless Paste)";
-
-const char kEnableCopylessPasteDescription[] =
-    "Provide suggestions for text input, based on your recent context. For "
-    "example, if you looked at a restaurant website and switched to the Maps "
-    "app, the keyboard would offer the name of that restaurant as a suggestion "
-    "to enter into the search bar. The data is indexed locally, and never sent "
-    "to the server. It's disabled in incognito mode.";
-
-const char kEnableWebNfcName[] = "WebNFC";
-
-const char kEnableWebNfcDescription[] = "Enable WebNFC support.";
-
-#endif  // defined(OS_ANDROID)
-
-#if defined(OS_ANDROID)
-
-const char kEnableOmniboxClipboardProviderName[] =
-    "Omnibox clipboard URL suggestions";
-
-const char kEnableOmniboxClipboardProviderDescription[] =
-    "Provide a suggestion of the URL stored in the clipboard (if any) upon "
-    "focus in the omnibox.";
-
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_WIN)
 
 // Name and description of the flag that enables D3D v-sync.
@@ -2934,13 +2697,4 @@
 
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID)
-
-const char kSpannableInlineAutocompleteName[] = "Spannable inline autocomplete";
-const char kSpannableInlineAutocompleteDescription[] =
-    "A new type of inline autocomplete for the omnibox that works with "
-    "keyboards that compose text.";
-
-#endif  // defined(OS_ANDROID)
-
 }  // namespace flag_descriptions
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index b985000e..3cd988f8 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -522,9 +522,6 @@
 extern const char kOmniboxUIElideSuggestionUrlAfterHostName[];
 extern const char kOmniboxUIElideSuggestionUrlAfterHostDescription[];
 
-extern const char kOmniboxSpareRendererName[];
-extern const char kOmniboxSpareRendererDescription[];
-
 extern const char kOmniboxUIHideSuggestionUrlSchemeName[];
 extern const char kOmniboxUIHideSuggestionUrlSchemeDescription[];
 
@@ -705,10 +702,11 @@
 extern const char kSpellingFeedbackFieldTrialName[];
 extern const char kSpellingFeedbackFieldTrialDescription[];
 
-extern const char kSslVersionMaxName[];
-extern const char kSslVersionMaxDescription[];
-extern const char kSslVersionMaxTls12[];
-extern const char kSslVersionMaxTls13[];
+extern const char kTLS13VariantName[];
+extern const char kTLS13VariantDescription[];
+extern const char kTLS13VariantDisabled[];
+extern const char kTLS13VariantDraft[];
+extern const char kTLS13VariantExperiment[];
 
 extern const char kSuggestionsWithSubStringMatchName[];
 extern const char kSuggestionsWithSubStringMatchDescription[];
@@ -959,12 +957,6 @@
 extern const char kEnableNtpOfflinePageDownloadSuggestionsName[];
 extern const char kEnableNtpOfflinePageDownloadSuggestionsDescription[];
 
-extern const char kEnableNtpPhysicalWebPageSuggestionsName[];
-extern const char kEnableNtpPhysicalWebPageSuggestionsDescription[];
-
-extern const char kEnableNtpRecentOfflineTabSuggestionsName[];
-extern const char kEnableNtpRecentOfflineTabSuggestionsDescription[];
-
 extern const char kEnableNtpRemoteSuggestionsName[];
 extern const char kEnableNtpRemoteSuggestionsDescription[];
 
diff --git a/chrome/browser/language/OWNERS b/chrome/browser/language/OWNERS
new file mode 100644
index 0000000..f1e82d5
--- /dev/null
+++ b/chrome/browser/language/OWNERS
@@ -0,0 +1 @@
+file://components/language/OWNERS
diff --git a/chrome/browser/language/url_language_histogram_factory.cc b/chrome/browser/language/url_language_histogram_factory.cc
new file mode 100644
index 0000000..f50763f
--- /dev/null
+++ b/chrome/browser/language/url_language_histogram_factory.cc
@@ -0,0 +1,36 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/language/url_language_histogram_factory.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/language/core/browser/url_language_histogram.h"
+
+// static
+UrlLanguageHistogramFactory* UrlLanguageHistogramFactory::GetInstance() {
+  return base::Singleton<UrlLanguageHistogramFactory>::get();
+}
+
+// static
+language::UrlLanguageHistogram*
+UrlLanguageHistogramFactory::GetForBrowserContext(
+    content::BrowserContext* const browser_context) {
+  return static_cast<language::UrlLanguageHistogram*>(
+      GetInstance()->GetServiceForBrowserContext(browser_context, true));
+}
+
+UrlLanguageHistogramFactory::UrlLanguageHistogramFactory()
+    : BrowserContextKeyedServiceFactory(
+          "UrlLanguageHistogram",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+UrlLanguageHistogramFactory::~UrlLanguageHistogramFactory() {}
+
+KeyedService* UrlLanguageHistogramFactory::BuildServiceInstanceFor(
+    content::BrowserContext* const browser_context) const {
+  Profile* const profile = Profile::FromBrowserContext(browser_context);
+  return new language::UrlLanguageHistogram(profile->GetPrefs());
+}
diff --git a/chrome/browser/language/url_language_histogram_factory.h b/chrome/browser/language/url_language_histogram_factory.h
new file mode 100644
index 0000000..7a6dd4e
--- /dev/null
+++ b/chrome/browser/language/url_language_histogram_factory.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_LANGUAGE_URL_LANGUAGE_HISTOGRAM_FACTORY_H_
+#define CHROME_BROWSER_LANGUAGE_URL_LANGUAGE_HISTOGRAM_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace language {
+class UrlLanguageHistogram;
+}
+
+class UrlLanguageHistogramFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static UrlLanguageHistogramFactory* GetInstance();
+  static language::UrlLanguageHistogram* GetForBrowserContext(
+      content::BrowserContext* browser_context);
+
+ private:
+  friend struct base::DefaultSingletonTraits<UrlLanguageHistogramFactory>;
+
+  UrlLanguageHistogramFactory();
+  ~UrlLanguageHistogramFactory() override;
+
+  // BrowserContextKeyedServiceFactory overrides.
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlLanguageHistogramFactory);
+};
+
+#endif  // CHROME_BROWSER_LANGUAGE_URL_LANGUAGE_HISTOGRAM_FACTORY_H_
diff --git a/chrome/browser/language/url_language_histogram_factory_unittest.cc b/chrome/browser/language/url_language_histogram_factory_unittest.cc
new file mode 100644
index 0000000..fc6add7
--- /dev/null
+++ b/chrome/browser/language/url_language_histogram_factory_unittest.cc
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/language/url_language_histogram_factory.h"
+
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::IsNull;
+using testing::Not;
+
+TEST(UrlLanguageHistogramFactoryTest, NotCreatedInIncognito) {
+  content::TestBrowserThreadBundle thread_bundle;
+  TestingProfile profile;
+
+  EXPECT_THAT(UrlLanguageHistogramFactory::GetForBrowserContext(&profile),
+              Not(IsNull()));
+
+  Profile* incognito = profile.GetOffTheRecordProfile();
+  ASSERT_THAT(incognito, Not(IsNull()));
+  EXPECT_THAT(UrlLanguageHistogramFactory::GetForBrowserContext(incognito),
+              IsNull());
+}
diff --git a/chrome/browser/media_galleries/media_galleries_permission_controller.cc b/chrome/browser/media_galleries/media_galleries_permission_controller.cc
index 3809784..0bac561 100644
--- a/chrome/browser/media_galleries/media_galleries_permission_controller.cc
+++ b/chrome/browser/media_galleries/media_galleries_permission_controller.cc
@@ -10,7 +10,6 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/media_galleries/media_file_system_registry.h"
 #include "chrome/browser/media_galleries/media_galleries_histograms.h"
 #include "chrome/browser/media_galleries/media_gallery_context_menu.h"
@@ -20,6 +19,7 @@
 #include "components/storage_monitor/storage_info.h"
 #include "components/storage_monitor/storage_monitor.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/permissions/media_galleries_permission.h"
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index 4a91125..8d223c3 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -20,12 +20,12 @@
 #include "chrome/browser/gcm/instance_id/instance_id_profile_service.h"
 #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/language/url_language_histogram_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/suggestions/image_decoder_impl.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/translate/language_model_factory.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
@@ -37,6 +37,7 @@
 #include "components/image_fetcher/core/image_fetcher_impl.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/keyed_service/core/service_access_type.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h"
 #include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
 #include "components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h"
@@ -60,7 +61,6 @@
 #include "components/safe_json/safe_json_parser.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager.h"
-#include "components/translate/core/browser/language_model.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -97,6 +97,7 @@
 using content::BrowserThread;
 using history::HistoryService;
 using image_fetcher::ImageFetcherImpl;
+using language::UrlLanguageHistogram;
 using ntp_snippets::BookmarkSuggestionsProvider;
 using ntp_snippets::BreakingNewsGCMAppHandler;
 using ntp_snippets::BreakingNewsSuggestionsProvider;
@@ -118,7 +119,6 @@
 using ntp_snippets::UserClassifier;
 using suggestions::ImageDecoderImpl;
 using syncer::SyncService;
-using translate::LanguageModel;
 
 #if defined(OS_ANDROID)
 using content::DownloadManager;
@@ -299,8 +299,8 @@
   PrefService* pref_service = profile->GetPrefs();
   OAuth2TokenService* token_service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
-  LanguageModel* language_model =
-      LanguageModelFactory::GetInstance()->GetForBrowserContext(profile);
+  UrlLanguageHistogram* language_histogram =
+      UrlLanguageHistogramFactory::GetInstance()->GetForBrowserContext(profile);
 
   scoped_refptr<net::URLRequestContextGetter> request_context =
       content::BrowserContext::GetDefaultStoragePartition(profile)
@@ -337,7 +337,7 @@
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
   auto suggestions_fetcher = base::MakeUnique<RemoteSuggestionsFetcherImpl>(
       signin_manager, token_service, request_context, pref_service,
-      language_model, base::Bind(&safe_json::SafeJsonParser::Parse),
+      language_histogram, base::Bind(&safe_json::SafeJsonParser::Parse),
       GetFetchEndpoint(chrome::GetChannel()), api_key, user_classifier);
   auto provider = base::MakeUnique<RemoteSuggestionsProviderImpl>(
       service, pref_service, g_browser_process->GetApplicationLocale(),
diff --git a/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.cc
index 7ad4636..17fd6a04 100644
--- a/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
 #include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
 
 namespace internal {
@@ -74,6 +76,13 @@
 const char kHistogramDocWriteBlockLoadingBehavior[] =
     "PageLoad.Clients.DocWrite.Block.DocumentWriteLoadingBehavior";
 
+const char kUkmDocWriteBlockName[] = "Intervention.DocumentWrite.ScriptBlock";
+const char kUkmDocWriteBlockReload[] = "Disabled.Reload";
+const char kUkmParseBlockedOnScriptLoadDocumentWrite[] =
+    "ParseTiming.ParseBlockedOnScriptLoadFromDocumentWrite";
+const char kUkmParseBlockedOnScriptExecutionDocumentWrite[] =
+    "ParseTiming.ParseBlockedOnScriptExecutionFromDocumentWrite";
+
 }  // namespace internal
 
 void DocumentWritePageLoadMetricsObserver::OnFirstContentfulPaintInPage(
@@ -119,11 +128,28 @@
   }
 }
 
-void LogLoadingBehaviorMetrics(
- DocumentWritePageLoadMetricsObserver::DocumentWriteLoadingBehavior behavior) {
-  UMA_HISTOGRAM_ENUMERATION(internal::kHistogramDocWriteBlockLoadingBehavior,
-                            behavior,
-                  DocumentWritePageLoadMetricsObserver::LOADING_BEHAVIOR_MAX);
+// static
+void DocumentWritePageLoadMetricsObserver::LogLoadingBehaviorMetrics(
+    DocumentWritePageLoadMetricsObserver::DocumentWriteLoadingBehavior behavior,
+    ukm::SourceId source_id) {
+  UMA_HISTOGRAM_ENUMERATION(
+      internal::kHistogramDocWriteBlockLoadingBehavior, behavior,
+      DocumentWritePageLoadMetricsObserver::LOADING_BEHAVIOR_MAX);
+
+  // We only log the block and reload behaviors in UKM.
+  if (behavior != LOADING_BEHAVIOR_BLOCK &&
+      behavior != LOADING_BEHAVIOR_RELOAD) {
+    return;
+  }
+  ukm::UkmRecorder* ukm_recorder = g_browser_process->ukm_recorder();
+  if (ukm_recorder) {
+    std::unique_ptr<ukm::UkmEntryBuilder> builder =
+        ukm_recorder->GetEntryBuilder(source_id,
+                                      internal::kUkmDocWriteBlockName);
+    if (behavior == LOADING_BEHAVIOR_RELOAD) {
+      builder->AddMetric(internal::kUkmDocWriteBlockReload, true);
+    }
+  }
 }
 
 void DocumentWritePageLoadMetricsObserver::OnLoadingBehaviorObserved(
@@ -136,21 +162,22 @@
         info.main_frame_metadata.behavior_flags &
         blink::WebLoadingBehaviorFlag::kWebLoadingBehaviorDocumentWriteBlock));
     UMA_HISTOGRAM_COUNTS(internal::kHistogramDocWriteBlockReloadCount, 1);
-    LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_RELOAD);
+    LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_RELOAD, info.source_id);
     doc_write_block_reload_observed_ = true;
   }
   if ((info.main_frame_metadata.behavior_flags &
        blink::WebLoadingBehaviorFlag::kWebLoadingBehaviorDocumentWriteBlock) &&
       !doc_write_block_observed_) {
     UMA_HISTOGRAM_BOOLEAN(internal::kHistogramDocWriteBlockCount, true);
-    LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_BLOCK);
+    LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_BLOCK, info.source_id);
     doc_write_block_observed_ = true;
   }
   if ((info.main_frame_metadata.behavior_flags &
        blink::WebLoadingBehaviorFlag::
            kWebLoadingBehaviorDocumentWriteBlockDifferentScheme) &&
       !doc_write_same_site_diff_scheme_) {
-    LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_SAME_SITE_DIFF_SCHEME);
+    LogLoadingBehaviorMetrics(LOADING_BEHAVIOR_SAME_SITE_DIFF_SCHEME,
+                              info.source_id);
     doc_write_same_site_diff_scheme_ = true;
   }
 }
@@ -291,6 +318,24 @@
         timing.parse_timing
             ->parse_blocked_on_script_execution_from_document_write_duration
             .value());
+
+    ukm::UkmRecorder* ukm_recorder = g_browser_process->ukm_recorder();
+    if (ukm_recorder) {
+      std::unique_ptr<ukm::UkmEntryBuilder> builder =
+          ukm_recorder->GetEntryBuilder(info.source_id,
+                                        internal::kUkmDocWriteBlockName);
+      builder->AddMetric(
+          internal::kUkmParseBlockedOnScriptLoadDocumentWrite,
+          timing.parse_timing
+              ->parse_blocked_on_script_load_from_document_write_duration
+              ->InMilliseconds());
+      builder->AddMetric(
+          internal::kUkmParseBlockedOnScriptExecutionDocumentWrite,
+          timing.parse_timing
+              ->parse_blocked_on_script_execution_from_document_write_duration
+              ->InMilliseconds());
+    }
+
   } else {
     PAGE_LOAD_HISTOGRAM(
         internal::kBackgroundHistogramDocWriteBlockParseDuration,
diff --git a/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.h
index 81468a6..705fd70 100644
--- a/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.h
@@ -16,6 +16,11 @@
 extern const char kHistogramDocWriteBlockCount[];
 extern const char kHistogramDocWriteBlockReloadCount[];
 
+extern const char kUkmDocWriteBlockName[];
+extern const char kUkmDocWriteBlockReload[];
+extern const char kUkmParseBlockedOnScriptLoadDocumentWrite[];
+extern const char kUkmParseBlockedOnScriptExecutionDocumentWrite[];
+
 }  // namespace internal
 
 class DocumentWritePageLoadMetricsObserver
@@ -47,6 +52,9 @@
   };
 
  private:
+  static void LogLoadingBehaviorMetrics(DocumentWriteLoadingBehavior behavior,
+                                        ukm::SourceId source_id);
+
   void LogDocumentWriteEvaluatorFirstContentfulPaint(
       const page_load_metrics::mojom::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& info);
diff --git a/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer_unittest.cc
index c41596f..0e90003 100644
--- a/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer_unittest.cc
@@ -30,6 +30,7 @@
 TEST_F(DocumentWritePageLoadMetricsObserverTest, NoMetrics) {
   AssertNoPreloadHistogramsLogged();
   AssertNoBlockHistogramsLogged();
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(DocumentWritePageLoadMetricsObserverTest, PossiblePreload) {
@@ -44,7 +45,7 @@
   page_load_metrics::mojom::PageLoadMetadata metadata;
   metadata.behavior_flags |=
       blink::WebLoadingBehaviorFlag::kWebLoadingBehaviorDocumentWriteEvaluator;
-  NavigateAndCommit(GURL("https://www.google.com"));
+  NavigateAndCommit(GURL("https://www.google.com/"));
   SimulateTimingAndMetadataUpdate(timing, metadata);
 
   histogram_tester().ExpectTotalCount(
@@ -53,7 +54,7 @@
       internal::kHistogramDocWriteParseStartToFirstContentfulPaint,
       contentful_paint.InMilliseconds(), 1);
 
-  NavigateAndCommit(GURL("https://www.example.com"));
+  NavigateAndCommit(GURL("https://www.example.com/"));
 
   histogram_tester().ExpectTotalCount(
       internal::kHistogramDocWriteParseStartToFirstContentfulPaint, 1);
@@ -71,9 +72,9 @@
   PopulateRequiredTimingFields(&timing);
 
   page_load_metrics::mojom::PageLoadMetadata metadata;
-  NavigateAndCommit(GURL("https://www.google.com"));
+  NavigateAndCommit(GURL("https://www.google.com/"));
   SimulateTimingAndMetadataUpdate(timing, metadata);
-  NavigateAndCommit(GURL("https://www.example.com"));
+  NavigateAndCommit(GURL("https://www.example.com/"));
   AssertNoPreloadHistogramsLogged();
 }
 
@@ -84,12 +85,23 @@
   timing.navigation_start = base::Time::FromDoubleT(1);
   timing.paint_timing->first_contentful_paint = contentful_paint;
   timing.parse_timing->parse_start = base::TimeDelta::FromMilliseconds(1);
+  timing.parse_timing->parse_stop = base::TimeDelta::FromMilliseconds(100);
+  timing.parse_timing->parse_blocked_on_script_load_duration =
+      base::TimeDelta::FromMilliseconds(5);
+  timing.parse_timing
+      ->parse_blocked_on_script_load_from_document_write_duration =
+      base::TimeDelta::FromMilliseconds(5);
+  timing.parse_timing->parse_blocked_on_script_execution_duration =
+      base::TimeDelta::FromMilliseconds(3);
+  timing.parse_timing
+      ->parse_blocked_on_script_execution_from_document_write_duration =
+      base::TimeDelta::FromMilliseconds(3);
   PopulateRequiredTimingFields(&timing);
 
   page_load_metrics::mojom::PageLoadMetadata metadata;
   metadata.behavior_flags |=
       blink::WebLoadingBehaviorFlag::kWebLoadingBehaviorDocumentWriteBlock;
-  NavigateAndCommit(GURL("https://www.google.com"));
+  NavigateAndCommit(GURL("https://www.google.com/"));
   SimulateTimingAndMetadataUpdate(timing, metadata);
 
   histogram_tester().ExpectTotalCount(internal::kHistogramDocWriteBlockCount,
@@ -100,7 +112,18 @@
       internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint,
       contentful_paint.InMilliseconds(), 1);
 
-  NavigateAndCommit(GURL("https://www.example.com"));
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl("https://www.google.com/");
+  EXPECT_TRUE(
+      test_ukm_recorder().HasEntry(*source, internal::kUkmDocWriteBlockName));
+  test_ukm_recorder().ExpectMetric(
+      *source, internal::kUkmDocWriteBlockName,
+      internal::kUkmParseBlockedOnScriptLoadDocumentWrite, 5);
+  test_ukm_recorder().ExpectMetric(
+      *source, internal::kUkmDocWriteBlockName,
+      internal::kUkmParseBlockedOnScriptExecutionDocumentWrite, 3);
+
+  NavigateAndCommit(GURL("https://www.example.com/"));
 
   histogram_tester().ExpectTotalCount(
       internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint, 1);
@@ -121,19 +144,27 @@
   page_load_metrics::mojom::PageLoadMetadata metadata;
   metadata.behavior_flags |= blink::WebLoadingBehaviorFlag::
       kWebLoadingBehaviorDocumentWriteBlockReload;
-  NavigateAndCommit(GURL("https://www.google.com"));
+  NavigateAndCommit(GURL("https://www.google.com/"));
   SimulateTimingAndMetadataUpdate(timing, metadata);
 
   histogram_tester().ExpectTotalCount(
       internal::kHistogramDocWriteBlockReloadCount, 1);
 
+  test_ukm_recorder().ExpectMetric(
+      *test_ukm_recorder().GetSourceForUrl("https://www.google.com/"),
+      internal::kUkmDocWriteBlockName, internal::kUkmDocWriteBlockReload, true);
+
   // Another reload.
-  NavigateAndCommit(GURL("https://www.example.com"));
+  NavigateAndCommit(GURL("https://www.example.com/"));
   SimulateTimingAndMetadataUpdate(timing, metadata);
 
   histogram_tester().ExpectTotalCount(
       internal::kHistogramDocWriteBlockReloadCount, 2);
 
+  test_ukm_recorder().ExpectMetric(
+      *test_ukm_recorder().GetSourceForUrl("https://www.example.com/"),
+      internal::kUkmDocWriteBlockName, internal::kUkmDocWriteBlockReload, true);
+
   // Another metadata update should not increase reload count.
   metadata.behavior_flags |=
       blink::WebLoadingBehaviorFlag::kWebLoadingBehaviorServiceWorkerControlled;
@@ -143,6 +174,8 @@
 
   histogram_tester().ExpectTotalCount(internal::kHistogramDocWriteBlockCount,
                                       0);
+
+  EXPECT_EQ(2ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(DocumentWritePageLoadMetricsObserverTest, NoPossibleBlock) {
@@ -154,9 +187,9 @@
   PopulateRequiredTimingFields(&timing);
 
   page_load_metrics::mojom::PageLoadMetadata metadata;
-  NavigateAndCommit(GURL("https://www.google.com"));
+  NavigateAndCommit(GURL("https://www.google.com/"));
   SimulateTimingAndMetadataUpdate(timing, metadata);
 
-  NavigateAndCommit(GURL("https://www.example.com"));
+  NavigateAndCommit(GURL("https://www.example.com/"));
   AssertNoBlockHistogramsLogged();
 }
diff --git a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
index 60ff8c6..7acdc648 100644
--- a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
@@ -7,8 +7,10 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
 #include "chrome/common/page_load_metrics/page_load_timing.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
 
 using page_load_metrics::PageAbortReason;
 
@@ -109,6 +111,8 @@
 const char kHistogramFromGWSForegroundDurationNoCommit[] =
     "PageLoad.Clients.FromGoogleSearch.PageTiming.ForegroundDuration.NoCommit";
 
+const char kUkmFromGoogleSearchName[] = "PageLoad.FromGoogleSearch";
+
 }  // namespace internal
 
 namespace {
@@ -359,6 +363,7 @@
           navigation_handle->GetPageTransition()));
 
   logger_.SetNavigationStart(navigation_handle->NavigationStart());
+  logger_.OnCommit(navigation_handle, source_id);
   return CONTINUE_OBSERVING;
 }
 
@@ -435,6 +440,18 @@
   logger_.OnUserInput(event);
 }
 
+void FromGWSPageLoadMetricsLogger::OnCommit(
+    content::NavigationHandle* navigation_handle,
+    ukm::SourceId source_id) {
+  if (!ShouldLogPostCommitMetrics(navigation_handle->GetURL()))
+    return;
+  ukm::UkmRecorder* ukm_recorder = g_browser_process->ukm_recorder();
+  if (ukm_recorder) {
+    ukm_recorder->GetEntryBuilder(source_id,
+                                  internal::kUkmFromGoogleSearchName);
+  }
+}
+
 void FromGWSPageLoadMetricsLogger::OnComplete(
     const page_load_metrics::mojom::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& extra_info) {
diff --git a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h
index 272126d..7edf2d2 100644
--- a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h
@@ -36,6 +36,8 @@
 extern const char kHistogramFromGWSForegroundDurationAfterPaint[];
 extern const char kHistogramFromGWSForegroundDurationNoCommit[];
 
+extern const char kUkmFromGoogleSearchName[];
+
 }  // namespace internal
 
 // FromGWSPageLoadMetricsLogger is a peer class to
@@ -63,6 +65,8 @@
   }
 
   // Invoked when metrics for the given page are complete.
+  void OnCommit(content::NavigationHandle* navigation_handle,
+                ukm::SourceId source_id);
   void OnComplete(const page_load_metrics::mojom::PageLoadTiming& timing,
                   const page_load_metrics::PageLoadExtraInfo& extra_info);
   void OnFailedProvisionalLoad(
diff --git a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer_unittest.cc
index bf52457..e21598d 100644
--- a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h"
 
+#include <vector>
+
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
@@ -56,6 +58,7 @@
 TEST_F(FromGWSPageLoadMetricsObserverTest, NoMetrics) {
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       0);
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest, NoPreviousCommittedUrl) {
@@ -69,9 +72,10 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       0);
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest, NonSearchPreviousCommittedUrl) {
@@ -86,9 +90,10 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       0);
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest,
@@ -104,9 +109,10 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       0);
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest,
@@ -124,9 +130,10 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       0);
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest, SearchPreviousCommittedUrl1) {
@@ -152,7 +159,7 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
 
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSParseStart, 1);
   histogram_tester().ExpectBucketCount(
@@ -212,6 +219,12 @@
   histogram_tester().ExpectBucketCount(
       internal::kHistogramFromGWSLoad,
       timing.document_timing->load_event_start.value().InMilliseconds(), 1);
+
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl(kExampleUrl);
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*source,
+                                           internal::kUkmFromGoogleSearchName));
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest, SearchPreviousCommittedUrl2) {
@@ -226,12 +239,18 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       1);
   histogram_tester().ExpectBucketCount(
       internal::kHistogramFromGWSFirstTextPaint,
       timing.paint_timing->first_text_paint.value().InMilliseconds(), 1);
+
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl(kExampleUrl);
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*source,
+                                           internal::kUkmFromGoogleSearchName));
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest, SearchPreviousCommittedUrl3) {
@@ -246,12 +265,18 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       1);
   histogram_tester().ExpectBucketCount(
       internal::kHistogramFromGWSFirstTextPaint,
       timing.paint_timing->first_text_paint.value().InMilliseconds(), 1);
+
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl(kExampleUrl);
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*source,
+                                           internal::kUkmFromGoogleSearchName));
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest, SearchPreviousCommittedUrl4) {
@@ -266,12 +291,18 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       1);
   histogram_tester().ExpectBucketCount(
       internal::kHistogramFromGWSFirstTextPaint,
       timing.paint_timing->first_text_paint.value().InMilliseconds(), 1);
+
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl(kExampleUrl);
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*source,
+                                           internal::kUkmFromGoogleSearchName));
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest, SearchToNonSearchToOtherPage) {
@@ -294,12 +325,18 @@
 
   // Navigate again to force logging. We expect to log timing for the page
   // navigated from search, but not for the page navigated from that page.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       1);
   histogram_tester().ExpectBucketCount(
       internal::kHistogramFromGWSFirstTextPaint,
       timing.paint_timing->first_text_paint.value().InMilliseconds(), 1);
+
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl(kExampleUrl);
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*source,
+                                           internal::kUkmFromGoogleSearchName));
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest, SearchToNonSearchToSearch) {
@@ -322,12 +359,18 @@
 
   // Navigate again to force logging. We expect to log timing for the page
   // navigated from search, but not for the search page we navigated to.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       1);
   histogram_tester().ExpectBucketCount(
       internal::kHistogramFromGWSFirstTextPaint,
       timing.paint_timing->first_text_paint.value().InMilliseconds(), 1);
+
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl(kExampleUrl);
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*source,
+                                           internal::kUkmFromGoogleSearchName));
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest,
@@ -359,7 +402,7 @@
 
   // Navigate again to force logging. We expect to log timing for both pages
   // navigated from search, but not for the search pages we navigated to.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       2);
   histogram_tester().ExpectBucketCount(
@@ -368,6 +411,14 @@
   histogram_tester().ExpectBucketCount(
       internal::kHistogramFromGWSFirstTextPaint,
       timing3.paint_timing->first_text_paint.value().InMilliseconds(), 1);
+
+  std::vector<const ukm::UkmSource*> sources =
+      test_ukm_recorder().GetSourcesForUrl(kExampleUrl);
+  EXPECT_EQ(2ul, sources.size());
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*sources.at(0),
+                                           internal::kUkmFromGoogleSearchName));
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*sources.at(1),
+                                           internal::kUkmFromGoogleSearchName));
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest,
@@ -400,12 +451,20 @@
 
   // Navigate again to force logging. We expect to log timing for the first page
   // navigated from search, but not the second since it was backgrounded.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       1);
   histogram_tester().ExpectBucketCount(
       internal::kHistogramFromGWSFirstTextPaint,
       timing.paint_timing->first_text_paint.value().InMilliseconds(), 1);
+
+  std::vector<const ukm::UkmSource*> sources =
+      test_ukm_recorder().GetSourcesForUrl(kExampleUrl);
+  EXPECT_EQ(2ul, sources.size());
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*sources.at(0),
+                                           internal::kUkmFromGoogleSearchName));
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*sources.at(1),
+                                           internal::kUkmFromGoogleSearchName));
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest,
@@ -422,12 +481,18 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       1);
   histogram_tester().ExpectBucketCount(
       internal::kHistogramFromGWSFirstTextPaint,
       timing.paint_timing->first_text_paint.value().InMilliseconds(), 1);
+
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl(kExampleUrl);
+  EXPECT_TRUE(test_ukm_recorder().HasEntry(*source,
+                                           internal::kUkmFromGoogleSearchName));
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest,
@@ -444,9 +509,11 @@
   SimulateTimingUpdate(timing);
 
   // Navigate again to force logging.
-  NavigateAndCommit(GURL("http://www.final.com"));
+  NavigateToUntrackedUrl();
   histogram_tester().ExpectTotalCount(internal::kHistogramFromGWSFirstTextPaint,
                                       0);
+
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(FromGWSPageLoadMetricsObserverTest,
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
index 3802f70f..7be32ab 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h"
 
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
 #include "net/http/http_response_headers.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
 #include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
 
 namespace internal {
@@ -110,6 +112,10 @@
     "PageLoad.Clients.NoServiceWorker.DocumentTiming."
     "NavigationToLoadEventFired.search";
 
+// UKM (URL-keyed metrics) entry identifier, recorded for pages (main frame
+// loads) controlled by a service worker.
+const char kUkmServiceWorkerName[] = "PageLoad.ServiceWorkerControlled";
+
 }  // namespace internal
 
 namespace {
@@ -343,3 +349,15 @@
                         timing.parse_timing->parse_start.value());
   }
 }
+
+void ServiceWorkerPageLoadMetricsObserver::OnLoadingBehaviorObserved(
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  if (!IsServiceWorkerControlled(info) || logged_ukm_event_)
+    return;
+  ukm::UkmRecorder* ukm_recorder = g_browser_process->ukm_recorder();
+  if (ukm_recorder) {
+    ukm_recorder->GetEntryBuilder(info.source_id,
+                                  internal::kUkmServiceWorkerName);
+    logged_ukm_event_ = true;
+  }
+}
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
index a5448c2..990bd75 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
@@ -46,6 +46,7 @@
     kHistogramServiceWorkerParseStartToFirstContentfulPaintSearch[];
 extern const char kHistogramServiceWorkerDomContentLoadedSearch[];
 extern const char kHistogramServiceWorkerLoadSearch[];
+extern const char kUkmServiceWorkerName[];
 
 extern const char kHistogramNoServiceWorkerFirstContentfulPaintSearch[];
 extern const char kHistogramNoServiceWorkerFirstMeaningfulPaintSearch[];
@@ -80,10 +81,13 @@
   void OnLoadEventStart(
       const page_load_metrics::mojom::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& extra_info) override;
+  void OnLoadingBehaviorObserved(
+      const page_load_metrics::PageLoadExtraInfo& extra_info) override;
 
  private:
   ui::PageTransition transition_ = ui::PAGE_TRANSITION_LINK;
   bool was_no_store_main_resource_ = false;
+  bool logged_ukm_event_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPageLoadMetricsObserver);
 };
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc
index abd488db..eb21461 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc
@@ -9,7 +9,7 @@
 
 namespace {
 
-const char kDefaultTestUrl[] = "https://google.com";
+const char kDefaultTestUrl[] = "https://google.com/";
 const char kInboxTestUrl[] = "https://inbox.google.com/test";
 const char kSearchTestUrl[] = "https://www.google.com/search?q=test";
 
@@ -135,6 +135,7 @@
   AssertNoInboxHistogramsLogged();
   AssertNoSearchHistogramsLogged();
   AssertNoSearchNoSWHistogramsLogged();
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(ServiceWorkerPageLoadMetricsObserverTest, NoServiceWorker) {
@@ -148,6 +149,7 @@
   AssertNoInboxHistogramsLogged();
   AssertNoSearchHistogramsLogged();
   AssertNoSearchNoSWHistogramsLogged();
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(ServiceWorkerPageLoadMetricsObserverTest, WithServiceWorker) {
@@ -201,6 +203,12 @@
   histogram_tester().ExpectTotalCount(
       internal::kHistogramServiceWorkerParseStartForwardBackNoStore, 0);
 
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl(kDefaultTestUrl);
+  EXPECT_TRUE(
+      test_ukm_recorder().HasEntry(*source, internal::kUkmServiceWorkerName));
+
   AssertNoInboxHistogramsLogged();
   AssertNoSearchHistogramsLogged();
   AssertNoSearchNoSWHistogramsLogged();
@@ -246,6 +254,12 @@
   // histogram_tester().ExpectTotalCount(
   //     internal::kBackgroundHistogramServiceWorkerParseStart, 1);
 
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
+  const ukm::UkmSource* source =
+      test_ukm_recorder().GetSourceForUrl(kDefaultTestUrl);
+  EXPECT_TRUE(
+      test_ukm_recorder().HasEntry(*source, internal::kUkmServiceWorkerName));
+
   AssertNoInboxHistogramsLogged();
   AssertNoSearchHistogramsLogged();
   AssertNoSearchNoSWHistogramsLogged();
diff --git a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc
index fc22351..74f8922 100644
--- a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc
@@ -4,10 +4,13 @@
 
 #include "chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h"
 
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
 #include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
 #include "components/subresource_filter/core/common/activation_decision.h"
+#include "services/metrics/public/cpp/ukm_entry_builder.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
 #include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
 
 using subresource_filter::ContentSubresourceFilterDriverFactory;
@@ -113,6 +116,10 @@
 const char kHistogramSubresourceFilterActivationDecisionReload[] =
     "PageLoad.Clients.SubresourceFilter.ActivationDecision.LoadType.Reload";
 
+const char kUkmSubresourceFilterName[] = "SubresourceFilter";
+const char kUkmSubresourceFilterActivationDecision[] = "ActivationDecision";
+const char kUkmSubresourceFilterDryRun[] = "DryRun";
+
 }  // namespace internal
 
 namespace {
@@ -185,6 +192,21 @@
   DCHECK(scoped_observer_.IsObservingSources());
   LogActivationDecisionMetrics(navigation_handle, *activation_decision_);
   scoped_observer_.RemoveAll();
+
+  ukm::UkmRecorder* ukm_recorder = g_browser_process->ukm_recorder();
+  if (ukm_recorder) {
+    std::unique_ptr<ukm::UkmEntryBuilder> builder =
+        ukm_recorder->GetEntryBuilder(source_id,
+                                      internal::kUkmSubresourceFilterName);
+    builder->AddMetric(internal::kUkmSubresourceFilterActivationDecision,
+                       static_cast<int64_t>(*activation_decision_));
+    if (*activation_level_ == subresource_filter::ActivationLevel::DRYRUN) {
+      DCHECK_EQ(subresource_filter::ActivationDecision::ACTIVATED,
+                *activation_decision_);
+      builder->AddMetric(internal::kUkmSubresourceFilterDryRun, true);
+    }
+  }
+
   return CONTINUE_OBSERVING;
 }
 
@@ -339,6 +361,9 @@
   DCHECK(!did_commit_);
   DCHECK(!activation_decision_);
   activation_decision_ = activation_decision;
+
+  DCHECK(!activation_level_);
+  activation_level_ = activation_state.activation_level;
 }
 
 void SubresourceFilterMetricsObserver::OnGoingAway(
diff --git a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h
index c45cf79..00a1199f 100644
--- a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h
@@ -11,6 +11,8 @@
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
+#include "components/subresource_filter/core/common/activation_decision.h"
+#include "components/subresource_filter/core/common/activation_level.h"
 #include "components/ukm/ukm_source.h"
 
 namespace internal {
@@ -60,6 +62,10 @@
 extern const char kHistogramSubresourceFilterActivationDecision[];
 extern const char kHistogramSubresourceFilterActivationDecisionReload[];
 
+extern const char kUkmSubresourceFilterName[];
+extern const char kUkmSubresourceFilterActivationDecision[];
+extern const char kUkmSubresourceFilterDryRun[];
+
 }  // namespace internal
 
 class SubresourceFilterMetricsObserver
@@ -115,6 +121,7 @@
                    base::TimeTicks app_background_time);
 
   base::Optional<subresource_filter::ActivationDecision> activation_decision_;
+  base::Optional<subresource_filter::ActivationLevel> activation_level_;
 
   ScopedObserver<subresource_filter::SubresourceFilterObserverManager,
                  subresource_filter::SubresourceFilterObserver>
diff --git a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer_unittest.cc
index 346dc16..07a8945 100644
--- a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer_unittest.cc
@@ -19,6 +19,8 @@
 namespace {
 const char kDefaultTestUrl[] = "https://example.com/";
 const char kDefaultTestUrlWithActivation[] = "https://example-activation.com/";
+const char kDefaultTestUrlWithActivationDryRun[] =
+    "https://dryrun.example-activation.com/";
 }  // namespace
 
 class SubresourceFilterMetricsObserverTest
@@ -78,6 +80,11 @@
           handle, subresource_filter::ActivationDecision::ACTIVATED,
           subresource_filter::ActivationState(
               subresource_filter::ActivationLevel::ENABLED));
+    } else if (handle->GetURL() == kDefaultTestUrlWithActivationDryRun) {
+      observer_manager_->NotifyPageActivationComputed(
+          handle, subresource_filter::ActivationDecision::ACTIVATED,
+          subresource_filter::ActivationState(
+              subresource_filter::ActivationLevel::DRYRUN));
     } else {
       observer_manager_->NotifyPageActivationComputed(
           handle,
@@ -88,6 +95,28 @@
     simulator->Commit();
   }
 
+  void ExpectActivationDecision(const char* url,
+                                subresource_filter::ActivationDecision decision,
+                                subresource_filter::ActivationLevel level) {
+    histogram_tester().ExpectBucketCount(
+        internal::kHistogramSubresourceFilterActivationDecision,
+        static_cast<int>(decision), 1);
+
+    ASSERT_EQ(1ul, test_ukm_recorder().entries_count());
+    const ukm::UkmSource* source = test_ukm_recorder().GetSourceForUrl(url);
+    EXPECT_TRUE(test_ukm_recorder().HasEntry(
+        *source, internal::kUkmSubresourceFilterName));
+    test_ukm_recorder().ExpectMetric(
+        *source, internal::kUkmSubresourceFilterName,
+        internal::kUkmSubresourceFilterActivationDecision,
+        static_cast<int64_t>(decision));
+    if (level == subresource_filter::ActivationLevel::DRYRUN) {
+      test_ukm_recorder().ExpectMetric(
+          *source, internal::kUkmSubresourceFilterName,
+          internal::kUkmSubresourceFilterDryRun, true);
+    }
+  }
+
  private:
   // Owned by the WebContents.
   subresource_filter::SubresourceFilterObserverManager* observer_manager_ =
@@ -109,11 +138,10 @@
   NavigateToUntrackedUrl();
 
   EXPECT_EQ(1u, TotalMetricsRecorded());
-  histogram_tester().ExpectBucketCount(
-      internal::kHistogramSubresourceFilterActivationDecision,
-      static_cast<int>(subresource_filter::ActivationDecision::
-                           ACTIVATION_CONDITIONS_NOT_MET),
-      1);
+  ExpectActivationDecision(
+      kDefaultTestUrl,
+      subresource_filter::ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
+      subresource_filter::ActivationLevel::DISABLED);
 }
 
 TEST_F(SubresourceFilterMetricsObserverTest, Basic) {
@@ -130,6 +158,9 @@
   NavigateToUntrackedUrl();
 
   EXPECT_GT(TotalMetricsRecorded(), 0u);
+  ExpectActivationDecision(kDefaultTestUrlWithActivation,
+                           subresource_filter::ActivationDecision::ACTIVATED,
+                           subresource_filter::ActivationLevel::ENABLED);
 
   histogram_tester().ExpectTotalCount(
       internal::kHistogramSubresourceFilterCount, 1);
@@ -207,6 +238,25 @@
       internal::kHistogramSubresourceFilterForegroundDuration, 1);
 }
 
+TEST_F(SubresourceFilterMetricsObserverTest, DryRun) {
+  SimulateNavigateAndCommit(GURL(kDefaultTestUrlWithActivationDryRun));
+
+  page_load_metrics::mojom::PageLoadTiming timing;
+  InitializePageLoadTiming(&timing);
+  page_load_metrics::mojom::PageLoadMetadata metadata;
+  metadata.behavior_flags |=
+      blink::WebLoadingBehaviorFlag::kWebLoadingBehaviorSubresourceFilterMatch;
+  SimulateTimingAndMetadataUpdate(timing, metadata);
+
+  // Navigate away from the current page to force logging of metrics.
+  NavigateToUntrackedUrl();
+
+  EXPECT_GT(TotalMetricsRecorded(), 0u);
+  ExpectActivationDecision(kDefaultTestUrlWithActivationDryRun,
+                           subresource_filter::ActivationDecision::ACTIVATED,
+                           subresource_filter::ActivationLevel::DRYRUN);
+}
+
 TEST_F(SubresourceFilterMetricsObserverTest, Subresources) {
   SimulateNavigateAndCommit(GURL(kDefaultTestUrlWithActivation));
 
@@ -239,6 +289,9 @@
                           nullptr /* data_reduction_proxy_data */,
                           content::ResourceType::RESOURCE_TYPE_SCRIPT, 0});
 
+  ExpectActivationDecision(kDefaultTestUrlWithActivation,
+                           subresource_filter::ActivationDecision::ACTIVATED,
+                           subresource_filter::ActivationLevel::ENABLED);
   histogram_tester().ExpectTotalCount(
       internal::kHistogramSubresourceFilterCount, 1);
 
@@ -342,6 +395,9 @@
                           nullptr /* data_reduction_proxy_data */,
                           content::ResourceType::RESOURCE_TYPE_SCRIPT, 0});
 
+  ExpectActivationDecision(kDefaultTestUrlWithActivation,
+                           subresource_filter::ActivationDecision::ACTIVATED,
+                           subresource_filter::ActivationLevel::ENABLED);
   histogram_tester().ExpectTotalCount(
       internal::kHistogramSubresourceFilterCount, 1);
 
diff --git a/chrome/browser/prefs/active_profile_pref_service.cc b/chrome/browser/prefs/active_profile_pref_service.cc
index 2d47cd4..8e7e0a7 100644
--- a/chrome/browser/prefs/active_profile_pref_service.cc
+++ b/chrome/browser/prefs/active_profile_pref_service.cc
@@ -19,17 +19,9 @@
 
 void ActiveProfilePrefService::Connect(
     prefs::mojom::PrefRegistryPtr pref_registry,
-    const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
     ConnectCallback callback) {
   GetPrefStoreConnector().Connect(std::move(pref_registry),
-                                  already_connected_types, std::move(callback));
-}
-
-void ActiveProfilePrefService::ConnectToUserPrefStore(
-    const std::vector<std::string>& prefs_to_observe,
-    ConnectToUserPrefStoreCallback callback) {
-  GetPrefStoreConnector().ConnectToUserPrefStore(prefs_to_observe,
-                                                 std::move(callback));
+                                  std::move(callback));
 }
 
 void ActiveProfilePrefService::Create(
diff --git a/chrome/browser/prefs/active_profile_pref_service.h b/chrome/browser/prefs/active_profile_pref_service.h
index 6909996..9ab23f4 100644
--- a/chrome/browser/prefs/active_profile_pref_service.h
+++ b/chrome/browser/prefs/active_profile_pref_service.h
@@ -28,12 +28,8 @@
 
  private:
   // prefs::mojom::PrefStoreConnector:
-  void Connect(
-      prefs::mojom::PrefRegistryPtr pref_registry,
-      const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
-      ConnectCallback callback) override;
-  void ConnectToUserPrefStore(const std::vector<std::string>& prefs_to_observe,
-                              ConnectToUserPrefStoreCallback callback) override;
+  void Connect(prefs::mojom::PrefRegistryPtr pref_registry,
+               ConnectCallback callback) override;
 
   // service_manager::Service:
   void OnStart() override;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 4659a1f..01c8299a 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -76,6 +76,7 @@
 #include "components/doodle/doodle_service.h"
 #include "components/flags_ui/pref_service_flags_storage.h"
 #include "components/gcm_driver/gcm_channel_status_syncer.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/network_time/network_time_tracker.h"
 #include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
 #include "components/ntp_snippets/breaking_news/subscription_manager.h"
@@ -106,7 +107,6 @@
 #include "components/subresource_filter/core/browser/ruleset_service.h"
 #include "components/sync/base/sync_prefs.h"
 #include "components/sync_preferences/pref_service_syncable.h"
-#include "components/translate/core/browser/language_model.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/update_client/update_client.h"
 #include "components/variations/service/variations_service.h"
@@ -239,6 +239,7 @@
 #include "components/invalidation/impl/invalidator_storage.h"
 #include "components/onc/onc_pref_names.h"
 #include "components/quirks/quirks_manager.h"
+#include "extensions/browser/api/lock_screen_data/lock_screen_item_storage.h"
 #else
 #include "chrome/browser/extensions/default_apps.h"
 #endif
@@ -406,6 +407,8 @@
   chromeos::WallpaperManager::RegisterPrefs(registry);
   chromeos::echo_offer::RegisterPrefs(registry);
   extensions::ExtensionAssetsManagerChromeOS::RegisterPrefs(registry);
+  extensions::lock_screen_data::LockScreenItemStorage::RegisterLocalState(
+      registry);
   invalidation::InvalidatorStorage::RegisterPrefs(registry);
   ::onc::RegisterPrefs(registry);
   policy::AutoEnrollmentClient::RegisterPrefs(registry);
@@ -459,10 +462,11 @@
   ImportantSitesUtil::RegisterProfilePrefs(registry);
   IncognitoModePrefs::RegisterProfilePrefs(registry);
   InstantUI::RegisterProfilePrefs(registry);
-  NavigationCorrectionTabObserver::RegisterProfilePrefs(registry);
+  language::UrlLanguageHistogram::RegisterProfilePrefs(registry);
   MediaCaptureDevicesDispatcher::RegisterProfilePrefs(registry);
   MediaDeviceIDSalt::RegisterProfilePrefs(registry);
   MediaStreamDevicesController::RegisterProfilePrefs(registry);
+  NavigationCorrectionTabObserver::RegisterProfilePrefs(registry);
   NetHttpSessionParamsObserver::RegisterProfilePrefs(registry);
   NotifierStateTracker::RegisterProfilePrefs(registry);
   ntp_snippets::BreakingNewsGCMAppHandler::RegisterProfilePrefs(registry);
@@ -488,7 +492,6 @@
   safe_browsing::RegisterProfilePrefs(registry);
   SessionStartupPref::RegisterProfilePrefs(registry);
   TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
-  translate::LanguageModel::RegisterProfilePrefs(registry);
   translate::TranslatePrefs::RegisterProfilePrefs(registry);
   UINetworkQualityEstimatorService::RegisterProfilePrefs(registry);
   ZeroSuggestProvider::RegisterProfilePrefs(registry);
@@ -731,30 +734,4 @@
   }
 }
 
-std::set<PrefValueStore::PrefStoreType> ExpectedPrefStores() {
-  return std::set<PrefValueStore::PrefStoreType>({
-      PrefValueStore::MANAGED_STORE,
-#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-      PrefValueStore::SUPERVISED_USER_STORE,
-#endif
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-      PrefValueStore::EXTENSION_STORE,
-#endif
-      PrefValueStore::COMMAND_LINE_STORE, PrefValueStore::RECOMMENDED_STORE,
-      PrefValueStore::USER_STORE, PrefValueStore::DEFAULT_STORE
-  });
-}
-
-std::set<PrefValueStore::PrefStoreType> InProcessPrefStores() {
-  auto pref_stores = ExpectedPrefStores();
-  // Until we have a distinction between owned and unowned prefs, we always have
-  // default values for all prefs locally. Since we already have the defaults it
-  // would be wasteful to request them from the service by connecting to the
-  // DEFAULT_STORE.
-  // TODO(sammc): Once we have this distinction, connect to the default pref
-  // store here (by erasing it from |pref_stores|).
-  pref_stores.erase(PrefValueStore::USER_STORE);
-  return pref_stores;
-}
-
 }  // namespace chrome
diff --git a/chrome/browser/prefs/browser_prefs.h b/chrome/browser/prefs/browser_prefs.h
index 257638ab..c7ab177 100644
--- a/chrome/browser/prefs/browser_prefs.h
+++ b/chrome/browser/prefs/browser_prefs.h
@@ -47,13 +47,6 @@
 // should remain *the* place to drop deprecated profile prefs at.
 void MigrateObsoleteProfilePrefs(Profile* profile);
 
-// The pref stores Chrome expects to exist.
-std::set<PrefValueStore::PrefStoreType> ExpectedPrefStores();
-
-// The pref stores Chrome creates in-process (and thus doesn't need to connect
-// to through the pref service).
-std::set<PrefValueStore::PrefStoreType> InProcessPrefStores();
-
 }  // namespace chrome
 
 #endif  // CHROME_BROWSER_PREFS_BROWSER_PREFS_H_
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc
index dd746c8..8ca6bbc 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
@@ -38,15 +38,15 @@
 
 const CommandLinePrefStore::SwitchToPreferenceMapEntry
     ChromeCommandLinePrefStore::string_switch_map_[] = {
-      { switches::kLang, prefs::kApplicationLocale },
-      { data_reduction_proxy::switches::kDataReductionProxy,
-          data_reduction_proxy::prefs::kDataReductionProxy },
-      { switches::kAuthServerWhitelist, prefs::kAuthServerWhitelist },
-      { switches::kSSLVersionMin, ssl_config::prefs::kSSLVersionMin },
-      { switches::kSSLVersionMax, ssl_config::prefs::kSSLVersionMax },
+        {switches::kLang, prefs::kApplicationLocale},
+        {data_reduction_proxy::switches::kDataReductionProxy,
+         data_reduction_proxy::prefs::kDataReductionProxy},
+        {switches::kAuthServerWhitelist, prefs::kAuthServerWhitelist},
+        {switches::kSSLVersionMin, ssl_config::prefs::kSSLVersionMin},
+        {switches::kTLS13Variant, ssl_config::prefs::kTLS13Variant},
 #if defined(OS_ANDROID)
-      { switches::kAuthAndroidNegotiateAccountType,
-          prefs::kAuthAndroidNegotiateAccountType },
+        {switches::kAuthAndroidNegotiateAccountType,
+         prefs::kAuthAndroidNegotiateAccountType},
 #endif
 };
 
@@ -160,6 +160,16 @@
     SetValue(ssl_config::prefs::kCipherSuiteBlacklist, std::move(list_value),
              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   }
+
+  // If a non-disabled TLS 1.3 variant flag is set, enable TLS 1.3 in
+  // SSLVersionMax.
+  if (command_line()->HasSwitch(switches::kTLS13Variant) &&
+      command_line()->GetSwitchValueASCII(switches::kTLS13Variant) !=
+          switches::kTLS13VariantDisabled) {
+    SetValue(ssl_config::prefs::kSSLVersionMax,
+             base::MakeUnique<base::Value>(switches::kSSLVersionTLSv13),
+             WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  }
 }
 
 void ChromeCommandLinePrefStore::ApplyBackgroundModeSwitches() {
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store_ssl_manager_unittest.cc b/chrome/browser/prefs/chrome_command_line_pref_store_ssl_manager_unittest.cc
index 15de0a8..f58f451 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store_ssl_manager_unittest.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store_ssl_manager_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/prefs/chrome_command_line_pref_store.h"
@@ -29,14 +30,15 @@
   base::MessageLoop message_loop_;
 };
 
-// Test that command-line settings for minimum and maximum SSL versions are
-// respected and that they do not persist to the preferences files.
+// Test that command-line settings for SSL versions and TLS 1.3 variants
+// are respected and that they do not persist to the preferences files.
 TEST_F(CommandLinePrefStoreSSLManagerTest, CommandLinePrefs) {
   scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
 
   base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
   command_line.AppendSwitchASCII(switches::kSSLVersionMin, "tls1.1");
-  command_line.AppendSwitchASCII(switches::kSSLVersionMax, "tls1.3");
+  command_line.AppendSwitchASCII(switches::kSSLVersionMax, "tls1.2");
+  command_line.AppendSwitchASCII(switches::kTLS13Variant, "draft");
 
   sync_preferences::PrefServiceMockFactory factory;
   factory.set_user_prefs(local_state_store);
@@ -58,6 +60,7 @@
   // Command-line flags should be respected.
   EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_1, ssl_config.version_min);
   EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max);
+  EXPECT_EQ(net::kTLS13VariantDraft, ssl_config.tls13_variant);
 
   // Explicitly double-check the settings are not in the preference store.
   const PrefService::Preference* version_min_pref =
@@ -68,10 +71,77 @@
       local_state->FindPreference(ssl_config::prefs::kSSLVersionMax);
   EXPECT_FALSE(version_max_pref->IsUserModifiable());
 
+  const PrefService::Preference* tls13_variant_pref =
+      local_state->FindPreference(ssl_config::prefs::kTLS13Variant);
+  EXPECT_FALSE(tls13_variant_pref->IsUserModifiable());
+
   std::string version_min_str;
   std::string version_max_str;
+  std::string tls13_variant_str;
   EXPECT_FALSE(local_state_store->GetString(ssl_config::prefs::kSSLVersionMin,
                                             &version_min_str));
   EXPECT_FALSE(local_state_store->GetString(ssl_config::prefs::kSSLVersionMax,
                                             &version_max_str));
+  EXPECT_FALSE(local_state_store->GetString(ssl_config::prefs::kTLS13Variant,
+                                            &tls13_variant_str));
+}
+
+// Test that setting an enabled TLS 1.3 variant correctly sets SSLVersionMax.
+TEST_F(CommandLinePrefStoreSSLManagerTest, TLS13VariantEnabled) {
+  scoped_refptr<TestingPrefStore> local_state_store =
+      base::MakeRefCounted<TestingPrefStore>();
+
+  base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+  command_line.AppendSwitchASCII(switches::kTLS13Variant, "experiment");
+
+  sync_preferences::PrefServiceMockFactory factory;
+  factory.set_user_prefs(local_state_store);
+  factory.set_command_line_prefs(new ChromeCommandLinePrefStore(&command_line));
+  scoped_refptr<PrefRegistrySimple> registry = new PrefRegistrySimple;
+  std::unique_ptr<PrefService> local_state(factory.Create(registry.get()));
+
+  SSLConfigServiceManager::RegisterPrefs(registry.get());
+
+  std::unique_ptr<SSLConfigServiceManager> config_manager(
+      SSLConfigServiceManager::CreateDefaultManager(
+          local_state.get(), base::ThreadTaskRunnerHandle::Get()));
+  ASSERT_TRUE(config_manager.get());
+  scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+  ASSERT_TRUE(config_service.get());
+
+  SSLConfig ssl_config;
+  config_service->GetSSLConfig(&ssl_config);
+  // Command-line flags should be respected.
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max);
+  EXPECT_EQ(net::kTLS13VariantExperiment, ssl_config.tls13_variant);
+}
+
+// Test that setting a disabled TLS 1.3 variant correctly sets SSLVersionMax.
+TEST_F(CommandLinePrefStoreSSLManagerTest, TLS13VariantDisabled) {
+  scoped_refptr<TestingPrefStore> local_state_store =
+      base::MakeRefCounted<TestingPrefStore>();
+
+  base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+  command_line.AppendSwitchASCII(switches::kSSLVersionMax, "tls1.3");
+  command_line.AppendSwitchASCII(switches::kTLS13Variant, "disabled");
+
+  sync_preferences::PrefServiceMockFactory factory;
+  factory.set_user_prefs(local_state_store);
+  factory.set_command_line_prefs(new ChromeCommandLinePrefStore(&command_line));
+  scoped_refptr<PrefRegistrySimple> registry = new PrefRegistrySimple;
+  std::unique_ptr<PrefService> local_state(factory.Create(registry.get()));
+
+  SSLConfigServiceManager::RegisterPrefs(registry.get());
+
+  std::unique_ptr<SSLConfigServiceManager> config_manager(
+      SSLConfigServiceManager::CreateDefaultManager(
+          local_state.get(), base::ThreadTaskRunnerHandle::Get()));
+  ASSERT_TRUE(config_manager.get());
+  scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+  ASSERT_TRUE(config_service.get());
+
+  SSLConfig ssl_config;
+  config_service->GetSSLConfig(&ssl_config);
+  // Command-line flags should be respected.
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_max);
 }
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
index 5344edf5..e8a9387 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -457,7 +457,8 @@
     const scoped_refptr<PrefStore>& extension_prefs,
     const scoped_refptr<user_prefs::PrefRegistrySyncable>& pref_registry,
     bool async,
-    service_manager::Connector* connector) {
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+    std::unique_ptr<PrefValueStore::Delegate> delegate) {
   TRACE_EVENT0("browser", "chrome_prefs::CreateProfilePrefs");
   SCOPED_UMA_HISTOGRAM_TIMER("PrefService.CreateProfilePrefsTime");
 
@@ -470,14 +471,13 @@
       CreateProfilePrefStoreManager(profile_path)
           ->CreateProfilePrefStore(
               GetTrackingConfiguration(), kTrackedPrefsReportingIDsCount,
-              content::BrowserThread::GetBlockingPool(),
-              std::move(reset_on_load_observer), std::move(validation_delegate),
-              connector, pref_registry));
+              std::move(io_task_runner), std::move(reset_on_load_observer),
+              std::move(validation_delegate)));
   PrepareFactory(&factory, profile_path, policy_service,
                  supervised_user_settings, user_pref_store, extension_prefs,
                  async);
   std::unique_ptr<sync_preferences::PrefServiceSyncable> pref_service =
-      factory.CreateSyncable(pref_registry.get(), connector);
+      factory.CreateSyncable(pref_registry.get(), std::move(delegate));
 
   return pref_service;
 }
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.h b/chrome/browser/prefs/chrome_pref_service_factory.h
index e2d53cf..8edd77c 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.h
+++ b/chrome/browser/prefs/chrome_pref_service_factory.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/memory/ref_counted.h"
+#include "components/prefs/pref_value_store.h"
 #include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
 
 namespace base {
@@ -21,10 +22,6 @@
 class PolicyService;
 }
 
-namespace service_manager {
-class Connector;
-}
-
 namespace sync_preferences {
 class PrefServiceSyncable;
 }
@@ -82,7 +79,8 @@
     const scoped_refptr<PrefStore>& extension_prefs,
     const scoped_refptr<user_prefs::PrefRegistrySyncable>& pref_registry,
     bool async,
-    service_manager::Connector* connector);
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+    std::unique_ptr<PrefValueStore::Delegate> delegate);
 
 // Call before startup tasks kick in to ignore the presence of a domain when
 // determining the active SettingsEnforcement group. For testing only.
diff --git a/chrome/browser/prefs/in_process_service_factory_factory.cc b/chrome/browser/prefs/in_process_service_factory_factory.cc
new file mode 100644
index 0000000..7cd369b7
--- /dev/null
+++ b/chrome/browser/prefs/in_process_service_factory_factory.cc
@@ -0,0 +1,43 @@
+// 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 "chrome/browser/prefs/in_process_service_factory_factory.h"
+
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "services/preferences/public/cpp/in_process_service_factory.h"
+#include "services/service_manager/public/cpp/service.h"
+
+// static
+InProcessPrefServiceFactoryFactory*
+InProcessPrefServiceFactoryFactory::GetInstance() {
+  CR_DEFINE_STATIC_LOCAL(InProcessPrefServiceFactoryFactory, factory, ());
+  return &factory;
+}
+
+// static
+prefs::InProcessPrefServiceFactory*
+InProcessPrefServiceFactoryFactory::GetInstanceForContext(
+    content::BrowserContext* context) {
+  return static_cast<prefs::InProcessPrefServiceFactory*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+InProcessPrefServiceFactoryFactory::InProcessPrefServiceFactoryFactory()
+    : BrowserContextKeyedServiceFactory(
+          "InProcessPrefServiceFactory",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+InProcessPrefServiceFactoryFactory::~InProcessPrefServiceFactoryFactory() =
+    default;
+
+KeyedService* InProcessPrefServiceFactoryFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new prefs::InProcessPrefServiceFactory;
+}
+
+content::BrowserContext*
+InProcessPrefServiceFactoryFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return context;
+}
diff --git a/chrome/browser/prefs/in_process_service_factory_factory.h b/chrome/browser/prefs/in_process_service_factory_factory.h
new file mode 100644
index 0000000..677b96ca
--- /dev/null
+++ b/chrome/browser/prefs/in_process_service_factory_factory.h
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PREFS_IN_PROCESS_SERVICE_FACTORY_FACTORY_H_
+#define CHROME_BROWSER_PREFS_IN_PROCESS_SERVICE_FACTORY_FACTORY_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace prefs {
+class InProcessPrefServiceFactory;
+}
+
+class InProcessPrefServiceFactoryFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static InProcessPrefServiceFactoryFactory* GetInstance();
+
+  static prefs::InProcessPrefServiceFactory* GetInstanceForContext(
+      content::BrowserContext* context);
+
+ private:
+  InProcessPrefServiceFactoryFactory();
+  ~InProcessPrefServiceFactoryFactory() override;
+
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(InProcessPrefServiceFactoryFactory);
+};
+
+#endif  // CHROME_BROWSER_PREFS_IN_PROCESS_SERVICE_FACTORY_FACTORY_H_
diff --git a/chrome/browser/prefs/pref_service_syncable_util.cc b/chrome/browser/prefs/pref_service_syncable_util.cc
index 8a552a5..dfe49a6c 100644
--- a/chrome/browser/prefs/pref_service_syncable_util.cc
+++ b/chrome/browser/prefs/pref_service_syncable_util.cc
@@ -31,9 +31,7 @@
 sync_preferences::PrefServiceSyncable* CreateIncognitoPrefServiceSyncable(
     sync_preferences::PrefServiceSyncable* pref_service,
     PrefStore* incognito_extension_pref_store,
-    std::set<PrefValueStore::PrefStoreType> already_connected_types,
-    service_manager::Connector* incognito_connector,
-    service_manager::Connector* user_connector) {
+    std::unique_ptr<PrefValueStore::Delegate> delegate) {
   // List of keys that cannot be changed in the user prefs file by the incognito
   // profile.  All preferences that store information about the browsing history
   // or behavior of the user should have this property.
@@ -45,6 +43,5 @@
   overlay_pref_names.push_back(proxy_config::prefs::kProxy);
 #endif
   return pref_service->CreateIncognitoPrefService(
-      incognito_extension_pref_store, overlay_pref_names,
-      std::move(already_connected_types), incognito_connector, user_connector);
+      incognito_extension_pref_store, overlay_pref_names, std::move(delegate));
 }
diff --git a/chrome/browser/prefs/pref_service_syncable_util.h b/chrome/browser/prefs/pref_service_syncable_util.h
index 1bcdc321..e3869f2e 100644
--- a/chrome/browser/prefs/pref_service_syncable_util.h
+++ b/chrome/browser/prefs/pref_service_syncable_util.h
@@ -12,10 +12,6 @@
 class PrefStore;
 class Profile;
 
-namespace service_manager {
-class Connector;
-}
-
 namespace sync_preferences {
 class PrefServiceSyncable;
 }
@@ -40,14 +36,10 @@
 // windows).
 //
 // If the Mojo pref service is in use |incognito_connector| and |user_connector|
-// must be non-null and |already_connected_types| should be the set of
-// |PrefStore|s that are running in the current service and thus don't need to
-// be connected to.
+// must be non-null.
 sync_preferences::PrefServiceSyncable* CreateIncognitoPrefServiceSyncable(
     sync_preferences::PrefServiceSyncable* pref_service,
     PrefStore* incognito_extension_pref_store,
-    std::set<PrefValueStore::PrefStoreType> already_connected_types,
-    service_manager::Connector* incognito_connector,
-    service_manager::Connector* user_connector);
+    std::unique_ptr<PrefValueStore::Delegate> delegate);
 
 #endif  // CHROME_BROWSER_PREFS_PREF_SERVICE_SYNCABLE_UTIL_H_
diff --git a/chrome/browser/prefs/profile_pref_store_manager.cc b/chrome/browser/prefs/profile_pref_store_manager.cc
index dac7ee22..faaeaf5 100644
--- a/chrome/browser/prefs/profile_pref_store_manager.cc
+++ b/chrome/browser/prefs/profile_pref_store_manager.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_features.h"
-#include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/json_pref_store.h"
 #include "components/prefs/persistent_pref_store.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -89,35 +88,18 @@
     std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
         tracking_configuration,
     size_t reporting_ids_count,
-    base::SequencedWorkerPool* worker_pool,
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
     prefs::mojom::ResetOnLoadObserverPtr reset_on_load_observer,
-    prefs::mojom::TrackedPreferenceValidationDelegatePtr validation_delegate,
-    service_manager::Connector* connector,
-    scoped_refptr<PrefRegistry> pref_registry) {
-  if (features::PrefServiceEnabled()) {
-    ConfigurePrefService(std::move(tracking_configuration), reporting_ids_count,
-                         std::move(reset_on_load_observer),
-                         std::move(validation_delegate), connector);
-    prefs::mojom::PrefStoreConnectorPtr pref_connector;
-    connector->BindInterface(prefs::mojom::kServiceName, &pref_connector);
-    auto in_process_types_set = chrome::InProcessPrefStores();
-    std::vector<PrefValueStore::PrefStoreType> in_process_types(
-        in_process_types_set.begin(), in_process_types_set.end());
-    return new prefs::PersistentPrefStoreClient(std::move(pref_connector),
-                                                std::move(pref_registry),
-                                                std::move(in_process_types));
-  }
+    prefs::mojom::TrackedPreferenceValidationDelegatePtr validation_delegate) {
   if (!kPlatformSupportsPreferenceTracking) {
-    return new JsonPrefStore(
-        profile_path_.Append(chrome::kPreferencesFilename),
-        JsonPrefStore::GetTaskRunnerForFile(profile_path_, worker_pool),
-        nullptr);
+    return new JsonPrefStore(profile_path_.Append(chrome::kPreferencesFilename),
+                             io_task_runner, nullptr);
   }
   return CreateTrackedPersistentPrefStore(
       CreateTrackedPrefStoreConfiguration(
           std::move(tracking_configuration), reporting_ids_count,
           std::move(reset_on_load_observer), std::move(validation_delegate)),
-      worker_pool);
+      io_task_runner);
 }
 
 bool ProfilePrefStoreManager::InitializePrefsFromMasterPrefs(
@@ -153,28 +135,6 @@
   return success;
 }
 
-void ProfilePrefStoreManager::ConfigurePrefService(
-    std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
-        tracking_configuration,
-    size_t reporting_ids_count,
-    prefs::mojom::ResetOnLoadObserverPtr reset_on_load_observer,
-    prefs::mojom::TrackedPreferenceValidationDelegatePtr validation_delegate,
-    service_manager::Connector* connector) {
-  auto config = prefs::mojom::PersistentPrefStoreConfiguration::New();
-  if (!kPlatformSupportsPreferenceTracking) {
-    config->set_simple_configuration(
-        prefs::mojom::SimplePersistentPrefStoreConfiguration::New(
-            profile_path_.Append(chrome::kPreferencesFilename)));
-  } else {
-    config->set_tracked_configuration(CreateTrackedPrefStoreConfiguration(
-        std::move(tracking_configuration), reporting_ids_count,
-        std::move(reset_on_load_observer), std::move(validation_delegate)));
-  }
-  prefs::mojom::PrefServiceControlPtr control;
-  connector->BindInterface(prefs::mojom::kServiceName, &control);
-  control->Init(std::move(config));
-}
-
 prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr
 ProfilePrefStoreManager::CreateTrackedPrefStoreConfiguration(
     std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
diff --git a/chrome/browser/prefs/profile_pref_store_manager.h b/chrome/browser/prefs/profile_pref_store_manager.h
index ee38a40..0601d954 100644
--- a/chrome/browser/prefs/profile_pref_store_manager.h
+++ b/chrome/browser/prefs/profile_pref_store_manager.h
@@ -18,12 +18,10 @@
 #include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
 
 class PersistentPrefStore;
-class PrefRegistry;
 class PrefService;
 
 namespace base {
 class DictionaryValue;
-class SequencedWorkerPool;
 }  // namespace base
 
 namespace service_manager {
@@ -85,11 +83,9 @@
       std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
           tracking_configuration,
       size_t reporting_ids_count,
-      base::SequencedWorkerPool* worker_pool,
+      scoped_refptr<base::SequencedTaskRunner> io_task_runner,
       prefs::mojom::ResetOnLoadObserverPtr reset_on_load_observer,
-      prefs::mojom::TrackedPreferenceValidationDelegatePtr validation_delegate,
-      service_manager::Connector* connector,
-      scoped_refptr<PrefRegistry> pref_registry);
+      prefs::mojom::TrackedPreferenceValidationDelegatePtr validation_delegate);
 
   // Initializes the preferences for the managed profile with the preference
   // values in |master_prefs|. Acts synchronously, including blocking IO.
diff --git a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
index cb431e1..77f58823 100644
--- a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
+++ b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
@@ -139,7 +139,7 @@
 
 }  // namespace
 
-class ProfilePrefStoreManagerTest : public testing::TestWithParam<bool>,
+class ProfilePrefStoreManagerTest : public testing::Test,
                                     public prefs::mojom::ResetOnLoadObserver {
  public:
   ProfilePrefStoreManagerTest()
@@ -150,32 +150,6 @@
         reset_recorded_(false) {}
 
   void SetUp() override {
-    worker_pool_ = base::MakeUnique<base::SequencedWorkerPoolOwner>(
-        2, "ProfilePrefStoreManagerTest");
-    if (GetParam()) {
-      feature_list_.InitAndEnableFeature(features::kPrefService);
-      service_manager::mojom::ServicePtr service_ptr;
-      pref_service_context_ = base::MakeUnique<service_manager::ServiceContext>(
-          prefs::CreatePrefService(
-              std::set<PrefValueStore::PrefStoreType>(
-                  {PrefValueStore::USER_STORE, PrefValueStore::DEFAULT_STORE}),
-              worker_pool_->pool()),
-          mojo::MakeRequest(&service_ptr));
-      connector_ = service_manager::Connector::Create(&connector_request_);
-      service_manager::Connector::TestApi test_api(connector_.get());
-      test_api.OverrideBinderForTesting(
-          prefs::mojom::kServiceName, prefs::mojom::PrefStoreConnector::Name_,
-          base::Bind(&ProfilePrefStoreManagerTest::BindInterface,
-                     base::Unretained(this),
-                     prefs::mojom::PrefStoreConnector::Name_));
-      test_api.OverrideBinderForTesting(
-          prefs::mojom::kServiceName, prefs::mojom::PrefServiceControl::Name_,
-          base::Bind(&ProfilePrefStoreManagerTest::BindInterface,
-                     base::Unretained(this),
-                     prefs::mojom::PrefServiceControl::Name_));
-    } else {
-      feature_list_.InitAndDisableFeature(features::kPrefService);
-    }
     mock_validation_delegate_record_ = new MockValidationDelegateRecord;
     mock_validation_delegate_ = base::MakeUnique<MockValidationDelegate>(
         mock_validation_delegate_record_);
@@ -208,34 +182,15 @@
   }
 
   void ReloadConfiguration() {
-    RelaunchPrefService();
     manager_.reset(new ProfilePrefStoreManager(profile_dir_.GetPath(), seed_,
                                                "device_id"));
   }
 
   void TearDown() override {
     DestroyPrefStore();
-    if (GetParam()) {
-      connector_.reset();
-      pref_service_context_.reset();
-    }
-    worker_pool_.reset();
   }
 
  protected:
-  void RelaunchPrefService() {
-    if (!GetParam())
-      return;
-
-    service_manager::mojom::ServicePtr service_ptr;
-    pref_service_context_ = base::MakeUnique<service_manager::ServiceContext>(
-        prefs::CreatePrefService(
-            std::set<PrefValueStore::PrefStoreType>(
-                {PrefValueStore::USER_STORE, PrefValueStore::DEFAULT_STORE}),
-            worker_pool_->pool()),
-        mojo::MakeRequest(&service_ptr));
-  }
-
   // Verifies whether a reset was reported via the OnResetOnLoad() hook. Also
   // verifies that GetResetTime() was set (or not) accordingly.
   void VerifyResetRecorded(bool reset_expected) {
@@ -278,15 +233,11 @@
     scoped_refptr<PersistentPrefStore> pref_store =
         manager_->CreateProfilePrefStore(
             prefs::CloneTrackedConfiguration(configuration_), kReportingIdCount,
-            worker_pool_->pool().get(), std::move(observer),
-            std::move(validation_delegate), connector_.get(),
-            profile_pref_registry_);
+            base::ThreadTaskRunnerHandle::Get(), std::move(observer),
+            std::move(validation_delegate));
     InitializePrefStore(pref_store.get());
     pref_store = nullptr;
     pref_service_context_.reset();
-    worker_pool_ = base::MakeUnique<base::SequencedWorkerPoolOwner>(
-        2, "ProfilePrefStoreManagerTest");
-    RelaunchPrefService();
   }
 
   void DestroyPrefStore() {
@@ -297,10 +248,8 @@
       pref_store_->CommitPendingWrite();
       base::RunLoop().RunUntilIdle();
       base::RunLoop run_loop;
-      JsonPrefStore::GetTaskRunnerForFile(profile_dir_.GetPath(),
-                                          worker_pool_->pool().get())
-          ->PostTaskAndReply(FROM_HERE, base::BindOnce(&base::DoNothing),
-                             run_loop.QuitClosure());
+      base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
+          FROM_HERE, base::BindOnce(&base::DoNothing), run_loop.QuitClosure());
       run_loop.Run();
 
       pref_store_->RemoveObserver(&registry_verifier_);
@@ -310,9 +259,6 @@
       base::RunLoop().RunUntilIdle();
     }
     pref_service_context_.reset();
-    worker_pool_ = base::MakeUnique<base::SequencedWorkerPoolOwner>(
-        2, "ProfilePrefStoreManagerTest");
-    RelaunchPrefService();
   }
 
   void InitializePrefStore(PersistentPrefStore* pref_store) {
@@ -332,10 +278,8 @@
     pref_store->CommitPendingWrite();
     base::RunLoop().RunUntilIdle();
     base::RunLoop run_loop;
-    JsonPrefStore::GetTaskRunnerForFile(profile_dir_.GetPath(),
-                                        worker_pool_->pool().get())
-        ->PostTaskAndReply(FROM_HERE, base::BindOnce(&base::DoNothing),
-                           run_loop.QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
+        FROM_HERE, base::BindOnce(&base::DoNothing), run_loop.QuitClosure());
     run_loop.Run();
   }
 
@@ -350,9 +294,8 @@
         mojo::MakeRequest(&validation_delegate));
     pref_store_ = manager_->CreateProfilePrefStore(
         prefs::CloneTrackedConfiguration(configuration_), kReportingIdCount,
-        worker_pool_->pool().get(), std::move(observer),
-        std::move(validation_delegate), connector_.get(),
-        profile_pref_registry_);
+        base::ThreadTaskRunnerHandle::Get(), std::move(observer),
+        std::move(validation_delegate));
     pref_store_->AddObserver(&registry_verifier_);
     PrefStoreReadObserver read_observer(pref_store_);
     read_observer.Read();
@@ -431,15 +374,13 @@
 
   base::test::ScopedFeatureList feature_list_;
   bool reset_recorded_;
-  std::unique_ptr<base::SequencedWorkerPoolOwner> worker_pool_;
   std::unique_ptr<service_manager::ServiceContext> pref_service_context_;
-  std::unique_ptr<service_manager::Connector> connector_;
   service_manager::mojom::ConnectorRequest connector_request_;
   mojo::BindingSet<prefs::mojom::ResetOnLoadObserver>
       reset_on_load_observer_bindings_;
 };
 
-TEST_P(ProfilePrefStoreManagerTest, StoreValues) {
+TEST_F(ProfilePrefStoreManagerTest, StoreValues) {
   InitializePrefs();
 
   LoadExistingPrefs();
@@ -451,7 +392,7 @@
   ExpectValidationObserved(kProtectedAtomic);
 }
 
-TEST_P(ProfilePrefStoreManagerTest, ProtectValues) {
+TEST_F(ProfilePrefStoreManagerTest, ProtectValues) {
   InitializePrefs();
 
   ReplaceStringInPrefs(kFoobar, kBarfoo);
@@ -474,7 +415,7 @@
   ExpectValidationObserved(kProtectedAtomic);
 }
 
-TEST_P(ProfilePrefStoreManagerTest, InitializePrefsFromMasterPrefs) {
+TEST_F(ProfilePrefStoreManagerTest, InitializePrefsFromMasterPrefs) {
   auto master_prefs = base::MakeUnique<base::DictionaryValue>();
   master_prefs->Set(kTrackedAtomic, base::MakeUnique<base::Value>(kFoobar));
   master_prefs->Set(kProtectedAtomic,
@@ -492,7 +433,7 @@
   VerifyResetRecorded(false);
 }
 
-TEST_P(ProfilePrefStoreManagerTest, UnprotectedToProtected) {
+TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtected) {
   InitializePrefs();
 
   ExpectValidationObserved(kTrackedAtomic);
@@ -538,7 +479,7 @@
       ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking);
 }
 
-TEST_P(ProfilePrefStoreManagerTest, NewPrefWhenFirstProtecting) {
+TEST_F(ProfilePrefStoreManagerTest, NewPrefWhenFirstProtecting) {
   std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
       original_configuration = prefs::CloneTrackedConfiguration(configuration_);
   for (const auto& metadata : configuration_) {
@@ -574,7 +515,7 @@
   VerifyResetRecorded(false);
 }
 
-TEST_P(ProfilePrefStoreManagerTest, UnprotectedToProtectedWithoutTrust) {
+TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtectedWithoutTrust) {
   InitializePrefs();
 
   ExpectValidationObserved(kTrackedAtomic);
@@ -601,7 +542,7 @@
 
 // This test verifies that preference values are correctly maintained when a
 // preference's protection state changes from protected to unprotected.
-TEST_P(ProfilePrefStoreManagerTest, ProtectedToUnprotected) {
+TEST_F(ProfilePrefStoreManagerTest, ProtectedToUnprotected) {
   InitializePrefs();
 
   ExpectValidationObserved(kTrackedAtomic);
@@ -640,9 +581,3 @@
   ExpectStringValueEquals(kProtectedAtomic, kGoodbyeWorld);
   VerifyResetRecorded(false);
 }
-
-// The parameter controls whether the user pref store is created within a
-// service.
-INSTANTIATE_TEST_CASE_P(ProfilePrefStoreManagerTest,
-                        ProfilePrefStoreManagerTest,
-                        testing::Bool());
diff --git a/chrome/browser/previews/previews_infobar_delegate.cc b/chrome/browser/previews/previews_infobar_delegate.cc
index d1cce99..1256282 100644
--- a/chrome/browser/previews/previews_infobar_delegate.cc
+++ b/chrome/browser/previews/previews_infobar_delegate.cc
@@ -37,7 +37,7 @@
 
 const char kMinStalenessParamName[] = "min_staleness_in_minutes";
 const char kMaxStalenessParamName[] = "max_staleness_in_minutes";
-const int kMinStalenessParamDefaultValue = 2;
+const int kMinStalenessParamDefaultValue = 5;
 const int kMaxStalenessParamDefaultValue = 1440;
 
 void RecordPreviewsInfoBarAction(
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index b84c1c8..44c51a8 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
 #include "chrome/browser/plugins/plugin_prefs.h"
 #include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/browser/prefs/in_process_service_factory_factory.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -62,6 +63,7 @@
 #include "net/http/http_server_properties.h"
 #include "net/http/transport_security_state.h"
 #include "ppapi/features/features.h"
+#include "services/preferences/public/cpp/in_process_service_factory.h"
 #include "services/preferences/public/cpp/pref_service_main.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
 #include "services/service_manager/public/cpp/service.h"
@@ -138,23 +140,15 @@
 }
 
 OffTheRecordProfileImpl::OffTheRecordProfileImpl(Profile* real_profile)
-    : profile_(real_profile),
-      start_time_(Time::Now()) {
+    : profile_(real_profile), start_time_(Time::Now()) {
   // Must happen before we ask for prefs as prefs needs the connection to the
   // service manager, which is set up in Initialize.
   BrowserContext::Initialize(this, profile_->GetPath());
-  service_manager::Connector* otr_connector = nullptr;
-  service_manager::Connector* user_connector = nullptr;
-  std::set<PrefValueStore::PrefStoreType> already_connected_types;
-  if (features::PrefServiceEnabled()) {
-    otr_connector = content::BrowserContext::GetConnectorFor(this);
-    user_connector = content::BrowserContext::GetConnectorFor(profile_);
-    already_connected_types = chrome::InProcessPrefStores();
-  }
   prefs_.reset(CreateIncognitoPrefServiceSyncable(
       PrefServiceSyncableFromProfile(profile_),
       CreateExtensionPrefStore(profile_, true),
-      std::move(already_connected_types), otr_connector, user_connector));
+      InProcessPrefServiceFactoryFactory::GetInstanceForContext(this)
+          ->CreateDelegate()));
   // Register on BrowserContext.
   user_prefs::UserPrefs::Set(this, prefs_.get());
 }
@@ -382,15 +376,13 @@
 
 void OffTheRecordProfileImpl::RegisterInProcessServices(
     StaticServiceMap* services) {
-  if (features::PrefServiceEnabled()) {
+  {
     service_manager::EmbeddedServiceInfo info;
-    info.factory = base::Bind(
-        &prefs::CreatePrefService, chrome::ExpectedPrefStores(),
-        make_scoped_refptr(content::BrowserThread::GetBlockingPool()));
-    info.task_runner = base::CreateSequencedTaskRunnerWithTraits(
-        {base::TaskShutdownBehavior::BLOCK_SHUTDOWN,
-         base::TaskPriority::USER_VISIBLE});
-    pref_service_task_runner_ = info.task_runner;
+    info.factory =
+        InProcessPrefServiceFactoryFactory::GetInstanceForContext(this)
+            ->CreatePrefServiceFactory();
+    info.task_runner = content::BrowserThread::GetTaskRunnerForThread(
+        content::BrowserThread::UI);
     services->insert(std::make_pair(prefs::mojom::kServiceName, info));
   }
 }
@@ -501,11 +493,6 @@
   return profile_->GetLastSessionExitType();
 }
 
-scoped_refptr<base::SequencedTaskRunner>
-OffTheRecordProfileImpl::GetPrefServiceTaskRunner() {
-  return pref_service_task_runner_;
-}
-
 #if defined(OS_CHROMEOS)
 void OffTheRecordProfileImpl::ChangeAppLocale(const std::string& locale,
                                               AppLocaleChangedVia) {
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index e720786..6574d6c 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -80,7 +80,6 @@
   bool WasCreatedByVersionOrLater(const std::string& version) override;
   void SetExitType(ExitType exit_type) override;
   ExitType GetLastSessionExitType() override;
-  scoped_refptr<base::SequencedTaskRunner> GetPrefServiceTaskRunner() override;
 
 #if defined(OS_CHROMEOS)
   void ChangeAppLocale(const std::string& locale, AppLocaleChangedVia) override;
@@ -140,7 +139,6 @@
   Profile* profile_;
 
   std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs_;
-  scoped_refptr<base::SequencedTaskRunner> pref_service_task_runner_;
 
 #if !defined(OS_ANDROID)
   std::unique_ptr<content::HostZoomMap::Subscription> track_zoom_subscription_;
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index c743a8b..dbbfa07e 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -303,10 +303,6 @@
   // Returns how the last session was shutdown.
   virtual ExitType GetLastSessionExitType() = 0;
 
-  // Returns the SequencedTaskRunner the pref service runs on.
-  virtual scoped_refptr<base::SequencedTaskRunner>
-  GetPrefServiceTaskRunner() = 0;
-
   // Stop sending accessibility events until ResumeAccessibilityEvents().
   // Calls to Pause nest; no events will be sent until the number of
   // Resume calls matches the number of Pause calls received.
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index 76c5ddd..7386031 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -716,9 +716,6 @@
     // Flush the profile data to disk for all loaded profiles.
     profile->SetExitType(Profile::EXIT_CRASHED);
     profile->GetPrefs()->CommitPendingWrite();
-    if (base::FeatureList::IsEnabled(features::kPrefService)) {
-      FlushTaskRunner(profile->GetPrefServiceTaskRunner().get());
-    }
     FlushTaskRunner(profile->GetIOTaskRunner().get());
 
     // Make sure that the prefs file was written with the expected key/value.
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 290c131..61c0fb8 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -62,6 +62,7 @@
 #include "chrome/browser/policy/schema_registry_service_factory.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
+#include "chrome/browser/prefs/in_process_service_factory_factory.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/profiles/bookmark_model_loaded_observer.h"
@@ -126,7 +127,7 @@
 #include "printing/features/features.h"
 #include "services/identity/identity_service.h"
 #include "services/identity/public/interfaces/constants.mojom.h"
-#include "services/preferences/public/cpp/pref_service_main.h"
+#include "services/preferences/public/cpp/in_process_service_factory.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
 #include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
 #include "services/service_manager/public/cpp/service.h"
@@ -420,11 +421,10 @@
   registry->RegisterIntegerPref(prefs::kMediaCacheSize, 0);
 }
 
-ProfileImpl::ProfileImpl(
-    const base::FilePath& path,
-    Delegate* delegate,
-    CreateMode create_mode,
-    base::SequencedTaskRunner* sequenced_task_runner)
+ProfileImpl::ProfileImpl(const base::FilePath& path,
+                         Delegate* delegate,
+                         CreateMode create_mode,
+                         base::SequencedTaskRunner* sequenced_task_runner)
     : path_(path),
       pref_registry_(new user_prefs::PrefRegistrySyncable),
       io_data_(this),
@@ -529,15 +529,15 @@
   content::BrowserContext::Initialize(this, path_);
 
   {
-    service_manager::Connector* connector = nullptr;
-    if (features::PrefServiceEnabled()) {
-      connector = content::BrowserContext::GetConnectorFor(this);
-    }
+    auto delegate =
+        InProcessPrefServiceFactoryFactory::GetInstanceForContext(this)
+            ->CreateDelegate();
+    delegate->InitPrefRegistry(pref_registry_.get());
     prefs_ = chrome_prefs::CreateProfilePrefs(
         path_, std::move(pref_validation_delegate),
         profile_policy_connector_->policy_service(), supervised_user_settings,
         CreateExtensionPrefStore(this, false), pref_registry_, async_prefs,
-        connector);
+        GetIOTaskRunner(), std::move(delegate));
     // Register on BrowserContext.
     user_prefs::UserPrefs::Set(this, prefs_.get());
   }
@@ -988,11 +988,6 @@
   return last_session_exit_type_;
 }
 
-scoped_refptr<base::SequencedTaskRunner>
-ProfileImpl::GetPrefServiceTaskRunner() {
-  return pref_service_task_runner_;
-}
-
 PrefService* ProfileImpl::GetPrefs() {
   return const_cast<PrefService*>(
       static_cast<const ProfileImpl*>(this)->GetPrefs());
@@ -1028,8 +1023,7 @@
 PrefService* ProfileImpl::GetReadOnlyOffTheRecordPrefs() {
   if (!dummy_otr_prefs_) {
     dummy_otr_prefs_.reset(CreateIncognitoPrefServiceSyncable(
-        prefs_.get(), CreateExtensionPrefStore(this, true),
-        std::set<PrefValueStore::PrefStoreType>(), nullptr, nullptr));
+        prefs_.get(), CreateExtensionPrefStore(this, true), nullptr));
   }
   return dummy_otr_prefs_.get();
 }
@@ -1135,15 +1129,13 @@
 }
 
 void ProfileImpl::RegisterInProcessServices(StaticServiceMap* services) {
-  if (features::PrefServiceEnabled()) {
+  {
     service_manager::EmbeddedServiceInfo info;
-    info.factory = base::Bind(
-        &prefs::CreatePrefService, chrome::ExpectedPrefStores(),
-        make_scoped_refptr(content::BrowserThread::GetBlockingPool()));
-    info.task_runner = base::CreateSequencedTaskRunnerWithTraits(
-        {base::TaskShutdownBehavior::BLOCK_SHUTDOWN,
-         base::TaskPriority::USER_VISIBLE});
-    pref_service_task_runner_ = info.task_runner;
+    info.factory =
+        InProcessPrefServiceFactoryFactory::GetInstanceForContext(this)
+            ->CreatePrefServiceFactory();
+    info.task_runner = content::BrowserThread::GetTaskRunnerForThread(
+        content::BrowserThread::UI);
     services->insert(std::make_pair(prefs::mojom::kServiceName, info));
   }
 
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 68132ca..0b5e691 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -145,7 +145,6 @@
   bool WasCreatedByVersionOrLater(const std::string& version) override;
   void SetExitType(ExitType exit_type) override;
   ExitType GetLastSessionExitType() override;
-  scoped_refptr<base::SequencedTaskRunner> GetPrefServiceTaskRunner() override;
 
 #if defined(OS_CHROMEOS)
   void ChangeAppLocale(const std::string& locale, AppLocaleChangedVia) override;
@@ -234,7 +233,6 @@
   // first.
   scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry_;
   std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs_;
-  scoped_refptr<base::SequencedTaskRunner> pref_service_task_runner_;
   // See comment in GetOffTheRecordPrefs. Field exists so something owns the
   // dummy.
   std::unique_ptr<sync_preferences::PrefServiceSyncable> dummy_otr_prefs_;
diff --git a/chrome/browser/resources/md_extensions/load_error.html b/chrome/browser/resources/md_extensions/load_error.html
index c2fd7d1..0f4c095 100644
--- a/chrome/browser/resources/md_extensions/load_error.html
+++ b/chrome/browser/resources/md_extensions/load_error.html
@@ -1,54 +1,21 @@
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
 <link rel="import" href="chrome://extensions/code_section.html">
 
 <dom-module id="extensions-load-error">
   <template>
-    <style>
-      dialog {
-        @apply(--shadow-elevation-2dp);
-        border: none;
-        border-radius: 2px;
-        padding: 0;
-        width: 512px;
-      }
-
-      header {
-        -webkit-padding-end: 20px;
-        -webkit-padding-start: 24px;
-        align-items: center;
-        border-bottom: 1px solid var(--paper-grey-200);
-        color: #333;
-        display: flex;
-        font-size: 16px;
-        justify-content: space-between;
-        padding-bottom: 16px;
-        padding-top: 16px;
-      }
-
-      #close-button {
-        height: 20px;
-        padding: 0;
-        width: 20px;
-      }
-
-      #main {
-        -webkit-margin-end: 16px;
-        -webkit-margin-start: 24px;
+    <style include="cr-shared-style">
+      .body {
+        /* TODO(scottchen): make a shared font-size/line-height css file. */
         font-size: 13px;
         line-height: 20px;
-        max-width: 800px;
-        padding-bottom: 16px;
-        padding-top: 20px;
       }
 
       .description-row {
-        color: #333;
         display: flex;
       }
 
@@ -67,30 +34,10 @@
         padding: 8px 12px;
         text-transform: uppercase;
       }
-
-      #buttons-container {
-        display: flex;
-        justify-content: flex-end;
-        padding: 20px;
-      }
-
-      #dismiss {
-        color: #5a5a5a;
-      }
-
-      #retry {
-        -webkit-margin-start: 12px;
-        background-color: var(--google-blue-500);
-        color: white;
-      }
     </style>
-    <dialog>
-      <header>
-        <span>$i18n{loadErrorHeading}</span>
-        <paper-icon-button id="close-button" icon="close" on-tap="close">
-        </paper-icon-button>
-      </header>
-      <div id="main">
+    <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
+      <div class="title">$i18n{loadErrorHeading}</div>
+      <div class="body">
         <div id="info">
           <div id="file" class="description-row">
             <span class="row-label">$i18n{loadErrorFileLabel}</span>
@@ -105,11 +52,11 @@
             could-not-display-code="$i18n{loadErrorCouldNotLoadManifest}">
         </extensions-code-section>
       </div>
-      <div id="buttons-container">
-        <paper-button id="dismiss" on-tap="close">
+      <div class="button-container">
+        <paper-button class="cancel-button" on-tap="close">
           $i18n{loadErrorCancel}
         </paper-button>
-        <paper-button id="retry" on-tap="onRetryTap_">
+        <paper-button class="action-button" on-tap="onRetryTap_">
           $i18n{loadErrorRetry}
         </paper-button>
       </div>
diff --git a/chrome/browser/resources/md_extensions/options_dialog.html b/chrome/browser/resources/md_extensions/options_dialog.html
index 92c24119..a01b3e7 100644
--- a/chrome/browser/resources/md_extensions/options_dialog.html
+++ b/chrome/browser/resources/md_extensions/options_dialog.html
@@ -1,25 +1,11 @@
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
 
 <dom-module id="extensions-options-dialog">
   <template>
     <style>
-      dialog {
-        @apply(--shadow-elevation-2dp);
-        border: none;
-        border-radius: 2px;
-        padding: 0;
-      }
-      header {
-        align-items: center;
-        border-bottom: 1px solid var(--paper-grey-200);
-        color: var(--paper-grey-800);
-        display: flex;
-        justify-content: space-between;
-        padding: 12px 20px;
-      }
       #icon {
         -webkit-margin-end: 10px;
         height: 32px;
@@ -29,22 +15,26 @@
         align-items: center;
         display: flex;
       }
+
       extensionoptions {
-        display: inline-block;
-        height: 100%;
+        display: block;
+      }
+
+      dialog {
+        /* Initially as wide as possible. This will be adjusted by js-code. */
         width: 100%;
       }
     </style>
-    <dialog>
-      <header>
+
+    <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
+      <div class="title">
         <div id="icon-and-name-wrapper">
           <img id="icon" src="[[data_.iconUrl]]"></img>
           <span>[[data_.name]]</span>
         </div>
-        <paper-icon-button id="close-button" icon="close" on-tap="close">
-        </paper-icon-button>
-      </header>
-      <div id="main"></div>
+      </div>
+      <div class="body" id="body">
+      </div>
     </dialog>
   </template>
   <script src="chrome://extensions/options_dialog.js"></script>
diff --git a/chrome/browser/resources/md_extensions/options_dialog.js b/chrome/browser/resources/md_extensions/options_dialog.js
index 61ccfdf..261f007 100644
--- a/chrome/browser/resources/md_extensions/options_dialog.js
+++ b/chrome/browser/resources/md_extensions/options_dialog.js
@@ -9,7 +9,8 @@
   var MAX_WIDTH = 600;
   var MIN_HEIGHT = 300;
   var MIN_WIDTH = 300;
-  var HEADER_PADDING = 40;
+  var HEADER_EXTRA_SPACING = 50;  // 40 from x-button + 10 from img margin.
+  var DIALOG_PADDING = 32;        // Padding from cr-dialog's .body styling.
 
   var OptionsDialog = Polymer({
     is: 'extensions-options-dialog',
@@ -37,16 +38,20 @@
       };
 
       var onSizeChanged = function(e) {
-        var minHeaderWidth = this.$['icon-and-name-wrapper'].offsetWidth +
-            this.$['close-button'].offsetWidth + HEADER_PADDING;
+        var minHeaderWidth = this.$$('#icon-and-name-wrapper img').offsetWidth +
+            this.$$('#icon-and-name-wrapper span').offsetWidth +
+            HEADER_EXTRA_SPACING;
         var minWidth = Math.max(minHeaderWidth, MIN_WIDTH);
-        this.$.main.style.height =
+        this.extensionOptions_.style.height =
             bounded(MIN_HEIGHT, MAX_HEIGHT, e.height) + 'px';
-        this.$.main.style.width = bounded(minWidth, MAX_WIDTH, e.width) + 'px';
+        this.extensionOptions_.style.width =
+            bounded(minWidth, MAX_WIDTH, e.width) + 'px';
+        this.$.dialog.style.width =
+            (bounded(minWidth, MAX_WIDTH, e.width) + DIALOG_PADDING) + 'px';
       }.bind(this);
 
       this.extensionOptions_.onpreferredsizechanged = onSizeChanged;
-      this.$.main.appendChild(this.extensionOptions_);
+      this.$.body.appendChild(this.extensionOptions_);
       this.$$('dialog').showModal();
       onSizeChanged({height: 0, width: 0});
     },
diff --git a/chrome/browser/resources/md_extensions/pack_dialog.html b/chrome/browser/resources/md_extensions/pack_dialog.html
index 218057e7..b315a819 100644
--- a/chrome/browser/resources/md_extensions/pack_dialog.html
+++ b/chrome/browser/resources/md_extensions/pack_dialog.html
@@ -1,55 +1,14 @@
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
 
 <dom-module id="extensions-pack-dialog">
   <template>
-    <style>
-      dialog {
-        @apply(--shadow-elevation-2dp);
-        border: none;
-        border-radius: 2px;
-        padding: 0;
-        width: 512px;
-      }
-
-      header {
-        -webkit-padding-end: 20px;
-        -webkit-padding-start: 24px;
-        align-items: center;
-        border-bottom: 1px solid var(--paper-grey-200);
-        color: #333;
-        display: flex;
-        font-size: 16px;
-        justify-content: space-between;
-        padding-bottom: 16px;
-        padding-top: 16px;
-      }
-
-      #close-button {
-        height: 20px;
-        padding: 0;
-        width: 20px;
-      }
-
-      #main {
-        -webkit-margin-end: 16px;
-        -webkit-margin-start: 24px;
-        font-size: 13px;
-        max-width: 800px;
-        padding-bottom: 16px;
-        padding-top: 20px;
-      }
-
-      #description {
-        color: #333;
-      }
-
+    <style include="cr-shared-style">
       paper-button {
         align-items: center;
         border-radius: 2px;
@@ -61,6 +20,12 @@
         text-transform: uppercase;
       }
 
+      .body {
+        /* TODO(scottchen): make a shared font-size/line-height css file. */
+        font-size: 13px;
+        line-height: 20px;
+      }
+
       .file-input {
         display: flex;
         --paper-input-container-input: {
@@ -76,31 +41,12 @@
         -webkit-margin-start: 10px;
         color: var(--google-blue-500);
       }
-
-      #buttons-container {
-        display: flex;
-        justify-content: flex-end;
-        padding: 20px;
-      }
-
-      #dismiss {
-        color: #5a5a5a;
-      }
-
-      #confirm {
-        -webkit-margin-start: 12px;
-        background-color: var(--google-blue-500);
-        color: white;
-      }
     </style>
-    <dialog>
-      <header>
-        <span>$i18n{packDialogTitle}</span>
-        <paper-icon-button id="close-button" icon="close" on-tap="close">
-        </paper-icon-button>
-      </header>
-      <div id="main">
-        <div id="description">$i18n{packDialogContent}</div>
+
+    <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
+      <div class="title">$i18n{packDialogTitle}</div>
+      <div class="body">
+        <div>$i18n{packDialogContent}</div>
         <div class="file-input">
           <paper-input id="root-dir" label="$i18n{packDialogExtensionRoot}"
               always-float-label value="[[packDirectory_]]">
@@ -118,11 +64,11 @@
           </paper-button>
         </div>
       </div>
-      <div id="buttons-container">
-        <paper-button id="dismiss" on-tap="close">
+      <div class="button-container">
+        <paper-button class="cancel-button" on-tap="close">
           $i18n{packDialogCancel}
         </paper-button>
-        <paper-button id="confirm" on-tap="onConfirmTap_">
+        <paper-button class="action-button" on-tap="onConfirmTap_">
           $i18n{packDialogConfirm}
         </paper-button>
       </div>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index fcff6d2c..26f5b266 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -19,6 +19,7 @@
 <link rel="import" href="../bluetooth_page/bluetooth_page.html">
 <link rel="import" href="../device_page/device_page.html">
 <link rel="import" href="../internet_page/internet_page.html">
+<link rel="import" href="../multidevice_page/multidevice_page.html">
 </if>
 
 <if expr="not chromeos">
@@ -263,6 +264,17 @@
               </settings-printing-page>
             </settings-section>
           </template>
+<if expr="chromeos">
+          <template is="dom-if"
+              if="[[shouldShowMultidevice_(showMultidevice, pageVisibility)]]"
+              restamp>
+            <settings-section page-title="$i18n{multidevicePageTitle}"
+                section="multidevice">
+              <settings-multidevice-page prefs="{{prefs}}">
+              </settings-multidevice-page>
+            </settings-section>
+          </template>
+</if>
           <template is="dom-if" if="[[showPage_(pageVisibility.a11y)]]" restamp>
             <settings-section page-title="$i18n{a11yPageTitle}" section="a11y">
               <settings-a11y-page prefs="{{prefs}}"></settings-a11y-page>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js
index 1f386cc..d2c1e421 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -18,9 +18,13 @@
       notify: true,
     },
 
+    // <if expr="chromeos">
     showAndroidApps: Boolean,
 
+    showMultidevice: Boolean,
+
     havePlayStoreApp: Boolean,
+    // </if>
 
     /** @type {!AndroidAppsInfo|undefined} */
     androidAppsInfo: Object,
@@ -220,6 +224,16 @@
   },
 
   /**
+   * @return {boolean} Whether to show the multidevice settings page.
+   * @private
+   */
+  shouldShowMultidevice_: function() {
+    var visibility = /** @type {boolean|undefined} */ (
+        this.get('pageVisibility.multidevice'));
+    return this.showMultidevice && this.showPage_(visibility);
+  },
+
+  /**
    * Hides everything but the newly expanded subpage.
    * @private
    */
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html
index 79bf12d..117ddbb 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html
@@ -34,7 +34,7 @@
       <div hidden$="[[!device.paired]]">
         <button is="paper-icon-button-light" class="icon-more-vert"
             on-tap="onMenuButtonTap_" tabindex$="[[tabindex]]"
-            title="$i18n{moreActions}">
+            title="$i18n{moreActions}" on-keydown="ignoreEnterKey_">
         </button>
         <dialog id="dotsMenu" is="cr-action-menu">
           <button class="dropdown-item" role="option"
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js
index 4c17eaf..e8fb8c4 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js
@@ -25,6 +25,16 @@
    * @param {!Event} event
    * @private
    */
+  ignoreEnterKey_: function(event) {
+    if (event.key == 'Enter') {
+      event.stopPropagation();
+    }
+  },
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
   onMenuButtonTap_: function(event) {
     var button = /** @type {!HTMLElement} */ (event.target);
     var menu = /** @type {!CrActionMenuElement} */ (this.$.dotsMenu);
diff --git a/chrome/browser/resources/settings/multidevice_page/compiled_resources2.gyp b/chrome/browser/resources/settings/multidevice_page/compiled_resources2.gyp
new file mode 100644
index 0000000..72df331
--- /dev/null
+++ b/chrome/browser/resources/settings/multidevice_page/compiled_resources2.gyp
@@ -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.
+{
+  'targets': [
+    {
+      'target_name': 'multidevice_page',
+      'dependencies': [],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+  ],
+}
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_page.html b/chrome/browser/resources/settings/multidevice_page/multidevice_page.html
new file mode 100644
index 0000000..fc03d5e
--- /dev/null
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_page.html
@@ -0,0 +1,21 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
+<link rel="import" href="../prefs/prefs.html">
+<link rel="import" href="../settings_shared_css.html">
+
+<dom-module id="settings-multidevice-page">
+  <template>
+    <style include="settings-shared"></style>
+    <div class="settings-box two-line">
+      <div id="smsConnectToggleLabel" class="start">
+        $i18n{smsConnect}
+        <div class="secondary">$i18n{smsConnectSummary}</div>
+      </div>
+      <paper-toggle-button checked="{{smsConnectToggleState_}}"
+          aria-labelledby="smsConnectToggleLabel">
+      </paper-toggle-button>
+    </div>
+  </template>
+  <script src="multidevice_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_page.js b/chrome/browser/resources/settings/multidevice_page/multidevice_page.js
new file mode 100644
index 0000000..e402512
--- /dev/null
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_page.js
@@ -0,0 +1,37 @@
+// 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.
+
+/**
+ * @fileoverview
+ * Settings page for managing multidevice features.
+ */
+
+Polymer({
+  is: 'settings-multidevice-page',
+
+  properties: {
+    /** Preferences state. */
+    prefs: {
+      type: Object,
+      notify: true,
+    },
+
+    /**
+     * Reflects the current state of the toggle buttons (in this page and the
+     * subpage). This will be set when the user changes the toggle.
+     * @private
+     */
+    smsConnectToggleState_: {
+      type: Boolean,
+      observer: 'smsConnectToggleStateChanged_',
+    },
+  },
+
+  /** @private */
+  smsConnectToggleStateChanged_: function() {
+    // TODO(orenb): Switch from paper-toggle-button to settings-toggle-button,
+    // which will manage the underlying pref state, once the new pref has been
+    // implemented. Propagate here the pref value to the SMS connect component.
+  },
+});
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
index e9ab6e80..289ed08 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
+++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
@@ -63,6 +63,10 @@
   /** @override */
   attached: function() {
     this.getNtpExtension_();
+    this.addWebUIListener('update-ntp-extension', function(ntpExtension) {
+      // Note that |ntpExtension| is empty if there is no NTP extension.
+      this.ntpExtension_ = ntpExtension;
+    }.bind(this));
 
     this.browserProxy_ = settings.StartupUrlsPageBrowserProxyImpl.getInstance();
     this.addWebUIListener('update-startup-pages', function(startupPages) {
diff --git a/chrome/browser/resources/settings/page_visibility.js b/chrome/browser/resources/settings/page_visibility.js
index 68fb662..80d9b201 100644
--- a/chrome/browser/resources/settings/page_visibility.js
+++ b/chrome/browser/resources/settings/page_visibility.js
@@ -10,6 +10,7 @@
  *   dateTime: (boolean|undefined|DateTimePageVisibility),
  *   defaultBrowser: (boolean|undefined),
  *   downloads: (boolean|undefined|DownloadsPageVisibility),
+ *   multidevice: (boolean|undefined),
  *   onStartup: (boolean|undefined),
  *   passwordsAndForms: (boolean|undefined),
  *   people: (boolean|undefined),
@@ -96,6 +97,7 @@
       downloads: {
         googleDrive: false,
       },
+      multidevice: false,
     };
     // </if>
   }
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 02add787..a719b0c2 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -44,6 +44,7 @@
  *   MANAGE_ACCESSIBILITY: (undefined|!settings.Route),
  *   MANAGE_PASSWORDS: (undefined|!settings.Route),
  *   MANAGE_PROFILE: (undefined|!settings.Route),
+ *   MULTIDEVICE: (undefined|!settings.Route),
  *   NETWORK_CONFIG: (undefined|!settings.Route),
  *   NETWORK_DETAIL: (undefined|!settings.Route),
  *   ON_STARTUP: (undefined|!settings.Route),
@@ -345,6 +346,8 @@
       r.CUPS_PRINTERS = r.PRINTING.createChild('/cupsPrinters');
       r.CUPS_PRINTER_DETAIL =
           r.CUPS_PRINTERS.createChild('/cupsPrinterDetails');
+
+      r.MULTIDEVICE = r.ADVANCED.createSection('/multidevice', 'multidevice');
       // </if>
 
       r.ACCESSIBILITY = r.ADVANCED.createSection('/accessibility', 'a11y');
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index e05030c..d5321b5 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -45,6 +45,7 @@
       <settings-basic-page prefs="{{prefs}}"
           page-visibility="[[pageVisibility]]"
           show-android-apps="[[showAndroidApps]]"
+          show-multidevice="[[showMultidevice]]"
           have-play-store-app="[[havePlayStoreApp]]"
           on-subpage-expand="onSubpageExpand_"
           in-search-mode="[[inSearchMode_]]"
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js
index 571e8076..d81ee241c 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.js
+++ b/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -78,6 +78,8 @@
 
     showAndroidApps: Boolean,
 
+    showMultidevice: Boolean,
+
     havePlayStoreApp: Boolean,
   },
 
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index 718fe7e..6f387f2 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -163,6 +163,12 @@
             <iron-icon icon="cr:print"></iron-icon>
             $i18n{printingPageTitle}
           </a>
+<if expr="chromeos">
+          <a href="/multidevice" hidden="[[!showMultidevice]]">
+            <iron-icon icon="settings:sync"></iron-icon>
+            $i18n{multidevicePageTitle}
+          </a>
+</if>
           <a href="/accessibility">
             <iron-icon icon="settings:accessibility"></iron-icon>
             $i18n{a11yPageTitle}
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 679c6c7..5a8c40e2 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -1164,6 +1164,12 @@
         <structure name="IDR_SETTINGS_INTERNET_SUBPAGE_JS"
                    file="internet_page/internet_subpage.js"
                    type="chrome_html" />
+        <structure name="IDR_SETTINGS_MULTIDEVICE_PAGE_HTML"
+                   file="multidevice_page/multidevice_page.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_MULTIDEVICE_PAGE_JS"
+                   file="multidevice_page/multidevice_page.js"
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_NETWORK_APNLIST_HTML"
                    file="internet_page/network_apnlist.html"
                    type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index 2163b1e4..b66626bf8 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -95,6 +95,7 @@
         <template is="dom-if" id="drawerTemplate">
           <settings-menu page-visibility="[[pageVisibility_]]"
               show-android-apps="[[showAndroidApps_]]"
+              show-multidevice="[[showMultidevice_]]"
               have-play-store-app="[[havePlayStoreApp_]]"
               on-iron-activate="onIronActivate_"
               advanced-opened="{{advancedOpened_}}">
@@ -110,6 +111,7 @@
           toolbar-spinner-active="{{toolbarSpinnerActive_}}"
           page-visibility="[[pageVisibility_]]"
           show-android-apps="[[showAndroidApps_]]"
+          show-multidevice="[[showMultidevice_]]"
           have-play-store-app="[[havePlayStoreApp_]]"
           advanced-toggle-expanded="{{advancedOpened_}}">
       </settings-main>
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 02e7d3f..351433de 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -57,6 +57,9 @@
     showAndroidApps_: Boolean,
 
     /** @private */
+    showMultidevice_: Boolean,
+
+    /** @private */
     havePlayStoreApp_: Boolean,
 
     /** @private */
@@ -128,6 +131,9 @@
 
     this.showAndroidApps_ = loadTimeData.valueExists('androidAppsVisible') &&
         loadTimeData.getBoolean('androidAppsVisible');
+    this.showMultidevice_ =
+        loadTimeData.valueExists('enableMultideviceSettings') &&
+        loadTimeData.getBoolean('enableMultideviceSettings');
     this.havePlayStoreApp_ = loadTimeData.valueExists('havePlayStoreApp') &&
         loadTimeData.getBoolean('havePlayStoreApp');
 
diff --git a/chrome/browser/ssl/chrome_expect_ct_reporter_browser_tests.cc b/chrome/browser/ssl/chrome_expect_ct_reporter_browser_tests.cc
new file mode 100644
index 0000000..657cd3e1
--- /dev/null
+++ b/chrome/browser/ssl/chrome_expect_ct_reporter_browser_tests.cc
@@ -0,0 +1,132 @@
+// 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/callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ssl/cert_verifier_browser_test.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "net/cert/mock_cert_verifier.h"
+#include "net/http/transport_security_state.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace {
+
+// A test fixture that allows tests to wait for an Expect-CT report to be
+// received by a server.
+class ExpectCTBrowserTest : public CertVerifierBrowserTest {
+ public:
+  ExpectCTBrowserTest() : CertVerifierBrowserTest() {}
+
+  void SetUpOnMainThread() override {
+    run_loop_ = base::MakeUnique<base::RunLoop>();
+  }
+
+  void TearDown() override { run_loop_.reset(nullptr); }
+
+  std::unique_ptr<net::test_server::HttpResponse> ReportRequestHandler(
+      const net::test_server::HttpRequest& request) {
+    EXPECT_TRUE(request.method == net::test_server::METHOD_POST ||
+                request.method == net::test_server::METHOD_OPTIONS)
+        << "Request method must be POST or OPTIONS. It is " << request.method
+        << ".";
+    std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
+        new net::test_server::BasicHttpResponse());
+    http_response->set_code(net::HTTP_OK);
+
+    // Respond properly to CORS preflights.
+    if (request.method == net::test_server::METHOD_OPTIONS) {
+      http_response->AddCustomHeader("Access-Control-Allow-Origin", "*");
+      http_response->AddCustomHeader("Access-Control-Allow-Methods", "POST");
+      http_response->AddCustomHeader("Access-Control-Allow-Headers",
+                                     "content-type");
+    } else if (request.method == net::test_server::METHOD_POST) {
+      auto it = request.headers.find("Content-Type");
+      EXPECT_NE(it, request.headers.end());
+      // The above EXPECT_NE is really an ASSERT_NE in spirit, but can't ASSERT
+      // because a response must be returned.
+      if (it != request.headers.end()) {
+        EXPECT_EQ("application/expect-ct-report+json; charset=utf-8",
+                  it->second);
+      }
+      run_loop_->QuitClosure().Run();
+    }
+
+    return http_response;
+  }
+
+ protected:
+  void WaitForReport() { run_loop_->Run(); }
+
+ private:
+  std::unique_ptr<base::RunLoop> run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExpectCTBrowserTest);
+};
+
+void AddExpectCTHeaderOnIO(net::URLRequestContextGetter* getter,
+                           const std::string& host,
+                           const GURL& report_uri) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  net::URLRequestContext* context = getter->GetURLRequestContext();
+  context->transport_security_state()->AddExpectCT(
+      host, base::Time::Now() + base::TimeDelta::FromSeconds(1000), true,
+      report_uri);
+}
+
+// Tests that an Expect-CT reporter is properly set up and used for violations
+// of Expect-CT HTTP headers.
+IN_PROC_BROWSER_TEST_F(ExpectCTBrowserTest, TestDynamicExpectCTReporting) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {features::kExpectCTReporting,
+       net::TransportSecurityState::kDynamicExpectCTFeature},
+      {});
+
+  net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  ASSERT_TRUE(test_server.Start());
+
+  net::EmbeddedTestServer report_server;
+  report_server.RegisterRequestHandler(base::Bind(
+      &ExpectCTBrowserTest::ReportRequestHandler, base::Unretained(this)));
+  ASSERT_TRUE(report_server.Start());
+
+  // Set up the mock cert verifier to accept |test_server|'s certificate as
+  // valid and as if it is issued by a known root. (CT checks are skipped for
+  // private roots.)
+  scoped_refptr<net::X509Certificate> cert(test_server.GetCertificate());
+  net::CertVerifyResult verify_result;
+  verify_result.is_issued_by_known_root = true;
+  verify_result.verified_cert = cert;
+  verify_result.cert_status = 0;
+  mock_cert_verifier()->AddResultForCert(cert, verify_result, net::OK);
+
+  // Fire off a task to simulate as if a previous request to |test_server| had
+  // set a valid Expect-CT header.
+  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
+      browser()->profile()->GetRequestContext();
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO, FROM_HERE,
+      base::BindOnce(
+          &AddExpectCTHeaderOnIO, base::RetainedRef(url_request_context_getter),
+          test_server.GetURL("/").host(), report_server.GetURL("/")));
+
+  // Navigate to a test server URL, which should trigger an Expect-CT report
+  // because the test server doesn't serve SCTs.
+  ui_test_utils::NavigateToURL(browser(), test_server.GetURL("/"));
+  WaitForReport();
+  // WaitForReport() does not return util ReportRequestHandler runs, and the
+  // handler does all the assertions, so there are no more assertions needed
+  // here.
+}
+
+}  // namespace
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc
index fa96355..205cc01 100644
--- a/chrome/browser/translate/chrome_translate_client.cc
+++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/user_event_service_factory.h"
-#include "chrome/browser/translate/language_model_factory.h"
 #include "chrome/browser/translate/translate_accept_languages_factory.h"
 #include "chrome/browser/translate/translate_ranker_factory.h"
 #include "chrome/browser/translate/translate_service.h"
@@ -35,7 +34,6 @@
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/protocol/user_event_specifics.pb.h"
 #include "components/sync/user_events/user_event_service.h"
-#include "components/translate/core/browser/language_model.h"
 #include "components/translate/core/browser/language_state.h"
 #include "components/translate/core/browser/page_translated_details.h"
 #include "components/translate/core/browser/translate_accept_languages.h"
@@ -121,8 +119,9 @@
           translate::TranslateRankerFactory::GetForBrowserContext(
               web_contents->GetBrowserContext()),
           prefs::kAcceptLanguages)),
-      language_model_(LanguageModelFactory::GetInstance()->GetForBrowserContext(
-          web_contents->GetBrowserContext())) {
+      language_histogram_(
+          UrlLanguageHistogramFactory::GetInstance()->GetForBrowserContext(
+              web_contents->GetBrowserContext())) {
   translate_driver_.AddObserver(this);
   translate_driver_.set_translate_manager(translate_manager_.get());
 }
@@ -391,8 +390,8 @@
   RecordLanguageDetectionEvent(details);
   // Unless we have no language model (e.g., in incognito), notify the model
   // about detected language of every page visited.
-  if (language_model_ && details.is_cld_reliable)
-    language_model_->OnPageVisited(details.cld_language);
+  if (language_histogram_ && details.is_cld_reliable)
+    language_histogram_->OnPageVisited(details.cld_language);
 }
 
 void ChromeTranslateClient::OnPageTranslated(
diff --git a/chrome/browser/translate/chrome_translate_client.h b/chrome/browser/translate/chrome_translate_client.h
index 33e890e..fc1b070 100644
--- a/chrome/browser/translate/chrome_translate_client.h
+++ b/chrome/browser/translate/chrome_translate_client.h
@@ -9,7 +9,9 @@
 #include <string>
 
 #include "base/macros.h"
+#include "chrome/browser/language/url_language_histogram_factory.h"
 #include "chrome/browser/ui/translate/translate_bubble_model.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/translate/content/browser/content_translate_driver.h"
 #include "components/translate/core/browser/translate_client.h"
 #include "components/translate/core/browser/translate_step.h"
@@ -25,8 +27,11 @@
 
 class PrefService;
 
+namespace language {
+class UrlLanguageHistogram;
+}  // namespace language
+
 namespace translate {
-class LanguageModel;
 class LanguageState;
 class TranslateAcceptLanguages;
 class TranslatePrefs;
@@ -137,9 +142,9 @@
   translate::ContentTranslateDriver translate_driver_;
   std::unique_ptr<translate::TranslateManager> translate_manager_;
 
-  // Model to be notified about detected language of every page visited. Not
+  // Histogram to be notified about detected language of every page visited. Not
   // owned here.
-  translate::LanguageModel* language_model_;
+  language::UrlLanguageHistogram* language_histogram_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeTranslateClient);
 };
diff --git a/chrome/browser/translate/language_model_factory.cc b/chrome/browser/translate/language_model_factory.cc
deleted file mode 100644
index 0c552cd..0000000
--- a/chrome/browser/translate/language_model_factory.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/translate/language_model_factory.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/translate/core/browser/language_model.h"
-
-// static
-LanguageModelFactory*
-LanguageModelFactory::GetInstance() {
-  return base::Singleton<LanguageModelFactory>::get();
-}
-
-// static
-translate::LanguageModel* LanguageModelFactory::GetForBrowserContext(
-    content::BrowserContext* browser_context) {
-  return static_cast<translate::LanguageModel*>(
-      GetInstance()->GetServiceForBrowserContext(browser_context, true));
-}
-
-LanguageModelFactory::LanguageModelFactory()
-    : BrowserContextKeyedServiceFactory(
-          "LanguageModel",
-          BrowserContextDependencyManager::GetInstance()) {}
-
-LanguageModelFactory::~LanguageModelFactory() {}
-
-KeyedService* LanguageModelFactory::BuildServiceInstanceFor(
-    content::BrowserContext* browser_context) const {
-  Profile* profile = Profile::FromBrowserContext(browser_context);
-  return new translate::LanguageModel(profile->GetPrefs());
-}
diff --git a/chrome/browser/translate/language_model_factory.h b/chrome/browser/translate/language_model_factory.h
deleted file mode 100644
index 1d68535..0000000
--- a/chrome/browser/translate/language_model_factory.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_TRANSLATE_LANGUAGE_MODEL_FACTORY_H_
-#define CHROME_BROWSER_TRANSLATE_LANGUAGE_MODEL_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-namespace translate {
-class LanguageModel;
-}
-
-class LanguageModelFactory
-    : public BrowserContextKeyedServiceFactory {
- public:
-  static LanguageModelFactory* GetInstance();
-  static translate::LanguageModel* GetForBrowserContext(
-      content::BrowserContext* browser_context);
-
- private:
-  friend struct base::DefaultSingletonTraits<LanguageModelFactory>;
-
-  LanguageModelFactory();
-  ~LanguageModelFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(LanguageModelFactory);
-};
-
-#endif  // CHROME_BROWSER_TRANSLATE_LANGUAGE_MODEL_FACTORY_H_
diff --git a/chrome/browser/translate/language_model_factory_unittest.cc b/chrome/browser/translate/language_model_factory_unittest.cc
deleted file mode 100644
index 46f1ca9..0000000
--- a/chrome/browser/translate/language_model_factory_unittest.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/translate/language_model_factory.h"
-
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using testing::IsNull;
-using testing::Not;
-
-TEST(LanguageModelFactoryTest, NotCreatedInIncognito) {
-  content::TestBrowserThreadBundle thread_bundle;
-  TestingProfile profile;
-
-  EXPECT_THAT(LanguageModelFactory::GetForBrowserContext(&profile),
-              Not(IsNull()));
-
-  Profile* incognito = profile.GetOffTheRecordProfile();
-  ASSERT_THAT(incognito, Not(IsNull()));
-  EXPECT_THAT(LanguageModelFactory::GetForBrowserContext(incognito), IsNull());
-}
diff --git a/chrome/browser/ui/app_list/test/fake_profile.cc b/chrome/browser/ui/app_list/test/fake_profile.cc
index 11edacb..81b94ef 100644
--- a/chrome/browser/ui/app_list/test/fake_profile.cc
+++ b/chrome/browser/ui/app_list/test/fake_profile.cc
@@ -210,9 +210,3 @@
 Profile::ExitType FakeProfile::GetLastSessionExitType() {
   return EXIT_NORMAL;
 }
-
-scoped_refptr<base::SequencedTaskRunner>
-FakeProfile::GetPrefServiceTaskRunner() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
diff --git a/chrome/browser/ui/app_list/test/fake_profile.h b/chrome/browser/ui/app_list/test/fake_profile.h
index ec3c26f..34a885a 100644
--- a/chrome/browser/ui/app_list/test/fake_profile.h
+++ b/chrome/browser/ui/app_list/test/fake_profile.h
@@ -94,7 +94,6 @@
   bool WasCreatedByVersionOrLater(const std::string& version) override;
   void SetExitType(ExitType exit_type) override;
   ExitType GetLastSessionExitType() override;
-  scoped_refptr<base::SequencedTaskRunner> GetPrefServiceTaskRunner() override;
 
  private:
   std::string name_;
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
index 6bb5288a..c01b2f4a 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
@@ -207,11 +207,12 @@
   ExpectBodyContains({"Cannot abort"});
 }
 
-class PaymentRequestBasicCardTest : public PaymentRequestBrowserTestBase {
+class PaymentRequestPaymentMethodIdentifierTest
+    : public PaymentRequestBrowserTestBase {
  protected:
-  PaymentRequestBasicCardTest()
-      : PaymentRequestBrowserTestBase("/payment_request_basic_card_test.html") {
-  }
+  PaymentRequestPaymentMethodIdentifierTest()
+      : PaymentRequestBrowserTestBase(
+            "/payment_request_payment_method_identifier_test.html") {}
 
   void InvokePaymentRequestWithJs(const std::string& js) {
     ResetEventObserver(DialogEvent::DIALOG_OPENED);
@@ -222,11 +223,11 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(PaymentRequestBasicCardTest);
+  DISALLOW_COPY_AND_ASSIGN(PaymentRequestPaymentMethodIdentifierTest);
 };
 
 // One network is specified in 'basic-card' data, one in supportedMethods.
-IN_PROC_BROWSER_TEST_F(PaymentRequestBasicCardTest,
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentMethodIdentifierTest,
                        BasicCard_NetworksSpecified) {
   InvokePaymentRequestWithJs("buy();");
 
@@ -244,7 +245,7 @@
 
 // Only specifying 'basic-card' with no supportedNetworks means all networks are
 // supported.
-IN_PROC_BROWSER_TEST_F(PaymentRequestBasicCardTest,
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentMethodIdentifierTest,
                        BasicCard_NoNetworksSpecified) {
   InvokePaymentRequestWithJs("buyBasicCard();");
 
@@ -267,7 +268,7 @@
 
 // Specifying 'basic-card' after having explicitely included a network yields
 // the expected order when in different supportedMethods lists.
-IN_PROC_BROWSER_TEST_F(PaymentRequestBasicCardTest,
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentMethodIdentifierTest,
                        BasicCard_NetworkThenBasicCard_DifferentList) {
   InvokePaymentRequestWithJs(
       "buyHelper([{"
@@ -296,7 +297,7 @@
 
 // Specifying 'basic-card' after having explicitely included a network yields
 // the expected order when in the same supportedMethods list.
-IN_PROC_BROWSER_TEST_F(PaymentRequestBasicCardTest,
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentMethodIdentifierTest,
                        BasicCard_NetworkThenBasicCard_SameList) {
   InvokePaymentRequestWithJs(
       "buyHelper([{"
@@ -323,7 +324,7 @@
 
 // Specifying 'basic-card' with some networks after having explicitely included
 // the same networks does not yield duplicates and has the expected order.
-IN_PROC_BROWSER_TEST_F(PaymentRequestBasicCardTest,
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentMethodIdentifierTest,
                        BasicCard_NetworkThenBasicCardWithSameNetwork) {
   InvokePaymentRequestWithJs(
       "buyHelper([{"
@@ -346,6 +347,59 @@
   EXPECT_EQ("jcb", supported_card_networks[2]);
 }
 
+// A url-based payment method identifier is only supported if it has an https
+// scheme.
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentMethodIdentifierTest, Url_Valid) {
+  InvokePaymentRequestWithJs(
+      "buyHelper([{"
+      "  supportedMethods: ['https://bobpay.xyz', 'http://bobpay.xyz']"
+      "}, {"
+      "  supportedMethods: ['basic-card']"
+      "}]);");
+
+  std::vector<PaymentRequest*> requests =
+      GetPaymentRequests(GetActiveWebContents());
+  EXPECT_EQ(1u, requests.size());
+  std::vector<std::string> url_payment_method_identifiers =
+      requests[0]->spec()->url_payment_method_identifiers();
+  EXPECT_EQ(1u, url_payment_method_identifiers.size());
+  EXPECT_EQ("https://bobpay.xyz", url_payment_method_identifiers[0]);
+}
+
+// Specifiying multiple different types of payment method identifiers still
+// yields the correct supported methods in payment request.
+IN_PROC_BROWSER_TEST_F(PaymentRequestPaymentMethodIdentifierTest,
+                       MultiplePaymentMethodIdentifiers) {
+  InvokePaymentRequestWithJs(
+      "buyHelper([{"
+      "  supportedMethods: ['https://bobpay.xyz']"
+      "}, {"
+      "  supportedMethods: ['mastercard', 'visa', 'https://alicepay.com']"
+      "}, {"
+      "  supportedMethods: ['basic-card'],"
+      "  data: {"
+      "    supportedNetworks: ['visa', 'mastercard', 'jcb'],"
+      "  }"
+      "}]);");
+
+  std::vector<PaymentRequest*> requests =
+      GetPaymentRequests(GetActiveWebContents());
+  EXPECT_EQ(1u, requests.size());
+
+  std::vector<std::string> supported_card_networks =
+      requests[0]->spec()->supported_card_networks();
+  EXPECT_EQ(3u, supported_card_networks.size());
+  EXPECT_EQ("mastercard", supported_card_networks[0]);
+  EXPECT_EQ("visa", supported_card_networks[1]);
+  EXPECT_EQ("jcb", supported_card_networks[2]);
+
+  std::vector<std::string> url_payment_method_identifiers =
+      requests[0]->spec()->url_payment_method_identifiers();
+  EXPECT_EQ(2u, url_payment_method_identifiers.size());
+  EXPECT_EQ("https://bobpay.xyz", url_payment_method_identifiers[0]);
+  EXPECT_EQ("https://alicepay.com", url_payment_method_identifiers[1]);
+}
+
 // Test harness integrating with DialogBrowserTest to present the dialog in an
 // interactive manner for visual testing.
 class PaymentsRequestVisualTest
diff --git a/chrome/browser/ui/views/payments/payment_request_can_make_payment_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_can_make_payment_browsertest.cc
index 7575799..75f14ec 100644
--- a/chrome/browser/ui/views/payments/payment_request_can_make_payment_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_can_make_payment_browsertest.cc
@@ -143,12 +143,12 @@
   ExpectBodyContains({"NotAllowedError"});
 }
 
-class PaymentRequestCanMakePaymentQueryBasicCardTest
+class PaymentRequestCanMakePaymentQueryPMITest
     : public PaymentRequestBrowserTestBase {
  protected:
-  PaymentRequestCanMakePaymentQueryBasicCardTest()
-      : PaymentRequestBrowserTestBase("/payment_request_basic_card_test.html") {
-  }
+  PaymentRequestCanMakePaymentQueryPMITest()
+      : PaymentRequestBrowserTestBase(
+            "/payment_request_payment_method_identifier_test.html") {}
 
   void CallCanMakePayment(bool visa) {
     ResetEventObserver(DialogEvent::CAN_MAKE_PAYMENT_CALLED);
@@ -159,11 +159,10 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(PaymentRequestCanMakePaymentQueryBasicCardTest);
+  DISALLOW_COPY_AND_ASSIGN(PaymentRequestCanMakePaymentQueryPMITest);
 };
 
-IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryBasicCardTest,
-                       QueryQuota) {
+IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryPMITest, QueryQuota) {
   // Query "basic-card" payment method with "supportedNetworks": ["visa"] in the
   // payment method specific data.
   CallCanMakePayment(/*visa=*/true);
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 54746781..f7a3ab68 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -352,12 +352,15 @@
     params.SetString("gaiaPath", eafe_path);
   }
 
+  // Easy bootstrap is not v2-compatible
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kCrosGaiaApiV1)) {
+          switches::kCrosGaiaApiV1) ||
+      use_easy_bootstrap_) {
     params.SetString("chromeOSApiVersion", "1");
-  } else if (use_easy_bootstrap_) {
-    // Easy bootstrap is not v2-compatible
-    params.SetString("chromeOSApiVersion", "1");
+  } else {
+    // This enables GLIF MM UI for the online Gaia screen by default.
+    // (see https://crbug.com/709244 ).
+    params.SetString("chromeOSApiVersion", "2");
   }
 
   frame_state_ = FRAME_STATE_LOADING;
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 7cefb0f..f6b72930 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -24,6 +24,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/google/core/browser/google_util.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -106,6 +107,10 @@
 
   source->SetJsonPath("strings.js");
 
+  // Add common strings.
+  source->AddLocalizedString("close", IDS_CLOSE);
+
+  // Add extension-specific strings.
   source->AddLocalizedString("title",
                              IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE);
   source->AddLocalizedString("toolbarTitle", IDS_MD_EXTENSIONS_TOOLBAR_TITLE);
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index d6659782..40894ce1 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -2034,6 +2034,21 @@
 }
 
 #if defined(OS_CHROMEOS)
+void AddMultideviceStrings(content::WebUIDataSource* html_source) {
+  LocalizedString localized_strings[] = {
+      {"multidevicePageTitle", IDS_SETTINGS_MULTIDEVICE},
+      {"smsConnect", IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT},
+      {"smsConnectSummary", IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT_SUMMARY},
+  };
+  AddLocalizedStringsBulk(html_source, localized_strings,
+                          arraysize(localized_strings));
+
+  html_source->AddBoolean("enableMultideviceSettings",
+                          base::FeatureList::IsEnabled(features::kMultidevice));
+}
+#endif
+
+#if defined(OS_CHROMEOS)
 void AddOncStrings(content::WebUIDataSource* html_source) {
   LocalizedString onc_property_strings[] = {
       // Thes strings are generated by prepending 'Onc' to the ONC property
@@ -2173,6 +2188,7 @@
   AddDeviceStrings(html_source);
   AddEasyUnlockStrings(html_source);
   AddInternetStrings(html_source);
+  AddMultideviceStrings(html_source);
   AddOncStrings(html_source);
   AddUsersStrings(html_source);
 #else
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index 99ea415..1f50f8f 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -6,7 +6,9 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <string>
+#include <utility>
 
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
@@ -134,7 +136,7 @@
 #if defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
   AddSettingsPageUIHandler(base::MakeUnique<MetricsReportingHandler>());
 #endif
-  AddSettingsPageUIHandler(base::MakeUnique<OnStartupHandler>());
+  AddSettingsPageUIHandler(base::MakeUnique<OnStartupHandler>(profile));
   AddSettingsPageUIHandler(base::MakeUnique<PeopleHandler>(profile));
   AddSettingsPageUIHandler(base::MakeUnique<ProfileInfoHandler>(profile));
   AddSettingsPageUIHandler(base::MakeUnique<ProtocolHandlersHandler>());
diff --git a/chrome/browser/ui/webui/settings/on_startup_handler.cc b/chrome/browser/ui/webui/settings/on_startup_handler.cc
index b42ffc8..fe50a55 100644
--- a/chrome/browser/ui/webui/settings/on_startup_handler.cc
+++ b/chrome/browser/ui/webui/settings/on_startup_handler.cc
@@ -4,12 +4,15 @@
 
 #include "chrome/browser/ui/webui/settings/on_startup_handler.h"
 
+#include <string>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "chrome/browser/extensions/settings_api_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/settings_utils.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_ui.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/management_policy.h"
@@ -17,9 +20,25 @@
 
 namespace settings {
 
-OnStartupHandler::OnStartupHandler() {}
+// static
+const char OnStartupHandler::kOnStartupNtpExtensionEventName[] =
+    "update-ntp-extension";
+
+OnStartupHandler::OnStartupHandler(Profile* profile)
+    : extension_registry_observer_(this), profile_(profile) {
+  DCHECK(profile);
+}
 OnStartupHandler::~OnStartupHandler() {}
 
+void OnStartupHandler::OnJavascriptAllowed() {
+  extension_registry_observer_.Add(
+      extensions::ExtensionRegistry::Get(profile_));
+}
+
+void OnStartupHandler::OnJavascriptDisallowed() {
+  extension_registry_observer_.RemoveAll();
+}
+
 void OnStartupHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
       "getNtpExtension", base::Bind(&OnStartupHandler::HandleGetNtpExtension,
@@ -30,41 +49,52 @@
                  base::Unretained(this)));
 }
 
+void OnStartupHandler::OnExtensionUnloaded(
+    content::BrowserContext* browser_context,
+    const extensions::Extension* extension,
+    extensions::UnloadedExtensionReason reason) {
+  FireWebUIListener(kOnStartupNtpExtensionEventName, *GetNtpExtension());
+}
+
+void OnStartupHandler::OnExtensionReady(
+    content::BrowserContext* browser_context,
+    const extensions::Extension* extension) {
+  FireWebUIListener(kOnStartupNtpExtensionEventName, *GetNtpExtension());
+}
+
+std::unique_ptr<base::Value> OnStartupHandler::GetNtpExtension() {
+  const extensions::Extension* ntp_extension =
+      extensions::GetExtensionOverridingNewTabPage(profile_);
+  if (!ntp_extension) {
+    std::unique_ptr<base::Value> none(new base::Value);
+    return none;
+  }
+
+  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
+  dict->SetString("id", ntp_extension->id());
+  dict->SetString("name", ntp_extension->name());
+  dict->SetBoolean("canBeDisabled",
+                   !extensions::ExtensionSystem::Get(profile_)
+                        ->management_policy()
+                        ->MustRemainEnabled(ntp_extension, nullptr));
+  return dict;
+}
+
 void OnStartupHandler::HandleGetNtpExtension(const base::ListValue* args) {
   const base::Value* callback_id;
   CHECK(args->Get(0, &callback_id));
-
   AllowJavascript();
 
-  Profile* profile = Profile::FromWebUI(web_ui());
-  const extensions::Extension* ntp_extension =
-      extensions::GetExtensionOverridingNewTabPage(profile);
-
-  if (!ntp_extension) {
-    ResolveJavascriptCallback(*callback_id, base::Value());
-    return;
-  }
-
-  base::DictionaryValue dict;
-  dict.SetString("id", ntp_extension->id());
-  dict.SetString("name", ntp_extension->name());
-  dict.SetBoolean("canBeDisabled",
-                  !extensions::ExtensionSystem::Get(profile)
-                       ->management_policy()
-                       ->MustRemainEnabled(ntp_extension, nullptr));
-  ResolveJavascriptCallback(*callback_id, dict);
+  ResolveJavascriptCallback(*callback_id, *GetNtpExtension());
 }
 
 void OnStartupHandler::HandleValidateStartupPage(const base::ListValue* args) {
-  AllowJavascript();
-
   CHECK_EQ(args->GetSize(), 2U);
-
   const base::Value* callback_id;
   CHECK(args->Get(0, &callback_id));
-
   std::string url_string;
   CHECK(args->GetString(1, &url_string));
+  AllowJavascript();
 
   bool valid = settings_utils::FixupAndValidateStartupPage(url_string, nullptr);
   ResolveJavascriptCallback(*callback_id, base::Value(valid));
diff --git a/chrome/browser/ui/webui/settings/on_startup_handler.h b/chrome/browser/ui/webui/settings/on_startup_handler.h
index 013d1d9..e5438a3 100644
--- a/chrome/browser/ui/webui/settings/on_startup_handler.h
+++ b/chrome/browser/ui/webui/settings/on_startup_handler.h
@@ -5,8 +5,15 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ON_STARTUP_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_ON_STARTUP_HANDLER_H_
 
+#include <memory>
+
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_registry_observer.h"
+
+class Profile;
 
 namespace base {
 class ListValue;
@@ -14,17 +21,29 @@
 
 namespace settings {
 
-class OnStartupHandler : public SettingsPageUIHandler {
+class OnStartupHandler : public SettingsPageUIHandler,
+                         public extensions::ExtensionRegistryObserver {
  public:
-  OnStartupHandler();
+  static const char kOnStartupNtpExtensionEventName[];
+
+  explicit OnStartupHandler(Profile* profile);
   ~OnStartupHandler() override;
 
   // SettingsPageUIHandler:
+  void OnJavascriptAllowed() override;
+  void OnJavascriptDisallowed() override;
   void RegisterMessages() override;
-  void OnJavascriptAllowed() override {}
-  void OnJavascriptDisallowed() override {}
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(OnStartupHandlerTest, HandleGetNtpExtension);
+  FRIEND_TEST_ALL_PREFIXES(OnStartupHandlerTest,
+                           HandleValidateStartupPage_Valid);
+  FRIEND_TEST_ALL_PREFIXES(OnStartupHandlerTest,
+                           HandleValidateStartupPage_Invalid);
+
+  // Info for extension controlling the NTP or empty value.
+  std::unique_ptr<base::Value> GetNtpExtension();
+
   // Handler for the "getNtpExtension" message. No arguments.
   void HandleGetNtpExtension(const base::ListValue* /*args*/);
 
@@ -32,6 +51,20 @@
   // valid startup page.
   void HandleValidateStartupPage(const base::ListValue* args);
 
+  // extensions::ExtensionRegistryObserver.
+  void OnExtensionUnloaded(content::BrowserContext* browser_context,
+                           const extensions::Extension* extension,
+                           extensions::UnloadedExtensionReason reason) override;
+  void OnExtensionReady(content::BrowserContext* browser_context,
+                        const extensions::Extension* extension) override;
+
+  // Listen to extension unloaded notifications.
+  ScopedObserver<extensions::ExtensionRegistry,
+                 extensions::ExtensionRegistryObserver>
+      extension_registry_observer_;
+
+  Profile* profile_;
+
   DISALLOW_COPY_AND_ASSIGN(OnStartupHandler);
 };
 
diff --git a/chrome/browser/ui/webui/settings/on_startup_handler_unittest.cc b/chrome/browser/ui/webui/settings/on_startup_handler_unittest.cc
new file mode 100644
index 0000000..380a7165
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/on_startup_handler_unittest.cc
@@ -0,0 +1,146 @@
+// 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 "chrome/browser/ui/webui/settings/on_startup_handler.h"
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
+#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
+#endif
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_web_ui.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kCallbackId[] = "test-on-startup-callback-id";
+
+class TestOnStartupHandler : public settings::OnStartupHandler {
+ public:
+  explicit TestOnStartupHandler(Profile* profile)
+      : settings::OnStartupHandler(profile) {}
+
+  using settings::OnStartupHandler::set_web_ui;
+};
+
+}  // namespace
+
+namespace settings {
+
+class OnStartupHandlerTest : public testing::Test {
+ public:
+  OnStartupHandlerTest()
+      : profile_manager_(TestingBrowserProcess::GetGlobal()),
+        profile_(nullptr) {}
+
+  void SetUp() override {
+    ASSERT_TRUE(profile_manager_.SetUp());
+
+#if defined(OS_CHROMEOS)
+    chromeos::FakeChromeUserManager* fake_user_manager =
+        new chromeos::FakeChromeUserManager;
+    user_manager_enabler_.reset(
+        new chromeos::ScopedUserManagerEnabler(fake_user_manager));
+    constexpr char kFakeEmail[] = "fake_id@gmail.com";
+    profile_ = profile_manager_.CreateTestingProfile(kFakeEmail);
+    fake_user_manager->AddUser(AccountId::FromUserEmail(kFakeEmail));
+#else
+    profile_ = profile_manager_.CreateTestingProfile("Profile 1");
+#endif
+
+    handler_.reset(new TestOnStartupHandler(profile_));
+    handler_->set_web_ui(&web_ui_);
+  }
+
+  TestOnStartupHandler* handler() { return handler_.get(); }
+  Profile* profile() const { return profile_; }
+  content::TestWebUI* web_ui() { return &web_ui_; }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  TestingProfileManager profile_manager_;
+  std::unique_ptr<TestOnStartupHandler> handler_;
+  Profile* profile_;
+#if defined(OS_CHROMEOS)
+  std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
+#endif
+  content::TestWebUI web_ui_;
+};
+
+TEST_F(OnStartupHandlerTest, HandleGetNtpExtension) {
+  base::ListValue list_args;
+  list_args.AppendString(kCallbackId);
+  handler()->HandleGetNtpExtension(&list_args);
+
+  EXPECT_EQ(1U, web_ui()->call_data().size());
+
+  const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
+  EXPECT_EQ("cr.webUIResponse", data.function_name());
+
+  std::string callback_id;
+  ASSERT_TRUE(data.arg1()->GetAsString(&callback_id));
+  EXPECT_EQ(kCallbackId, callback_id);
+
+  bool success = false;
+  ASSERT_TRUE(data.arg2()->GetAsBoolean(&success));
+  EXPECT_TRUE(success);
+}
+
+TEST_F(OnStartupHandlerTest, HandleValidateStartupPage_Valid) {
+  base::ListValue list_args;
+  list_args.AppendString(kCallbackId);
+  list_args.AppendString("http://example.com");
+  handler()->HandleValidateStartupPage(&list_args);
+
+  EXPECT_EQ(1U, web_ui()->call_data().size());
+
+  const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
+  EXPECT_EQ("cr.webUIResponse", data.function_name());
+
+  std::string callback_id;
+  ASSERT_TRUE(data.arg1()->GetAsString(&callback_id));
+  EXPECT_EQ(kCallbackId, callback_id);
+
+  bool success = false;
+  ASSERT_TRUE(data.arg2()->GetAsBoolean(&success));
+  EXPECT_TRUE(success);
+
+  bool is_valid = false;
+  ASSERT_TRUE(data.arg2()->GetAsBoolean(&is_valid));
+  EXPECT_TRUE(is_valid);
+}
+
+TEST_F(OnStartupHandlerTest, HandleValidateStartupPage_Invalid) {
+  base::ListValue list_args;
+  list_args.AppendString(kCallbackId);
+  list_args.AppendString("@");
+  handler()->HandleValidateStartupPage(&list_args);
+
+  EXPECT_EQ(1U, web_ui()->call_data().size());
+
+  const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
+  EXPECT_EQ("cr.webUIResponse", data.function_name());
+
+  std::string callback_id;
+  ASSERT_TRUE(data.arg1()->GetAsString(&callback_id));
+  EXPECT_EQ(kCallbackId, callback_id);
+
+  bool success = false;
+  ASSERT_TRUE(data.arg2()->GetAsBoolean(&success));
+  EXPECT_TRUE(success);
+
+  bool is_valid = false;
+  ASSERT_TRUE(data.arg3()->GetAsBoolean(&is_valid));
+  EXPECT_FALSE(is_valid);
+}
+
+}  // namespace settings
diff --git a/chrome/browser/ui/webui/version_ui.cc b/chrome/browser/ui/webui/version_ui.cc
index 2ef9c38..d01a8c8 100644
--- a/chrome/browser/ui/webui/version_ui.cc
+++ b/chrome/browser/ui/webui/version_ui.cc
@@ -144,7 +144,7 @@
 #else
   html_source->AddString(version_ui::kCompiler, "MSVC 2015");
 #endif
-#elif defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1911
+#elif defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER < 2000
 #if BUILDFLAG(PGO_BUILD)
   html_source->AddString(version_ui::kCompiler, "MSVC 2017 (PGO)");
 #else
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index be11d25b..26b80349 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -85,14 +85,23 @@
     "toolbar_state.cc",
     "toolbar_state.h",
     "ui_browser_interface.h",
+    "ui_element_renderer.h",
     "ui_input_manager.cc",
     "ui_input_manager.h",
     "ui_interface.h",
+    "ui_renderer.cc",
+    "ui_renderer.h",
     "ui_scene.cc",
     "ui_scene.h",
     "ui_scene_manager.cc",
     "ui_scene_manager.h",
     "ui_unsupported_mode.h",
+    "vr_controller_model.cc",
+    "vr_controller_model.h",
+    "vr_gl_util.cc",
+    "vr_gl_util.h",
+    "vr_shell_renderer.cc",
+    "vr_shell_renderer.h",
   ]
 
   deps = [
diff --git a/chrome/browser/vr/ui_renderer.cc b/chrome/browser/vr/ui_renderer.cc
new file mode 100644
index 0000000..b75b24b
--- /dev/null
+++ b/chrome/browser/vr/ui_renderer.cc
@@ -0,0 +1,329 @@
+// 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 "chrome/browser/vr/ui_renderer.h"
+
+#include "base/trace_event/trace_event.h"
+#include "chrome/browser/vr/elements/ui_element.h"
+#include "chrome/browser/vr/ui_scene.h"
+#include "chrome/browser/vr/vr_controller_model.h"
+#include "chrome/browser/vr/vr_shell_renderer.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace vr {
+
+namespace {
+
+static constexpr gfx::Point3F kOrigin = {0.0f, 0.0f, 0.0f};
+
+// Fraction of the distance to the object the reticle is drawn at to avoid
+// rounding errors drawing the reticle behind the object.
+// TODO(mthiesse): Find a better approach for drawing the reticle on an object.
+// Right now we have to wedge it very precisely between the content window and
+// backplane to avoid rendering artifacts.
+static constexpr float kReticleOffset = 0.999f;
+
+static constexpr float kLaserWidth = 0.01f;
+
+static constexpr float kReticleWidth = 0.025f;
+static constexpr float kReticleHeight = 0.025f;
+
+}  // namespace
+
+UiRenderer::UiRenderer(UiScene* scene,
+                       int content_texture_id,
+                       VrShellRenderer* vr_shell_renderer)
+    : scene_(scene),
+      content_texture_id_(content_texture_id),
+      vr_shell_renderer_(vr_shell_renderer) {}
+
+UiRenderer::~UiRenderer() = default;
+
+void UiRenderer::Draw(const RenderInfo& render_info,
+                      const ControllerInfo& controller_info,
+                      bool web_vr_mode) {
+  DrawWorldElements(render_info, controller_info, web_vr_mode);
+  DrawOverlayElements(render_info, controller_info);
+}
+
+void UiRenderer::DrawHeadLocked(const RenderInfo& render_info,
+                                const ControllerInfo& controller_info) {
+  TRACE_EVENT0("gpu", "VrShellGl::DrawHeadLockedElements");
+  std::vector<const UiElement*> elements = scene_->GetHeadLockedElements();
+
+  glEnable(GL_CULL_FACE);
+  glEnable(GL_DEPTH_TEST);
+  glDepthMask(GL_TRUE);
+
+  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  gfx::Transform identity_matrix;
+  DrawUiView(render_info, controller_info, elements, false);
+}
+
+void UiRenderer::DrawWorldElements(const RenderInfo& render_info,
+                                   const ControllerInfo& controller_info,
+                                   bool web_vr_mode) {
+  TRACE_EVENT0("gpu", "VrShellGl::DrawWorldElements");
+
+  if (web_vr_mode) {
+    // WebVR is incompatible with 3D world compositing since the
+    // depth buffer was already populated with unknown scaling - the
+    // WebVR app has full control over zNear/zFar. Just leave the
+    // existing content in place in the primary buffer without
+    // clearing. Currently, there aren't any world elements in WebVR
+    // mode, this will need further testing if those get added
+    // later.
+  } else {
+    // Non-WebVR mode, enable depth testing and clear the primary buffers.
+    glEnable(GL_CULL_FACE);
+    glEnable(GL_DEPTH_TEST);
+    glDepthMask(GL_TRUE);
+
+    const SkColor backgroundColor = scene_->GetWorldBackgroundColor();
+    glClearColor(SkColorGetR(backgroundColor) / 255.0,
+                 SkColorGetG(backgroundColor) / 255.0,
+                 SkColorGetB(backgroundColor) / 255.0,
+                 SkColorGetA(backgroundColor) / 255.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  }
+  std::vector<const UiElement*> elements = scene_->GetWorldElements();
+  bool draw_reticle =
+      !(scene_->is_exiting() || scene_->showing_splash_screen() || web_vr_mode);
+  DrawUiView(render_info, controller_info, elements, draw_reticle);
+}
+
+void UiRenderer::DrawOverlayElements(const RenderInfo& render_info,
+                                     const ControllerInfo& controller_info) {
+  std::vector<const UiElement*> elements = scene_->GetOverlayElements();
+  if (elements.empty()) {
+    return;
+  }
+
+  glDisable(GL_CULL_FACE);
+  glDisable(GL_DEPTH_TEST);
+  glDepthMask(GL_FALSE);
+
+  DrawUiView(render_info, controller_info, elements, false);
+}
+
+void UiRenderer::DrawUiView(const RenderInfo& render_info,
+                            const ControllerInfo& controller_info,
+                            const std::vector<const UiElement*>& elements,
+                            bool draw_reticle) {
+  TRACE_EVENT0("gpu", "VrShellGl::DrawUiView");
+
+  auto sorted_elements =
+      GetElementsInDrawOrder(render_info.head_pose, elements);
+
+  for (auto& eye_info :
+       {render_info.left_eye_info, render_info.right_eye_info}) {
+    glViewport(eye_info.viewport.x(), eye_info.viewport.y(),
+               eye_info.viewport.width(), eye_info.viewport.height());
+
+    DrawElements(eye_info.view_proj_matrix, sorted_elements, render_info,
+                 controller_info, draw_reticle);
+    if (draw_reticle) {
+      DrawController(eye_info.view_proj_matrix, render_info, controller_info);
+      DrawLaser(eye_info.view_proj_matrix, render_info, controller_info);
+    }
+  }
+}
+
+void UiRenderer::DrawElements(const gfx::Transform& view_proj_matrix,
+                              const std::vector<const UiElement*>& elements,
+                              const RenderInfo& render_info,
+                              const ControllerInfo& controller_info,
+                              bool draw_reticle) {
+  if (elements.empty()) {
+    return;
+  }
+  int initial_draw_phase = elements.front()->draw_phase();
+  bool drawn_reticle = false;
+  for (const auto* element : elements) {
+    // If we have no element to draw the reticle on, draw it after the
+    // background (the initial draw phase).
+    if (!controller_info.reticle_render_target && draw_reticle &&
+        !drawn_reticle && element->draw_phase() > initial_draw_phase) {
+      DrawReticle(view_proj_matrix, render_info, controller_info);
+      drawn_reticle = true;
+    }
+
+    DrawElement(view_proj_matrix, *element, render_info.content_texture_size);
+
+    if (draw_reticle && (controller_info.reticle_render_target == element)) {
+      DrawReticle(view_proj_matrix, render_info, controller_info);
+    }
+  }
+  vr_shell_renderer_->Flush();
+}
+
+void UiRenderer::DrawElement(const gfx::Transform& view_proj_matrix,
+                             const UiElement& element,
+                             const gfx::Size& content_texture_size) {
+  gfx::Transform transform =
+      view_proj_matrix * element.screen_space_transform();
+
+  switch (element.fill()) {
+    case Fill::OPAQUE_GRADIENT: {
+      vr_shell_renderer_->GetGradientQuadRenderer()->Draw(
+          transform, element.edge_color(), element.center_color(),
+          element.computed_opacity());
+      break;
+    }
+    case Fill::GRID_GRADIENT: {
+      vr_shell_renderer_->GetGradientGridRenderer()->Draw(
+          transform, element.edge_color(), element.center_color(),
+          element.grid_color(), element.gridline_count(),
+          element.computed_opacity());
+      break;
+    }
+    case Fill::CONTENT: {
+      vr_shell_renderer_->GetExternalTexturedQuadRenderer()->Draw(
+          content_texture_id_, transform, content_texture_size,
+          gfx::SizeF(element.size().x(), element.size().y()),
+          element.computed_opacity(), element.corner_radius());
+      break;
+    }
+    case Fill::SELF: {
+      element.Render(vr_shell_renderer_, transform);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+std::vector<const UiElement*> UiRenderer::GetElementsInDrawOrder(
+    const gfx::Transform& view_matrix,
+    const std::vector<const UiElement*>& elements) {
+  std::vector<const UiElement*> sorted_elements = elements;
+
+  // Sort elements primarily based on their draw phase (lower draw phase first)
+  // and secondarily based on their z-axis distance (more distant first).
+  // TODO(mthiesse, crbug.com/721356): This will not work well for elements not
+  // directly in front of the user, but works well enough for our initial
+  // release, and provides a consistent ordering that we can easily design
+  // around.
+  std::sort(sorted_elements.begin(), sorted_elements.end(),
+            [](const UiElement* first, const UiElement* second) {
+              if (first->draw_phase() != second->draw_phase()) {
+                return first->draw_phase() < second->draw_phase();
+              } else {
+                return first->screen_space_transform().matrix().get(2, 3) <
+                       second->screen_space_transform().matrix().get(2, 3);
+              }
+            });
+
+  return sorted_elements;
+}
+
+void UiRenderer::DrawReticle(const gfx::Transform& render_matrix,
+                             const RenderInfo& render_info,
+                             const ControllerInfo& controller_info) {
+  // Scale the reticle to have a fixed FOV size at any distance.
+  const float eye_to_target =
+      std::sqrt(controller_info.target_point.SquaredDistanceTo(kOrigin));
+
+  gfx::Transform mat;
+  mat.Scale3d(kReticleWidth * eye_to_target, kReticleHeight * eye_to_target, 1);
+
+  gfx::Quaternion rotation;
+
+  if (controller_info.reticle_render_target != nullptr) {
+    // Make the reticle planar to the element it's hitting.
+    rotation =
+        gfx::Quaternion(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
+                        controller_info.reticle_render_target->GetNormal());
+  } else {
+    // Rotate the reticle to directly face the eyes.
+    rotation = gfx::Quaternion(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
+                               controller_info.target_point - kOrigin);
+  }
+  gfx::Transform rotation_mat(rotation);
+  mat = rotation_mat * mat;
+
+  gfx::Point3F target_point =
+      ScalePoint(controller_info.target_point, kReticleOffset);
+  // Place the pointer slightly in front of the plane intersection point.
+  mat.matrix().postTranslate(target_point.x(), target_point.y(),
+                             target_point.z());
+
+  gfx::Transform transform = render_matrix * mat;
+  vr_shell_renderer_->GetReticleRenderer()->Draw(transform);
+}
+
+void UiRenderer::DrawLaser(const gfx::Transform& render_matrix,
+                           const RenderInfo& render_info,
+                           const ControllerInfo& controller_info) {
+  // Find the length of the beam (from hand to target).
+  const float laser_length =
+      std::sqrt(controller_info.laser_origin.SquaredDistanceTo(
+          ScalePoint(controller_info.target_point, kReticleOffset)));
+
+  // Build a beam, originating from the origin.
+  gfx::Transform mat;
+
+  // Move the beam half its height so that its end sits on the origin.
+  mat.matrix().postTranslate(0.0f, 0.5f, 0.0f);
+  mat.matrix().postScale(kLaserWidth, laser_length, 1);
+
+  // Tip back 90 degrees to flat, pointing at the scene.
+  const gfx::Quaternion quat(gfx::Vector3dF(1.0f, 0.0f, 0.0f), -M_PI / 2);
+  gfx::Transform rotation_mat(quat);
+  mat = rotation_mat * mat;
+
+  const gfx::Vector3dF beam_direction =
+      controller_info.target_point - controller_info.laser_origin;
+
+  gfx::Transform beam_direction_mat(
+      gfx::Quaternion(gfx::Vector3dF(0.0f, 0.0f, -1.0f), beam_direction));
+
+  // Render multiple faces to make the laser appear cylindrical.
+  const int faces = 4;
+  gfx::Transform face_transform;
+  gfx::Transform transform;
+  for (int i = 0; i < faces; i++) {
+    // Rotate around Z.
+    const float angle = M_PI * 2 * i / faces;
+    const gfx::Quaternion rot({0.0f, 0.0f, 1.0f}, angle);
+    face_transform = beam_direction_mat * gfx::Transform(rot) * mat;
+
+    // Move the beam origin to the hand.
+    face_transform.matrix().postTranslate(controller_info.laser_origin.x(),
+                                          controller_info.laser_origin.y(),
+                                          controller_info.laser_origin.z());
+    transform = render_matrix * face_transform;
+    vr_shell_renderer_->GetLaserRenderer()->Draw(controller_info.opacity,
+                                                 transform);
+  }
+}
+
+void UiRenderer::DrawController(const gfx::Transform& view_proj_matrix,
+                                const RenderInfo& render_info,
+                                const ControllerInfo& controller_info) {
+  if (!vr_shell_renderer_->GetControllerRenderer()->IsSetUp()) {
+    return;
+  }
+
+  VrControllerModel::State state;
+  if (controller_info.touchpad_button_state ==
+      UiInputManager::ButtonState::DOWN) {
+    state = VrControllerModel::TOUCHPAD;
+  } else if (controller_info.app_button_state ==
+             UiInputManager::ButtonState::DOWN) {
+    state = VrControllerModel::APP;
+  } else if (controller_info.home_button_state ==
+             UiInputManager::ButtonState::DOWN) {
+    state = VrControllerModel::SYSTEM;
+  } else {
+    state = VrControllerModel::IDLE;
+  }
+
+  gfx::Transform transform = view_proj_matrix * controller_info.transform;
+  vr_shell_renderer_->GetControllerRenderer()->Draw(
+      state, controller_info.opacity, transform);
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/ui_renderer.h b/chrome/browser/vr/ui_renderer.h
new file mode 100644
index 0000000..057e08c
--- /dev/null
+++ b/chrome/browser/vr/ui_renderer.h
@@ -0,0 +1,99 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VR_UI_RENDERER_H_
+#define CHROME_BROWSER_VR_UI_RENDERER_H_
+
+#include "chrome/browser/vr/ui_input_manager.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/transform.h"
+
+namespace vr {
+
+class UiScene;
+class UiElement;
+class VrShellRenderer;
+
+// Provides information needed to render the controller.
+struct ControllerInfo {
+  gfx::Point3F target_point;
+  gfx::Point3F laser_origin;
+  UiInputManager::ButtonState touchpad_button_state;
+  UiInputManager::ButtonState app_button_state;
+  UiInputManager::ButtonState home_button_state;
+  gfx::Transform transform;
+  float opacity;
+  UiElement* reticle_render_target;
+};
+
+// Provides information for rendering such as the viewport and view/projection
+// matrix.
+struct RenderInfo {
+  struct EyeInfo {
+    gfx::Rect viewport;
+    gfx::Transform view_matrix;
+    gfx::Transform proj_matrix;
+    gfx::Transform view_proj_matrix;
+  };
+
+  gfx::Transform head_pose;
+  EyeInfo left_eye_info;
+  EyeInfo right_eye_info;
+
+  gfx::Size content_texture_size;
+};
+
+// Renders a UI scene.
+class UiRenderer {
+ public:
+  UiRenderer(UiScene* scene,
+             int content_texture_id,
+             VrShellRenderer* vr_shell_renderer);
+  ~UiRenderer();
+
+  void Draw(const RenderInfo& render_info,
+            const ControllerInfo& controller_info,
+            bool web_vr_mode);
+  void DrawHeadLocked(const RenderInfo& render_info,
+                      const ControllerInfo& controller_info);
+
+ private:
+  void DrawWorldElements(const RenderInfo& render_info,
+                         const ControllerInfo& controller_info,
+                         bool web_vr_mode);
+  void DrawOverlayElements(const RenderInfo& render_info,
+                           const ControllerInfo& controller_info);
+  void DrawUiView(const RenderInfo& render_info,
+                  const ControllerInfo& controller_info,
+                  const std::vector<const UiElement*>& elements,
+                  bool draw_reticle);
+  void DrawElements(const gfx::Transform& view_proj_matrix,
+                    const std::vector<const UiElement*>& elements,
+                    const RenderInfo& render_info,
+                    const ControllerInfo& controller_info,
+                    bool draw_reticle);
+  void DrawElement(const gfx::Transform& view_proj_matrix,
+                   const UiElement& element,
+                   const gfx::Size& content_texture_size);
+  std::vector<const UiElement*> GetElementsInDrawOrder(
+      const gfx::Transform& view_matrix,
+      const std::vector<const UiElement*>& elements);
+  void DrawReticle(const gfx::Transform& render_matrix,
+                   const RenderInfo& render_info,
+                   const ControllerInfo& controller_info);
+  void DrawLaser(const gfx::Transform& render_matrix,
+                 const RenderInfo& render_info,
+                 const ControllerInfo& controller_info);
+  void DrawController(const gfx::Transform& view_proj_matrix,
+                      const RenderInfo& render_info,
+                      const ControllerInfo& controller_info);
+
+  UiScene* scene_ = nullptr;
+  int content_texture_id_ = 0;
+  VrShellRenderer* vr_shell_renderer_ = nullptr;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_UI_RENDERER_H_
diff --git a/chrome/browser/vr/ui_scene_manager.cc b/chrome/browser/vr/ui_scene_manager.cc
index 2e1716b..cba3abbf 100644
--- a/chrome/browser/vr/ui_scene_manager.cc
+++ b/chrome/browser/vr/ui_scene_manager.cc
@@ -142,8 +142,8 @@
       scene_(scene),
       in_cct_(in_cct),
       web_vr_mode_(in_web_vr),
-      web_vr_autopresentation_(web_vr_autopresentation_expected),
-      web_vr_autopresentation_expected_(web_vr_autopresentation_expected),
+      started_for_autopresentation_(web_vr_autopresentation_expected),
+      waiting_for_first_web_vr_frame_(web_vr_autopresentation_expected),
       weak_ptr_factory_(this) {
   CreateSplashScreen();
   CreateBackground();
@@ -489,11 +489,11 @@
   }
 
   web_vr_mode_ = web_vr;
-  web_vr_autopresentation_expected_ = false;
   web_vr_show_toast_ = show_toast;
-  if (!web_vr_mode_)
-    web_vr_autopresentation_ = false;
-  scene_->set_showing_splash_screen(false);
+  if (!web_vr_mode_) {
+    waiting_for_first_web_vr_frame_ = false;
+    started_for_autopresentation_ = false;
+  }
   ConfigureScene();
 
   // Because we may be transitioning from and to fullscreen, where the toast is
@@ -505,10 +505,22 @@
   }
 }
 
+void UiSceneManager::OnWebVrFrameAvailable() {
+  if (!waiting_for_first_web_vr_frame_)
+    return;
+  waiting_for_first_web_vr_frame_ = false;
+  ConfigureScene();
+}
+
 void UiSceneManager::ConfigureScene() {
+  // We disable WebVR rendering if we're expecting to auto present so that we
+  // can continue to show the 2D splash screen while the site submits the first
+  // WebVR frame.
+  scene_->SetWebVrRenderingEnabled(web_vr_mode_ &&
+                                   !waiting_for_first_web_vr_frame_);
   // Splash screen.
-  scene_->set_showing_splash_screen(web_vr_autopresentation_expected_);
-  splash_screen_icon_->SetEnabled(web_vr_autopresentation_expected_);
+  scene_->set_showing_splash_screen(waiting_for_first_web_vr_frame_);
+  splash_screen_icon_->SetEnabled(waiting_for_first_web_vr_frame_);
 
   // Exit warning.
   exit_warning_->SetEnabled(scene_->is_exiting());
@@ -578,7 +590,7 @@
       -kBackgroundDistanceMultiplier);
   UpdateBackgroundColor();
 
-  transient_url_bar_->SetEnabled(web_vr_autopresentation_ &&
+  transient_url_bar_->SetEnabled(started_for_autopresentation_ &&
                                  !scene_->showing_splash_screen());
 
   ConfigureExclusiveScreenToast();
diff --git a/chrome/browser/vr/ui_scene_manager.h b/chrome/browser/vr/ui_scene_manager.h
index c306026..167726b 100644
--- a/chrome/browser/vr/ui_scene_manager.h
+++ b/chrome/browser/vr/ui_scene_manager.h
@@ -58,6 +58,7 @@
   void OnGLInitialized();
   void OnAppButtonClicked();
   void OnAppButtonGesturePerformed(UiInterface::Direction direction);
+  void OnWebVrFrameAvailable();
 
   void OnSecurityIconClickedForTesting();
   void OnExitPromptPrimaryButtonClickedForTesting();
@@ -122,8 +123,11 @@
   bool in_cct_;
   bool web_vr_mode_;
   bool web_vr_show_toast_ = false;
-  bool web_vr_autopresentation_ = false;
-  bool web_vr_autopresentation_expected_ = false;
+  bool started_for_autopresentation_ = false;
+  // Flag to indicate that we're waiting for the first WebVR frame to show up
+  // before we hide the splash screen. This is used in the case of WebVR
+  // auto-presentation.
+  bool waiting_for_first_web_vr_frame_ = false;
   bool secure_origin_ = false;
   bool fullscreen_ = false;
   bool incognito_ = false;
diff --git a/chrome/browser/vr/ui_scene_manager_unittest.cc b/chrome/browser/vr/ui_scene_manager_unittest.cc
index 22923339..c4518c6 100644
--- a/chrome/browser/vr/ui_scene_manager_unittest.cc
+++ b/chrome/browser/vr/ui_scene_manager_unittest.cc
@@ -308,6 +308,7 @@
 
   // Enter WebVR with autopresentation.
   manager_->SetWebVrMode(true, false);
+  manager_->OnWebVrFrameAvailable();
   VerifyElementsVisible("Autopresented",
                         std::set<UiElementDebugId>{kTransientUrlBar});
 
diff --git a/chrome/browser/android/vr_shell/vr_controller_model.cc b/chrome/browser/vr/vr_controller_model.cc
similarity index 97%
rename from chrome/browser/android/vr_shell/vr_controller_model.cc
rename to chrome/browser/vr/vr_controller_model.cc
index edd30e4..5b874a66 100644
--- a/chrome/browser/android/vr_shell/vr_controller_model.cc
+++ b/chrome/browser/vr/vr_controller_model.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/vr_shell/vr_controller_model.h"
+#include "chrome/browser/vr/vr_controller_model.h"
 
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/trace_event.h"
@@ -14,7 +14,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/codec/png_codec.h"
 
-namespace vr_shell {
+namespace vr {
 
 namespace {
 
@@ -170,4 +170,4 @@
   return controller_model;
 }
 
-}  // namespace vr_shell
+}  // namespace vr
diff --git a/chrome/browser/android/vr_shell/vr_controller_model.h b/chrome/browser/vr/vr_controller_model.h
similarity index 86%
rename from chrome/browser/android/vr_shell/vr_controller_model.h
rename to chrome/browser/vr/vr_controller_model.h
index 4f010ca..04bedef 100644
--- a/chrome/browser/android/vr_shell/vr_controller_model.h
+++ b/chrome/browser/vr/vr_controller_model.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_VR_CONTROLLER_MODEL_H_
-#define CHROME_BROWSER_ANDROID_VR_SHELL_VR_CONTROLLER_MODEL_H_
+#ifndef CHROME_BROWSER_VR_VR_CONTROLLER_MODEL_H_
+#define CHROME_BROWSER_VR_VR_CONTROLLER_MODEL_H_
 
 #include <memory>
 
@@ -12,7 +12,7 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gl/gl_bindings.h"
 
-namespace vr_shell {
+namespace vr {
 
 class VrControllerModel {
  public:
@@ -54,6 +54,6 @@
   const vr::gltf::Accessor* Accessor(const std::string& key) const;
 };
 
-}  // namespace vr_shell
+}  // namespace vr
 
-#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_VR_CONTROLLER_MODEL_H_
+#endif  // CHROME_BROWSER_VR_VR_CONTROLLER_MODEL_H_
diff --git a/chrome/browser/android/vr_shell/vr_gl_util.cc b/chrome/browser/vr/vr_gl_util.cc
similarity index 96%
rename from chrome/browser/android/vr_shell/vr_gl_util.cc
rename to chrome/browser/vr/vr_gl_util.cc
index e087b892..cd68dab 100644
--- a/chrome/browser/android/vr_shell/vr_gl_util.cc
+++ b/chrome/browser/vr/vr_gl_util.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/vr_shell/vr_gl_util.h"
+#include "chrome/browser/vr/vr_gl_util.h"
 
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/transform.h"
 
-namespace vr_shell {
+namespace vr {
 
 // This code is adapted from the GVR Treasure Hunt demo source.
 std::array<float, 16> MatrixToGLArray(const gfx::Transform& transform) {
@@ -92,4 +92,4 @@
   return program_handle;
 }
 
-}  // namespace vr_shell
+}  // namespace vr
diff --git a/chrome/browser/android/vr_shell/vr_gl_util.h b/chrome/browser/vr/vr_gl_util.h
similarity index 80%
rename from chrome/browser/android/vr_shell/vr_gl_util.h
rename to chrome/browser/vr/vr_gl_util.h
index ff0b2e6..2280c2d 100644
--- a/chrome/browser/android/vr_shell/vr_gl_util.h
+++ b/chrome/browser/vr/vr_gl_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_VR_GL_UTIL_H_
-#define CHROME_BROWSER_ANDROID_VR_SHELL_VR_GL_UTIL_H_
+#ifndef CHROME_BROWSER_VR_VR_GL_UTIL_H_
+#define CHROME_BROWSER_VR_VR_GL_UTIL_H_
 
 #include <array>
 #include <string>
@@ -17,7 +17,7 @@
 class Transform;
 }  // namespace gfx
 
-namespace vr_shell {
+namespace vr {
 
 std::array<float, 16> MatrixToGLArray(const gfx::Transform& matrix);
 
@@ -34,6 +34,6 @@
                             GLuint fragment_shader_handle,
                             std::string& error);
 
-}  // namespace vr_shell
+}  // namespace vr
 
-#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_VR_GL_UTIL_H_
+#endif  // CHROME_BROWSER_VR_VR_GL_UTIL_H_
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.cc b/chrome/browser/vr/vr_shell_renderer.cc
similarity index 96%
rename from chrome/browser/android/vr_shell/vr_shell_renderer.cc
rename to chrome/browser/vr/vr_shell_renderer.cc
index a2242aaa..2a8169e6 100644
--- a/chrome/browser/android/vr_shell/vr_shell_renderer.cc
+++ b/chrome/browser/vr/vr_shell_renderer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/vr_shell/vr_shell_renderer.h"
+#include "chrome/browser/vr/vr_shell_renderer.h"
 
 #include <math.h>
 #include <algorithm>
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/trace_event.h"
-#include "chrome/browser/android/vr_shell/vr_gl_util.h"
+#include "chrome/browser/vr/vr_gl_util.h"
 #include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/vector3d_f.h"
@@ -162,11 +162,11 @@
 #define OEIE_SHADER(Src) "#extension GL_OES_EGL_image_external : require\n" #Src
 #define VOID_OFFSET(x) reinterpret_cast<void*>(x)
 
-const char* GetShaderSource(vr_shell::ShaderID shader) {
+const char* GetShaderSource(vr::ShaderID shader) {
   switch (shader) {
-    case vr_shell::ShaderID::RETICLE_VERTEX_SHADER:
-    case vr_shell::ShaderID::LASER_VERTEX_SHADER:
-    case vr_shell::ShaderID::TEXTURED_QUAD_VERTEX_SHADER:
+    case vr::ShaderID::RETICLE_VERTEX_SHADER:
+    case vr::ShaderID::LASER_VERTEX_SHADER:
+    case vr::ShaderID::TEXTURED_QUAD_VERTEX_SHADER:
       return SHADER(
           /* clang-format off */
           precision mediump float;
@@ -179,7 +179,7 @@
             gl_Position = u_ModelViewProjMatrix * a_Position;
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::CONTROLLER_VERTEX_SHADER:
+    case vr::ShaderID::CONTROLLER_VERTEX_SHADER:
       return SHADER(
           /* clang-format off */
           precision mediump float;
@@ -193,8 +193,8 @@
             gl_Position = u_ModelViewProjMatrix * a_Position;
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::GRADIENT_QUAD_VERTEX_SHADER:
-    case vr_shell::ShaderID::GRADIENT_GRID_VERTEX_SHADER:
+    case vr::ShaderID::GRADIENT_QUAD_VERTEX_SHADER:
+    case vr::ShaderID::GRADIENT_GRID_VERTEX_SHADER:
       return SHADER(
           /* clang-format off */
           precision mediump float;
@@ -208,7 +208,7 @@
             gl_Position = u_ModelViewProjMatrix * a_Position;
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::EXTERNAL_TEXTURED_QUAD_VERTEX_SHADER:
+    case vr::ShaderID::EXTERNAL_TEXTURED_QUAD_VERTEX_SHADER:
       return SHADER(
           /* clang-format off */
           precision mediump float;
@@ -231,7 +231,7 @@
             gl_Position = u_ModelViewProjMatrix * position;
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::EXTERNAL_TEXTURED_QUAD_FRAGMENT_SHADER:
+    case vr::ShaderID::EXTERNAL_TEXTURED_QUAD_FRAGMENT_SHADER:
       return OEIE_SHADER(
           /* clang-format off */
           precision highp float;
@@ -249,7 +249,7 @@
             gl_FragColor = color * u_Opacity * mask;
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::TEXTURED_QUAD_FRAGMENT_SHADER:
+    case vr::ShaderID::TEXTURED_QUAD_FRAGMENT_SHADER:
       return SHADER(
           /* clang-format off */
           precision highp float;
@@ -267,7 +267,7 @@
             gl_FragColor = color * opacity;
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::WEBVR_VERTEX_SHADER:
+    case vr::ShaderID::WEBVR_VERTEX_SHADER:
       return SHADER(
           /* clang-format off */
           precision mediump float;
@@ -279,7 +279,7 @@
             gl_Position = vec4(a_Position.xyz * 2.0, 1.0);
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::WEBVR_FRAGMENT_SHADER:
+    case vr::ShaderID::WEBVR_FRAGMENT_SHADER:
       return OEIE_SHADER(
           /* clang-format off */
           precision highp float;
@@ -290,7 +290,7 @@
             gl_FragColor = texture2D(u_Texture, v_TexCoordinate);
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::RETICLE_FRAGMENT_SHADER:
+    case vr::ShaderID::RETICLE_FRAGMENT_SHADER:
       return SHADER(
           /* clang-format off */
           precision mediump float;
@@ -326,7 +326,7 @@
             gl_FragColor = vec4(color_rgb * color.w * alpha, color.w * alpha);
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::LASER_FRAGMENT_SHADER:
+    case vr::ShaderID::LASER_FRAGMENT_SHADER:
       return SHADER(
           /* clang-format off */
           varying mediump vec2 v_TexCoordinate;
@@ -349,7 +349,7 @@
             gl_FragColor = vec4(final_color.xyz * final_opacity, final_opacity);
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::GRADIENT_QUAD_FRAGMENT_SHADER:
+    case vr::ShaderID::GRADIENT_QUAD_FRAGMENT_SHADER:
       return SHADER(
           /* clang-format off */
           precision lowp float;
@@ -367,7 +367,7 @@
                                 color.w * u_Opacity);
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::GRADIENT_GRID_FRAGMENT_SHADER:
+    case vr::ShaderID::GRADIENT_GRID_FRAGMENT_SHADER:
       return SHADER(
           /* clang-format off */
           precision lowp float;
@@ -402,7 +402,7 @@
             }
           }
           /* clang-format on */);
-    case vr_shell::ShaderID::CONTROLLER_FRAGMENT_SHADER:
+    case vr::ShaderID::CONTROLLER_FRAGMENT_SHADER:
       return SHADER(
           /* clang-format off */
           precision mediump float;
@@ -428,7 +428,7 @@
 
 }  // namespace
 
-namespace vr_shell {
+namespace vr {
 
 BaseRenderer::BaseRenderer(ShaderID vertex_id, ShaderID fragment_id) {
   std::string error;
@@ -1057,4 +1057,4 @@
   textured_quad_renderer_->Flush();
 }
 
-}  // namespace vr_shell
+}  // namespace vr
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.h b/chrome/browser/vr/vr_shell_renderer.h
similarity index 96%
rename from chrome/browser/android/vr_shell/vr_shell_renderer.h
rename to chrome/browser/vr/vr_shell_renderer.h
index 657fd4eb9..534dadc 100644
--- a/chrome/browser/android/vr_shell/vr_shell_renderer.h
+++ b/chrome/browser/vr/vr_shell_renderer.h
@@ -2,22 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_VR_SHELL_RENDERER_H_
-#define CHROME_BROWSER_ANDROID_VR_SHELL_VR_SHELL_RENDERER_H_
+#ifndef CHROME_BROWSER_VR_VR_SHELL_RENDERER_H_
+#define CHROME_BROWSER_VR_VR_SHELL_RENDERER_H_
 
 #include <memory>
 #include <queue>
 #include <vector>
 
 #include "base/macros.h"
-#include "chrome/browser/android/vr_shell/vr_controller_model.h"
 #include "chrome/browser/vr/ui_element_renderer.h"
+#include "chrome/browser/vr/vr_controller_model.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/size_f.h"
 #include "ui/gfx/transform.h"
 #include "ui/gl/gl_bindings.h"
 
-namespace vr_shell {
+namespace vr {
 
 constexpr float kFogBrightness = 0.57f;
 
@@ -327,6 +327,6 @@
   DISALLOW_COPY_AND_ASSIGN(VrShellRenderer);
 };
 
-}  // namespace vr_shell
+}  // namespace vr
 
-#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_VR_SHELL_RENDERER_H_
+#endif  // CHROME_BROWSER_VR_VR_SHELL_RENDERER_H_
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index a11cec4..ee8d811 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -312,10 +312,6 @@
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-// Enables the pref service. See https://crbug.com/654988.
-const base::Feature kPrefService{"PrefService",
-                                 base::FEATURE_DISABLED_BY_DEFAULT};
-
 #if defined(OS_CHROMEOS)
 // The lock screen will be preloaded so it is instantly available when the user
 // locks the Chromebook device.
@@ -435,14 +431,4 @@
                                       base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_CHROMEOS)
 
-bool PrefServiceEnabled() {
-  return base::FeatureList::IsEnabled(features::kPrefService) ||
-#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
-         base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-             switches::kMusConfig) == switches::kMash;
-#else
-         false;
-#endif
-}
-
 }  // namespace features
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 0f38c2f0f..afa4eb4 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -159,8 +159,6 @@
 extern const base::Feature kPreferHtmlOverPlugins;
 #endif
 
-extern const base::Feature kPrefService;
-
 #if defined(OS_CHROMEOS)
 extern const base::Feature kPreloadLockScreen;
 #endif
diff --git a/chrome/common/extensions/api/BUILD.gn b/chrome/common/extensions/api/BUILD.gn
index 902a539..8d2d73e 100644
--- a/chrome/common/extensions/api/BUILD.gn
+++ b/chrome/common/extensions/api/BUILD.gn
@@ -43,7 +43,6 @@
   "easy_unlock_private.idl",
   "experience_sampling_private.json",
   "feedback_private.idl",
-  "file_system.idl",
   "font_settings.json",
   "gcm.json",
   "history.json",
diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn
index 315f8b6..883a70c 100644
--- a/chrome/installer/linux/BUILD.gn
+++ b/chrome/installer/linux/BUILD.gn
@@ -191,10 +191,6 @@
     public_deps += [ ":rpm_packaging_files" ]
   }
 
-  # TODO(thomasanderson): Move this variable into a .gni file
-  # somewhere.  It is currently copied from
-  # buildtools/third_party/libc++/BUILD.gn.
-  libcpp_is_static = !is_component_build && !using_sanitizer
   if (!libcpp_is_static && use_custom_libcxx) {
     public_deps += [ "//buildtools/third_party/libc++:libc++" ]
   }
@@ -244,10 +240,6 @@
     ]
   }
 
-  # TODO(thomasanderson): Move this variable into a .gni file
-  # somewhere.  It is currently copied from
-  # buildtools/third_party/libc++/BUILD.gn.
-  libcpp_is_static = !is_component_build && !using_sanitizer
   if (!libcpp_is_static && use_custom_libcxx) {
     packaging_files_binaries += [ "$root_out_dir/libc++.so" ]
   }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 4c638ebc0..cfceb1c5a 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1446,6 +1446,7 @@
       "../browser/ssl/cert_verifier_browser_test.h",
       "../browser/ssl/certificate_reporting_test_utils.cc",
       "../browser/ssl/certificate_reporting_test_utils.h",
+      "../browser/ssl/chrome_expect_ct_reporter_browser_tests.cc",
       "../browser/ssl/chrome_ssl_host_state_delegate_test.cc",
       "../browser/ssl/security_state_tab_helper_browser_tests.cc",
       "../browser/ssl/ssl_browser_tests.cc",
@@ -3016,6 +3017,7 @@
     "../browser/android/physical_web/physical_web_data_source_android_unittest.cc",
     "../browser/android/preferences/pref_service_bridge_unittest.cc",
     "../browser/android/shortcut_info_unittest.cc",
+    "../browser/android/signin/signin_manager_android_unittest.cc",
     "../browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc",
     "../browser/android/webapk/webapk_icon_hasher_unittest.cc",
     "../browser/android/webapk/webapk_installer_unittest.cc",
@@ -3285,6 +3287,7 @@
 
     # TODO(hashimoto): those tests should be componentized and moved to
     # //components:components_unittests, http://crbug.com/527882.
+    "../browser/language/url_language_histogram_factory_unittest.cc",
     "../browser/search_engines/template_url_fetcher_unittest.cc",
     "../browser/search_engines/template_url_parser_unittest.cc",
     "../browser/search_engines/template_url_service_sync_unittest.cc",
@@ -3323,7 +3326,6 @@
     "../browser/thumbnails/thumbnail_service_unittest.cc",
     "../browser/thumbnails/thumbnail_utils_unittest.cc",
     "../browser/translate/chrome_translate_client_unittest.cc",
-    "../browser/translate/language_model_factory_unittest.cc",
     "../browser/translate/translate_service_unittest.cc",
     "../browser/ui/android/tab_model/tab_model_list_unittest.cc",
     "../browser/ui/android/tab_model/tab_model_unittest.cc",
@@ -3721,6 +3723,7 @@
       "../browser/ui/webui/settings/downloads_handler_unittest.cc",
       "../browser/ui/webui/settings/md_settings_ui_unittest.cc",
       "../browser/ui/webui/settings/metrics_reporting_handler_unittest.cc",
+      "../browser/ui/webui/settings/on_startup_handler_unittest.cc",
       "../browser/ui/webui/settings/people_handler_unittest.cc",
       "../browser/ui/webui/settings/profile_info_handler_unittest.cc",
       "../browser/ui/webui/settings/reset_settings_handler_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java
index 2ef79e0..698f061 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java
@@ -9,7 +9,6 @@
 import android.graphics.Bitmap;
 
 import org.chromium.base.Callback;
-import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo;
 import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
@@ -29,7 +28,7 @@
  * A fake Suggestions source for use in unit and instrumentation tests.
  */
 public class FakeSuggestionsSource implements SuggestionsSource {
-    private ObserverList<Observer> mObserverList = new ObserverList<>();
+    private SuggestionsSource.Observer mObserver;
     private final List<Integer> mCategories = new ArrayList<>();
     private final Map<Integer, List<SnippetArticle>> mSuggestions = new HashMap<>();
     private final Map<Integer, Integer> mCategoryStatus = new LinkedHashMap<>();
@@ -46,9 +45,6 @@
             new HashMap<>();
     private final Map<Integer, Integer> mDismissedCategoryStatus = new LinkedHashMap<>();
     private final Map<Integer, SuggestionsCategoryInfo> mDismissedCategoryInfo = new HashMap<>();
-
-    private boolean mRemoteSuggestionsEnabled = true;
-
     /**
      * Sets the status to be returned for a given category.
      */
@@ -59,7 +55,7 @@
         } else if (!mCategories.contains(category)) {
             mCategories.add(category);
         }
-        for (Observer observer : mObserverList) observer.onCategoryStatusChanged(category, status);
+        if (mObserver != null) mObserver.onCategoryStatusChanged(category, status);
     }
 
     /**
@@ -69,7 +65,7 @@
             @CategoryInt int category, List<SnippetArticle> suggestions) {
         // Copy the suggestions list so that it can't be modified anymore.
         mSuggestions.put(category, new ArrayList<>(suggestions));
-        for (Observer observer : mObserverList) observer.onNewSuggestions(category);
+        if (mObserver != null) mObserver.onNewSuggestions(category);
     }
 
     /**
@@ -140,16 +136,14 @@
                 break;
             }
         }
-        for (Observer observer : mObserverList) {
-            observer.onSuggestionInvalidated(category, idWithinCategory);
-        }
+        mObserver.onSuggestionInvalidated(category, idWithinCategory);
     }
 
     /**
      * Notifies the observer that a full refresh is required.
      */
     public void fireFullRefreshRequired() {
-        for (Observer observer : mObserverList) observer.onFullRefreshRequired();
+        mObserver.onFullRefreshRequired();
     }
 
     /**
@@ -166,15 +160,6 @@
     public void fetchRemoteSuggestions() {}
 
     @Override
-    public boolean areRemoteSuggestionsEnabled() {
-        return mRemoteSuggestionsEnabled;
-    }
-
-    public void setRemoteSuggestionsEnabled(boolean enabled) {
-        mRemoteSuggestionsEnabled = enabled;
-    }
-
-    @Override
     public void dismissSuggestion(SnippetArticle suggestion) {
         for (List<SnippetArticle> suggestions : mSuggestions.values()) {
             suggestions.remove(suggestion);
@@ -244,13 +229,8 @@
     }
 
     @Override
-    public void addObserver(Observer observer) {
-        mObserverList.addObserver(observer);
-    }
-
-    @Override
-    public void removeObserver(Observer observer) {
-        mObserverList.removeObserver(observer);
+    public void setObserver(Observer observer) {
+        mObserver = observer;
     }
 
     @Override
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 3ca823299..3bc34cc 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -833,8 +833,7 @@
   // Simplified version of ProfileImpl::GetOffTheRecordPrefs(). Note this
   // leaves testing_prefs_ unset.
   prefs_.reset(CreateIncognitoPrefServiceSyncable(
-      original_profile_->prefs_.get(), nullptr,
-      std::set<PrefValueStore::PrefStoreType>(), nullptr, nullptr));
+      original_profile_->prefs_.get(), nullptr, nullptr));
   user_prefs::UserPrefs::Set(this, prefs_.get());
 }
 
@@ -1055,12 +1054,6 @@
   return last_session_exited_cleanly_ ? EXIT_NORMAL : EXIT_CRASHED;
 }
 
-scoped_refptr<base::SequencedTaskRunner>
-TestingProfile::GetPrefServiceTaskRunner() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
 TestingProfile::Builder::Builder()
     : build_called_(false),
       delegate_(NULL),
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index 9aefe2d..2384f0c 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -327,7 +327,6 @@
   bool IsGuestSession() const override;
   void SetExitType(ExitType exit_type) override {}
   ExitType GetLastSessionExitType() override;
-  scoped_refptr<base::SequencedTaskRunner> GetPrefServiceTaskRunner() override;
 #if defined(OS_CHROMEOS)
   void ChangeAppLocale(const std::string&, AppLocaleChangedVia) override {}
   void OnLogin() override {}
diff --git a/chrome/test/data/payments/basic_card.js b/chrome/test/data/payments/payment_method_identifier.js
similarity index 100%
rename from chrome/test/data/payments/basic_card.js
rename to chrome/test/data/payments/payment_method_identifier.js
diff --git a/chrome/test/data/payments/payment_request_basic_card_test.html b/chrome/test/data/payments/payment_request_payment_method_identifier_test.html
similarity index 95%
rename from chrome/test/data/payments/payment_request_basic_card_test.html
rename to chrome/test/data/payments/payment_request_payment_method_identifier_test.html
index 541c32e3..425e667 100644
--- a/chrome/test/data/payments/payment_request_basic_card_test.html
+++ b/chrome/test/data/payments/payment_request_payment_method_identifier_test.html
@@ -23,6 +23,6 @@
 <button onclick="buyBasicMasterCard()" id="buyBasicMasterCard">Buy With Basic MasterCardTest</button>
 <pre id="result"></pre>
 <script src="util.js"></script>
-<script src="basic_card.js"></script>
+<script src="payment_method_identifier.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/extensions/extension_load_error_test.js b/chrome/test/data/webui/extensions/extension_load_error_test.js
index d7b18b7..54787b6 100644
--- a/chrome/test/data/webui/extensions/extension_load_error_test.js
+++ b/chrome/test/data/webui/extensions/extension_load_error_test.js
@@ -61,11 +61,11 @@
         expectTrue(isDialogVisible());
 
         mockDelegate.testClickingCalls(
-            loadError.$$('#retry'), 'retryLoadUnpacked', [fakeGuid]);
+            loadError.$$('.action-button'), 'retryLoadUnpacked', [fakeGuid]);
         expectFalse(isDialogVisible());
 
         loadError.show();
-        MockInteractions.tap(loadError.$$('#dismiss'));
+        MockInteractions.tap(loadError.$$('.cancel-button'));
         expectFalse(isDialogVisible());
       });
 
diff --git a/chrome/test/data/webui/extensions/extension_options_dialog_test.js b/chrome/test/data/webui/extensions/extension_options_dialog_test.js
index 7a44af6..890b419 100644
--- a/chrome/test/data/webui/extensions/extension_options_dialog_test.js
+++ b/chrome/test/data/webui/extensions/extension_options_dialog_test.js
@@ -46,11 +46,11 @@
             assert(optionsDialog.$$('#icon-and-name-wrapper span')).
                 textContent.trim());
 
-        var mainDiv = optionsDialog.$.main;
+        var optionEle = optionsDialog.$$('extensionoptions');
 
         // To start, the options page should be set to the min width/height.
-        expectEquals(MIN_HEIGHT, mainDiv.style.height);
-        expectEquals(MIN_WIDTH, mainDiv.style.width);
+        expectEquals(MIN_HEIGHT, optionEle.style.height);
+        expectEquals(MIN_WIDTH, optionEle.style.width);
 
         var mockOptions = optionsDialog.extensionOptions_;
         expectEquals(data.id, mockOptions.extension);
@@ -58,19 +58,19 @@
         // Setting the preferred size to something below the min width/height
         // shouldn't change the actual width/height.
         mockOptions.onpreferredsizechanged({height: 100, width: 100});
-        expectEquals(MIN_HEIGHT, mainDiv.style.height);
-        expectEquals(MIN_WIDTH, mainDiv.style.width);
+        expectEquals(MIN_HEIGHT, optionEle.style.height);
+        expectEquals(MIN_WIDTH, optionEle.style.width);
 
         // Setting the preferred size to between the min and max dimensions
         // should change the dimensions.
         mockOptions.onpreferredsizechanged({height: 500, width: 400});
-        expectEquals('500px', mainDiv.style.height);
-        expectEquals('400px', mainDiv.style.width);
+        expectEquals('500px', optionEle.style.height);
+        expectEquals('400px', optionEle.style.width);
 
         // Max values should pin the dialog.
         mockOptions.onpreferredsizechanged({height: 900, width: 400});
-        expectEquals(MAX_HEIGHT, mainDiv.style.height);
-        expectEquals('400px', mainDiv.style.width);
+        expectEquals(MAX_HEIGHT, optionEle.style.height);
+        expectEquals('400px', optionEle.style.width);
 
         mockOptions.onclose();
         expectFalse(isDialogVisible());
@@ -88,15 +88,15 @@
                 textContent.trim());
         // The width of the dialog should be set to match the width of the
         // header, which is greater than the default min width.
-        expectTrue(mainDiv.style.width > MIN_WIDTH, mainDiv.style.height);
-        expectEquals(MIN_HEIGHT, mainDiv.style.height);
+        expectTrue(optionsDialog.$.dialog.style.width > MIN_WIDTH);
+        expectEquals(MIN_HEIGHT, optionEle.style.height);
 
         // Going back to an extension with a shorter name should resize the
         // dialog.
         optionsDialog.close();
         optionsDialog.show(data);
-        expectEquals(MIN_HEIGHT, mainDiv.style.height);
-        expectEquals(MIN_WIDTH, mainDiv.style.width);
+        expectEquals(MIN_HEIGHT, optionEle.style.height);
+        expectEquals(MIN_WIDTH, optionEle.style.width);
       });
     });
   }
diff --git a/chrome/test/data/webui/extensions/extension_pack_dialog_test.js b/chrome/test/data/webui/extensions/extension_pack_dialog_test.js
index 299b5f4a..60b8860c 100644
--- a/chrome/test/data/webui/extensions/extension_pack_dialog_test.js
+++ b/chrome/test/data/webui/extensions/extension_pack_dialog_test.js
@@ -88,7 +88,7 @@
         mockDelegate.keyPromise.resolve(kKeyPath);
 
         return Promise.all(promises).then(function() {
-          MockInteractions.tap(packDialog.$$('#confirm'));
+          MockInteractions.tap(packDialog.$$('.action-button'));
           expectEquals(kRootPath, mockDelegate.rootPath);
           expectEquals(kKeyPath, mockDelegate.keyPath);
           expectFalse(isDialogVisible());
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index a8a0515..2ee706cc 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -1640,6 +1640,29 @@
   mocha.run();
 });
 
+/**
+ * Test fixture for the multidevice settings page.
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsMultidevicePageTest() {}
+
+CrSettingsMultidevicePageTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://md-settings/multidevice_page/multidevice_page.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    'multidevice_page_tests.js',
+  ]),
+};
+
+TEST_F('CrSettingsMultidevicePageTest', 'All', function() {
+  mocha.run();
+});
+
 GEN('#endif');
 
 GEN('#if defined(OS_CHROMEOS)');
diff --git a/chrome/test/data/webui/settings/multidevice_page_tests.js b/chrome/test/data/webui/settings/multidevice_page_tests.js
new file mode 100644
index 0000000..6a0f7aa
--- /dev/null
+++ b/chrome/test/data/webui/settings/multidevice_page_tests.js
@@ -0,0 +1,27 @@
+// 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.
+
+suite('Multidevice', function() {
+  var multidevicePage = null;
+
+  suiteSetup(function() {
+  });
+
+  setup(function() {
+    PolymerTest.clearBody();
+    multidevicePage = document.createElement('settings-multidevice-page');
+    assertTrue(!!multidevicePage);
+
+    document.body.appendChild(multidevicePage);
+    Polymer.dom.flush();
+  });
+
+  teardown(function() {
+    multidevicePage.remove();
+  });
+
+  test('MainPage', function() {
+    // TODO: Write test once the setting is actually functional.
+  });
+});
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
index 0604c6d..585bc33 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -56,13 +56,12 @@
 const char kSendMessageAndExpectConnectionCloseOnErrorScript[] =
     "sendMessageAndExpectConnectionCloseOnError()";
 const char kChooseSinkScript[] =
-    "var sinks = document.getElementById('media-router-container')."
-    "  shadowRoot.getElementById('sink-list').getElementsByTagName('span');"
-    "for (var i=0; i<sinks.length; i++) {"
-    "  if(sinks[i].textContent.trim() == '%s') {"
-    "    sinks[i].click();"
-    "    break;"
-    "}}";
+    "var sinks = Array.from(document.getElementById('media-router-container')."
+    "  shadowRoot.getElementById('sink-list').getElementsByTagName('span'));"
+    "var sink = sinks.find(sink => sink.textContent.trim() == '%s');"
+    "if (sink) {"
+    "  sink.click();"
+    "}";
 const char kCloseRouteScript[] =
     "window.document.getElementById('media-router-container').shadowRoot."
     "  getElementById('route-details').shadowRoot.getElementById("
@@ -72,31 +71,23 @@
 const char kGetSinkIdScript[] =
     "var sinks = window.document.getElementById('media-router-container')."
     "  allSinks;"
-    "for (var i=0; i<sinks.length; i++) {"
-    "  if (sinks[i].name == '%s') {"
-    "    domAutomationController.send(sinks[i].id);"
-    "  }"
-    "}"
-    "domAutomationController.send('');";
+    "var sink = sinks.find(sink => sink.name == '%s');"
+    "window.domAutomationController.send(sink ? sink.id : '');";
 const char kGetRouteIdScript[] =
     "var routes = window.document.getElementById('media-router-container')."
     "  routeList;"
-    "for (var i=0; i<routes.length; i++) {"
-    "  if (routes[i].sinkId == '%s') {"
-    "    domAutomationController.send(routes[i].id);"
-    "  }"
-    "}"
-    "domAutomationController.send('');";
+    "var route = routes.find(route => route.sinkId == '%s');"
+    "window.domAutomationController.send(route ? route.id : '');";
 const char kFindSinkScript[] =
     "var sinkList = document.getElementById('media-router-container')."
     "  shadowRoot.getElementById('sink-list');"
-    "if (sinkList) {"
-    "  var sinks = sinkList.getElementsByTagName('span');"
-    "  for (var i=0; i<sinks.length; i++) {"
-    "    if (sinks[i].textContent.trim() == '%s') {"
-    "      domAutomationController.send(true);"
-    "}}}"
-    "domAutomationController.send(false);";
+    "if (!sinkList) {"
+    "  window.domAutomationController.send(false);"
+    "} else {"
+    "  var sinks = Array.from(sinkList.getElementsByTagName('span'));"
+    "  var result = sinks.some(sink => sink.textContent.trim() == '%s');"
+    "  window.domAutomationController.send(result);"
+    "}";
 const char kCheckDialogLoadedScript[] =
     "var container = document.getElementById('media-router-container');"
     "/** Wait until media router container is not undefined and "
@@ -104,10 +95,8 @@
     "*   once deviceMissingUrl is not undefined, which means "
     "*   the dialog is fully loaded."
     "*/"
-    "if (container != undefined && container.deviceMissingUrl != undefined) {"
-    "  domAutomationController.send(true);"
-    "}"
-    "domAutomationController.send(false);";
+    "window.domAutomationController.send(!!container && "
+    "    !!container.deviceMissingUrl);";
 
 std::string GetStartedConnectionId(WebContents* web_contents) {
   std::string session_id;
diff --git a/chrome/test/media_router/resources/common.js b/chrome/test/media_router/resources/common.js
index 05b8d9b..7942413 100644
--- a/chrome/test/media_router/resources/common.js
+++ b/chrome/test/media_router/resources/common.js
@@ -122,13 +122,13 @@
     }).catch(function(e) {
       if (expectedErrorName != e.name) {
         sendResult(false, 'Got unexpected error: ' + e.name);
-      }
-      if (e.message.indexOf(expectedErrorMessageSubstring) == -1) {
+      } else if (e.message.indexOf(expectedErrorMessageSubstring) == -1) {
         sendResult(false,
-          'Error message is not correct, it should contain "' +
-          expectedErrorMessageSubstring + '"');
+            'Error message is not correct, it should contain "' +
+            expectedErrorMessageSubstring + '"');
+      } else {
+        sendResult(true, '');
       }
-      sendResult(true, '');
     })
   }
 }
@@ -154,6 +154,7 @@
   if (startedConnection) {
     if (startedConnection.state == 'closed') {
       sendResult(false, 'startedConnection is unexpectedly closed.');
+      return;
     }
     startedConnection.onclose = function() {
       sendResult(true, '');
diff --git a/chromeos/components/tether/BUILD.gn b/chromeos/components/tether/BUILD.gn
index 563cff6..07bde75 100644
--- a/chromeos/components/tether/BUILD.gn
+++ b/chromeos/components/tether/BUILD.gn
@@ -59,6 +59,8 @@
     "network_connection_handler_tether_delegate.cc",
     "network_connection_handler_tether_delegate.h",
     "notification_presenter.h",
+    "persistent_host_scan_cache.cc",
+    "persistent_host_scan_cache.h",
     "pref_names.cc",
     "pref_names.h",
     "tether_connector.cc",
@@ -115,6 +117,8 @@
     "fake_tether_host_fetcher.h",
     "fake_wifi_hotspot_connector.cc",
     "fake_wifi_hotspot_connector.h",
+    "host_scan_test_util.cc",
+    "host_scan_test_util.h",
     "mock_host_connection_metrics_logger.cc",
     "mock_host_connection_metrics_logger.h",
     "mock_tether_host_response_recorder.cc",
@@ -164,6 +168,7 @@
     "message_wrapper_unittest.cc",
     "network_configuration_remover_unittest.cc",
     "network_connection_handler_tether_delegate_unittest.cc",
+    "persistent_host_scan_cache_unittest.cc",
     "tether_connector_unittest.cc",
     "tether_disconnector_impl_unittest.cc",
     "tether_host_fetcher_unittest.cc",
diff --git a/chromeos/components/tether/host_scan_cache_entry.cc b/chromeos/components/tether/host_scan_cache_entry.cc
index 10ceb06e..83b15483 100644
--- a/chromeos/components/tether/host_scan_cache_entry.cc
+++ b/chromeos/components/tether/host_scan_cache_entry.cc
@@ -81,6 +81,14 @@
 
 HostScanCacheEntry::~HostScanCacheEntry() {}
 
+bool HostScanCacheEntry::operator==(const HostScanCacheEntry& other) const {
+  return tether_network_guid == other.tether_network_guid &&
+         device_name == other.device_name && carrier == other.carrier &&
+         battery_percentage == other.battery_percentage &&
+         signal_strength == other.signal_strength &&
+         setup_required == other.setup_required;
+}
+
 }  // namespace tether
 
 }  // namespace chromeos
diff --git a/chromeos/components/tether/host_scan_cache_entry.h b/chromeos/components/tether/host_scan_cache_entry.h
index 150e512..eefa682 100644
--- a/chromeos/components/tether/host_scan_cache_entry.h
+++ b/chromeos/components/tether/host_scan_cache_entry.h
@@ -43,6 +43,8 @@
   HostScanCacheEntry(const HostScanCacheEntry& other);
   virtual ~HostScanCacheEntry();
 
+  bool operator==(const HostScanCacheEntry& other) const;
+
   // GUID corresponding to the scanned device.
   const std::string tether_network_guid;
 
diff --git a/chromeos/components/tether/host_scan_test_util.cc b/chromeos/components/tether/host_scan_test_util.cc
new file mode 100644
index 0000000..bc32fc9
--- /dev/null
+++ b/chromeos/components/tether/host_scan_test_util.cc
@@ -0,0 +1,63 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/tether/host_scan_test_util.h"
+
+namespace chromeos {
+
+namespace tether {
+
+namespace host_scan_test_util {
+
+std::unordered_map<std::string, HostScanCacheEntry> CreateTestEntries() {
+  std::unordered_map<std::string, HostScanCacheEntry> entries;
+
+  entries.emplace(kTetherGuid0,
+                  *HostScanCacheEntry::Builder()
+                       .SetTetherNetworkGuid(kTetherGuid0)
+                       .SetDeviceName(kTetherDeviceName0)
+                       .SetCarrier(kTetherCarrier0)
+                       .SetBatteryPercentage(kTetherBatteryPercentage0)
+                       .SetSignalStrength(kTetherSignalStrength0)
+                       .SetSetupRequired(kTetherSetupRequired0)
+                       .Build());
+
+  entries.emplace(kTetherGuid1,
+                  *HostScanCacheEntry::Builder()
+                       .SetTetherNetworkGuid(kTetherGuid1)
+                       .SetDeviceName(kTetherDeviceName1)
+                       .SetCarrier(kTetherCarrier1)
+                       .SetBatteryPercentage(kTetherBatteryPercentage1)
+                       .SetSignalStrength(kTetherSignalStrength1)
+                       .SetSetupRequired(kTetherSetupRequired1)
+                       .Build());
+
+  entries.emplace(kTetherGuid2,
+                  *HostScanCacheEntry::Builder()
+                       .SetTetherNetworkGuid(kTetherGuid2)
+                       .SetDeviceName(kTetherDeviceName2)
+                       .SetCarrier(kTetherCarrier2)
+                       .SetBatteryPercentage(kTetherBatteryPercentage2)
+                       .SetSignalStrength(kTetherSignalStrength2)
+                       .SetSetupRequired(kTetherSetupRequired2)
+                       .Build());
+
+  entries.emplace(kTetherGuid3,
+                  *HostScanCacheEntry::Builder()
+                       .SetTetherNetworkGuid(kTetherGuid3)
+                       .SetDeviceName(kTetherDeviceName3)
+                       .SetCarrier(kTetherCarrier3)
+                       .SetBatteryPercentage(kTetherBatteryPercentage3)
+                       .SetSignalStrength(kTetherSignalStrength3)
+                       .SetSetupRequired(kTetherSetupRequired3)
+                       .Build());
+
+  return entries;
+}
+
+}  // namespace host_scan_test_util
+
+}  // namespace tether
+
+}  // namespace chromeos
diff --git a/chromeos/components/tether/host_scan_test_util.h b/chromeos/components/tether/host_scan_test_util.h
new file mode 100644
index 0000000..a221a20
--- /dev/null
+++ b/chromeos/components/tether/host_scan_test_util.h
@@ -0,0 +1,60 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_TETHER_HOST_SCAN_TEST_UTIL_H_
+#define CHROMEOS_COMPONENTS_TETHER_HOST_SCAN_TEST_UTIL_H_
+
+#include <string>
+#include <unordered_map>
+
+#include "chromeos/components/tether/host_scan_cache_entry.h"
+
+namespace chromeos {
+
+namespace tether {
+
+namespace host_scan_test_util {
+
+constexpr char kTetherGuid0[] = "kTetherGuid0";
+constexpr char kTetherGuid1[] = "kTetherGuid1";
+constexpr char kTetherGuid2[] = "kTetherGuid2";
+constexpr char kTetherGuid3[] = "kTetherGuid3";
+
+constexpr char kTetherDeviceName0[] = "kDeviceName0";
+constexpr char kTetherDeviceName1[] = "kDeviceName1";
+constexpr char kTetherDeviceName2[] = "kDeviceName2";
+constexpr char kTetherDeviceName3[] = "kDeviceName3";
+
+constexpr char kTetherCarrier0[] = "kTetherCarrier0";
+constexpr char kTetherCarrier1[] = "kTetherCarrier1";
+constexpr char kTetherCarrier2[] = "kTetherCarrier2";
+constexpr char kTetherCarrier3[] = "kTetherCarrier3";
+
+constexpr int kTetherBatteryPercentage0 = 20;
+constexpr int kTetherBatteryPercentage1 = 40;
+constexpr int kTetherBatteryPercentage2 = 60;
+constexpr int kTetherBatteryPercentage3 = 80;
+
+constexpr int kTetherSignalStrength0 = 25;
+constexpr int kTetherSignalStrength1 = 50;
+constexpr int kTetherSignalStrength2 = 75;
+constexpr int kTetherSignalStrength3 = 100;
+
+constexpr bool kTetherSetupRequired0 = true;
+constexpr bool kTetherSetupRequired1 = false;
+constexpr bool kTetherSetupRequired2 = true;
+constexpr bool kTetherSetupRequired3 = false;
+
+// Returns a map from tether network GUID to entry containing test entries.
+// The returned map has 4 entries corresponding to the 4 sets of constains
+// defined above.
+std::unordered_map<std::string, HostScanCacheEntry> CreateTestEntries();
+
+}  // namespace host_scan_test_util
+
+}  // namespace tether
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_TETHER_HOST_SCAN_TEST_UTIL_H_
diff --git a/chromeos/components/tether/initializer.cc b/chromeos/components/tether/initializer.cc
index 7ebafd7..3da98de 100644
--- a/chromeos/components/tether/initializer.cc
+++ b/chromeos/components/tether/initializer.cc
@@ -18,6 +18,7 @@
 #include "chromeos/components/tether/network_configuration_remover.h"
 #include "chromeos/components/tether/network_connection_handler_tether_delegate.h"
 #include "chromeos/components/tether/notification_presenter.h"
+#include "chromeos/components/tether/persistent_host_scan_cache.h"
 #include "chromeos/components/tether/tether_connector.h"
 #include "chromeos/components/tether/tether_disconnector_impl.h"
 #include "chromeos/components/tether/tether_host_fetcher.h"
@@ -94,6 +95,7 @@
 // static
 void Initializer::RegisterProfilePrefs(PrefRegistrySimple* registry) {
   ActiveHost::RegisterPrefs(registry);
+  PersistentHostScanCache::RegisterPrefs(registry);
   TetherHostResponseRecorder::RegisterPrefs(registry);
   TetherDisconnectorImpl::RegisterPrefs(registry);
 }
diff --git a/chromeos/components/tether/master_host_scan_cache_unittest.cc b/chromeos/components/tether/master_host_scan_cache_unittest.cc
index 9632631..78e6172 100644
--- a/chromeos/components/tether/master_host_scan_cache_unittest.cc
+++ b/chromeos/components/tether/master_host_scan_cache_unittest.cc
@@ -15,6 +15,7 @@
 #include "chromeos/components/tether/device_id_tether_network_guid_map.h"
 #include "chromeos/components/tether/fake_active_host.h"
 #include "chromeos/components/tether/fake_host_scan_cache.h"
+#include "chromeos/components/tether/host_scan_test_util.h"
 #include "chromeos/components/tether/mock_tether_host_response_recorder.h"
 #include "chromeos/components/tether/timer_factory.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -33,36 +34,6 @@
 
 namespace {
 
-const char kTetherGuid0[] = "kTetherGuid0";
-const char kTetherGuid1[] = "kTetherGuid1";
-const char kTetherGuid2[] = "kTetherGuid2";
-const char kTetherGuid3[] = "kTetherGuid3";
-
-const char kTetherDeviceName0[] = "kDeviceName0";
-const char kTetherDeviceName1[] = "kDeviceName1";
-const char kTetherDeviceName2[] = "kDeviceName2";
-const char kTetherDeviceName3[] = "kDeviceName3";
-
-const char kTetherCarrier0[] = "kTetherCarrier0";
-const char kTetherCarrier1[] = "kTetherCarrier1";
-const char kTetherCarrier2[] = "kTetherCarrier2";
-const char kTetherCarrier3[] = "kTetherCarrier3";
-
-const int kTetherBatteryPercentage0 = 20;
-const int kTetherBatteryPercentage1 = 40;
-const int kTetherBatteryPercentage2 = 60;
-const int kTetherBatteryPercentage3 = 80;
-
-const int kTetherSignalStrength0 = 25;
-const int kTetherSignalStrength1 = 50;
-const int kTetherSignalStrength2 = 75;
-const int kTetherSignalStrength3 = 100;
-
-const bool kTetherSetupRequired0 = true;
-const bool kTetherSetupRequired1 = false;
-const bool kTetherSetupRequired2 = true;
-const bool kTetherSetupRequired3 = false;
-
 // MockTimer which invokes a callback in its destructor.
 class ExtendedMockTimer : public base::MockTimer {
  public:
@@ -121,7 +92,8 @@
 // FakeHostScanCache if possible.
 class MasterHostScanCacheTest : public NetworkStateTest {
  protected:
-  MasterHostScanCacheTest() {}
+  MasterHostScanCacheTest()
+      : test_entries_(host_scan_test_util::CreateTestEntries()) {}
 
   void SetUp() override {
     DBusThreadManager::Initialize();
@@ -201,51 +173,28 @@
   // Sets host scan results in the cache for the device at index |index|. Index
   // can be from 0 to 3 and corresponds to the index of the constants declared
   // at the top of this test file.
-  void SetCacheScanResultForDeviceIndex(int32_t index) {
-    // There are 4 sets of test constants.
-    ASSERT_TRUE(index >= 0 && index <= 3);
+  void SetCacheScanResultForDeviceIndex(uint32_t index) {
+    ASSERT_TRUE(index >= 0 && index <= test_entries_.size());
 
-    HostScanCacheEntry::Builder builder;
-
+    std::string tether_network_guid;
     switch (index) {
       case 0:
-        builder.SetTetherNetworkGuid(kTetherGuid0)
-            .SetDeviceName(kTetherDeviceName0)
-            .SetCarrier(kTetherCarrier0)
-            .SetBatteryPercentage(kTetherBatteryPercentage0)
-            .SetSignalStrength(kTetherSignalStrength0)
-            .SetSetupRequired(kTetherSetupRequired0);
+        tether_network_guid = host_scan_test_util::kTetherGuid0;
         break;
-      case 1:
-        builder.SetTetherNetworkGuid(kTetherGuid1)
-            .SetDeviceName(kTetherDeviceName1)
-            .SetCarrier(kTetherCarrier1)
-            .SetBatteryPercentage(kTetherBatteryPercentage1)
-            .SetSignalStrength(kTetherSignalStrength1)
-            .SetSetupRequired(kTetherSetupRequired1);
+      case 1u:
+        tether_network_guid = host_scan_test_util::kTetherGuid1;
         break;
-      case 2:
-        builder.SetTetherNetworkGuid(kTetherGuid2)
-            .SetDeviceName(kTetherDeviceName2)
-            .SetCarrier(kTetherCarrier2)
-            .SetBatteryPercentage(kTetherBatteryPercentage2)
-            .SetSignalStrength(kTetherSignalStrength2)
-            .SetSetupRequired(kTetherSetupRequired2);
+      case 2u:
+        tether_network_guid = host_scan_test_util::kTetherGuid2;
         break;
-      case 3:
-        builder.SetTetherNetworkGuid(kTetherGuid3)
-            .SetDeviceName(kTetherDeviceName3)
-            .SetCarrier(kTetherCarrier3)
-            .SetBatteryPercentage(kTetherBatteryPercentage3)
-            .SetSignalStrength(kTetherSignalStrength3)
-            .SetSetupRequired(kTetherSetupRequired3);
+      case 3u:
+        tether_network_guid = host_scan_test_util::kTetherGuid3;
         break;
       default:
         NOTREACHED();
-        break;
     }
 
-    SetHostScanResult(*builder.Build());
+    SetHostScanResult(test_entries_.at(tether_network_guid));
   }
 
   void SetHostScanResult(const HostScanCacheEntry& entry) {
@@ -305,6 +254,7 @@
   }
 
   const base::test::ScopedTaskEnvironment scoped_task_environment_;
+  const std::unordered_map<std::string, HostScanCacheEntry> test_entries_;
 
   TestTimerFactory* test_timer_factory_;
   std::unique_ptr<FakeActiveHost> fake_active_host_;
@@ -328,31 +278,31 @@
   EXPECT_EQ(1u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  SetCacheScanResultForDeviceIndex(1);
+  SetCacheScanResultForDeviceIndex(1u);
   EXPECT_EQ(2u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  SetCacheScanResultForDeviceIndex(2);
+  SetCacheScanResultForDeviceIndex(2u);
   EXPECT_EQ(3u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  SetCacheScanResultForDeviceIndex(3);
+  SetCacheScanResultForDeviceIndex(3u);
   EXPECT_EQ(4u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  FireTimer(kTetherGuid0);
+  FireTimer(host_scan_test_util::kTetherGuid0);
   EXPECT_EQ(3u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  FireTimer(kTetherGuid1);
+  FireTimer(host_scan_test_util::kTetherGuid1);
   EXPECT_EQ(2u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  FireTimer(kTetherGuid2);
+  FireTimer(host_scan_test_util::kTetherGuid2);
   EXPECT_EQ(1u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  FireTimer(kTetherGuid3);
+  FireTimer(host_scan_test_util::kTetherGuid3);
   EXPECT_TRUE(expected_cache_->empty());
   VerifyCacheMatchesNetworkStack();
 }
@@ -364,19 +314,20 @@
 
   // Change the fields for tether network with GUID |kTetherGuid0| to the
   // fields corresponding to |kTetherGuid1|.
-  SetHostScanResult(*HostScanCacheEntry::Builder()
-                         .SetTetherNetworkGuid(kTetherGuid0)
-                         .SetDeviceName(kTetherDeviceName0)
-                         .SetCarrier(kTetherCarrier1)
-                         .SetBatteryPercentage(kTetherBatteryPercentage1)
-                         .SetSignalStrength(kTetherSignalStrength1)
-                         .SetSetupRequired(kTetherSetupRequired1)
-                         .Build());
+  SetHostScanResult(
+      *HostScanCacheEntry::Builder()
+           .SetTetherNetworkGuid(host_scan_test_util::kTetherGuid0)
+           .SetDeviceName(host_scan_test_util::kTetherDeviceName0)
+           .SetCarrier(host_scan_test_util::kTetherCarrier1)
+           .SetBatteryPercentage(host_scan_test_util::kTetherBatteryPercentage1)
+           .SetSignalStrength(host_scan_test_util::kTetherSignalStrength1)
+           .SetSetupRequired(host_scan_test_util::kTetherSetupRequired1)
+           .Build());
   EXPECT_EQ(1u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
   // Now, remove that result.
-  RemoveHostScanResult(kTetherGuid0);
+  RemoveHostScanResult(host_scan_test_util::kTetherGuid0);
   EXPECT_TRUE(expected_cache_->empty());
   VerifyCacheMatchesNetworkStack();
 }
@@ -386,16 +337,16 @@
   EXPECT_EQ(1u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  SetCacheScanResultForDeviceIndex(1);
+  SetCacheScanResultForDeviceIndex(1u);
   EXPECT_EQ(2u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  SetCacheScanResultForDeviceIndex(2);
+  SetCacheScanResultForDeviceIndex(2u);
   EXPECT_EQ(3u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
   // Now, set the active host to be the device 0.
-  SetActiveHost(kTetherGuid0);
+  SetActiveHost(host_scan_test_util::kTetherGuid0);
 
   // Clear the cache except for the active host.
   ClearCacheExceptForActiveHost();
@@ -404,13 +355,13 @@
 
   // Attempt to remove the active host. This operation should fail since
   // removing the active host from the cache is not allowed.
-  RemoveHostScanResult(kTetherGuid0);
+  RemoveHostScanResult(host_scan_test_util::kTetherGuid0);
   EXPECT_EQ(1u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
   // Fire the timer for the active host. Likewise, this should not result in the
   // cache entry being removed.
-  FireTimer(kTetherGuid0);
+  FireTimer(host_scan_test_util::kTetherGuid0);
   EXPECT_EQ(1u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
@@ -418,26 +369,26 @@
   SetActiveHost("");
 
   // Removing the device should now succeed.
-  RemoveHostScanResult(kTetherGuid0);
+  RemoveHostScanResult(host_scan_test_util::kTetherGuid0);
   EXPECT_TRUE(expected_cache_->empty());
   VerifyCacheMatchesNetworkStack();
 }
 
 TEST_F(MasterHostScanCacheTest, TestHasConnectedToHost) {
   // Before the test starts, set device 0 as having already connected.
-  SetHasConnectedToHost(kTetherGuid0);
+  SetHasConnectedToHost(host_scan_test_util::kTetherGuid0);
 
   SetCacheScanResultForDeviceIndex(0);
   EXPECT_EQ(1u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
-  SetCacheScanResultForDeviceIndex(1);
+  SetCacheScanResultForDeviceIndex(1u);
   EXPECT_EQ(2u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
   // Simulate a connection to device 1.
-  SetActiveHost(kTetherGuid1);
-  SetHasConnectedToHost(kTetherGuid1);
+  SetActiveHost(host_scan_test_util::kTetherGuid1);
+  SetHasConnectedToHost(host_scan_test_util::kTetherGuid1);
   VerifyCacheMatchesNetworkStack();
 }
 
diff --git a/chromeos/components/tether/persistent_host_scan_cache.cc b/chromeos/components/tether/persistent_host_scan_cache.cc
new file mode 100644
index 0000000..4f87e250
--- /dev/null
+++ b/chromeos/components/tether/persistent_host_scan_cache.cc
@@ -0,0 +1,201 @@
+// 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 "chromeos/components/tether/persistent_host_scan_cache.h"
+
+#include <unordered_set>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "chromeos/components/tether/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/proximity_auth/logging/logging.h"
+
+namespace chromeos {
+
+namespace tether {
+
+namespace {
+
+constexpr char kTetherNetworkGuidKey[] = "tether_network_guid";
+constexpr char kDeviceNameKey[] = "device_name";
+constexpr char kCarrierKey[] = "carrier";
+constexpr char kBatteryPercentageKey[] = "battery_percentage";
+constexpr char kSignalStrengthKey[] = "signal_strength";
+constexpr char kSetupRequiredKey[] = "setup_required";
+
+std::unique_ptr<base::DictionaryValue> HostScanCacheEntryToDictionary(
+    const HostScanCacheEntry& entry) {
+  std::unique_ptr<base::DictionaryValue> dictionary =
+      base::MakeUnique<base::DictionaryValue>();
+
+  dictionary->SetString(kTetherNetworkGuidKey, entry.tether_network_guid);
+  dictionary->SetString(kDeviceNameKey, entry.device_name);
+  dictionary->SetString(kCarrierKey, entry.carrier);
+  dictionary->SetInteger(kBatteryPercentageKey, entry.battery_percentage);
+  dictionary->SetInteger(kSignalStrengthKey, entry.signal_strength);
+  dictionary->SetBoolean(kSetupRequiredKey, entry.setup_required);
+
+  return dictionary;
+}
+
+std::unique_ptr<HostScanCacheEntry> DictionaryToHostScanCacheEntry(
+    const base::DictionaryValue& dictionary) {
+  HostScanCacheEntry::Builder builder;
+
+  std::string tether_network_guid;
+  if (!dictionary.GetString(kTetherNetworkGuidKey, &tether_network_guid) ||
+      tether_network_guid.empty()) {
+    return nullptr;
+  }
+  builder.SetTetherNetworkGuid(tether_network_guid);
+
+  std::string device_name;
+  if (!dictionary.GetString(kDeviceNameKey, &device_name)) {
+    return nullptr;
+  }
+  builder.SetDeviceName(device_name);
+
+  std::string carrier;
+  if (!dictionary.GetString(kCarrierKey, &carrier)) {
+    return nullptr;
+  }
+  builder.SetCarrier(carrier);
+
+  int battery_percentage;
+  if (!dictionary.GetInteger(kBatteryPercentageKey, &battery_percentage) ||
+      battery_percentage < 0 || battery_percentage > 100) {
+    return nullptr;
+  }
+  builder.SetBatteryPercentage(battery_percentage);
+
+  int signal_strength;
+  if (!dictionary.GetInteger(kSignalStrengthKey, &signal_strength) ||
+      signal_strength < 0 || signal_strength > 100) {
+    return nullptr;
+  }
+  builder.SetSignalStrength(signal_strength);
+
+  bool setup_required;
+  if (!dictionary.GetBoolean(kSetupRequiredKey, &setup_required)) {
+    return nullptr;
+  }
+  builder.SetSetupRequired(setup_required);
+
+  return builder.Build();
+}
+
+}  // namespace
+
+// static
+void PersistentHostScanCache::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterListPref(prefs::kHostScanCache);
+}
+
+PersistentHostScanCache::PersistentHostScanCache(PrefService* pref_service)
+    : pref_service_(pref_service) {}
+
+PersistentHostScanCache::~PersistentHostScanCache() {}
+
+std::unordered_map<std::string, HostScanCacheEntry>
+PersistentHostScanCache::GetStoredCacheEntries() {
+  const base::ListValue* cache_entry_list =
+      pref_service_->GetList(prefs::kHostScanCache);
+  DCHECK(cache_entry_list);
+
+  std::unordered_map<std::string, HostScanCacheEntry> entries;
+  std::unordered_set<std::string> ids_processed_so_far;
+  for (auto& cache_entry_value : cache_entry_list->GetList()) {
+    const base::DictionaryValue* cache_entry_dict;
+
+    if (!cache_entry_value.GetAsDictionary(&cache_entry_dict)) {
+      // All prefs stored in the ListValue should be valid DictionaryValues.
+      NOTREACHED();
+    }
+
+    std::unique_ptr<HostScanCacheEntry> entry =
+        DictionaryToHostScanCacheEntry(*cache_entry_dict);
+    DCHECK(entry);
+
+    std::string tether_network_guid = entry->tether_network_guid;
+    DCHECK(!tether_network_guid.empty());
+
+    // There should never be duplicate entries stored for one Tether network
+    // GUID.
+    DCHECK(ids_processed_so_far.find(tether_network_guid) ==
+           ids_processed_so_far.end());
+    ids_processed_so_far.insert(tether_network_guid);
+
+    entries.emplace(tether_network_guid, *entry);
+  }
+
+  return entries;
+}
+
+void PersistentHostScanCache::SetHostScanResult(
+    const HostScanCacheEntry& entry) {
+  std::unordered_map<std::string, HostScanCacheEntry> entries =
+      GetStoredCacheEntries();
+
+  // Erase any existing scan result for this GUID (if none currently exists,
+  // this is a no-op).
+  entries.erase(entry.tether_network_guid);
+
+  // Add the entry supplied.
+  entries.emplace(entry.tether_network_guid, entry);
+
+  StoreCacheEntriesToPrefs(entries);
+}
+
+bool PersistentHostScanCache::RemoveHostScanResult(
+    const std::string& tether_network_guid) {
+  std::unordered_map<std::string, HostScanCacheEntry> entries =
+      GetStoredCacheEntries();
+
+  bool result_was_removed = entries.erase(tether_network_guid);
+
+  // Only store the updated entries if a scan result was actually removed.
+  // Otherwise, nothing has changed and there is no reason to re-write the same
+  // data.
+  if (result_was_removed)
+    StoreCacheEntriesToPrefs(entries);
+
+  return result_was_removed;
+}
+
+void PersistentHostScanCache::ClearCacheExceptForActiveHost() {
+  // This function will be removed in a future CL, so it is not implemented
+  // here.
+  NOTIMPLEMENTED();
+}
+
+bool PersistentHostScanCache::DoesHostRequireSetup(
+    const std::string& tether_network_guid) {
+  std::unordered_map<std::string, HostScanCacheEntry> entries =
+      GetStoredCacheEntries();
+
+  auto it = entries.find(tether_network_guid);
+  DCHECK(it != entries.end());
+
+  return it->second.setup_required;
+}
+
+void PersistentHostScanCache::StoreCacheEntriesToPrefs(
+    const std::unordered_map<std::string, HostScanCacheEntry>& entries) {
+  base::ListValue entries_list;
+
+  for (const auto& it : entries) {
+    std::unique_ptr<base::DictionaryValue> entry_dict =
+        HostScanCacheEntryToDictionary(it.second);
+    DCHECK(entry_dict);
+    entries_list.Append(std::move(entry_dict));
+  }
+
+  pref_service_->Set(prefs::kHostScanCache, entries_list);
+}
+
+}  // namespace tether
+
+}  // namespace chromeos
diff --git a/chromeos/components/tether/persistent_host_scan_cache.h b/chromeos/components/tether/persistent_host_scan_cache.h
new file mode 100644
index 0000000..ab277ce
--- /dev/null
+++ b/chromeos/components/tether/persistent_host_scan_cache.h
@@ -0,0 +1,54 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_H_
+#define CHROMEOS_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_H_
+
+#include <unordered_map>
+
+#include "base/macros.h"
+#include "base/values.h"
+#include "chromeos/components/tether/host_scan_cache.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace chromeos {
+
+namespace tether {
+
+// HostScanCache implementation which stores scan results in persistent user
+// prefs.
+class PersistentHostScanCache : public HostScanCache {
+ public:
+  // Registers the prefs used by this class to the given |registry|.
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+
+  PersistentHostScanCache(PrefService* pref_service);
+  ~PersistentHostScanCache() override;
+
+  // Returns the cache entries that are currently stored in user prefs as a map
+  // from Tether network GUID to entry.
+  std::unordered_map<std::string, HostScanCacheEntry> GetStoredCacheEntries();
+
+  // HostScanCache:
+  void SetHostScanResult(const HostScanCacheEntry& entry) override;
+  bool RemoveHostScanResult(const std::string& tether_network_guid) override;
+  void ClearCacheExceptForActiveHost() override;
+  bool DoesHostRequireSetup(const std::string& tether_network_guid) override;
+
+ private:
+  void StoreCacheEntriesToPrefs(
+      const std::unordered_map<std::string, HostScanCacheEntry>& entries);
+
+  PrefService* pref_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(PersistentHostScanCache);
+};
+
+}  // namespace tether
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_H_
diff --git a/chromeos/components/tether/persistent_host_scan_cache_unittest.cc b/chromeos/components/tether/persistent_host_scan_cache_unittest.cc
new file mode 100644
index 0000000..fdee25a
--- /dev/null
+++ b/chromeos/components/tether/persistent_host_scan_cache_unittest.cc
@@ -0,0 +1,158 @@
+// 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 "chromeos/components/tether/persistent_host_scan_cache.h"
+
+#include <memory>
+#include <unordered_map>
+
+#include "base/memory/ptr_util.h"
+#include "chromeos/components/tether/fake_host_scan_cache.h"
+#include "chromeos/components/tether/host_scan_test_util.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace tether {
+
+class PersistentHostScanCacheTest : public testing::Test {
+ protected:
+  PersistentHostScanCacheTest()
+      : test_entries_(host_scan_test_util::CreateTestEntries()) {}
+
+  void SetUp() override {
+    test_pref_service_ = base::MakeUnique<TestingPrefServiceSimple>();
+    PersistentHostScanCache::RegisterPrefs(test_pref_service_->registry());
+
+    host_scan_cache_ =
+        base::MakeUnique<PersistentHostScanCache>(test_pref_service_.get());
+    expected_cache_ = base::MakeUnique<FakeHostScanCache>();
+  }
+
+  void SetHostScanResult(const HostScanCacheEntry& entry) {
+    host_scan_cache_->SetHostScanResult(entry);
+    expected_cache_->SetHostScanResult(entry);
+  }
+
+  void RemoveHostScanResult(const std::string& tether_network_guid) {
+    host_scan_cache_->RemoveHostScanResult(tether_network_guid);
+    expected_cache_->RemoveHostScanResult(tether_network_guid);
+  }
+
+  void VerifyPersistentCacheMatchesInMemoryCache(size_t expected_size) {
+    std::unordered_map<std::string, HostScanCacheEntry> entries =
+        host_scan_cache_->GetStoredCacheEntries();
+    EXPECT_EQ(expected_size, entries.size());
+    EXPECT_EQ(expected_size, expected_cache_->cache().size());
+    EXPECT_EQ(expected_cache_->cache(), entries);
+  }
+
+  const std::unordered_map<std::string, HostScanCacheEntry> test_entries_;
+
+  std::unique_ptr<TestingPrefServiceSimple> test_pref_service_;
+  std::unique_ptr<FakeHostScanCache> expected_cache_;
+
+  std::unique_ptr<PersistentHostScanCache> host_scan_cache_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PersistentHostScanCacheTest);
+};
+
+TEST_F(PersistentHostScanCacheTest, TestSetAndRemove) {
+  SetHostScanResult(test_entries_.at(host_scan_test_util::kTetherGuid0));
+  VerifyPersistentCacheMatchesInMemoryCache(1u /* expected_size */);
+
+  SetHostScanResult(test_entries_.at(host_scan_test_util::kTetherGuid1));
+  VerifyPersistentCacheMatchesInMemoryCache(2u /* expected_size */);
+
+  SetHostScanResult(test_entries_.at(host_scan_test_util::kTetherGuid2));
+  VerifyPersistentCacheMatchesInMemoryCache(3u /* expected_size */);
+
+  SetHostScanResult(test_entries_.at(host_scan_test_util::kTetherGuid3));
+  VerifyPersistentCacheMatchesInMemoryCache(4u /* expected_size */);
+
+  RemoveHostScanResult(host_scan_test_util::kTetherGuid0);
+  VerifyPersistentCacheMatchesInMemoryCache(3u /* expected_size */);
+
+  RemoveHostScanResult(host_scan_test_util::kTetherGuid1);
+  VerifyPersistentCacheMatchesInMemoryCache(2u /* expected_size */);
+
+  RemoveHostScanResult(host_scan_test_util::kTetherGuid2);
+  VerifyPersistentCacheMatchesInMemoryCache(1u /* expected_size */);
+
+  RemoveHostScanResult(host_scan_test_util::kTetherGuid3);
+  VerifyPersistentCacheMatchesInMemoryCache(0u /* expected_size */);
+}
+
+TEST_F(PersistentHostScanCacheTest, TestUpdate) {
+  SetHostScanResult(test_entries_.at(host_scan_test_util::kTetherGuid0));
+  VerifyPersistentCacheMatchesInMemoryCache(1u /* expected_size */);
+  EXPECT_EQ(host_scan_test_util::kTetherSetupRequired0,
+            host_scan_cache_->DoesHostRequireSetup(
+                host_scan_test_util::kTetherGuid0));
+
+  // Update existing entry, including changing the "setup required" field.
+  SetHostScanResult(
+      *HostScanCacheEntry::Builder()
+           .SetTetherNetworkGuid(host_scan_test_util::kTetherGuid0)
+           .SetDeviceName(host_scan_test_util::kTetherDeviceName0)
+           .SetCarrier(host_scan_test_util::kTetherCarrier1)
+           .SetBatteryPercentage(host_scan_test_util::kTetherBatteryPercentage1)
+           .SetSignalStrength(host_scan_test_util::kTetherSignalStrength1)
+           .SetSetupRequired(host_scan_test_util::kTetherSetupRequired1)
+           .Build());
+  VerifyPersistentCacheMatchesInMemoryCache(1u /* expected_size */);
+  EXPECT_EQ(host_scan_test_util::kTetherSetupRequired1,
+            host_scan_cache_->DoesHostRequireSetup(
+                host_scan_test_util::kTetherGuid0));
+}
+
+TEST_F(PersistentHostScanCacheTest, TestStoredPersistently) {
+  SetHostScanResult(test_entries_.at(host_scan_test_util::kTetherGuid0));
+  VerifyPersistentCacheMatchesInMemoryCache(1u /* expected_size */);
+
+  SetHostScanResult(test_entries_.at(host_scan_test_util::kTetherGuid1));
+  VerifyPersistentCacheMatchesInMemoryCache(2u /* expected_size */);
+
+  // Now, delete the existing PersistentHostScanCache object. All of its
+  // in-memory state will be cleaned up, but it should have stored the scanned
+  // data persistently.
+  host_scan_cache_.reset();
+
+  // Create a new object.
+  host_scan_cache_ =
+      base::MakeUnique<PersistentHostScanCache>(test_pref_service_.get());
+
+  // The new object should still access the stored scanned data.
+  VerifyPersistentCacheMatchesInMemoryCache(2u /* expected_size */);
+
+  // Make some changes - update one existing result, add a new one, and remove
+  // an old one.
+  SetHostScanResult(
+      *HostScanCacheEntry::Builder()
+           .SetTetherNetworkGuid(host_scan_test_util::kTetherGuid0)
+           .SetDeviceName(host_scan_test_util::kTetherDeviceName0)
+           .SetCarrier(host_scan_test_util::kTetherCarrier1)
+           .SetBatteryPercentage(host_scan_test_util::kTetherBatteryPercentage1)
+           .SetSignalStrength(host_scan_test_util::kTetherSignalStrength1)
+           .SetSetupRequired(host_scan_test_util::kTetherSetupRequired1)
+           .Build());
+  VerifyPersistentCacheMatchesInMemoryCache(2u /* expected_size */);
+
+  SetHostScanResult(test_entries_.at(host_scan_test_util::kTetherGuid2));
+  VerifyPersistentCacheMatchesInMemoryCache(3u /* expected_size */);
+
+  RemoveHostScanResult(host_scan_test_util::kTetherGuid1);
+  VerifyPersistentCacheMatchesInMemoryCache(2u /* expected_size */);
+
+  // Delete the current PersistentHostScanCache and create another new one. It
+  // should still contain the same data.
+  host_scan_cache_.reset(new PersistentHostScanCache(test_pref_service_.get()));
+  VerifyPersistentCacheMatchesInMemoryCache(2u /* expected_size */);
+}
+
+}  // namespace tether
+
+}  // namespace chromeos
diff --git a/chromeos/components/tether/pref_names.cc b/chromeos/components/tether/pref_names.cc
index 387aa2c..0d1b8ef 100644
--- a/chromeos/components/tether/pref_names.cc
+++ b/chromeos/components/tether/pref_names.cc
@@ -27,6 +27,8 @@
 const char kDisconnectingWifiNetworkGuid[] =
     "tether.disconnecting_wifi_network_id";
 
+const char kHostScanCache[] = "tether.host_scan_cache";
+
 }  // namespace prefs
 
 }  // namespace tether
diff --git a/chromeos/components/tether/pref_names.h b/chromeos/components/tether/pref_names.h
index 9b77277..b95c59c4 100644
--- a/chromeos/components/tether/pref_names.h
+++ b/chromeos/components/tether/pref_names.h
@@ -50,6 +50,11 @@
 // the GUID is cleared from prefs.
 extern const char kDisconnectingWifiNetworkGuid[];
 
+// Scanned Tether host results. The value stored is a ListValue containing
+// DictionaryValues containing the scan results. See PersistentHostScanCache for
+// more details.
+extern const char kHostScanCache[];
+
 }  // namespace prefs
 
 }  // namespace tether
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 8f6d89d3..8c0eb5c 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -92,6 +92,7 @@
     "//components/image_fetcher/core:unit_tests",
     "//components/json_schema:unit_tests",
     "//components/keyed_service/core:unit_tests",
+    "//components/language/core/browser:unit_tests",
     "//components/language_usage_metrics:unit_tests",
     "//components/leveldb_proto:unit_tests",
     "//components/login:unit_tests",
diff --git a/components/download/content/internal/BUILD.gn b/components/download/content/internal/BUILD.gn
index 74dada9e..09d11a2 100644
--- a/components/download/content/internal/BUILD.gn
+++ b/components/download/content/internal/BUILD.gn
@@ -35,6 +35,7 @@
 
   deps = [
     ":internal",
+    "//base/test:test_support",
     "//content/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/download/content/internal/download_driver_impl.cc b/components/download/content/internal/download_driver_impl.cc
index 455372a..2b4641f 100644
--- a/components/download/content/internal/download_driver_impl.cc
+++ b/components/download/content/internal/download_driver_impl.cc
@@ -108,6 +108,13 @@
     client_->OnDriverReady(true);
 }
 
+void DownloadDriverImpl::HardRecover() {
+  // TODO(dtrainor, xingliu): Implement recovery for the DownloadManager.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&DownloadDriverImpl::OnHardRecoverComplete,
+                            weak_ptr_factory_.GetWeakPtr(), true));
+}
+
 bool DownloadDriverImpl::IsReady() const {
   return client_ && download_manager_ &&
          download_manager_->IsManagerInitialized();
@@ -259,4 +266,8 @@
   download_manager_ = nullptr;
 }
 
+void DownloadDriverImpl::OnHardRecoverComplete(bool success) {
+  client_->OnDriverHardRecoverComplete(success);
+}
+
 }  // namespace download
diff --git a/components/download/content/internal/download_driver_impl.h b/components/download/content/internal/download_driver_impl.h
index 35ffc1b..18b7d3e 100644
--- a/components/download/content/internal/download_driver_impl.h
+++ b/components/download/content/internal/download_driver_impl.h
@@ -35,6 +35,7 @@
 
   // DownloadDriver implementation.
   void Initialize(DownloadDriver::Client* client) override;
+  void HardRecover() override;
   bool IsReady() const override;
   void Start(
       const RequestParams& request_params,
@@ -58,6 +59,8 @@
   void OnManagerInitialized() override;
   void ManagerGoingDown(content::DownloadManager* manager) override;
 
+  void OnHardRecoverComplete(bool success);
+
   // Remove the download, used to be posted to the task queue.
   void DoRemoveDownload(const std::string& guid);
 
diff --git a/components/download/content/internal/download_driver_impl_unittest.cc b/components/download/content/internal/download_driver_impl_unittest.cc
index 2b753148..32c1a987 100644
--- a/components/download/content/internal/download_driver_impl_unittest.cc
+++ b/components/download/content/internal/download_driver_impl_unittest.cc
@@ -9,6 +9,8 @@
 
 #include "base/guid.h"
 #include "base/memory/ptr_util.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "content/public/test/fake_download_item.h"
 #include "content/public/test/mock_download_manager.h"
 #include "net/http/http_response_headers.h"
@@ -44,6 +46,7 @@
 class MockDriverClient : public DownloadDriver::Client {
  public:
   MOCK_METHOD1(OnDriverReady, void(bool));
+  MOCK_METHOD1(OnDriverHardRecoverComplete, void(bool));
   MOCK_METHOD1(OnDownloadCreated, void(const DriverEntry&));
   MOCK_METHOD2(OnDownloadFailed, void(const DriverEntry&, FailureType));
   MOCK_METHOD1(OnDownloadSucceeded, void(const DriverEntry&));
@@ -52,7 +55,9 @@
 
 class DownloadDriverImplTest : public testing::Test {
  public:
-  DownloadDriverImplTest() = default;
+  DownloadDriverImplTest()
+      : task_runner_(new base::TestSimpleTaskRunner), handle_(task_runner_) {}
+
   ~DownloadDriverImplTest() override = default;
 
   void SetUp() override {
@@ -64,6 +69,10 @@
   MockDriverClient mock_client_;
   std::unique_ptr<DownloadDriverImpl> driver_;
 
+ protected:
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  base::ThreadTaskRunnerHandle handle_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(DownloadDriverImplTest);
 };
@@ -80,6 +89,17 @@
       ->OnManagerInitialized();
 }
 
+TEST_F(DownloadDriverImplTest, TestHardRecover) {
+  EXPECT_CALL(mock_manager_, IsManagerInitialized())
+      .Times(1)
+      .WillOnce(Return(false));
+  driver_->Initialize(&mock_client_);
+
+  EXPECT_CALL(mock_client_, OnDriverHardRecoverComplete(true)).Times(1);
+  driver_->HardRecover();
+  task_runner_->RunUntilIdle();
+}
+
 // Ensures download updates from download items are propagated correctly.
 TEST_F(DownloadDriverImplTest, DownloadItemUpdateEvents) {
   using DownloadState = content::DownloadItem::DownloadState;
diff --git a/components/download/internal/controller.h b/components/download/internal/controller.h
index af75fca..fac0be40 100644
--- a/components/download/internal/controller.h
+++ b/components/download/internal/controller.h
@@ -42,8 +42,8 @@
   Controller() = default;
   virtual ~Controller() = default;
 
-  // Initializes the controller.  Initialization may be asynchronous.
-  virtual void Initialize() = 0;
+  // Initializes the controller. Initialization may be asynchronous.
+  virtual void Initialize(const base::Closure& callback) = 0;
 
   // Returns the status of Controller.
   virtual const StartupStatus* GetStartupStatus() = 0;
diff --git a/components/download/internal/controller_impl.cc b/components/download/internal/controller_impl.cc
index fc272a6..b0dcaad 100644
--- a/components/download/internal/controller_impl.cc
+++ b/components/download/internal/controller_impl.cc
@@ -95,9 +95,10 @@
 
 ControllerImpl::~ControllerImpl() = default;
 
-void ControllerImpl::Initialize() {
+void ControllerImpl::Initialize(const base::Closure& callback) {
   DCHECK(!startup_status_.Complete());
 
+  init_callback_ = callback;
   initializing_internals_ = true;
   driver_->Initialize(this);
   model_->Initialize(this);
@@ -110,7 +111,14 @@
 }
 
 void ControllerImpl::StartDownload(const DownloadParams& params) {
-  DCHECK(startup_status_.Ok());
+  DCHECK(startup_status_.Complete());
+  if (!startup_status_.Ok()) {
+    HandleStartDownloadResponse(params.client, params.guid,
+                                DownloadParams::StartResult::INTERNAL_ERROR,
+                                params.callback);
+    return;
+  }
+
   DCHECK_LE(base::Time::Now(), params.scheduling_params.cancel_time);
   KillTimedOutDownloads();
 
@@ -150,7 +158,9 @@
 }
 
 void ControllerImpl::PauseDownload(const std::string& guid) {
-  DCHECK(startup_status_.Ok());
+  DCHECK(startup_status_.Complete());
+  if (!startup_status_.Ok())
+    return;
 
   auto* entry = model_->Get(guid);
 
@@ -169,7 +179,9 @@
 }
 
 void ControllerImpl::ResumeDownload(const std::string& guid) {
-  DCHECK(startup_status_.Ok());
+  DCHECK(startup_status_.Complete());
+  if (!startup_status_.Ok())
+    return;
 
   auto* entry = model_->Get(guid);
   DCHECK(entry);
@@ -184,7 +196,9 @@
 }
 
 void ControllerImpl::CancelDownload(const std::string& guid) {
-  DCHECK(startup_status_.Ok());
+  DCHECK(startup_status_.Complete());
+  if (!startup_status_.Ok())
+    return;
 
   auto* entry = model_->Get(guid);
   if (!entry)
@@ -203,7 +217,9 @@
 
 void ControllerImpl::ChangeDownloadCriteria(const std::string& guid,
                                             const SchedulingParams& params) {
-  DCHECK(startup_status_.Ok());
+  DCHECK(startup_status_.Complete());
+  if (!startup_status_.Ok())
+    return;
 
   auto* entry = model_->Get(guid);
   if (!entry || entry->scheduling_params == params) {
@@ -221,6 +237,10 @@
 }
 
 DownloadClient ControllerImpl::GetOwnerOfDownload(const std::string& guid) {
+  DCHECK(startup_status_.Complete());
+  if (!startup_status_.Ok())
+    return DownloadClient::INVALID;
+
   auto* entry = model_->Get(guid);
   return entry ? entry->client : DownloadClient::INVALID;
 }
@@ -228,16 +248,19 @@
 void ControllerImpl::OnStartScheduledTask(
     DownloadTaskType task_type,
     const TaskFinishedCallback& callback) {
+  DCHECK(startup_status_.Complete());
   task_finished_callbacks_[task_type] = callback;
-  if (!startup_status_.Complete()) {
-    return;
-  } else if (!startup_status_.Ok()) {
+  if (!startup_status_.Ok()) {
     HandleTaskFinished(task_type, false,
                        stats::ScheduledTaskStatus::ABORTED_ON_FAILED_INIT);
     return;
   }
 
-  ProcessScheduledTasks();
+  if (task_type == DownloadTaskType::DOWNLOAD_TASK) {
+    ActivateMoreDownloads();
+  } else if (task_type == DownloadTaskType::CLEANUP_TASK) {
+    RemoveCleanupEligibleDownloads();
+  }
 }
 
 bool ControllerImpl::OnStopScheduledTask(DownloadTaskType task_type) {
@@ -246,37 +269,29 @@
   return true;
 }
 
-void ControllerImpl::ProcessScheduledTasks() {
-  if (!startup_status_.Ok()) {
-    while (!task_finished_callbacks_.empty()) {
-      auto it = task_finished_callbacks_.begin();
-      HandleTaskFinished(it->first, false,
-                         stats::ScheduledTaskStatus::ABORTED_ON_FAILED_INIT);
-    }
-    return;
-  }
+void ControllerImpl::OnCompleteCleanupTask() {
+  HandleTaskFinished(DownloadTaskType::CLEANUP_TASK, false,
+                     stats::ScheduledTaskStatus::COMPLETED_NORMALLY);
+}
 
-  while (!task_finished_callbacks_.empty()) {
-    auto it = task_finished_callbacks_.begin();
-    if (it->first == DownloadTaskType::DOWNLOAD_TASK) {
-      ActivateMoreDownloads();
-    } else if (it->first == DownloadTaskType::CLEANUP_TASK) {
-      auto timed_out_entries =
-          file_monitor_->CleanupFilesForCompletedEntries(model_->PeekEntries());
-      for (auto* entry : timed_out_entries) {
-        DCHECK_EQ(Entry::State::COMPLETE, entry->state);
-        model_->Remove(entry->guid);
-      }
-    }
-
-    HandleTaskFinished(it->first, false,
-                       stats::ScheduledTaskStatus::COMPLETED_NORMALLY);
+void ControllerImpl::RemoveCleanupEligibleDownloads() {
+  auto timed_out_entries = file_monitor_->CleanupFilesForCompletedEntries(
+      model_->PeekEntries(), base::Bind(&ControllerImpl::OnCompleteCleanupTask,
+                                        weak_ptr_factory_.GetWeakPtr()));
+  for (auto* entry : timed_out_entries) {
+    DCHECK_EQ(Entry::State::COMPLETE, entry->state);
+    model_->Remove(entry->guid);
   }
 }
 
 void ControllerImpl::HandleTaskFinished(DownloadTaskType task_type,
                                         bool needs_reschedule,
                                         stats::ScheduledTaskStatus status) {
+  if (task_finished_callbacks_.find(task_type) ==
+      task_finished_callbacks_.end()) {
+    return;
+  }
+
   if (status != stats::ScheduledTaskStatus::CANCELLED_ON_STOP) {
     base::ResetAndReturn(&task_finished_callbacks_[task_type])
         .Run(needs_reschedule);
@@ -293,6 +308,8 @@
   AttemptToFinalizeSetup();
 }
 
+void ControllerImpl::OnDriverHardRecoverComplete(bool success) {}
+
 void ControllerImpl::OnDownloadCreated(const DriverEntry& download) {
   if (initializing_internals_)
     return;
@@ -443,7 +460,7 @@
         FROM_HERE, base::Bind(&ControllerImpl::SendOnServiceUnavailable,
                               weak_ptr_factory_.GetWeakPtr()));
 
-    ProcessScheduledTasks();
+    NotifyServiceOfStartup();
     return;
   }
 
@@ -451,6 +468,7 @@
   PollActiveDriverDownloads();
   CancelOrphanedRequests();
   CleanupUnknownFiles();
+  RemoveCleanupEligibleDownloads();
   ResolveInitialRequestStates();
 
   NotifyClientsOfStartup();
@@ -458,9 +476,9 @@
   initializing_internals_ = false;
 
   UpdateDriverStates();
-  ProcessScheduledTasks();
 
   KillTimedOutDownloads();
+  NotifyServiceOfStartup();
 
   // Pull the initial straw if active downloads haven't reach maximum.
   ActivateMoreDownloads();
@@ -690,6 +708,14 @@
   }
 }
 
+void ControllerImpl::NotifyServiceOfStartup() {
+  if (init_callback_.is_null())
+    return;
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::ResetAndReturn(&init_callback_));
+}
+
 void ControllerImpl::HandleStartDownloadResponse(
     DownloadClient client,
     const std::string& guid,
@@ -837,18 +863,25 @@
   uint32_t paused_count = entries_states[Entry::State::PAUSED];
   uint32_t active_count = entries_states[Entry::State::ACTIVE];
 
+  bool has_actionable_downloads = false;
   while (CanActivateMoreDownloads(config_, active_count, paused_count)) {
     Entry* next = scheduler_->Next(
         model_->PeekEntries(), device_status_listener_->CurrentDeviceStatus());
     if (!next)
       break;
 
+    has_actionable_downloads = true;
     DCHECK_EQ(Entry::State::AVAILABLE, next->state);
     TransitTo(next, Entry::State::ACTIVE, model_.get());
     active_count++;
     UpdateDriverState(next);
   }
 
+  if (!has_actionable_downloads) {
+    HandleTaskFinished(DownloadTaskType::DOWNLOAD_TASK, false,
+                       stats::ScheduledTaskStatus::COMPLETED_NORMALLY);
+  }
+
   scheduler_->Reschedule(scheduling_candidates);
 }
 
diff --git a/components/download/internal/controller_impl.h b/components/download/internal/controller_impl.h
index 554bce8..c0e9669 100644
--- a/components/download/internal/controller_impl.h
+++ b/components/download/internal/controller_impl.h
@@ -55,7 +55,7 @@
   ~ControllerImpl() override;
 
   // Controller implementation.
-  void Initialize() override;
+  void Initialize(const base::Closure& callback) override;
   const StartupStatus* GetStartupStatus() override;
   void StartDownload(const DownloadParams& params) override;
   void PauseDownload(const std::string& guid) override;
@@ -71,6 +71,7 @@
  private:
   // DownloadDriver::Client implementation.
   void OnDriverReady(bool success) override;
+  void OnDriverHardRecoverComplete(bool success) override;
   void OnDownloadCreated(const DriverEntry& download) override;
   void OnDownloadFailed(const DriverEntry& download,
                         FailureType failure_type) override;
@@ -127,6 +128,10 @@
   // DownloadClient.
   void NotifyClientsOfStartup();
 
+  // Notifies the service that the startup has completed so that it can start
+  // processing any pending requests.
+  void NotifyServiceOfStartup();
+
   void HandleStartDownloadResponse(DownloadClient client,
                                    const std::string& guid,
                                    DownloadParams::StartResult result);
@@ -136,13 +141,11 @@
       DownloadParams::StartResult result,
       const DownloadParams::StartCallback& callback);
 
-  // Entry point for a scheduled task after the task is fired.
-  void ProcessScheduledTasks();
-
   // Handles and clears any pending task finished callbacks.
   void HandleTaskFinished(DownloadTaskType task_type,
                           bool needs_reschedule,
                           stats::ScheduledTaskStatus status);
+  void OnCompleteCleanupTask();
 
   void HandleCompleteDownload(CompletionType type, const std::string& guid);
 
@@ -150,6 +153,8 @@
   // reached maximum.
   void ActivateMoreDownloads();
 
+  void RemoveCleanupEligibleDownloads();
+
   void HandleExternalDownload(const std::string& guid, bool active);
 
   // Postable methods meant to just be pass throughs to Client APIs.  This is
@@ -199,6 +204,7 @@
   // is complete *and* all internal structures are set up.  This is to prevent
   // outside signals from triggering state updates before we are ready.
   bool initializing_internals_;
+  base::Closure init_callback_;
   StartupStatus startup_status_;
   std::set<std::string> externally_active_downloads_;
   std::map<std::string, DownloadParams::StartCallback> start_callbacks_;
diff --git a/components/download/internal/controller_impl_unittest.cc b/components/download/internal/controller_impl_unittest.cc
index 8b32f27..7abc8b7 100644
--- a/components/download/internal/controller_impl_unittest.cc
+++ b/components/download/internal/controller_impl_unittest.cc
@@ -85,8 +85,9 @@
   void Initialize(const FileMonitor::InitCallback& callback) override;
   MOCK_METHOD2(DeleteUnknownFiles,
                void(const Model::EntryList&, const std::vector<DriverEntry>&));
-  MOCK_METHOD1(CleanupFilesForCompletedEntries,
-               std::vector<Entry*>(const Model::EntryList&));
+  MOCK_METHOD2(CleanupFilesForCompletedEntries,
+               std::vector<Entry*>(const Model::EntryList&,
+                                   const base::Closure&));
   MOCK_METHOD2(DeleteFiles,
                void(const std::set<base::FilePath>&, stats::FileCleanupReason));
   MOCK_METHOD1(HardRecover, void(const FileMonitor::InitCallback&));
@@ -108,7 +109,8 @@
         model_(nullptr),
         device_status_listener_(nullptr),
         scheduler_(nullptr),
-        file_monitor_(nullptr) {
+        file_monitor_(nullptr),
+        init_callback_called_(false) {
     start_callback_ =
         base::Bind(&DownloadServiceControllerImplTest::StartCallback,
                    base::Unretained(this));
@@ -157,6 +159,17 @@
   }
 
  protected:
+  void OnInitCompleted() {
+    DCHECK(controller_->GetStartupStatus()->Complete());
+    init_callback_called_ = true;
+  }
+
+  void InitializeController() {
+    controller_->Initialize(
+        base::Bind(&DownloadServiceControllerImplTest::OnInitCompleted,
+                   base::Unretained(this)));
+  }
+
   DownloadParams MakeDownloadParams() {
     DownloadParams params;
     params.client = DownloadClient::TEST;
@@ -183,6 +196,7 @@
   MockFileMonitor* file_monitor_;
 
   DownloadParams::StartCallback start_callback_;
+  bool init_callback_called_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DownloadServiceControllerImplTest);
@@ -193,7 +207,7 @@
 TEST_F(DownloadServiceControllerImplTest, SuccessfulInitModelFirst) {
   EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(0);
 
-  controller_->Initialize();
+  InitializeController();
   EXPECT_TRUE(store_->init_called());
   EXPECT_FALSE(controller_->GetStartupStatus()->Complete());
 
@@ -217,7 +231,7 @@
 TEST_F(DownloadServiceControllerImplTest, SuccessfulInitDriverFirst) {
   EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(0);
 
-  controller_->Initialize();
+  InitializeController();
   EXPECT_TRUE(store_->init_called());
   EXPECT_FALSE(controller_->GetStartupStatus()->Complete());
 
@@ -225,6 +239,7 @@
   EXPECT_FALSE(controller_->GetStartupStatus()->Complete());
   EXPECT_FALSE(controller_->GetStartupStatus()->model_ok.has_value());
   EXPECT_TRUE(controller_->GetStartupStatus()->driver_ok.value());
+  EXPECT_FALSE(init_callback_called_);
 
   EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1);
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(1);
@@ -236,6 +251,7 @@
   EXPECT_TRUE(controller_->GetStartupStatus()->Ok());
 
   task_runner_->RunUntilIdle();
+  EXPECT_TRUE(init_callback_called_);
 }
 
 TEST_F(DownloadServiceControllerImplTest, SuccessfulInitWithExistingDownload) {
@@ -253,11 +269,12 @@
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(1);
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
 
-  controller_->Initialize();
+  InitializeController();
   driver_->MakeReady();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
 
   task_runner_->RunUntilIdle();
+  EXPECT_TRUE(init_callback_called_);
 }
 
 TEST_F(DownloadServiceControllerImplTest, UnknownFileDeletion) {
@@ -278,7 +295,7 @@
   EXPECT_CALL(*file_monitor_, DeleteUnknownFiles(_, _)).Times(1);
 
   driver_->AddTestData(dentries);
-  controller_->Initialize();
+  InitializeController();
   driver_->MakeReady();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
 
@@ -293,9 +310,9 @@
 
   std::vector<Entry> entries = {entry1, entry2, entry3};
 
-  EXPECT_CALL(*file_monitor_, CleanupFilesForCompletedEntries(_)).Times(1);
+  EXPECT_CALL(*file_monitor_, CleanupFilesForCompletedEntries(_, _)).Times(2);
 
-  controller_->Initialize();
+  InitializeController();
   driver_->MakeReady();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   controller_->OnStartScheduledTask(DownloadTaskType::CLEANUP_TASK,
@@ -308,7 +325,7 @@
   EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(0);
   EXPECT_CALL(*client_, OnServiceUnavailable()).Times(1);
 
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(false, base::MakeUnique<std::vector<Entry>>());
   driver_->MakeReady();
 
@@ -323,7 +340,7 @@
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(1);
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
 
-  controller_->Initialize();
+  InitializeController();
   driver_->MakeReady();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
 
@@ -340,7 +357,7 @@
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
 
   // Set up the Controller.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>());
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -375,7 +392,7 @@
   std::vector<Entry> entries = {entry};
 
   // Set up the Controller.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -405,7 +422,7 @@
   std::vector<Entry> entries = {entry};
 
   // Set up the Controller.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -430,7 +447,7 @@
   EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1);
 
   // Set up the Controller.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>());
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -462,7 +479,7 @@
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
 
   // Set up the Controller.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>());
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -485,7 +502,7 @@
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
 
   // Set up the Controller.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>());
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -510,7 +527,7 @@
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
 
   // Set up the Controller.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>());
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -543,7 +560,7 @@
 
   // Set the network status to disconnected so no entries will be polled from
   // the scheduler.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
 
@@ -588,7 +605,7 @@
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(2);
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(2);
 
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
 
@@ -628,7 +645,7 @@
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(2);
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(2);
 
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
 
@@ -654,7 +671,7 @@
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(2);
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(2);
 
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
 
@@ -685,7 +702,7 @@
       DeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED));
 
   driver_->AddTestData(dentries);
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -720,7 +737,7 @@
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(2);
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(2);
 
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
 
@@ -748,7 +765,7 @@
   entry2.completion_time = base::Time::Now() - base::TimeDelta::FromMinutes(2);
   std::vector<Entry> entries = {entry1, entry2};
 
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
 
@@ -776,7 +793,7 @@
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(1);
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
 
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
 
@@ -821,7 +838,7 @@
 
   // Set up the Controller.
   driver_->AddTestData(dentries);
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -930,7 +947,7 @@
   device_status_listener_->SetDeviceStatus(
       DeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED));
 
-  controller_->Initialize();
+  InitializeController();
   driver_->AddTestData(driver_entries);
   driver_->MakeReady();
   store_->AutomaticallyTriggerAllFutureCallbacks(true);
@@ -1030,7 +1047,7 @@
       DeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED));
 
   driver_->AddTestData(dentries);
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -1074,7 +1091,7 @@
       DeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED));
 
   driver_->AddTestData(dentries);
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -1151,7 +1168,7 @@
 
   EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1);
 
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   driver_->MakeReady();
   task_runner_->RunUntilIdle();
@@ -1175,7 +1192,7 @@
   config_->max_running_downloads = 1u;
 
   // Setup the controller.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   store_->AutomaticallyTriggerAllFutureCallbacks(true);
 
@@ -1203,7 +1220,7 @@
   config_->max_running_downloads = 1u;
 
   // Setup the controller.
-  controller_->Initialize();
+  InitializeController();
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries));
   store_->AutomaticallyTriggerAllFutureCallbacks(true);
 
diff --git a/components/download/internal/download_driver.h b/components/download/internal/download_driver.h
index aead0d4d..40bac08 100644
--- a/components/download/internal/download_driver.h
+++ b/components/download/internal/download_driver.h
@@ -42,6 +42,10 @@
     // when the low level download library is ready.
     virtual void OnDriverReady(bool success) = 0;
 
+    // Called asynchronously in response to a DownloadDriver::HardRecover call.
+    // If |success| is |false|, recovery of the DownloadDriver failed.
+    virtual void OnDriverHardRecoverComplete(bool success) = 0;
+
     // Called when any download is created.
     virtual void OnDownloadCreated(const DriverEntry& download) = 0;
 
@@ -62,6 +66,10 @@
   // Initialize the driver to receive download updates.
   virtual void Initialize(Client* client) = 0;
 
+  // Attempts to clean up and reset the DownloadDriver.  It should remove all
+  // state relevant to the DownloadService.
+  virtual void HardRecover() = 0;
+
   // Returns if the driver is ready after the low level library has loaded all
   // the data. Returns false when the driver is not initialized by the client,
   // or low level download library has been shut down.
diff --git a/components/download/internal/download_service_impl.cc b/components/download/internal/download_service_impl.cc
index 5a05885..e2ba3bfc 100644
--- a/components/download/internal/download_service_impl.cc
+++ b/components/download/internal/download_service_impl.cc
@@ -4,6 +4,7 @@
 
 #include "components/download/internal/download_service_impl.h"
 
+#include "base/bind.h"
 #include "base/strings/string_util.h"
 #include "components/download/internal/controller.h"
 #include "components/download/internal/startup_status.h"
@@ -15,8 +16,10 @@
                                          std::unique_ptr<Controller> controller)
     : config_(std::move(config)),
       controller_(std::move(controller)),
-      service_config_(config_.get()) {
-  controller_->Initialize();
+      service_config_(config_.get()),
+      startup_completed_(false) {
+  controller_->Initialize(base::Bind(
+      &DownloadServiceImpl::OnControllerInitialized, base::Unretained(this)));
 }
 
 DownloadServiceImpl::~DownloadServiceImpl() = default;
@@ -28,11 +31,30 @@
 void DownloadServiceImpl::OnStartScheduledTask(
     DownloadTaskType task_type,
     const TaskFinishedCallback& callback) {
-  controller_->OnStartScheduledTask(task_type, callback);
+  if (startup_completed_) {
+    controller_->OnStartScheduledTask(task_type, callback);
+    return;
+  }
+
+  pending_tasks_[task_type] =
+      base::Bind(&Controller::OnStartScheduledTask,
+                 base::Unretained(controller_.get()), task_type, callback);
 }
 
 bool DownloadServiceImpl::OnStopScheduledTask(DownloadTaskType task_type) {
-  return controller_->OnStopScheduledTask(task_type);
+  if (startup_completed_) {
+    return controller_->OnStopScheduledTask(task_type);
+  }
+
+  auto iter = pending_tasks_.find(task_type);
+  if (iter != pending_tasks_.end()) {
+    // We still need to run the callback in order to properly cleanup and notify
+    // the system by running the respective task finished callbacks.
+    iter->second.Run();
+    pending_tasks_.erase(iter);
+  }
+
+  return true;
 }
 
 DownloadService::ServiceStatus DownloadServiceImpl::GetStatus() {
@@ -49,28 +71,55 @@
   stats::LogServiceApiAction(download_params.client,
                              stats::ServiceApiAction::START_DOWNLOAD);
   DCHECK_EQ(download_params.guid, base::ToUpperASCII(download_params.guid));
-  controller_->StartDownload(download_params);
+
+  if (startup_completed_) {
+    controller_->StartDownload(download_params);
+  } else {
+    pending_actions_.push_back(base::Bind(&Controller::StartDownload,
+                                          base::Unretained(controller_.get()),
+                                          download_params));
+  }
 }
 
 void DownloadServiceImpl::PauseDownload(const std::string& guid) {
   stats::LogServiceApiAction(controller_->GetOwnerOfDownload(guid),
                              stats::ServiceApiAction::PAUSE_DOWNLOAD);
   DCHECK_EQ(guid, base::ToUpperASCII(guid));
-  controller_->PauseDownload(guid);
+
+  if (startup_completed_) {
+    controller_->PauseDownload(guid);
+  } else {
+    pending_actions_.push_back(base::Bind(
+        &Controller::PauseDownload, base::Unretained(controller_.get()), guid));
+  }
 }
 
 void DownloadServiceImpl::ResumeDownload(const std::string& guid) {
   stats::LogServiceApiAction(controller_->GetOwnerOfDownload(guid),
                              stats::ServiceApiAction::RESUME_DOWNLOAD);
   DCHECK_EQ(guid, base::ToUpperASCII(guid));
-  controller_->ResumeDownload(guid);
+
+  if (startup_completed_) {
+    controller_->ResumeDownload(guid);
+  } else {
+    pending_actions_.push_back(base::Bind(&Controller::ResumeDownload,
+                                          base::Unretained(controller_.get()),
+                                          guid));
+  }
 }
 
 void DownloadServiceImpl::CancelDownload(const std::string& guid) {
   stats::LogServiceApiAction(controller_->GetOwnerOfDownload(guid),
                              stats::ServiceApiAction::CANCEL_DOWNLOAD);
   DCHECK_EQ(guid, base::ToUpperASCII(guid));
-  controller_->CancelDownload(guid);
+
+  if (startup_completed_) {
+    controller_->CancelDownload(guid);
+  } else {
+    pending_actions_.push_back(base::Bind(&Controller::CancelDownload,
+                                          base::Unretained(controller_.get()),
+                                          guid));
+  }
 }
 
 void DownloadServiceImpl::ChangeDownloadCriteria(
@@ -79,7 +128,30 @@
   stats::LogServiceApiAction(controller_->GetOwnerOfDownload(guid),
                              stats::ServiceApiAction::CHANGE_CRITERIA);
   DCHECK_EQ(guid, base::ToUpperASCII(guid));
-  controller_->ChangeDownloadCriteria(guid, params);
+
+  if (startup_completed_) {
+    controller_->ChangeDownloadCriteria(guid, params);
+  } else {
+    pending_actions_.push_back(base::Bind(&Controller::ChangeDownloadCriteria,
+                                          base::Unretained(controller_.get()),
+                                          guid, params));
+  }
+}
+
+void DownloadServiceImpl::OnControllerInitialized() {
+  while (!pending_actions_.empty()) {
+    auto callback = pending_actions_.front();
+    callback.Run();
+    pending_actions_.pop_front();
+  }
+
+  while (!pending_tasks_.empty()) {
+    auto iter = pending_tasks_.begin();
+    iter->second.Run();
+    pending_tasks_.erase(iter);
+  }
+
+  startup_completed_ = true;
 }
 
 }  // namespace download
diff --git a/components/download/internal/download_service_impl.h b/components/download/internal/download_service_impl.h
index 8c5b80e..0333f9d0 100644
--- a/components/download/internal/download_service_impl.h
+++ b/components/download/internal/download_service_impl.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_DOWNLOAD_INTERNAL_DOWNLOAD_SERVICE_IMPL_H_
 #define COMPONENTS_DOWNLOAD_INTERNAL_DOWNLOAD_SERVICE_IMPL_H_
 
+#include <deque>
+#include <map>
 #include <memory>
 #include <string>
 
@@ -40,6 +42,8 @@
                               const SchedulingParams& params) override;
 
  private:
+  void OnControllerInitialized();
+
   // config_ needs to be destructed after controller_ and service_config_ which
   // hold onto references to it.
   std::unique_ptr<Configuration> config_;
@@ -47,6 +51,10 @@
   std::unique_ptr<Controller> controller_;
   ServiceConfigImpl service_config_;
 
+  std::deque<base::Closure> pending_actions_;
+  std::map<DownloadTaskType, base::Closure> pending_tasks_;
+  bool startup_completed_;
+
   DISALLOW_COPY_AND_ASSIGN(DownloadServiceImpl);
 };
 
diff --git a/components/download/internal/download_service_impl_unittest.cc b/components/download/internal/download_service_impl_unittest.cc
index 0245b18..5bda4402 100644
--- a/components/download/internal/download_service_impl_unittest.cc
+++ b/components/download/internal/download_service_impl_unittest.cc
@@ -9,6 +9,8 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "components/download/internal/startup_status.h"
 #include "components/download/internal/test/download_params_utils.h"
 #include "components/download/internal/test/mock_controller.h"
@@ -23,16 +25,16 @@
 
 class DownloadServiceImplTest : public testing::Test {
  public:
-  DownloadServiceImplTest() : controller_(nullptr) {}
+  DownloadServiceImplTest()
+      : controller_(nullptr),
+        task_runner_(new base::TestSimpleTaskRunner),
+        handle_(task_runner_) {}
   ~DownloadServiceImplTest() override = default;
 
   void SetUp() override {
     auto config = base::MakeUnique<Configuration>();
     auto controller = base::MakeUnique<test::MockController>();
     controller_ = controller.get();
-
-    EXPECT_CALL(*controller_, Initialize()).Times(1);
-
     service_ = base::MakeUnique<DownloadServiceImpl>(std::move(config),
                                                      std::move(controller));
   }
@@ -40,6 +42,8 @@
  protected:
   test::MockController* controller_;
   std::unique_ptr<DownloadServiceImpl> service_;
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  base::ThreadTaskRunnerHandle handle_;
 
   DISALLOW_COPY_AND_ASSIGN(DownloadServiceImplTest);
 };
@@ -74,26 +78,46 @@
   EXPECT_CALL(*controller_, GetOwnerOfDownload(_))
       .WillRepeatedly(Return(DownloadClient::TEST));
 
-  testing::Sequence seq;
-  EXPECT_CALL(*controller_, StartDownload(_)).Times(1).InSequence(seq);
-  EXPECT_CALL(*controller_, PauseDownload(params.guid))
-      .Times(1)
-      .InSequence(seq);
-  EXPECT_CALL(*controller_, ResumeDownload(params.guid))
-      .Times(1)
-      .InSequence(seq);
-  EXPECT_CALL(*controller_, CancelDownload(params.guid))
-      .Times(1)
-      .InSequence(seq);
-  EXPECT_CALL(*controller_, ChangeDownloadCriteria(params.guid, _))
-      .Times(1)
-      .InSequence(seq);
+  EXPECT_CALL(*controller_, StartDownload(_)).Times(0);
+  EXPECT_CALL(*controller_, PauseDownload(params.guid)).Times(0);
+  EXPECT_CALL(*controller_, ResumeDownload(params.guid)).Times(0);
+  EXPECT_CALL(*controller_, CancelDownload(params.guid)).Times(0);
+  EXPECT_CALL(*controller_, ChangeDownloadCriteria(params.guid, _)).Times(0);
 
   service_->StartDownload(params);
   service_->PauseDownload(params.guid);
   service_->ResumeDownload(params.guid);
   service_->CancelDownload(params.guid);
   service_->ChangeDownloadCriteria(params.guid, scheduling_params);
+  task_runner_->RunUntilIdle();
+
+  testing::Sequence seq1;
+  EXPECT_CALL(*controller_, StartDownload(_)).Times(1).InSequence(seq1);
+  EXPECT_CALL(*controller_, PauseDownload(params.guid))
+      .Times(1)
+      .InSequence(seq1);
+  EXPECT_CALL(*controller_, ResumeDownload(params.guid))
+      .Times(1)
+      .InSequence(seq1);
+  EXPECT_CALL(*controller_, CancelDownload(params.guid))
+      .Times(1)
+      .InSequence(seq1);
+  EXPECT_CALL(*controller_, ChangeDownloadCriteria(params.guid, _))
+      .Times(1)
+      .InSequence(seq1);
+
+  controller_->TriggerInitCompleted();
+  task_runner_->RunUntilIdle();
+
+  EXPECT_CALL(*controller_, PauseDownload(params.guid))
+      .Times(1)
+      .InSequence(seq1);
+  EXPECT_CALL(*controller_, ResumeDownload(params.guid))
+      .Times(1)
+      .InSequence(seq1);
+  service_->PauseDownload(params.guid);
+  service_->ResumeDownload(params.guid);
+  task_runner_->RunUntilIdle();
 }
 
 }  // namespace download
diff --git a/components/download/internal/file_monitor.h b/components/download/internal/file_monitor.h
index 7c98c91..9df409c 100644
--- a/components/download/internal/file_monitor.h
+++ b/components/download/internal/file_monitor.h
@@ -39,7 +39,8 @@
   // Deletes the files for the database entries which have been completed and
   // ready for cleanup. Returns the entries eligible for clean up.
   virtual std::vector<Entry*> CleanupFilesForCompletedEntries(
-      const Model::EntryList& entries) = 0;
+      const Model::EntryList& entries,
+      const base::Closure& completion_callback) = 0;
 
   // Deletes a list of files and logs UMA.
   virtual void DeleteFiles(const std::set<base::FilePath>& files_to_remove,
diff --git a/components/download/internal/file_monitor_impl.cc b/components/download/internal/file_monitor_impl.cc
index 5f1e8f55..cf0d57b7 100644
--- a/components/download/internal/file_monitor_impl.cc
+++ b/components/download/internal/file_monitor_impl.cc
@@ -121,7 +121,8 @@
 }
 
 std::vector<Entry*> FileMonitorImpl::CleanupFilesForCompletedEntries(
-    const Model::EntryList& entries) {
+    const Model::EntryList& entries,
+    const base::Closure& completion_callback) {
   std::vector<Entry*> entries_to_remove;
   std::set<base::FilePath> files_to_remove;
   for (auto* entry : entries) {
@@ -132,9 +133,11 @@
     files_to_remove.insert(entry->target_file_path);
   }
 
-  file_thread_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&DeleteFilesOnFileThread, files_to_remove,
-                            stats::FileCleanupReason::TIMEOUT));
+  file_thread_task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&DeleteFilesOnFileThread, files_to_remove,
+                 stats::FileCleanupReason::TIMEOUT),
+      completion_callback);
   return entries_to_remove;
 }
 
diff --git a/components/download/internal/file_monitor_impl.h b/components/download/internal/file_monitor_impl.h
index 6d2e615..f0e5b55 100644
--- a/components/download/internal/file_monitor_impl.h
+++ b/components/download/internal/file_monitor_impl.h
@@ -40,7 +40,8 @@
       const Model::EntryList& known_entries,
       const std::vector<DriverEntry>& known_driver_entries) override;
   std::vector<Entry*> CleanupFilesForCompletedEntries(
-      const Model::EntryList& entries) override;
+      const Model::EntryList& entries,
+      const base::Closure& completion_callback) override;
   void DeleteFiles(const std::set<base::FilePath>& files_to_remove,
                    stats::FileCleanupReason reason) override;
   void HardRecover(const InitCallback& callback) override;
diff --git a/components/download/internal/file_monitor_unittest.cc b/components/download/internal/file_monitor_unittest.cc
index a1a78151..d668872 100644
--- a/components/download/internal/file_monitor_unittest.cc
+++ b/components/download/internal/file_monitor_unittest.cc
@@ -27,7 +27,9 @@
 class FileMonitorTest : public testing::Test {
  public:
   FileMonitorTest()
-      : task_runner_(new base::TestSimpleTaskRunner), handle_(task_runner_) {
+      : task_runner_(new base::TestSimpleTaskRunner),
+        handle_(task_runner_),
+        completion_callback_called_(false) {
     EXPECT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
     download_dir_ = scoped_temp_dir_.GetPath();
     base::TimeDelta keep_alive_time = base::TimeDelta::FromHours(12);
@@ -37,6 +39,7 @@
   ~FileMonitorTest() override = default;
 
   void HardRecoveryResponse(bool result);
+  void CompletionCallback() { completion_callback_called_ = true; }
 
  protected:
   base::FilePath CreateTemporaryFile(std::string file_name);
@@ -45,6 +48,7 @@
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   base::ThreadTaskRunnerHandle handle_;
   base::FilePath download_dir_;
+  bool completion_callback_called_;
   std::unique_ptr<FileMonitor> monitor_;
 
   base::Optional<bool> hard_recovery_result_;
@@ -136,12 +140,15 @@
 
   std::vector<Entry*> entries = {&entry1, &entry2};
   std::vector<Entry*> entries_to_remove =
-      monitor_->CleanupFilesForCompletedEntries(entries);
+      monitor_->CleanupFilesForCompletedEntries(
+          entries, base::Bind(&FileMonitorTest::CompletionCallback,
+                              base::Unretained(this)));
   task_runner_->RunUntilIdle();
 
   EXPECT_EQ(1u, entries_to_remove.size());
   EXPECT_FALSE(base::PathExists(entry1.target_file_path));
   EXPECT_TRUE(base::PathExists(entry2.target_file_path));
+  EXPECT_TRUE(completion_callback_called_);
 }
 
 TEST_F(FileMonitorTest, TestHardRecovery) {
diff --git a/components/download/internal/test/mock_controller.cc b/components/download/internal/test/mock_controller.cc
index a0bf90a..9b32e04b 100644
--- a/components/download/internal/test/mock_controller.cc
+++ b/components/download/internal/test/mock_controller.cc
@@ -10,5 +10,13 @@
 MockController::MockController() = default;
 MockController::~MockController() = default;
 
+void MockController::Initialize(const base::Closure& callback) {
+  init_callback_ = callback;
+}
+
+void MockController::TriggerInitCompleted() {
+  init_callback_.Run();
+}
+
 }  // namespace test
 }  // namespace download
diff --git a/components/download/internal/test/mock_controller.h b/components/download/internal/test/mock_controller.h
index 5c5ff76..0c987d0e 100644
--- a/components/download/internal/test/mock_controller.h
+++ b/components/download/internal/test/mock_controller.h
@@ -20,7 +20,7 @@
   ~MockController() override;
 
   // Controller implementation.
-  MOCK_METHOD0(Initialize, void());
+  void Initialize(const base::Closure& callback) override;
   MOCK_METHOD0(GetStartupStatus, const StartupStatus*());
   MOCK_METHOD1(StartDownload, void(const DownloadParams&));
   MOCK_METHOD1(PauseDownload, void(const std::string&));
@@ -33,7 +33,10 @@
                void(DownloadTaskType, const TaskFinishedCallback&));
   MOCK_METHOD1(OnStopScheduledTask, bool(DownloadTaskType task_type));
 
+  void TriggerInitCompleted();
+
  private:
+  base::Closure init_callback_;
   DISALLOW_COPY_AND_ASSIGN(MockController);
 };
 
diff --git a/components/download/internal/test/test_download_driver.cc b/components/download/internal/test/test_download_driver.cc
index 891251b..8891ab6 100644
--- a/components/download/internal/test/test_download_driver.cc
+++ b/components/download/internal/test/test_download_driver.cc
@@ -22,6 +22,11 @@
     client_->OnDriverReady(is_ready_);
 }
 
+void TestDownloadDriver::TriggerHardRecoverComplete(bool success) {
+  if (client_)
+    client_->OnDriverHardRecoverComplete(success);
+}
+
 void TestDownloadDriver::AddTestData(const std::vector<DriverEntry>& entries) {
   for (const auto& entry : entries) {
     DCHECK(entries_.find(entry.guid) == entries_.end()) << "Existing guid.";
@@ -56,6 +61,8 @@
   client_ = client;
 }
 
+void TestDownloadDriver::HardRecover() {}
+
 bool TestDownloadDriver::IsReady() const {
   return is_ready_;
 }
diff --git a/components/download/internal/test/test_download_driver.h b/components/download/internal/test/test_download_driver.h
index 22a8d37..6a9c7c69 100644
--- a/components/download/internal/test/test_download_driver.h
+++ b/components/download/internal/test/test_download_driver.h
@@ -24,6 +24,7 @@
   // Marks download driver as ready, used to test logic that depends on
   // data initialization.
   void MakeReady();
+  void TriggerHardRecoverComplete(bool success);
 
   // Adds driver entries data that will be returned
   void AddTestData(const std::vector<DriverEntry>& entries);
@@ -35,6 +36,7 @@
 
   // DownloadDriver implementation.
   void Initialize(DownloadDriver::Client* client) override;
+  void HardRecover() override;
   bool IsReady() const override;
   void Start(
       const RequestParams& params,
diff --git a/components/exo/DEPS b/components/exo/DEPS
index 1c40ca1..860fb11 100644
--- a/components/exo/DEPS
+++ b/components/exo/DEPS
@@ -2,7 +2,7 @@
   "+ash",
   "+cc",
   "+chromeos/audio/chromeos_sounds.h",
-  "+components/viz/common/quads",
+  "+components/viz/common",
   "+components/viz/service",
   "+device/gamepad",
   "+gpu",
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 24c8f34..40a23ab 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -18,13 +18,13 @@
 #include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/resources/single_release_callback.h"
-#include "cc/surfaces/sequence_surface_reference_factory.h"
 #include "cc/surfaces/surface.h"
 #include "cc/surfaces/surface_manager.h"
 #include "components/exo/buffer.h"
 #include "components/exo/pointer.h"
 #include "components/exo/surface_delegate.h"
 #include "components/exo/surface_observer.h"
+#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
diff --git a/components/google/core/browser/google_util.cc b/components/google/core/browser/google_util.cc
index b8f8c1da..845e22a6 100644
--- a/components/google/core/browser/google_util.cc
+++ b/components/google/core/browser/google_util.cc
@@ -283,4 +283,30 @@
                       nullptr);
 }
 
+const std::vector<std::string>& GetGoogleRegistrableDomains() {
+  CR_DEFINE_STATIC_LOCAL(std::vector<std::string>, kGoogleRegisterableDomains,
+                         ());
+
+  // Initialize the list.
+  if (kGoogleRegisterableDomains.empty()) {
+    std::vector<std::string> tlds{GOOGLE_TLD_LIST};
+    for (const std::string& tld : tlds) {
+      std::string domain = "google." + tld;
+
+      // The Google TLD list might contain domains that are not considered
+      // to be registrable domains by net::registry_controlled_domains.
+      if (GetDomainAndRegistry(
+              domain,
+              net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES) !=
+          domain) {
+        continue;
+      }
+
+      kGoogleRegisterableDomains.push_back(domain);
+    }
+  }
+
+  return kGoogleRegisterableDomains;
+}
+
 }  // namespace google_util
diff --git a/components/google/core/browser/google_util.h b/components/google/core/browser/google_util.h
index d2526b2..d4730ef 100644
--- a/components/google/core/browser/google_util.h
+++ b/components/google/core/browser/google_util.h
@@ -8,6 +8,7 @@
 #define COMPONENTS_GOOGLE_CORE_BROWSER_GOOGLE_UTIL_H_
 
 #include <string>
+#include <vector>
 
 #include "base/strings/string_piece.h"
 
@@ -112,6 +113,14 @@
                         SubdomainPermission subdomain_permission,
                         PortPermission port_permission);
 
+// Returns the list of all Google's registerable domains, i.e. domains named
+// google.<eTLD> owned by Google.
+// TODO(msramek): This is currently only used to ensure the deletion of Google
+// service workers on signout. Remove this once we have other options to do it,
+// such as service workers discovering that signin cookies are missing and
+// unregistering themselves.
+const std::vector<std::string>& GetGoogleRegistrableDomains();
+
 }  // namespace google_util
 
 #endif  // COMPONENTS_GOOGLE_CORE_BROWSER_GOOGLE_UTIL_H_
diff --git a/components/language/DEPS b/components/language/DEPS
new file mode 100644
index 0000000..a6d4a63
--- /dev/null
+++ b/components/language/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+  "+components/pref_registry",
+  "+components/prefs",
+
+  # Language is a layered component; subdirectories must explicitly introduce
+  # the ability to use the content layer as appropriate.
+  "-components/language/content",
+]
diff --git a/components/language/OWNERS b/components/language/OWNERS
new file mode 100644
index 0000000..019412ab
--- /dev/null
+++ b/components/language/OWNERS
@@ -0,0 +1,4 @@
+sammc@chromium.org
+
+# TEAM: language@chromium.org
+# COMPONENT: UI>Browser>Language
diff --git a/components/language/README b/components/language/README
new file mode 100644
index 0000000..e4c4821
--- /dev/null
+++ b/components/language/README
@@ -0,0 +1,15 @@
+This component provides a unified model of user language which will serve as the
+single source of truth for other components.
+
+Language is implemented as a layered component
+(https://sites.google.com/a/chromium.org/dev/developers/design-documents/layered-components-design)
+to enable it to be shared cleanly on iOS.
+
+This component has the following structure:
+
+core/: shared code that does not depend on src/content or src/ios.
+content/: Driver for the shared code based on the content layer.
+  browser/: Browser process code.
+  renderer/: Renderer process code.
+  common/: Code shared by the browser and the renderer.
+ios/: Driver for the shared code based on src/ios.
diff --git a/components/language/content/DEPS b/components/language/content/DEPS
new file mode 100644
index 0000000..c57486b
--- /dev/null
+++ b/components/language/content/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+content/public/common",
+  "+mojo/public",
+]
diff --git a/components/language/content/browser/DEPS b/components/language/content/browser/DEPS
new file mode 100644
index 0000000..1c35d9c
--- /dev/null
+++ b/components/language/content/browser/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+content/public/browser",
+]
diff --git a/components/language/content/renderer/DEPS b/components/language/content/renderer/DEPS
new file mode 100644
index 0000000..725e151
--- /dev/null
+++ b/components/language/content/renderer/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+content/public/renderer",
+]
diff --git a/components/language/core/browser/BUILD.gn b/components/language/core/browser/BUILD.gn
new file mode 100644
index 0000000..54b103a5
--- /dev/null
+++ b/components/language/core/browser/BUILD.gn
@@ -0,0 +1,33 @@
+# 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.
+
+static_library("browser") {
+  sources = [
+    "url_language_histogram.cc",
+    "url_language_histogram.h",
+  ]
+
+  deps = [
+    "//base",
+    "//components/keyed_service/core",
+    "//components/pref_registry",
+    "//components/prefs",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "url_language_histogram_unittest.cc",
+  ]
+  deps = [
+    ":browser",
+    "//base",
+    "//components/pref_registry:pref_registry",
+    "//components/prefs",
+    "//components/prefs:test_support",
+    "//net:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/language/core/browser/DEPS b/components/language/core/browser/DEPS
new file mode 100644
index 0000000..f0bf3d9
--- /dev/null
+++ b/components/language/core/browser/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/keyed_service/core",
+]
diff --git a/components/translate/core/browser/language_model.cc b/components/language/core/browser/url_language_histogram.cc
similarity index 68%
rename from components/translate/core/browser/language_model.cc
rename to components/language/core/browser/url_language_histogram.cc
index 6899b38..a0b092b 100644
--- a/components/translate/core/browser/language_model.cc
+++ b/components/language/core/browser/url_language_histogram.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/translate/core/browser/language_model.h"
+#include "components/language/core/browser/url_language_histogram.h"
 
 #include <algorithm>
 #include <map>
@@ -12,18 +12,18 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 
-namespace translate {
+namespace language {
 
 namespace {
 
-const char kLanguageModelCounters[] = "language_model_counters";
+const char kUrlLanguageHistogramCounters[] = "language_model_counters";
 
 const int kMaxCountersSum = 1000;
 const int kMinCountersSum = 10;
 const float kCutoffRatio = 0.005f;
 const float kDiscountFactor = 0.75f;
 
-// Gets the sum of the counter for all languages in the model.
+// Gets the sum of the counter for all languages in the histogram.
 int GetCountersSum(const base::DictionaryValue& dict) {
   int sum = 0;
   int counter_value = 0;
@@ -58,16 +58,15 @@
 }
 
 // Transforms the counters from prefs into a list of LanguageInfo structs.
-std::vector<LanguageModel::LanguageInfo> GetAllLanguages(
+std::vector<UrlLanguageHistogram::LanguageInfo> GetAllLanguages(
     const base::DictionaryValue& dict) {
-
   int counters_sum = GetCountersSum(dict);
 
   // If the sample is not large enough yet, pretend there are no top languages.
   if (counters_sum < kMinCountersSum)
-    return std::vector<LanguageModel::LanguageInfo>();
+    return std::vector<UrlLanguageHistogram::LanguageInfo>();
 
-  std::vector<LanguageModel::LanguageInfo> top_languages;
+  std::vector<UrlLanguageHistogram::LanguageInfo> top_languages;
   int counter_value = 0;
   for (base::DictionaryValue::Iterator itr(dict); !itr.IsAtEnd();
        itr.Advance()) {
@@ -81,33 +80,35 @@
 
 }  // namespace
 
-LanguageModel::LanguageModel(PrefService* pref_service)
+UrlLanguageHistogram::UrlLanguageHistogram(PrefService* pref_service)
     : pref_service_(pref_service) {}
 
-LanguageModel::~LanguageModel() = default;
+UrlLanguageHistogram::~UrlLanguageHistogram() = default;
 
 // static
-void LanguageModel::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterDictionaryPref(kLanguageModelCounters);
+void UrlLanguageHistogram::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterDictionaryPref(kUrlLanguageHistogramCounters);
 }
 
-std::vector<LanguageModel::LanguageInfo> LanguageModel::GetTopLanguages()
-    const {
-  std::vector<LanguageModel::LanguageInfo> top_languages =
-      GetAllLanguages(*pref_service_->GetDictionary(kLanguageModelCounters));
+std::vector<UrlLanguageHistogram::LanguageInfo>
+UrlLanguageHistogram::GetTopLanguages() const {
+  std::vector<UrlLanguageHistogram::LanguageInfo> top_languages =
+      GetAllLanguages(
+          *pref_service_->GetDictionary(kUrlLanguageHistogramCounters));
 
   std::sort(top_languages.begin(), top_languages.end(),
-            [](LanguageModel::LanguageInfo a, LanguageModel::LanguageInfo b) {
+            [](UrlLanguageHistogram::LanguageInfo a,
+               UrlLanguageHistogram::LanguageInfo b) {
               return a.frequency > b.frequency;
             });
 
   return top_languages;
 }
 
-float LanguageModel::GetLanguageFrequency(
+float UrlLanguageHistogram::GetLanguageFrequency(
     const std::string& language_code) const {
   const base::DictionaryValue* dict =
-      pref_service_->GetDictionary(kLanguageModelCounters);
+      pref_service_->GetDictionary(kUrlLanguageHistogramCounters);
   int counters_sum = GetCountersSum(*dict);
   // If the sample is not large enough yet, pretend there are no top languages.
   if (counters_sum < kMinCountersSum)
@@ -120,8 +121,8 @@
   return static_cast<float>(counter_value) / counters_sum;
 }
 
-void LanguageModel::OnPageVisited(const std::string& language_code) {
-  DictionaryPrefUpdate update(pref_service_, kLanguageModelCounters);
+void UrlLanguageHistogram::OnPageVisited(const std::string& language_code) {
+  DictionaryPrefUpdate update(pref_service_, kUrlLanguageHistogramCounters);
   base::DictionaryValue* dict = update.Get();
   int counter_value = 0;
   // If the key |language_code| does not exist, |counter_value| stays 0.
@@ -132,14 +133,14 @@
     DiscountAndCleanCounters(dict);
 }
 
-void LanguageModel::ClearHistory(base::Time begin, base::Time end) {
+void UrlLanguageHistogram::ClearHistory(base::Time begin, base::Time end) {
   // Ignore all partial removals and react only to "entire" history removal.
   bool is_entire_history = (begin == base::Time() && end == base::Time::Max());
   if (!is_entire_history) {
     return;
   }
 
-  pref_service_->ClearPref(kLanguageModelCounters);
+  pref_service_->ClearPref(kUrlLanguageHistogramCounters);
 }
 
-}  // namespace translate
+}  // namespace language
diff --git a/components/language/core/browser/url_language_histogram.h b/components/language/core/browser/url_language_histogram.h
new file mode 100644
index 0000000..11226ce
--- /dev/null
+++ b/components/language/core/browser/url_language_histogram.h
@@ -0,0 +1,71 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_LANGUAGE_CORE_BROWSER_URL_LANGUAGE_HISTOGRAM_H_
+#define COMPONENTS_LANGUAGE_CORE_BROWSER_URL_LANGUAGE_HISTOGRAM_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace language {
+
+// Collects data about languages in which the user reads the web and provides
+// access to current estimated language preferences. The past behaviour is
+// discounted so that the histogram reflects changes in browsing habits. This
+// histogram does not have to contain all languages that ever appeared in user's
+// browsing, languages with insignificant frequency are removed, eventually.
+class UrlLanguageHistogram : public KeyedService {
+ public:
+  struct LanguageInfo {
+    LanguageInfo() = default;
+    LanguageInfo(const std::string& language_code, float frequency)
+        : language_code(language_code), frequency(frequency) {}
+
+    // The ISO 639 language code.
+    std::string language_code;
+
+    // The current estimated frequency of the language share, a number between 0
+    // and 1 (can be understood as the probability that the next page the user
+    // opens is in this language). Frequencies over all LanguageInfos from
+    // GetTopLanguages() sum to 1 (unless there are no top languages, yet).
+    float frequency = 0.0f;
+  };
+
+  explicit UrlLanguageHistogram(PrefService* pref_service);
+  ~UrlLanguageHistogram() override;
+
+  // Registers profile prefs for the histogram.
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+  // Returns a list of the languages currently tracked by the histogram, sorted
+  // by frequency in decreasing order. The list is empty, if the histogram has
+  // not enough data points.
+  std::vector<LanguageInfo> GetTopLanguages() const;
+
+  // Returns the estimated frequency for the given language or 0 if the language
+  // is not among the top languages kept in the histogram.
+  float GetLanguageFrequency(const std::string& language_code) const;
+
+  // Informs the histogram that a page with the given language has been visited.
+  void OnPageVisited(const std::string& language_code);
+
+  // Reflect in the histogram that history from |begin| to |end| gets cleared.
+  void ClearHistory(base::Time begin, base::Time end);
+
+ private:
+  PrefService* pref_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlLanguageHistogram);
+};
+
+}  // namespace language
+
+#endif  // COMPONENTS_LANGUAGE_CORE_BROWSER_URL_LANGUAGE_HISTOGRAM_H_
diff --git a/components/language/core/browser/url_language_histogram_unittest.cc b/components/language/core/browser/url_language_histogram_unittest.cc
new file mode 100644
index 0000000..6e5c4a89
--- /dev/null
+++ b/components/language/core/browser/url_language_histogram_unittest.cc
@@ -0,0 +1,147 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language/core/browser/url_language_histogram.h"
+
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ElementsAre;
+using testing::FloatEq;
+using testing::Gt;
+using testing::SizeIs;
+
+namespace {
+
+const char kLang1[] = "en";
+const char kLang2[] = "de";
+const char kLang3[] = "es";
+
+}  // namespace
+
+namespace language {
+
+bool operator==(const UrlLanguageHistogram::LanguageInfo& lhs,
+                const UrlLanguageHistogram::LanguageInfo& rhs) {
+  return lhs.language_code == rhs.language_code;
+}
+
+TEST(UrlLanguageHistogramTest, ListSorted) {
+  TestingPrefServiceSimple prefs;
+  UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+  UrlLanguageHistogram hist(&prefs);
+
+  for (int i = 0; i < 50; i++) {
+    hist.OnPageVisited(kLang1);
+    hist.OnPageVisited(kLang1);
+    hist.OnPageVisited(kLang1);
+    hist.OnPageVisited(kLang2);
+  }
+
+  // Note: LanguageInfo's operator== only checks the language code, not the
+  // frequency.
+  EXPECT_THAT(hist.GetTopLanguages(),
+              ElementsAre(UrlLanguageHistogram::LanguageInfo(kLang1, 0.0f),
+                          UrlLanguageHistogram::LanguageInfo(kLang2, 0.0f)));
+}
+
+TEST(UrlLanguageHistogramTest, ListSortedReversed) {
+  TestingPrefServiceSimple prefs;
+  UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+  UrlLanguageHistogram hist(&prefs);
+
+  for (int i = 0; i < 50; i++) {
+    hist.OnPageVisited(kLang2);
+    hist.OnPageVisited(kLang1);
+    hist.OnPageVisited(kLang1);
+    hist.OnPageVisited(kLang1);
+  }
+
+  // Note: LanguageInfo's operator== only checks the language code, not the
+  // frequency.
+  EXPECT_THAT(hist.GetTopLanguages(),
+              ElementsAre(UrlLanguageHistogram::LanguageInfo(kLang1, 0.0f),
+                          UrlLanguageHistogram::LanguageInfo(kLang2, 0.0f)));
+}
+
+TEST(UrlLanguageHistogramTest, RightFrequencies) {
+  TestingPrefServiceSimple prefs;
+  UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+  UrlLanguageHistogram hist(&prefs);
+
+  for (int i = 0; i < 50; i++) {
+    hist.OnPageVisited(kLang1);
+    hist.OnPageVisited(kLang1);
+    hist.OnPageVisited(kLang1);
+    hist.OnPageVisited(kLang2);
+  }
+
+  // Corresponding frequencies are given by the hist.
+  EXPECT_THAT(hist.GetLanguageFrequency(kLang1), FloatEq(0.75f));
+  EXPECT_THAT(hist.GetLanguageFrequency(kLang2), FloatEq(0.25f));
+  // An unknown language gets frequency 0.
+  EXPECT_THAT(hist.GetLanguageFrequency(kLang3), 0);
+}
+
+TEST(UrlLanguageHistogramTest, RareLanguageDiscarded) {
+  TestingPrefServiceSimple prefs;
+  UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+  UrlLanguageHistogram hist(&prefs);
+
+  hist.OnPageVisited(kLang2);
+
+  for (int i = 0; i < 900; i++)
+    hist.OnPageVisited(kLang1);
+
+  // Lang 2 is in the hist.
+  EXPECT_THAT(hist.GetLanguageFrequency(kLang2), Gt(0.0f));
+
+  // Another 100 visits cause the cleanup (total > 1000).
+  for (int i = 0; i < 100; i++)
+    hist.OnPageVisited(kLang1);
+  // Lang 2 is removed from the hist.
+  EXPECT_THAT(hist.GetTopLanguages(),
+              ElementsAre(UrlLanguageHistogram::LanguageInfo{kLang1, 1}));
+}
+
+TEST(UrlLanguageHistogramTest, ShouldClearHistoryIfAllTimes) {
+  TestingPrefServiceSimple prefs;
+  UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+  UrlLanguageHistogram hist(&prefs);
+
+  for (int i = 0; i < 100; i++) {
+    hist.OnPageVisited(kLang1);
+  }
+
+  EXPECT_THAT(hist.GetTopLanguages(), SizeIs(1));
+  EXPECT_THAT(hist.GetLanguageFrequency(kLang1), FloatEq(1.0));
+
+  hist.ClearHistory(base::Time(), base::Time::Max());
+
+  EXPECT_THAT(hist.GetTopLanguages(), SizeIs(0));
+  EXPECT_THAT(hist.GetLanguageFrequency(kLang1), FloatEq(0.0));
+}
+
+TEST(UrlLanguageHistogramTest, ShouldNotClearHistoryIfNotAllTimes) {
+  TestingPrefServiceSimple prefs;
+  UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+  UrlLanguageHistogram hist(&prefs);
+
+  for (int i = 0; i < 100; i++) {
+    hist.OnPageVisited(kLang1);
+  }
+
+  EXPECT_THAT(hist.GetTopLanguages(), SizeIs(1));
+  EXPECT_THAT(hist.GetLanguageFrequency(kLang1), FloatEq(1.0));
+
+  // Clearing only the last hour of the history has no effect.
+  hist.ClearHistory(base::Time::Now() - base::TimeDelta::FromHours(2),
+                    base::Time::Max());
+
+  EXPECT_THAT(hist.GetTopLanguages(), SizeIs(1));
+  EXPECT_THAT(hist.GetLanguageFrequency(kLang1), FloatEq(1.0));
+}
+
+}  // namespace language
diff --git a/components/language/ios/DEPS b/components/language/ios/DEPS
new file mode 100644
index 0000000..0fc0ddd
--- /dev/null
+++ b/components/language/ios/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+ios/web/public",
+]
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn
index 6c14ee2f..7ad4db1 100644
--- a/components/ntp_snippets/BUILD.gn
+++ b/components/ntp_snippets/BUILD.gn
@@ -124,6 +124,7 @@
     "//components/gcm_driver",
     "//components/history/core/browser",
     "//components/image_fetcher/core",
+    "//components/language/core/browser",
     "//components/metrics",
     "//components/ntp_snippets/remote/proto",
     "//components/offline_pages/core",
@@ -134,7 +135,6 @@
     "//components/sessions",
     "//components/strings",
     "//components/sync_sessions",
-    "//components/translate/core/browser",
     "//components/url_formatter",
     "//components/variations",
     "//components/variations/net",
diff --git a/components/ntp_snippets/DEPS b/components/ntp_snippets/DEPS
index 6af85ea..cd0ce25 100644
--- a/components/ntp_snippets/DEPS
+++ b/components/ntp_snippets/DEPS
@@ -6,6 +6,7 @@
   "+components/history/core",
   "+components/image_fetcher",
   "+components/keyed_service/core",
+  "+components/language/core/browser",
   "+components/leveldb_proto",
   "+components/metrics",
   "+components/prefs",
@@ -13,7 +14,6 @@
   "+components/signin",
   "+components/strings/grit/components_strings.h",
   "+components/sync/driver",
-  "+components/translate/core/browser",
   "+components/url_formatter",
   "+components/variations",
   "+components/version_info",
diff --git a/components/ntp_snippets/breaking_news/subscription_json_request.h b/components/ntp_snippets/breaking_news/subscription_json_request.h
index 75c10a4..f2aef592 100644
--- a/components/ntp_snippets/breaking_news/subscription_json_request.h
+++ b/components/ntp_snippets/breaking_news/subscription_json_request.h
@@ -14,7 +14,6 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "components/ntp_snippets/status.h"
-#include "components/translate/core/browser/language_model.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 #include "net/http/http_request_headers.h"
 
diff --git a/components/ntp_snippets/breaking_news/subscription_manager.h b/components/ntp_snippets/breaking_news/subscription_manager.h
index 8854797..e75c241 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager.h
+++ b/components/ntp_snippets/breaking_news/subscription_manager.h
@@ -12,6 +12,7 @@
 #include "url/gurl.h"
 
 class PrefRegistrySimple;
+class PrefService;
 
 namespace ntp_snippets {
 
diff --git a/components/ntp_snippets/remote/json_request.cc b/components/ntp_snippets/remote/json_request.cc
index 2ea9f4f7..2be9a6b 100644
--- a/components/ntp_snippets/remote/json_request.cc
+++ b/components/ntp_snippets/remote/json_request.cc
@@ -37,11 +37,11 @@
 #include "third_party/icu/source/common/unicode/utypes.h"
 #include "ui/base/l10n/l10n_util.h"
 
+using language::UrlLanguageHistogram;
 using net::URLFetcher;
 using net::URLRequestContextGetter;
 using net::HttpRequestHeaders;
 using net::URLRequestStatus;
-using translate::LanguageModel;
 
 namespace ntp_snippets {
 
@@ -52,7 +52,7 @@
 // Variation parameter for disabling the retry.
 const char kBackground5xxRetriesName[] = "background_5xx_retries_count";
 
-// Variation parameter for sending LanguageModel info to the server.
+// Variation parameter for sending UrlLanguageHistogram info to the server.
 const char kSendTopLanguagesName[] = "send_top_languages";
 
 // Variation parameter for sending UserClassifier info to the server.
@@ -108,7 +108,7 @@
 }
 
 void AppendLanguageInfoToList(base::ListValue* list,
-                              const LanguageModel::LanguageInfo& info) {
+                              const UrlLanguageHistogram::LanguageInfo& info) {
   auto lang = base::MakeUnique<base::DictionaryValue>();
   lang->SetString("language", info.language_code);
   lang->SetDouble("frequency", info.frequency);
@@ -216,7 +216,7 @@
            /*error_details=*/base::StringPrintf(" (error %s)", error.c_str()));
 }
 
-JsonRequest::Builder::Builder() : language_model_(nullptr) {}
+JsonRequest::Builder::Builder() : language_histogram_(nullptr) {}
 JsonRequest::Builder::Builder(JsonRequest::Builder&&) = default;
 JsonRequest::Builder::~Builder() = default;
 
@@ -246,9 +246,9 @@
   return *this;
 }
 
-JsonRequest::Builder& JsonRequest::Builder::SetLanguageModel(
-    const translate::LanguageModel* language_model) {
-  language_model_ = language_model;
+JsonRequest::Builder& JsonRequest::Builder::SetLanguageHistogram(
+    const language::UrlLanguageHistogram* language_histogram) {
+  language_histogram_ = language_histogram;
   return *this;
 }
 
@@ -326,8 +326,8 @@
     request->SetString("userActivenessClass", user_class_);
   }
 
-  translate::LanguageModel::LanguageInfo ui_language;
-  translate::LanguageModel::LanguageInfo other_top_language;
+  language::UrlLanguageHistogram::LanguageInfo ui_language;
+  language::UrlLanguageHistogram::LanguageInfo other_top_language;
   PrepareLanguages(&ui_language, &other_top_language);
   if (ui_language.frequency != 0 || other_top_language.frequency != 0) {
     auto language_list = base::MakeUnique<base::ListValue>();
@@ -366,8 +366,8 @@
             "request."
           data:
             "The Chromium UI language, as well as a second language the user "
-            "understands, based on translate::LanguageModel. For signed-in "
-            "users, the requests is authenticated."
+            "understands, based on language::UrlLanguageHistogram. For "
+            "signed-in users, the requests is authenticated."
           destination: GOOGLE_OWNED_SERVICE
         }
         policy {
@@ -402,12 +402,12 @@
 }
 
 void JsonRequest::Builder::PrepareLanguages(
-    translate::LanguageModel::LanguageInfo* ui_language,
-    translate::LanguageModel::LanguageInfo* other_top_language) const {
+    language::UrlLanguageHistogram::LanguageInfo* ui_language,
+    language::UrlLanguageHistogram::LanguageInfo* other_top_language) const {
   // TODO(jkrcal): Add language model factory for iOS and add fakes to tests so
-  // that |language_model| is never nullptr. Remove this check and add a DCHECK
-  // into the constructor.
-  if (!language_model_ || !IsSendingTopLanguagesEnabled()) {
+  // that |language_histogram| is never nullptr. Remove this check and add a
+  // DCHECK into the constructor.
+  if (!language_histogram_ || !IsSendingTopLanguagesEnabled()) {
     return;
   }
 
@@ -415,11 +415,11 @@
   ui_language->language_code = ISO639FromPosixLocale(
       PosixLocaleFromBCP47Language(params_.language_code));
   ui_language->frequency =
-      language_model_->GetLanguageFrequency(ui_language->language_code);
+      language_histogram_->GetLanguageFrequency(ui_language->language_code);
 
-  std::vector<LanguageModel::LanguageInfo> top_languages =
-      language_model_->GetTopLanguages();
-  for (const LanguageModel::LanguageInfo& info : top_languages) {
+  std::vector<UrlLanguageHistogram::LanguageInfo> top_languages =
+      language_histogram_->GetTopLanguages();
+  for (const UrlLanguageHistogram::LanguageInfo& info : top_languages) {
     if (info.language_code != ui_language->language_code) {
       *other_top_language = info;
 
diff --git a/components/ntp_snippets/remote/json_request.h b/components/ntp_snippets/remote/json_request.h
index 849df611..e7770e1 100644
--- a/components/ntp_snippets/remote/json_request.h
+++ b/components/ntp_snippets/remote/json_request.h
@@ -13,9 +13,9 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/time/time.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/ntp_snippets/remote/request_params.h"
 #include "components/ntp_snippets/status.h"
-#include "components/translate/core/browser/language_model.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 #include "net/http/http_request_headers.h"
 
@@ -70,9 +70,10 @@
     Builder& SetAuthentication(const std::string& account_id,
                                const std::string& auth_header);
     Builder& SetCreationTime(base::TimeTicks creation_time);
-    // The language_model borrowed from the fetcher needs to stay alive until
-    // the request body is built.
-    Builder& SetLanguageModel(const translate::LanguageModel* language_model);
+    // The language_histogram borrowed from the fetcher needs to stay alive
+    // until the request body is built.
+    Builder& SetLanguageHistogram(
+        const language::UrlLanguageHistogram* language_histogram);
     Builder& SetParams(const RequestParams& params);
     Builder& SetParseJsonCallback(ParseJSONCallback callback);
     // The clock borrowed from the fetcher will be injected into the
@@ -104,8 +105,8 @@
         const std::string& body) const;
 
     void PrepareLanguages(
-        translate::LanguageModel::LanguageInfo* ui_language,
-        translate::LanguageModel::LanguageInfo* other_top_language) const;
+        language::UrlLanguageHistogram::LanguageInfo* ui_language,
+        language::UrlLanguageHistogram::LanguageInfo* other_top_language) const;
 
     // Only required, if the request needs to be sent.
     std::string auth_header_;
@@ -118,7 +119,7 @@
     // Optional properties.
     std::string obfuscated_gaia_id_;
     std::string user_class_;
-    const translate::LanguageModel* language_model_;
+    const language::UrlLanguageHistogram* language_histogram_;
 
     DISALLOW_COPY_AND_ASSIGN(Builder);
   };
diff --git a/components/ntp_snippets/remote/json_request_unittest.cc b/components/ntp_snippets/remote/json_request_unittest.cc
index 3791ccd..0e52824c 100644
--- a/components/ntp_snippets/remote/json_request_unittest.cc
+++ b/components/ntp_snippets/remote/json_request_unittest.cc
@@ -69,20 +69,21 @@
         clock_(mock_task_runner_->GetMockClock()),
         request_context_getter_(
             new net::TestURLRequestContextGetter(mock_task_runner_.get())) {
-    translate::LanguageModel::RegisterProfilePrefs(pref_service_->registry());
+    language::UrlLanguageHistogram::RegisterProfilePrefs(
+        pref_service_->registry());
   }
 
-  std::unique_ptr<translate::LanguageModel> MakeLanguageModel(
+  std::unique_ptr<language::UrlLanguageHistogram> MakeLanguageHistogram(
       const std::set<std::string>& codes) {
-    std::unique_ptr<translate::LanguageModel> language_model =
-        base::MakeUnique<translate::LanguageModel>(pref_service_.get());
+    std::unique_ptr<language::UrlLanguageHistogram> language_histogram =
+        base::MakeUnique<language::UrlLanguageHistogram>(pref_service_.get());
     // There must be at least 10 visits before the top languages are defined.
     for (int i = 0; i < 10; i++) {
       for (const std::string& code : codes) {
-        language_model->OnPageVisited(code);
+        language_histogram->OnPageVisited(code);
       }
     }
-    return language_model;
+    return language_histogram;
   }
 
   JsonRequest::Builder CreateMinimalBuilder() {
@@ -221,12 +222,12 @@
 
 TEST_F(JsonRequestTest, BuildRequestWithTwoLanguages) {
   JsonRequest::Builder builder;
-  std::unique_ptr<translate::LanguageModel> language_model =
-      MakeLanguageModel({"de", "en"});
+  std::unique_ptr<language::UrlLanguageHistogram> language_histogram =
+      MakeLanguageHistogram({"de", "en"});
   RequestParams params;
   params.interactive_request = true;
   params.language_code = "en";
-  builder.SetParams(params).SetLanguageModel(language_model.get());
+  builder.SetParams(params).SetLanguageHistogram(language_histogram.get());
 
   EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
               EqualsJSON("{"
@@ -248,12 +249,12 @@
 
 TEST_F(JsonRequestTest, BuildRequestWithUILanguageOnly) {
   JsonRequest::Builder builder;
-  std::unique_ptr<translate::LanguageModel> language_model =
-      MakeLanguageModel({"en"});
+  std::unique_ptr<language::UrlLanguageHistogram> language_histogram =
+      MakeLanguageHistogram({"en"});
   RequestParams params;
   params.interactive_request = true;
   params.language_code = "en";
-  builder.SetParams(params).SetLanguageModel(language_model.get());
+  builder.SetParams(params).SetLanguageHistogram(language_histogram.get());
 
   EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
               EqualsJSON("{"
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
index 24bdd01..cf3fdb7b 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
@@ -11,6 +11,7 @@
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/ntp_snippets/category.h"
 #include "components/ntp_snippets/user_classifier.h"
 #include "components/signin/core/browser/access_token_fetcher.h"
@@ -18,11 +19,11 @@
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
 
+using language::UrlLanguageHistogram;
 using net::HttpRequestHeaders;
 using net::URLFetcher;
 using net::URLRequestContextGetter;
 using net::URLRequestStatus;
-using translate::LanguageModel;
 
 namespace ntp_snippets {
 
@@ -128,7 +129,7 @@
     OAuth2TokenService* token_service,
     scoped_refptr<URLRequestContextGetter> url_request_context_getter,
     PrefService* pref_service,
-    LanguageModel* language_model,
+    UrlLanguageHistogram* language_histogram,
     const ParseJSONCallback& parse_json_callback,
     const GURL& api_endpoint,
     const std::string& api_key,
@@ -136,7 +137,7 @@
     : signin_manager_(signin_manager),
       token_service_(token_service),
       url_request_context_getter_(std::move(url_request_context_getter)),
-      language_model_(language_model),
+      language_histogram_(language_histogram),
       parse_json_callback_(parse_json_callback),
       fetch_url_(api_endpoint),
       api_key_(api_key),
@@ -172,7 +173,7 @@
   }
 
   JsonRequest::Builder builder;
-  builder.SetLanguageModel(language_model_)
+  builder.SetLanguageHistogram(language_histogram_)
       .SetParams(params)
       .SetParseJsonCallback(parse_json_callback_)
       .SetClock(clock_.get())
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h
index 5d8444af..770ea50 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h
@@ -29,6 +29,10 @@
 class Value;
 }  // namespace base
 
+namespace language {
+class UrlLanguageHistogram;
+}  // namespace language
+
 namespace ntp_snippets {
 
 class UserClassifier;
@@ -40,7 +44,7 @@
       OAuth2TokenService* token_service,
       scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
       PrefService* pref_service,
-      translate::LanguageModel* language_model,
+      language::UrlLanguageHistogram* language_histogram,
       const ParseJSONCallback& parse_json_callback,
       const GURL& api_endpoint,
       const std::string& api_key,
@@ -115,7 +119,7 @@
       pending_requests_;
 
   // Weak reference, not owned.
-  translate::LanguageModel* const language_model_;
+  language::UrlLanguageHistogram* const language_histogram_;
 
   const ParseJSONCallback parse_json_callback_;
 
diff --git a/components/payments/content/payment_request_spec.cc b/components/payments/content/payment_request_spec.cc
index bc6a5a9..3af09f3 100644
--- a/components/payments/content/payment_request_spec.cc
+++ b/components/payments/content/payment_request_spec.cc
@@ -77,17 +77,19 @@
 }
 
 // Validates the |method_data| and fills |supported_card_networks_|,
-// |supported_card_networks_set_| and |basic_card_specified_networks_|.
+// |supported_card_networks_set_|, |basic_card_specified_networks_|,
+// and |url_payment_method_identifiers_|.
 void PopulateValidatedMethodData(
     const std::vector<PaymentMethodData>& method_data_vector,
     std::vector<std::string>* supported_card_networks,
     std::set<std::string>* basic_card_specified_networks,
     std::set<std::string>* supported_card_networks_set,
     std::set<autofill::CreditCard::CardType>* supported_card_types_set,
+    std::vector<std::string>* url_payment_method_identifiers,
     std::map<std::string, std::set<std::string>>* stringified_method_data) {
-  data_util::ParseBasicCardSupportedNetworks(method_data_vector,
-                                             supported_card_networks,
-                                             basic_card_specified_networks);
+  data_util::ParseSupportedMethods(method_data_vector, supported_card_networks,
+                                   basic_card_specified_networks,
+                                   url_payment_method_identifiers);
   supported_card_networks_set->insert(supported_card_networks->begin(),
                                       supported_card_networks->end());
 
@@ -101,6 +103,7 @@
     std::set<std::string>* basic_card_specified_networks,
     std::set<std::string>* supported_card_networks_set,
     std::set<autofill::CreditCard::CardType>* supported_card_types_set,
+    std::vector<std::string>* url_payment_method_identifiers,
     std::map<std::string, std::set<std::string>>* stringified_method_data) {
   std::vector<PaymentMethodData> method_data_vector;
   method_data_vector.reserve(method_data_mojom.size());
@@ -117,7 +120,8 @@
   PopulateValidatedMethodData(
       method_data_vector, supported_card_networks,
       basic_card_specified_networks, supported_card_networks_set,
-      supported_card_types_set, stringified_method_data);
+      supported_card_types_set, url_payment_method_identifiers,
+      stringified_method_data);
 }
 
 }  // namespace
@@ -140,7 +144,7 @@
   PopulateValidatedMethodData(
       method_data, &supported_card_networks_, &basic_card_specified_networks_,
       &supported_card_networks_set_, &supported_card_types_set_,
-      &stringified_method_data_);
+      &url_payment_method_identifiers_, &stringified_method_data_);
 }
 PaymentRequestSpec::~PaymentRequestSpec() {}
 
@@ -265,14 +269,16 @@
   for (const auto& modifier : details().modifiers) {
     std::vector<std::string> supported_networks;
     std::set<autofill::CreditCard::CardType> supported_types;
-    // The following 3 are unused but required by PopulateValidatedMethodData.
+    // The following 4 are unused but required by PopulateValidatedMethodData.
     std::set<std::string> basic_card_specified_networks;
     std::set<std::string> supported_card_networks_set;
+    std::vector<std::string> url_payment_method_identifiers;
     std::map<std::string, std::set<std::string>> stringified_method_data;
     PopulateValidatedMethodData(
         {CreatePaymentMethodData(modifier->method_data)}, &supported_networks,
         &basic_card_specified_networks, &supported_card_networks_set,
-        &supported_types, &stringified_method_data);
+        &supported_types, &url_payment_method_identifiers,
+        &stringified_method_data);
 
     if (selected_instrument->IsValidForModifier(
             modifier->method_data->supported_methods, supported_types,
diff --git a/components/payments/content/payment_request_spec.h b/components/payments/content/payment_request_spec.h
index 9930459..798e31d 100644
--- a/components/payments/content/payment_request_spec.h
+++ b/components/payments/content/payment_request_spec.h
@@ -89,6 +89,9 @@
       const {
     return supported_card_types_set_;
   }
+  const std::vector<std::string>& url_payment_method_identifiers() const {
+    return url_payment_method_identifiers_;
+  }
   // Returns whether the |method_name| was specified as supported through the
   // "basic-card" payment method. If false, it means either the |method_name| is
   // not supported at all, or specified directly in supportedMethods.
@@ -181,6 +184,12 @@
   // |supported_card_networks_set_| to check merchant support.
   std::set<std::string> basic_card_specified_networks_;
 
+  // A list of supported url-based payment method identifers specified by the
+  // merchant. This encompasses one of the two types of payment method
+  // identifers, the other being standardized payment method identifiers i.e.,
+  // basic-card.
+  std::vector<std::string> url_payment_method_identifiers_;
+
   // A mapping of the payment method names to the corresponding JSON-stringified
   // payment method specific data.
   std::map<std::string, std::set<std::string>> stringified_method_data_;
diff --git a/components/payments/core/payment_request_data_util.cc b/components/payments/core/payment_request_data_util.cc
index bee795f..65e29b0 100644
--- a/components/payments/core/payment_request_data_util.cc
+++ b/components/payments/core/payment_request_data_util.cc
@@ -19,6 +19,8 @@
 #include "components/payments/core/payment_address.h"
 #include "components/payments/core/payment_method_data.h"
 #include "third_party/libphonenumber/phonenumber_api.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
 
 namespace payments {
 namespace data_util {
@@ -91,12 +93,14 @@
   return response;
 }
 
-void ParseBasicCardSupportedNetworks(
+void ParseSupportedMethods(
     const std::vector<PaymentMethodData>& method_data,
     std::vector<std::string>* out_supported_networks,
-    std::set<std::string>* out_basic_card_specified_networks) {
+    std::set<std::string>* out_basic_card_specified_networks,
+    std::vector<std::string>* out_url_payment_method_identifiers) {
   DCHECK(out_supported_networks->empty());
   DCHECK(out_basic_card_specified_networks->empty());
+  DCHECK(out_url_payment_method_identifiers->empty());
 
   const std::set<std::string> kBasicCardNetworks{
       "amex",       "diners", "discover", "jcb",
@@ -149,6 +153,13 @@
             }
           }
         }
+      } else {
+        // Here |method| could be a repeated deprecated supported network (e.g.,
+        // "visa"), some invalid string or a URL Payment Method Identifier.
+        // Capture this last category if the URL is https.
+        GURL url(method);
+        if (url.is_valid() && url.SchemeIs(url::kHttpsScheme))
+          out_url_payment_method_identifiers->push_back(method);
       }
     }
   }
diff --git a/components/payments/core/payment_request_data_util.h b/components/payments/core/payment_request_data_util.h
index 93b80f1..7ede39a3 100644
--- a/components/payments/core/payment_request_data_util.h
+++ b/components/payments/core/payment_request_data_util.h
@@ -38,8 +38,10 @@
     const autofill::AutofillProfile& billing_profile,
     const std::string& app_locale);
 
-// Parse the supported card networks from supportedMethods and  "basic-card"'s
-// supportedNetworks. |out_supported_networks| is filled with list of networks
+// Parse all the supported payment methods from the merchant including 1) the
+// supported card networks from supportedMethods and  "basic-card"'s
+// supportedNetworks and 2) the url-based payment method identifiers.
+// |out_supported_networks| is filled with a list of networks
 // in the order that they were specified by the merchant.
 // |out_basic_card_supported_networks| is a subset of |out_supported_networks|
 // that includes all networks that were specified as part of "basic-card". This
@@ -47,10 +49,13 @@
 // "basic-card" in the PaymentResponse. |method_data.supported_networks| is
 // expected to only contain basic-card card network names (the list is at
 // https://www.w3.org/Payments/card-network-ids).
-void ParseBasicCardSupportedNetworks(
+// |out_url_payment_method_identifiers| is filled with a list of all the
+// payment method identifiers specicied by the merchant that are URL-based.
+void ParseSupportedMethods(
     const std::vector<PaymentMethodData>& method_data,
     std::vector<std::string>* out_supported_networks,
-    std::set<std::string>* out_basic_card_supported_networks);
+    std::set<std::string>* out_basic_card_supported_networks,
+    std::vector<std::string>* out_url_payment_method_identifiers);
 
 // Parses the supported card types (e.g., credit, debit, prepaid) from
 // supportedTypes. |out_supported_card_types_set| is expected to be empty. It
diff --git a/components/prefs/pref_value_store.h b/components/prefs/pref_value_store.h
index 7fb84f0..9fb9ed1 100644
--- a/components/prefs/pref_value_store.h
+++ b/components/prefs/pref_value_store.h
@@ -17,7 +17,9 @@
 #include "components/prefs/base_prefs_export.h"
 #include "components/prefs/pref_store.h"
 
+class PersistentPrefStore;
 class PrefNotifier;
+class PrefRegistry;
 class PrefStore;
 
 // The PrefValueStore manages various sources of values for Preferences
@@ -47,6 +49,11 @@
                       PrefStore* default_prefs,
                       PrefNotifier* pref_notifier) = 0;
 
+    virtual void InitIncognitoUnderlay(
+        PersistentPrefStore* incognito_user_prefs_underlay) = 0;
+
+    virtual void InitPrefRegistry(PrefRegistry* pref_registry) = 0;
+
     // Called whenever PrefValueStore::UpdateCommandLinePrefStore is called,
     // with the same argument.
     virtual void UpdateCommandLinePrefStore(PrefStore* command_line_prefs) = 0;
diff --git a/components/security_interstitials/core/common/resources/interstitial_common.js b/components/security_interstitials/core/common/resources/interstitial_common.js
index cd88b21a..8a4bf05c 100644
--- a/components/security_interstitials/core/common/resources/interstitial_common.js
+++ b/components/security_interstitials/core/common/resources/interstitial_common.js
@@ -35,7 +35,6 @@
  */
 function sendCommand(cmd) {
 // <if expr="not is_ios">
-  window.domAutomationController.setAutomationId(1);
   window.domAutomationController.send(cmd);
 // </if>
 // <if expr="is_ios">
diff --git a/components/ssl_config/BUILD.gn b/components/ssl_config/BUILD.gn
index d514ca633..4f3bca7 100644
--- a/components/ssl_config/BUILD.gn
+++ b/components/ssl_config/BUILD.gn
@@ -31,6 +31,7 @@
     "//base",
     "//base/test:test_support",
     "//components/prefs:test_support",
+    "//components/variations:test_support",
     "//net",
     "//testing/gtest",
   ]
diff --git a/components/ssl_config/DEPS b/components/ssl_config/DEPS
index 0fa195e..35579bbf 100644
--- a/components/ssl_config/DEPS
+++ b/components/ssl_config/DEPS
@@ -2,6 +2,7 @@
   "+components/content_settings/core/browser",
   "+components/content_settings/core/common",
   "+components/prefs",
+  "+components/variations",
   "+net/socket",
   "+net/ssl",
 ]
diff --git a/components/ssl_config/ssl_config_prefs.cc b/components/ssl_config/ssl_config_prefs.cc
index c255286..978ee3a 100644
--- a/components/ssl_config/ssl_config_prefs.cc
+++ b/components/ssl_config/ssl_config_prefs.cc
@@ -16,6 +16,7 @@
     "ssl.common_name_fallback_enabled_for_local_anchors";
 const char kSSLVersionMin[] = "ssl.version_min";
 const char kSSLVersionMax[] = "ssl.version_max";
+const char kTLS13Variant[] = "ssl.tls13_variant";
 const char kCipherSuiteBlacklist[] = "ssl.cipher_suites.blacklist";
 
 }  // namespace prefs
diff --git a/components/ssl_config/ssl_config_prefs.h b/components/ssl_config/ssl_config_prefs.h
index 2f38652..55121fc5 100644
--- a/components/ssl_config/ssl_config_prefs.h
+++ b/components/ssl_config/ssl_config_prefs.h
@@ -14,6 +14,7 @@
 extern const char kCertEnableCommonNameFallbackLocalAnchors[];
 extern const char kSSLVersionMin[];
 extern const char kSSLVersionMax[];
+extern const char kTLS13Variant[];
 extern const char kCipherSuiteBlacklist[];
 
 }  // namespace prefs
diff --git a/components/ssl_config/ssl_config_service_manager_pref.cc b/components/ssl_config/ssl_config_service_manager_pref.cc
index df78e58..f6aaa9a 100644
--- a/components/ssl_config/ssl_config_service_manager_pref.cc
+++ b/components/ssl_config/ssl_config_service_manager_pref.cc
@@ -10,9 +10,9 @@
 #include <vector>
 
 #include "base/bind.h"
-#include "base/feature_list.h"
 #include "base/location.h"
 #include "base/macros.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
@@ -85,9 +85,7 @@
   return version;
 }
 
-const base::Feature kTLS13Feature{
-    "NegotiateTLS13", base::FEATURE_DISABLED_BY_DEFAULT,
-};
+const char kTLS13VariantExperimentName[] = "TLS13Variant";
 
 }  // namespace
 
@@ -176,6 +174,7 @@
   BooleanPrefMember common_name_fallback_local_anchors_enabled_;
   StringPrefMember ssl_version_min_;
   StringPrefMember ssl_version_max_;
+  StringPrefMember tls13_variant_;
 
   // The cached list of disabled SSL cipher suites.
   std::vector<uint16_t> disabled_cipher_suites_;
@@ -194,7 +193,23 @@
       io_task_runner_(io_task_runner) {
   DCHECK(local_state);
 
-  if (base::FeatureList::IsEnabled(kTLS13Feature)) {
+  const std::string tls13_variant =
+      base::GetFieldTrialParamValue(kTLS13VariantExperimentName, "variant");
+  if (tls13_variant == "disabled") {
+    local_state->SetDefaultPrefValue(
+        ssl_config::prefs::kTLS13Variant,
+        new base::Value(switches::kTLS13VariantDisabled));
+  } else if (tls13_variant == "draft") {
+    local_state->SetDefaultPrefValue(
+        ssl_config::prefs::kTLS13Variant,
+        new base::Value(switches::kTLS13VariantDraft));
+    local_state->SetDefaultPrefValue(
+        ssl_config::prefs::kSSLVersionMax,
+        new base::Value(switches::kSSLVersionTLSv13));
+  } else if (tls13_variant == "experiment") {
+    local_state->SetDefaultPrefValue(
+        ssl_config::prefs::kTLS13Variant,
+        new base::Value(switches::kTLS13VariantExperiment));
     local_state->SetDefaultPrefValue(
         ssl_config::prefs::kSSLVersionMax,
         new base::Value(switches::kSSLVersionTLSv13));
@@ -219,6 +234,8 @@
                         local_state_callback);
   ssl_version_max_.Init(ssl_config::prefs::kSSLVersionMax, local_state,
                         local_state_callback);
+  tls13_variant_.Init(ssl_config::prefs::kTLS13Variant, local_state,
+                      local_state_callback);
 
   local_state_change_registrar_.Init(local_state);
   local_state_change_registrar_.Add(ssl_config::prefs::kCipherSuiteBlacklist,
@@ -248,6 +265,7 @@
                                std::string());
   registry->RegisterStringPref(ssl_config::prefs::kSSLVersionMax,
                                std::string());
+  registry->RegisterStringPref(ssl_config::prefs::kTLS13Variant, std::string());
   registry->RegisterListPref(ssl_config::prefs::kCipherSuiteBlacklist);
 }
 
@@ -287,6 +305,7 @@
       common_name_fallback_local_anchors_enabled_.GetValue();
   std::string version_min_str = ssl_version_min_.GetValue();
   std::string version_max_str = ssl_version_max_.GetValue();
+  std::string tls13_variant_str = tls13_variant_.GetValue();
   config->version_min = net::kDefaultSSLVersionMin;
   config->version_max = net::kDefaultSSLVersionMax;
   uint16_t version_min = SSLProtocolVersionFromString(version_min_str);
@@ -297,6 +316,16 @@
   if (version_max && version_max >= net::SSL_PROTOCOL_VERSION_TLS1_2) {
     config->version_max = version_max;
   }
+
+  if (tls13_variant_str == switches::kTLS13VariantDisabled) {
+    if (config->version_max > net::SSL_PROTOCOL_VERSION_TLS1_2)
+      config->version_max = net::SSL_PROTOCOL_VERSION_TLS1_2;
+  } else if (tls13_variant_str == switches::kTLS13VariantDraft) {
+    config->tls13_variant = net::kTLS13VariantDraft;
+  } else if (tls13_variant_str == switches::kTLS13VariantExperiment) {
+    config->tls13_variant = net::kTLS13VariantExperiment;
+  }
+
   config->disabled_cipher_suites = disabled_cipher_suites_;
 }
 
diff --git a/components/ssl_config/ssl_config_service_manager_pref_unittest.cc b/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
index bb94f68..32cf0e3 100644
--- a/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
+++ b/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
@@ -5,18 +5,18 @@
 #include <memory>
 #include <utility>
 
-#include "base/feature_list.h"
+#include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/ssl_config/ssl_config_prefs.h"
 #include "components/ssl_config/ssl_config_service_manager.h"
 #include "components/ssl_config/ssl_config_switches.h"
+#include "components/variations/variations_params_manager.h"
 #include "net/ssl/ssl_config.h"
 #include "net/ssl/ssl_config_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -146,18 +146,23 @@
   // enabled.
   EXPECT_EQ(net::kDefaultSSLVersionMin, ssl_config.version_min);
   EXPECT_EQ(net::kDefaultSSLVersionMax, ssl_config.version_max);
+  EXPECT_EQ(net::kDefaultTLS13Variant, ssl_config.tls13_variant);
 
   // The settings should not be added to the local_state.
   EXPECT_FALSE(local_state.HasPrefPath(ssl_config::prefs::kSSLVersionMin));
   EXPECT_FALSE(local_state.HasPrefPath(ssl_config::prefs::kSSLVersionMax));
+  EXPECT_FALSE(local_state.HasPrefPath(ssl_config::prefs::kTLS13Variant));
 
   // Explicitly double-check the settings are not in the preference store.
   std::string version_min_str;
   std::string version_max_str;
+  std::string tls13_variant_str;
   EXPECT_FALSE(local_state_store->GetString(ssl_config::prefs::kSSLVersionMin,
                                             &version_min_str));
   EXPECT_FALSE(local_state_store->GetString(ssl_config::prefs::kSSLVersionMax,
                                             &version_max_str));
+  EXPECT_FALSE(local_state_store->GetString(ssl_config::prefs::kTLS13Variant,
+                                            &tls13_variant_str));
 }
 
 // Tests that "ssl3" is not treated as a valid minimum version.
@@ -225,11 +230,31 @@
   EXPECT_LE(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_max);
 }
 
-// Tests that TLS 1.3 may be enabled via features.
-TEST_F(SSLConfigServiceManagerPrefTest, TLS13Feature) {
-  // Toggle the feature.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine("NegotiateTLS13", std::string());
+// Tests that TLS 1.3 can be disabled via field trials.
+TEST_F(SSLConfigServiceManagerPrefTest, TLS13VariantFeatureDisabled) {
+  // Toggle the field trial.
+  variations::testing::VariationParamsManager variation_params(
+      "TLS13Variant", {{"variant", "disabled"}});
+
+  TestingPrefServiceSimple local_state;
+  SSLConfigServiceManager::RegisterPrefs(local_state.registry());
+
+  std::unique_ptr<SSLConfigServiceManager> config_manager(
+      SSLConfigServiceManager::CreateDefaultManager(
+          &local_state, base::ThreadTaskRunnerHandle::Get()));
+  scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+  ASSERT_TRUE(config_service.get());
+
+  SSLConfig ssl_config;
+  config_service->GetSSLConfig(&ssl_config);
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_max);
+}
+
+// Tests that Draft TLS 1.3 can be enabled via field trials.
+TEST_F(SSLConfigServiceManagerPrefTest, TLS13VariantFeatureDraft) {
+  // Toggle the field trial.
+  variations::testing::VariationParamsManager variation_params(
+      "TLS13Variant", {{"variant", "draft"}});
 
   TestingPrefServiceSimple local_state;
   SSLConfigServiceManager::RegisterPrefs(local_state.registry());
@@ -243,15 +268,38 @@
   SSLConfig ssl_config;
   config_service->GetSSLConfig(&ssl_config);
   EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max);
+  EXPECT_EQ(net::kTLS13VariantDraft, ssl_config.tls13_variant);
 }
 
-// Tests that the SSLVersionMax preference overwites the TLS 1.3 feature.
+// Tests that Experiment TLS 1.3 can be enabled via field trials.
+TEST_F(SSLConfigServiceManagerPrefTest, TLS13VariantFeatureExperiment) {
+  // Toggle the field trial.
+  variations::testing::VariationParamsManager variation_params(
+      "TLS13Variant", {{"variant", "experiment"}});
+
+  TestingPrefServiceSimple local_state;
+  SSLConfigServiceManager::RegisterPrefs(local_state.registry());
+
+  std::unique_ptr<SSLConfigServiceManager> config_manager(
+      SSLConfigServiceManager::CreateDefaultManager(
+          &local_state, base::ThreadTaskRunnerHandle::Get()));
+  scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+  ASSERT_TRUE(config_service.get());
+
+  SSLConfig ssl_config;
+  config_service->GetSSLConfig(&ssl_config);
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max);
+  EXPECT_EQ(net::kTLS13VariantExperiment, ssl_config.tls13_variant);
+}
+
+// Tests that the SSLVersionMax preference overwites the TLS 1.3 variant
+// field trial.
 TEST_F(SSLConfigServiceManagerPrefTest, TLS13SSLVersionMax) {
   scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
 
-  // Toggle the feature.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine("NegotiateTLS13", std::string());
+  // Toggle the field trial.
+  variations::testing::VariationParamsManager variation_params(
+      "TLS13Variant", {{"variant", "experiment"}});
 
   TestingPrefServiceSimple local_state;
   local_state.SetUserPref(ssl_config::prefs::kSSLVersionMax,
@@ -270,6 +318,60 @@
   EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_max);
 }
 
+// Tests that disabling TLS 1.3 by preference overwrites the TLS 1.3 field
+// trial.
+TEST_F(SSLConfigServiceManagerPrefTest, TLS13VariantOverrideDisable) {
+  scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
+
+  // Toggle the field trial.
+  variations::testing::VariationParamsManager variation_params(
+      "TLS13Variant", {{"variant", "experiment"}});
+
+  TestingPrefServiceSimple local_state;
+  local_state.SetUserPref(ssl_config::prefs::kTLS13Variant,
+                          base::MakeUnique<base::Value>("disabled"));
+  SSLConfigServiceManager::RegisterPrefs(local_state.registry());
+
+  std::unique_ptr<SSLConfigServiceManager> config_manager(
+      SSLConfigServiceManager::CreateDefaultManager(
+          &local_state, base::ThreadTaskRunnerHandle::Get()));
+  ASSERT_TRUE(config_manager.get());
+  scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+  ASSERT_TRUE(config_service.get());
+
+  SSLConfig ssl_config;
+  config_service->GetSSLConfig(&ssl_config);
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_max);
+}
+
+// Tests that enabling TLS 1.3 by preference overwrites the TLS 1.3 field trial.
+TEST_F(SSLConfigServiceManagerPrefTest, TLS13VariantOverrideEnable) {
+  scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
+
+  // Toggle the field trial.
+  variations::testing::VariationParamsManager variation_params(
+      "TLS13Variant", {{"variant", "disabled"}});
+
+  TestingPrefServiceSimple local_state;
+  local_state.SetUserPref(ssl_config::prefs::kSSLVersionMax,
+                          base::MakeUnique<base::Value>("tls1.3"));
+  local_state.SetUserPref(ssl_config::prefs::kTLS13Variant,
+                          base::MakeUnique<base::Value>("experiment"));
+  SSLConfigServiceManager::RegisterPrefs(local_state.registry());
+
+  std::unique_ptr<SSLConfigServiceManager> config_manager(
+      SSLConfigServiceManager::CreateDefaultManager(
+          &local_state, base::ThreadTaskRunnerHandle::Get()));
+  ASSERT_TRUE(config_manager.get());
+  scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+  ASSERT_TRUE(config_service.get());
+
+  SSLConfig ssl_config;
+  config_service->GetSSLConfig(&ssl_config);
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max);
+  EXPECT_EQ(net::kTLS13VariantExperiment, ssl_config.tls13_variant);
+}
+
 // Tests that SHA-1 signatures for local trust anchors can be enabled.
 TEST_F(SSLConfigServiceManagerPrefTest, SHA1ForLocalAnchors) {
   scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
diff --git a/components/ssl_config/ssl_config_switches.cc b/components/ssl_config/ssl_config_switches.cc
index 2152f87e..691bb89 100644
--- a/components/ssl_config/ssl_config_switches.cc
+++ b/components/ssl_config/ssl_config_switches.cc
@@ -14,6 +14,9 @@
 // "tls1.3").
 const char kSSLVersionMin[] = "ssl-version-min";
 
+// Specifies the enabled TLS 1.3 variant ("disabled", "draft", "experiment").
+const char kTLS13Variant[] = "tls13-variant";
+
 // These values aren't switches, but rather the values that kSSLVersionMax and
 // kSSLVersionMin can have.
 const char kSSLVersionTLSv1[] = "tls1";
@@ -21,4 +24,8 @@
 const char kSSLVersionTLSv12[] = "tls1.2";
 const char kSSLVersionTLSv13[] = "tls1.3";
 
+const char kTLS13VariantDisabled[] = "disabled";
+const char kTLS13VariantDraft[] = "draft";
+const char kTLS13VariantExperiment[] = "experiment";
+
 }  // namespace switches
diff --git a/components/ssl_config/ssl_config_switches.h b/components/ssl_config/ssl_config_switches.h
index 34c7d24..2d115dd3 100644
--- a/components/ssl_config/ssl_config_switches.h
+++ b/components/ssl_config/ssl_config_switches.h
@@ -9,10 +9,14 @@
 
 extern const char kSSLVersionMax[];
 extern const char kSSLVersionMin[];
+extern const char kTLS13Variant[];
 extern const char kSSLVersionTLSv1[];
 extern const char kSSLVersionTLSv11[];
 extern const char kSSLVersionTLSv12[];
 extern const char kSSLVersionTLSv13[];
+extern const char kTLS13VariantDisabled[];
+extern const char kTLS13VariantDraft[];
+extern const char kTLS13VariantExperiment[];
 
 }  // namespace switches
 
diff --git a/components/sync_preferences/BUILD.gn b/components/sync_preferences/BUILD.gn
index e878677..a3ae9d25 100644
--- a/components/sync_preferences/BUILD.gn
+++ b/components/sync_preferences/BUILD.gn
@@ -25,6 +25,7 @@
     "//components/prefs",
     "//components/sync",
     "//services/preferences/public/cpp",
+    "//services/preferences/public/cpp:service_main",
   ]
 
   if (!is_ios) {
diff --git a/components/sync_preferences/pref_service_syncable.cc b/components/sync_preferences/pref_service_syncable.cc
index 488f859..e86cb800 100644
--- a/components/sync_preferences/pref_service_syncable.cc
+++ b/components/sync_preferences/pref_service_syncable.cc
@@ -16,33 +16,14 @@
 #include "components/prefs/pref_registry.h"
 #include "components/sync_preferences/pref_model_associator.h"
 #include "components/sync_preferences/pref_service_syncable_observer.h"
+#include "services/preferences/public/cpp/in_process_service_factory.h"
 #include "services/preferences/public/cpp/persistent_pref_store_client.h"
 #include "services/preferences/public/cpp/pref_registry_serializer.h"
-#include "services/preferences/public/cpp/pref_store_impl.h"
-#include "services/preferences/public/cpp/registering_delegate.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace sync_preferences {
 
-namespace {
-
-// This only needs to be called once per incognito profile.
-void InitIncognitoService(service_manager::Connector* incognito_connector,
-                          service_manager::Connector* user_connector) {
-  prefs::mojom::PrefStoreConnectorPtr connector;
-  user_connector->BindInterface(prefs::mojom::kServiceName, &connector);
-  auto config = prefs::mojom::PersistentPrefStoreConfiguration::New();
-  config->set_incognito_configuration(
-      prefs::mojom::IncognitoPersistentPrefStoreConfiguration::New(
-          std::move(connector)));
-  prefs::mojom::PrefServiceControlPtr control;
-  incognito_connector->BindInterface(prefs::mojom::kServiceName, &control);
-  control->Init(std::move(config));
-}
-
-}  // namespace
-
 PrefServiceSyncable::PrefServiceSyncable(
     PrefNotifierImpl* pref_notifier,
     PrefValueStore* pref_value_store,
@@ -94,9 +75,7 @@
 PrefServiceSyncable* PrefServiceSyncable::CreateIncognitoPrefService(
     PrefStore* incognito_extension_pref_store,
     const std::vector<const char*>& overlay_pref_names,
-    std::set<PrefValueStore::PrefStoreType> already_connected_types,
-    service_manager::Connector* incognito_connector,
-    service_manager::Connector* user_connector) {
+    std::unique_ptr<PrefValueStore::Delegate> delegate) {
   pref_service_forked_ = true;
   PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
 
@@ -104,19 +83,12 @@
       static_cast<user_prefs::PrefRegistrySyncable*>(pref_registry_.get())
           ->ForkForIncognito();
 
-  scoped_refptr<OverlayUserPrefStore> incognito_pref_store;
-  std::unique_ptr<RegisteringDelegate> delegate;
-  if (incognito_connector) {
-    DCHECK(user_connector);
-    incognito_pref_store = CreateOverlayUsingPrefService(
-        forked_registry.get(), std::move(already_connected_types),
-        incognito_connector, user_connector);
-    prefs::mojom::PrefStoreRegistryPtr registry;
-    incognito_connector->BindInterface(prefs::mojom::kServiceName, &registry);
-    delegate = base::MakeUnique<RegisteringDelegate>(std::move(registry));
-  } else {
-    incognito_pref_store = new OverlayUserPrefStore(user_pref_store_.get());
+  if (delegate) {
+    delegate->InitIncognitoUnderlay(user_pref_store_.get());
+    delegate->InitPrefRegistry(forked_registry.get());
   }
+  auto incognito_pref_store =
+      base::MakeRefCounted<OverlayUserPrefStore>(user_pref_store_.get());
 
   for (const char* overlay_pref_name : overlay_pref_names)
     incognito_pref_store->RegisterOverlayPref(overlay_pref_name);
@@ -226,35 +198,4 @@
   priority_pref_sync_associator_.ProcessPrefChange(name);
 }
 
-OverlayUserPrefStore* PrefServiceSyncable::CreateOverlayUsingPrefService(
-    user_prefs::PrefRegistrySyncable* pref_registry,
-    std::set<PrefValueStore::PrefStoreType> already_connected_types,
-    service_manager::Connector* incognito_connector,
-    service_manager::Connector* user_connector) const {
-  InitIncognitoService(incognito_connector, user_connector);
-
-  prefs::mojom::PrefStoreConnectorPtr pref_connector;
-  incognito_connector->BindInterface(prefs::mojom::kServiceName,
-                                     &pref_connector);
-  std::vector<PrefValueStore::PrefStoreType> in_process_types(
-      already_connected_types.begin(), already_connected_types.end());
-
-  // Connect to the writable, in-memory incognito pref store.
-  prefs::mojom::PersistentPrefStoreConnectionPtr connection;
-  prefs::mojom::PersistentPrefStoreConnectionPtr incognito_connection;
-  std::vector<prefs::mojom::PrefRegistrationPtr> remote_defaults;
-  std::unordered_map<PrefValueStore::PrefStoreType,
-                     prefs::mojom::PrefStoreConnectionPtr>
-      other_pref_stores;
-  mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_calls;
-  bool success = pref_connector->Connect(
-      prefs::SerializePrefRegistry(*pref_registry), in_process_types,
-      &incognito_connection, &connection, &remote_defaults, &other_pref_stores);
-  DCHECK(success);
-
-  return new OverlayUserPrefStore(
-      new prefs::PersistentPrefStoreClient(std::move(incognito_connection)),
-      user_pref_store_.get());
-}
-
 }  // namespace sync_preferences
diff --git a/components/sync_preferences/pref_service_syncable.h b/components/sync_preferences/pref_service_syncable.h
index 2af6803..21f58b9 100644
--- a/components/sync_preferences/pref_service_syncable.h
+++ b/components/sync_preferences/pref_service_syncable.h
@@ -18,12 +18,6 @@
 #include "components/sync_preferences/pref_model_associator.h"
 #include "components/sync_preferences/synced_pref_observer.h"
 
-class OverlayUserPrefStore;
-
-namespace service_manager {
-class Connector;
-}
-
 namespace syncer {
 class SyncableService;
 }
@@ -59,9 +53,7 @@
   PrefServiceSyncable* CreateIncognitoPrefService(
       PrefStore* incognito_extension_pref_store,
       const std::vector<const char*>& overlay_pref_names,
-      std::set<PrefValueStore::PrefStoreType> already_connected_types,
-      service_manager::Connector* incognito_connector,
-      service_manager::Connector* user_connector);
+      std::unique_ptr<PrefValueStore::Delegate> delegate);
 
   // Returns true if preferences state has synchronized with the remote
   // preferences. If true is returned it can be assumed the local preferences
@@ -115,14 +107,6 @@
   // sent to the syncer.
   void ProcessPrefChange(const std::string& name);
 
-  // Create an |OverlayUserPrefStore| where the overlayed in-memory pref store
-  // is accessed remotely through the pref service.
-  OverlayUserPrefStore* CreateOverlayUsingPrefService(
-      user_prefs::PrefRegistrySyncable* pref_registry,
-      std::set<PrefValueStore::PrefStoreType> already_connected_types,
-      service_manager::Connector* incognito_connector,
-      service_manager::Connector* user_connector) const;
-
   // Whether CreateIncognitoPrefService() has been called to create a
   // "forked" PrefService.
   bool pref_service_forked_;
diff --git a/components/sync_preferences/pref_service_syncable_factory.cc b/components/sync_preferences/pref_service_syncable_factory.cc
index bf3367b9..516415a0 100644
--- a/components/sync_preferences/pref_service_syncable_factory.cc
+++ b/components/sync_preferences/pref_service_syncable_factory.cc
@@ -11,9 +11,6 @@
 #include "components/prefs/pref_notifier_impl.h"
 #include "components/prefs/pref_value_store.h"
 #include "components/sync_preferences/pref_service_syncable.h"
-#include "services/preferences/public/cpp/registering_delegate.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
 
 #if !defined(OS_IOS)
 #include "components/policy/core/browser/browser_policy_connector.h"
@@ -57,17 +54,10 @@
 
 std::unique_ptr<PrefServiceSyncable> PrefServiceSyncableFactory::CreateSyncable(
     user_prefs::PrefRegistrySyncable* pref_registry,
-    service_manager::Connector* connector) {
+    std::unique_ptr<PrefValueStore::Delegate> delegate) {
   TRACE_EVENT0("browser", "PrefServiceSyncableFactory::CreateSyncable");
   PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
 
-  std::unique_ptr<RegisteringDelegate> delegate;
-  if (connector) {
-    prefs::mojom::PrefStoreRegistryPtr registry;
-    connector->BindInterface(prefs::mojom::kServiceName, &registry);
-    delegate = base::MakeUnique<RegisteringDelegate>(std::move(registry));
-  }
-
   std::unique_ptr<PrefServiceSyncable> pref_service(new PrefServiceSyncable(
       pref_notifier,
       new PrefValueStore(managed_prefs_.get(), supervised_user_prefs_.get(),
diff --git a/components/sync_preferences/pref_service_syncable_factory.h b/components/sync_preferences/pref_service_syncable_factory.h
index 3b9bb394..b6726b3 100644
--- a/components/sync_preferences/pref_service_syncable_factory.h
+++ b/components/sync_preferences/pref_service_syncable_factory.h
@@ -9,16 +9,13 @@
 
 #include "base/macros.h"
 #include "components/prefs/pref_service_factory.h"
+#include "components/prefs/pref_value_store.h"
 
 namespace policy {
 class BrowserPolicyConnector;
 class PolicyService;
 }
 
-namespace service_manager {
-class Connector;
-}
-
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
@@ -46,11 +43,11 @@
   void SetPrefModelAssociatorClient(
       PrefModelAssociatorClient* pref_model_associator_client);
 
-  // |connector| might be null during test or if we're not using the Mojo pref
-  // |service.
+  // |delegate| might be null during test or if we're not using the Mojo pref
+  // service.
   std::unique_ptr<PrefServiceSyncable> CreateSyncable(
       user_prefs::PrefRegistrySyncable* registry,
-      service_manager::Connector* connector = nullptr);
+      std::unique_ptr<PrefValueStore::Delegate> delegate = nullptr);
 
  private:
   PrefModelAssociatorClient* pref_model_associator_client_;
diff --git a/components/translate/DEPS b/components/translate/DEPS
index bae7be4..a94c34b8 100644
--- a/components/translate/DEPS
+++ b/components/translate/DEPS
@@ -2,6 +2,7 @@
   "+components/data_use_measurement/core",
   "+components/grit/components_resources.h",
   "+components/infobars",
+  "+components/language",
   "+components/language_usage_metrics",
   "+components/metrics/proto",
   "+components/pref_registry",
diff --git a/components/translate/core/browser/BUILD.gn b/components/translate/core/browser/BUILD.gn
index 83db458..2932340 100644
--- a/components/translate/core/browser/BUILD.gn
+++ b/components/translate/core/browser/BUILD.gn
@@ -6,8 +6,6 @@
 
 static_library("browser") {
   sources = [
-    "language_model.cc",
-    "language_model.h",
     "language_state.cc",
     "language_state.h",
     "page_translated_details.h",
@@ -89,7 +87,6 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "language_model_unittest.cc",
     "language_state_unittest.cc",
     "mock_translate_client.cc",
     "mock_translate_client.h",
diff --git a/components/translate/core/browser/language_model.h b/components/translate/core/browser/language_model.h
deleted file mode 100644
index b6547f0..0000000
--- a/components/translate/core/browser/language_model.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_LANGUAGE_MODEL_H_
-#define COMPONENTS_TRANSLATE_CORE_BROWSER_LANGUAGE_MODEL_H_
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-namespace translate {
-
-// Collects data about languages in which the user reads the web and provides
-// access to current estimated language preferences. The past behaviour is
-// discounted so that this model reflects changes in browsing habits. This model
-// does not have to contain all languages that ever appeared in user's browsing,
-// languages with insignificant frequency are removed, eventually.
-class LanguageModel : public KeyedService {
- public:
-  struct LanguageInfo {
-    LanguageInfo() = default;
-    LanguageInfo(const std::string& language_code, float frequency)
-        : language_code(language_code), frequency(frequency) {}
-
-    // The ISO 639 language code.
-    std::string language_code;
-
-    // The current estimated frequency of the language share, a number between 0
-    // and 1 (can be understood as the probability that the next page the user
-    // opens is in this language). Frequencies over all LanguageInfos from
-    // GetTopLanguages() sum to 1 (unless there are no top languages, yet).
-    float frequency = 0.0f;
-  };
-
-  explicit LanguageModel(PrefService* pref_service);
-  ~LanguageModel() override;
-
-  // Registers profile prefs for the model.
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
-  // Returns a list of the languages currently tracked by the model, sorted by
-  // frequency in decreasing order. The list is empty, if the model has not
-  // enough data points.
-  std::vector<LanguageInfo> GetTopLanguages() const;
-
-  // Returns the estimated frequency for the given language or 0 if the language
-  // is not among the top languages kept in the model.
-  float GetLanguageFrequency(const std::string& language_code) const;
-
-  // Informs the model that a page with the given language has been visited.
-  void OnPageVisited(const std::string& language_code);
-
-  // Reflect in the model that history from |begin| to |end| gets cleared.
-  void ClearHistory(base::Time begin, base::Time end);
-
- private:
-  PrefService* pref_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(LanguageModel);
-};
-
-}  // namespace translate
-
-#endif  // COMPONENTS_TRANSLATE_CORE_BROWSER_LANGUAGE_MODEL_H_
diff --git a/components/translate/core/browser/language_model_unittest.cc b/components/translate/core/browser/language_model_unittest.cc
deleted file mode 100644
index f59a31b..0000000
--- a/components/translate/core/browser/language_model_unittest.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/translate/core/browser/language_model.h"
-
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::ElementsAre;
-using testing::FloatEq;
-using testing::Gt;
-using testing::SizeIs;
-
-namespace {
-
-const char kLang1[] = "en";
-const char kLang2[] = "de";
-const char kLang3[] = "es";
-
-}  // namespace
-
-namespace translate {
-
-bool operator==(const LanguageModel::LanguageInfo& lhs,
-                const LanguageModel::LanguageInfo& rhs) {
-  return lhs.language_code == rhs.language_code;
-}
-
-TEST(LanguageModelTest, ListSorted) {
-  TestingPrefServiceSimple prefs;
-  LanguageModel::RegisterProfilePrefs(prefs.registry());
-  LanguageModel model(&prefs);
-
-  for (int i = 0; i < 50; i++) {
-    model.OnPageVisited(kLang1);
-    model.OnPageVisited(kLang1);
-    model.OnPageVisited(kLang1);
-    model.OnPageVisited(kLang2);
-  }
-
-  // Note: LanguageInfo's operator== only checks the language code, not the
-  // frequency.
-  EXPECT_THAT(model.GetTopLanguages(),
-              ElementsAre(LanguageModel::LanguageInfo(kLang1, 0.0f),
-                          LanguageModel::LanguageInfo(kLang2, 0.0f)));
-}
-
-TEST(LanguageModelTest, ListSortedReversed) {
-  TestingPrefServiceSimple prefs;
-  LanguageModel::RegisterProfilePrefs(prefs.registry());
-  LanguageModel model(&prefs);
-
-  for (int i = 0; i < 50; i++) {
-    model.OnPageVisited(kLang2);
-    model.OnPageVisited(kLang1);
-    model.OnPageVisited(kLang1);
-    model.OnPageVisited(kLang1);
-  }
-
-  // Note: LanguageInfo's operator== only checks the language code, not the
-  // frequency.
-  EXPECT_THAT(model.GetTopLanguages(),
-              ElementsAre(LanguageModel::LanguageInfo(kLang1, 0.0f),
-                          LanguageModel::LanguageInfo(kLang2, 0.0f)));
-}
-
-TEST(LanguageModelTest, RightFrequencies) {
-  TestingPrefServiceSimple prefs;
-  LanguageModel::RegisterProfilePrefs(prefs.registry());
-  LanguageModel model(&prefs);
-
-  for (int i = 0; i < 50; i++) {
-    model.OnPageVisited(kLang1);
-    model.OnPageVisited(kLang1);
-    model.OnPageVisited(kLang1);
-    model.OnPageVisited(kLang2);
-  }
-
-  // Corresponding frequencies are given by the model.
-  EXPECT_THAT(model.GetLanguageFrequency(kLang1), FloatEq(0.75f));
-  EXPECT_THAT(model.GetLanguageFrequency(kLang2), FloatEq(0.25f));
-  // An unknown language gets frequency 0.
-  EXPECT_THAT(model.GetLanguageFrequency(kLang3), 0);
-}
-
-TEST(LanguageModelTest, RareLanguageDiscarded) {
-  TestingPrefServiceSimple prefs;
-  LanguageModel::RegisterProfilePrefs(prefs.registry());
-  LanguageModel model(&prefs);
-
-  model.OnPageVisited(kLang2);
-
-  for (int i = 0; i < 900; i++)
-    model.OnPageVisited(kLang1);
-
-  // Lang 2 is in the model.
-  EXPECT_THAT(model.GetLanguageFrequency(kLang2), Gt(0.0f));
-
-  // Another 100 visits cause the cleanup (total > 1000).
-  for (int i = 0; i < 100; i++)
-    model.OnPageVisited(kLang1);
-  // Lang 2 is removed from the model.
-  EXPECT_THAT(model.GetTopLanguages(),
-              ElementsAre(LanguageModel::LanguageInfo{kLang1, 1}));
-}
-
-TEST(LanguageModelTest, ShouldClearHistoryIfAllTimes) {
-  TestingPrefServiceSimple prefs;
-  LanguageModel::RegisterProfilePrefs(prefs.registry());
-  LanguageModel model(&prefs);
-
-  for (int i = 0; i < 100; i++) {
-    model.OnPageVisited(kLang1);
-  }
-
-  EXPECT_THAT(model.GetTopLanguages(), SizeIs(1));
-  EXPECT_THAT(model.GetLanguageFrequency(kLang1), FloatEq(1.0));
-
-  model.ClearHistory(base::Time(), base::Time::Max());
-
-  EXPECT_THAT(model.GetTopLanguages(), SizeIs(0));
-  EXPECT_THAT(model.GetLanguageFrequency(kLang1), FloatEq(0.0));
-}
-
-TEST(LanguageModelTest, ShouldNotClearHistoryIfNotAllTimes) {
-  TestingPrefServiceSimple prefs;
-  LanguageModel::RegisterProfilePrefs(prefs.registry());
-  LanguageModel model(&prefs);
-
-  for (int i = 0; i < 100; i++) {
-    model.OnPageVisited(kLang1);
-  }
-
-  EXPECT_THAT(model.GetTopLanguages(), SizeIs(1));
-  EXPECT_THAT(model.GetLanguageFrequency(kLang1), FloatEq(1.0));
-
-  // Clearing only the last hour of the history has no effect.
-  model.ClearHistory(base::Time::Now() - base::TimeDelta::FromHours(2),
-                     base::Time::Max());
-
-  EXPECT_THAT(model.GetTopLanguages(), SizeIs(1));
-  EXPECT_THAT(model.GetLanguageFrequency(kLang1), FloatEq(1.0));
-}
-
-}  // namespace translate
diff --git a/components/translate/ios/browser/BUILD.gn b/components/translate/ios/browser/BUILD.gn
index 878ec3949..ea58e53 100644
--- a/components/translate/ios/browser/BUILD.gn
+++ b/components/translate/ios/browser/BUILD.gn
@@ -24,6 +24,7 @@
   deps = [
     ":injected_js",
     "//base",
+    "//components/language/core/browser",
     "//components/prefs",
     "//components/translate/core/browser",
     "//components/translate/core/common",
diff --git a/components/translate/ios/browser/DEPS b/components/translate/ios/browser/DEPS
new file mode 100644
index 0000000..a3d71d672
--- /dev/null
+++ b/components/translate/ios/browser/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/language/core/browser",
+]
diff --git a/components/translate/ios/browser/ios_translate_driver.h b/components/translate/ios/browser/ios_translate_driver.h
index 7043de1..e4ce60a6 100644
--- a/components/translate/ios/browser/ios_translate_driver.h
+++ b/components/translate/ios/browser/ios_translate_driver.h
@@ -17,6 +17,10 @@
 
 @class CRWJSInjectionReceiver;
 
+namespace language {
+class UrlLanguageHistogram;
+}
+
 namespace web {
 class NavigationManager;
 class WebState;
@@ -25,7 +29,6 @@
 namespace translate {
 
 class TranslateManager;
-class LanguageModel;
 
 // Content implementation of TranslateDriver.
 class IOSTranslateDriver : public TranslateDriver,
@@ -35,7 +38,7 @@
   IOSTranslateDriver(web::WebState* web_state,
                      web::NavigationManager* navigation_manager,
                      TranslateManager* translate_manager,
-                     LanguageModel* language_model);
+                     language::UrlLanguageHistogram* language_histogram);
   ~IOSTranslateDriver() override;
 
   LanguageDetectionController* language_detection_controller() {
@@ -101,7 +104,7 @@
   web::NavigationManager* navigation_manager_;
 
   // Model to be notified about detected language of every page visited.
-  translate::LanguageModel* language_model_;
+  language::UrlLanguageHistogram* language_histogram_;
 
   base::WeakPtr<TranslateManager> translate_manager_;
   std::unique_ptr<TranslateController> translate_controller_;
diff --git a/components/translate/ios/browser/ios_translate_driver.mm b/components/translate/ios/browser/ios_translate_driver.mm
index f51ea101..9c14288 100644
--- a/components/translate/ios/browser/ios_translate_driver.mm
+++ b/components/translate/ios/browser/ios_translate_driver.mm
@@ -9,7 +9,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "components/translate/core/browser/language_model.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/translate/core/browser/translate_client.h"
 #include "components/translate/core/browser/translate_manager.h"
 #include "components/translate/core/common/language_detection_details.h"
@@ -52,10 +52,10 @@
     web::WebState* web_state,
     web::NavigationManager* navigation_manager,
     TranslateManager* translate_manager,
-    LanguageModel* language_model)
+    language::UrlLanguageHistogram* language_histogram)
     : web::WebStateObserver(web_state),
       navigation_manager_(navigation_manager),
-      language_model_(language_model),
+      language_histogram_(language_histogram),
       translate_manager_(translate_manager->GetWeakPtr()),
       page_seq_no_(0),
       pending_page_seq_no_(0),
@@ -96,9 +96,9 @@
   translate_manager_->GetLanguageState().LanguageDetermined(
       details.adopted_language, true);
 
-  // Update language model.
-  if (language_model_ && details.is_cld_reliable) {
-    language_model_->OnPageVisited(details.cld_language);
+  // Update language histogram.
+  if (language_histogram_ && details.is_cld_reliable) {
+    language_histogram_->OnPageVisited(details.cld_language);
   }
 
   translate::LanguageDetectionDetails detection_details;
diff --git a/components/variations/service/BUILD.gn b/components/variations/service/BUILD.gn
index 6e8da5d..0de738ee 100644
--- a/components/variations/service/BUILD.gn
+++ b/components/variations/service/BUILD.gn
@@ -6,6 +6,8 @@
   sources = [
     "ui_string_overrider.cc",
     "ui_string_overrider.h",
+    "variations_field_trial_creator.cc",
+    "variations_field_trial_creator.h",
     "variations_service.cc",
     "variations_service.h",
     "variations_service_client.h",
@@ -30,6 +32,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "field_trial_creator_unittest.cc",
     "ui_string_overrider_unittest.cc",
     "variations_service_unittest.cc",
   ]
diff --git a/components/variations/service/field_trial_creator_unittest.cc b/components/variations/service/field_trial_creator_unittest.cc
new file mode 100644
index 0000000..d3d4ebf
--- /dev/null
+++ b/components/variations/service/field_trial_creator_unittest.cc
@@ -0,0 +1,260 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/variations/service/variations_field_trial_creator.h"
+
+#include <stddef.h>
+
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/version.h"
+#include "components/metrics/clean_exit_beacon.h"
+#include "components/metrics/client_info.h"
+#include "components/metrics/metrics_state_manager.h"
+#include "components/metrics/test_enabled_state_provider.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/variations/pref_names.h"
+#include "components/variations/service/variations_service.h"
+#include "components/web_resource/resource_request_allowed_notifier_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace variations {
+namespace {
+
+// A stub for the metrics state manager.
+void StubStoreClientInfo(const metrics::ClientInfo& /* client_info */) {}
+
+// A stub for the metrics state manager.
+std::unique_ptr<metrics::ClientInfo> StubLoadClientInfo() {
+  return std::unique_ptr<metrics::ClientInfo>();
+}
+
+class TestVariationsServiceClient : public VariationsServiceClient {
+ public:
+  TestVariationsServiceClient() {}
+  ~TestVariationsServiceClient() override {}
+
+  // VariationsServiceClient:
+  std::string GetApplicationLocale() override { return std::string(); }
+  base::Callback<base::Version(void)> GetVersionForSimulationCallback()
+      override {
+    return base::Callback<base::Version(void)>();
+  }
+  net::URLRequestContextGetter* GetURLRequestContext() override {
+    return nullptr;
+  }
+  network_time::NetworkTimeTracker* GetNetworkTimeTracker() override {
+    return nullptr;
+  }
+  version_info::Channel GetChannel() override {
+    return version_info::Channel::UNKNOWN;
+  }
+  bool OverridesRestrictParameter(std::string* parameter) override {
+    if (restrict_parameter_.empty())
+      return false;
+    *parameter = restrict_parameter_;
+    return true;
+  }
+
+  void set_restrict_parameter(const std::string& value) {
+    restrict_parameter_ = value;
+  }
+
+ private:
+  std::string restrict_parameter_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestVariationsServiceClient);
+};
+
+class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator {
+ public:
+  TestVariationsFieldTrialCreator(
+      std::unique_ptr<web_resource::TestRequestAllowedNotifier> test_notifier,
+      PrefService* local_state,
+      TestVariationsServiceClient* client)
+      : VariationsFieldTrialCreator(local_state, client, UIStringOverrider()),
+        client_(client) {
+    SetCreateTrialsFromSeedCalledForTesting(true);
+  }
+
+  ~TestVariationsFieldTrialCreator() {
+    delete client_;
+    client_ = 0;
+  }
+
+  bool StoreSeed(const std::string& seed_data,
+                 const std::string& seed_signature,
+                 const std::string& country_code,
+                 const base::Time& date_fetched,
+                 bool is_delta_compressed,
+                 bool is_gzip_compressed) {
+    seed_stored_ = true;
+    stored_seed_data_ = seed_data;
+    stored_country_ = country_code;
+    delta_compressed_seed_ = is_delta_compressed;
+    gzip_compressed_seed_ = is_gzip_compressed;
+    return true;
+  }
+
+ private:
+  bool LoadSeed(VariationsSeed* seed) override {
+    if (!seed_stored_)
+      return false;
+    return seed->ParseFromString(stored_seed_data_);
+  }
+
+  bool seed_stored_;
+  std::string stored_seed_data_;
+  std::string stored_country_;
+  bool delta_compressed_seed_;
+  bool gzip_compressed_seed_;
+
+  TestVariationsServiceClient* client_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestVariationsFieldTrialCreator);
+};
+
+// Constants used to create the test seed.
+const char kTestSeedStudyName[] = "test";
+const char kTestSeedExperimentName[] = "abc";
+const int kTestSeedExperimentProbability = 100;
+const char kTestSeedSerialNumber[] = "123";
+
+// Populates |seed| with simple test data. The resulting seed will contain one
+// study called "test", which contains one experiment called "abc" with
+// probability weight 100. |seed|'s study field will be cleared before adding
+// the new study.
+VariationsSeed CreateTestSeed() {
+  VariationsSeed seed;
+  Study* study = seed.add_study();
+  study->set_name(kTestSeedStudyName);
+  study->set_default_experiment_name(kTestSeedExperimentName);
+  Study_Experiment* experiment = study->add_experiment();
+  experiment->set_name(kTestSeedExperimentName);
+  experiment->set_probability_weight(kTestSeedExperimentProbability);
+  seed.set_serial_number(kTestSeedSerialNumber);
+  return seed;
+}
+
+// Serializes |seed| to protobuf binary format.
+std::string SerializeSeed(const VariationsSeed& seed) {
+  std::string serialized_seed;
+  seed.SerializeToString(&serialized_seed);
+  return serialized_seed;
+}
+
+}  // namespace
+
+class FieldTrialCreatorTest : public ::testing::Test {
+ protected:
+  FieldTrialCreatorTest()
+      : enabled_state_provider_(
+            new metrics::TestEnabledStateProvider(false, false)) {
+    VariationsService::RegisterPrefs(prefs_.registry());
+    metrics::CleanExitBeacon::RegisterPrefs(prefs_.registry());
+    metrics::MetricsStateManager::RegisterPrefs(prefs_.registry());
+  }
+
+  metrics::MetricsStateManager* GetMetricsStateManager() {
+    // Lazy-initialize the metrics_state_manager so that it correctly reads the
+    // stability state from prefs after tests have a chance to initialize it.
+    if (!metrics_state_manager_) {
+      metrics_state_manager_ = metrics::MetricsStateManager::Create(
+          &prefs_, enabled_state_provider_.get(), base::string16(),
+          base::Bind(&StubStoreClientInfo), base::Bind(&StubLoadClientInfo));
+    }
+    return metrics_state_manager_.get();
+  }
+
+ protected:
+  TestingPrefServiceSimple prefs_;
+
+ private:
+  base::MessageLoop message_loop_;
+  std::unique_ptr<metrics::TestEnabledStateProvider> enabled_state_provider_;
+  std::unique_ptr<metrics::MetricsStateManager> metrics_state_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrialCreatorTest);
+};
+
+TEST_F(FieldTrialCreatorTest, CreateTrialsFromSeed) {
+  // Create a local base::FieldTrialList, to hold the field trials created in
+  // this test.
+  base::FieldTrialList field_trial_list(nullptr);
+
+  // Create a variations service.
+  TestVariationsFieldTrialCreator field_trial_creator(
+      base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs_),
+      &prefs_, new TestVariationsServiceClient());
+  field_trial_creator.SetCreateTrialsFromSeedCalledForTesting(false);
+
+  // Store a seed.
+  field_trial_creator.StoreSeed(SerializeSeed(CreateTestSeed()), std::string(),
+                                std::string(), base::Time::Now(), false, false);
+  prefs_.SetInt64(prefs::kVariationsLastFetchTime,
+                  base::Time::Now().ToInternalValue());
+
+  // Check that field trials are created from the seed. Since the test study has
+  // only 1 experiment with 100% probability weight, we must be part of it.
+  EXPECT_TRUE(field_trial_creator.CreateTrialsFromSeed(
+      std::unique_ptr<const base::FieldTrial::EntropyProvider>(nullptr),
+      base::FeatureList::GetInstance()));
+  EXPECT_EQ(kTestSeedExperimentName,
+            base::FieldTrialList::FindFullName(kTestSeedStudyName));
+}
+
+TEST_F(FieldTrialCreatorTest, CreateTrialsFromSeedNoLastFetchTime) {
+  // Create a local base::FieldTrialList, to hold the field trials created in
+  // this test.
+  base::FieldTrialList field_trial_list(nullptr);
+
+  // Create a variations service
+  TestVariationsFieldTrialCreator field_trial_creator(
+      base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs_),
+      &prefs_, new TestVariationsServiceClient());
+  field_trial_creator.SetCreateTrialsFromSeedCalledForTesting(false);
+
+  // Store a seed. To simulate a first run, |prefs::kVariationsLastFetchTime|
+  // is left empty.
+  field_trial_creator.StoreSeed(SerializeSeed(CreateTestSeed()), std::string(),
+                                std::string(), base::Time::Now(), false, false);
+  EXPECT_EQ(0, prefs_.GetInt64(prefs::kVariationsLastFetchTime));
+
+  // Check that field trials are created from the seed. Since the test study has
+  // only 1 experiment with 100% probability weight, we must be part of it.
+  EXPECT_TRUE(field_trial_creator.CreateTrialsFromSeed(
+      std::unique_ptr<const base::FieldTrial::EntropyProvider>(nullptr),
+      base::FeatureList::GetInstance()));
+  EXPECT_EQ(base::FieldTrialList::FindFullName(kTestSeedStudyName),
+            kTestSeedExperimentName);
+}
+
+TEST_F(FieldTrialCreatorTest, CreateTrialsFromOutdatedSeed) {
+  // Create a local base::FieldTrialList, to hold the field trials created in
+  // this test.
+  base::FieldTrialList field_trial_list(nullptr);
+
+  // Create a variations service.
+  TestVariationsFieldTrialCreator field_trial_creator(
+      base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs_),
+      &prefs_, new TestVariationsServiceClient());
+  field_trial_creator.SetCreateTrialsFromSeedCalledForTesting(false);
+
+  // Store a seed, with a fetch time 31 days in the past.
+  const base::Time seed_date =
+      base::Time::Now() - base::TimeDelta::FromDays(31);
+  field_trial_creator.StoreSeed(SerializeSeed(CreateTestSeed()), std::string(),
+                                std::string(), seed_date, false, false);
+  prefs_.SetInt64(prefs::kVariationsLastFetchTime, seed_date.ToInternalValue());
+
+  // Check that field trials are not created from the seed.
+  EXPECT_FALSE(field_trial_creator.CreateTrialsFromSeed(
+      std::unique_ptr<const base::FieldTrial::EntropyProvider>(nullptr),
+      base::FeatureList::GetInstance()));
+  EXPECT_TRUE(base::FieldTrialList::FindFullName(kTestSeedStudyName).empty());
+}
+
+}  // namespace variations
diff --git a/components/variations/service/variations_field_trial_creator.cc b/components/variations/service/variations_field_trial_creator.cc
new file mode 100644
index 0000000..d9108c43
--- /dev/null
+++ b/components/variations/service/variations_field_trial_creator.cc
@@ -0,0 +1,329 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/variations/service/variations_field_trial_creator.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "base/build_time.h"
+#include "base/command_line.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/sys_info.h"
+#include "base/version.h"
+#include "build/build_config.h"
+#include "components/prefs/pref_service.h"
+#include "components/variations/pref_names.h"
+#include "components/variations/proto/variations_seed.pb.h"
+#include "components/variations/service/variations_service_client.h"
+#include "components/variations/variations_seed_processor.h"
+#include "components/variations/variations_switches.h"
+#include "ui/base/device_form_factor.h"
+
+namespace variations {
+
+// Maximum age permitted for a variations seed, in days.
+const int kMaxVariationsSeedAgeDays = 30;
+
+enum VariationsSeedExpiry {
+  VARIATIONS_SEED_EXPIRY_NOT_EXPIRED,
+  VARIATIONS_SEED_EXPIRY_FETCH_TIME_MISSING,
+  VARIATIONS_SEED_EXPIRY_EXPIRED,
+  VARIATIONS_SEED_EXPIRY_ENUM_SIZE,
+};
+
+// Gets current form factor and converts it from enum DeviceFormFactor to enum
+// Study_FormFactor.
+Study::FormFactor GetCurrentFormFactor() {
+  switch (ui::GetDeviceFormFactor()) {
+    case ui::DEVICE_FORM_FACTOR_PHONE:
+      return Study::PHONE;
+    case ui::DEVICE_FORM_FACTOR_TABLET:
+      return Study::TABLET;
+    case ui::DEVICE_FORM_FACTOR_DESKTOP:
+      return Study::DESKTOP;
+  }
+  NOTREACHED();
+  return Study::DESKTOP;
+}
+
+// Gets the hardware class and returns it as a string. This returns an empty
+// string if the client is not ChromeOS.
+std::string GetHardwareClass() {
+#if defined(OS_CHROMEOS)
+  return base::SysInfo::GetLsbReleaseBoard();
+#endif  // OS_CHROMEOS
+  return std::string();
+}
+
+// Returns the date that should be used by the VariationsSeedProcessor to do
+// expiry and start date checks.
+base::Time GetReferenceDateForExpiryChecks(PrefService* local_state) {
+  const int64_t date_value = local_state->GetInt64(prefs::kVariationsSeedDate);
+  const base::Time seed_date = base::Time::FromInternalValue(date_value);
+  const base::Time build_time = base::GetBuildTime();
+  // Use the build time for date checks if either the seed date is invalid or
+  // the build time is newer than the seed date.
+  base::Time reference_date = seed_date;
+  if (seed_date.is_null() || seed_date < build_time)
+    reference_date = build_time;
+  return reference_date;
+}
+
+// Wrapper around channel checking, used to enable channel mocking for
+// testing. If the current browser channel is not UNKNOWN, this will return
+// that channel value. Otherwise, if the fake channel flag is provided, this
+// will return the fake channel. Failing that, this will return the UNKNOWN
+// channel.
+Study::Channel GetChannelForVariations(version_info::Channel product_channel) {
+  switch (product_channel) {
+    case version_info::Channel::CANARY:
+      return Study::CANARY;
+    case version_info::Channel::DEV:
+      return Study::DEV;
+    case version_info::Channel::BETA:
+      return Study::BETA;
+    case version_info::Channel::STABLE:
+      return Study::STABLE;
+    case version_info::Channel::UNKNOWN:
+      break;
+  }
+  const std::string forced_channel =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kFakeVariationsChannel);
+  if (forced_channel == "stable")
+    return Study::STABLE;
+  if (forced_channel == "beta")
+    return Study::BETA;
+  if (forced_channel == "dev")
+    return Study::DEV;
+  if (forced_channel == "canary")
+    return Study::CANARY;
+  DVLOG(1) << "Invalid channel provided: " << forced_channel;
+  return Study::UNKNOWN;
+}
+
+// Records UMA histogram with the result of the variations seed expiry check.
+void RecordCreateTrialsSeedExpiry(VariationsSeedExpiry expiry_check_result) {
+  UMA_HISTOGRAM_ENUMERATION("Variations.CreateTrials.SeedExpiry",
+                            expiry_check_result,
+                            VARIATIONS_SEED_EXPIRY_ENUM_SIZE);
+}
+
+VariationsFieldTrialCreator::VariationsFieldTrialCreator(
+    PrefService* local_state,
+    VariationsServiceClient* client,
+    const UIStringOverrider& ui_string_overrider)
+    : client_(client),
+      ui_string_overrider_(ui_string_overrider),
+      local_state_(local_state),
+      seed_store_(local_state),
+      create_trials_from_seed_called_(false) {}
+
+VariationsFieldTrialCreator::~VariationsFieldTrialCreator() {}
+
+std::string VariationsFieldTrialCreator::GetLatestCountry() const {
+  const std::string override_country =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kVariationsOverrideCountry);
+  return !override_country.empty()
+             ? override_country
+             : local_state_->GetString(prefs::kVariationsCountry);
+}
+
+bool VariationsFieldTrialCreator::CreateTrialsFromSeed(
+    std::unique_ptr<const base::FieldTrial::EntropyProvider>
+        low_entropy_provider,
+    base::FeatureList* feature_list) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CHECK(!create_trials_from_seed_called_);
+
+  create_trials_from_seed_called_ = true;
+
+  VariationsSeed seed;
+  if (!LoadSeed(&seed))
+    return false;
+
+  const int64_t last_fetch_time_internal =
+      local_state_->GetInt64(prefs::kVariationsLastFetchTime);
+  const base::Time last_fetch_time =
+      base::Time::FromInternalValue(last_fetch_time_internal);
+  if (last_fetch_time.is_null()) {
+    // If the last fetch time is missing and we have a seed, then this must be
+    // the first run of Chrome. Store the current time as the last fetch time.
+    RecordLastFetchTime();
+    RecordCreateTrialsSeedExpiry(VARIATIONS_SEED_EXPIRY_FETCH_TIME_MISSING);
+  } else {
+    // Reject the seed if it is more than 30 days old.
+    const base::TimeDelta seed_age = base::Time::Now() - last_fetch_time;
+    if (seed_age.InDays() > kMaxVariationsSeedAgeDays) {
+      RecordCreateTrialsSeedExpiry(VARIATIONS_SEED_EXPIRY_EXPIRED);
+      return false;
+    }
+    RecordCreateTrialsSeedExpiry(VARIATIONS_SEED_EXPIRY_NOT_EXPIRED);
+  }
+
+  const base::Version current_version(version_info::GetVersionNumber());
+  if (!current_version.IsValid())
+    return false;
+
+  std::unique_ptr<ClientFilterableState> client_state =
+      GetClientFilterableStateForVersion(current_version);
+
+  // Note that passing |&ui_string_overrider_| via base::Unretained below is
+  // safe because the callback is executed synchronously. It is not possible
+  // to pass UIStringOverrider itself to VariationSeedProcessor as variations
+  // components should not depends on //ui/base.
+  VariationsSeedProcessor().CreateTrialsFromSeed(
+      seed, *client_state,
+      base::Bind(&UIStringOverrider::OverrideUIString,
+                 base::Unretained(&ui_string_overrider_)),
+      low_entropy_provider.get(), feature_list);
+
+  const base::Time now = base::Time::Now();
+
+  // Log the "freshness" of the seed that was just used. The freshness is the
+  // time between the last successful seed download and now.
+  if (!last_fetch_time.is_null()) {
+    const base::TimeDelta delta = now - last_fetch_time;
+    // Log the value in number of minutes.
+    UMA_HISTOGRAM_CUSTOM_COUNTS("Variations.SeedFreshness", delta.InMinutes(),
+                                1, base::TimeDelta::FromDays(30).InMinutes(),
+                                50);
+  }
+
+  return true;
+}
+
+void VariationsFieldTrialCreator::SetCreateTrialsFromSeedCalledForTesting(
+    bool called) {
+  create_trials_from_seed_called_ = called;
+}
+
+std::unique_ptr<ClientFilterableState>
+VariationsFieldTrialCreator::GetClientFilterableStateForVersion(
+    const base::Version& version) {
+  std::unique_ptr<ClientFilterableState> state =
+      base::MakeUnique<ClientFilterableState>();
+  state->locale = client_->GetApplicationLocale();
+  state->reference_date = GetReferenceDateForExpiryChecks(local_state_);
+  state->version = version;
+  state->channel = GetChannelForVariations(client_->GetChannel());
+  state->form_factor = GetCurrentFormFactor();
+  state->platform = ClientFilterableState::GetCurrentPlatform();
+  state->hardware_class = GetHardwareClass();
+#if defined(OS_ANDROID)
+  // This is set on Android only currently, because the IsLowEndDevice() API
+  // on other platforms has no intrinsic meaning outside of a field trial that
+  // controls its value. Since this is before server-side field trials are
+  // evaluated, that field trial would not be able to apply for this case.
+  state->is_low_end_device = base::SysInfo::IsLowEndDevice();
+#endif
+  state->session_consistency_country = GetLatestCountry();
+  state->permanent_consistency_country = LoadPermanentConsistencyCountry(
+      version, state->session_consistency_country);
+  return state;
+}
+
+std::string VariationsFieldTrialCreator::LoadPermanentConsistencyCountry(
+    const base::Version& version,
+    const std::string& latest_country) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(version.IsValid());
+
+  const std::string override_country =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kVariationsOverrideCountry);
+  if (!override_country.empty())
+    return override_country;
+
+  const base::ListValue* list_value =
+      local_state_->GetList(prefs::kVariationsPermanentConsistencyCountry);
+  std::string stored_version_string;
+  std::string stored_country;
+
+  // Determine if the saved pref value is present and valid.
+  const bool is_pref_empty = list_value->empty();
+  const bool is_pref_valid = list_value->GetSize() == 2 &&
+                             list_value->GetString(0, &stored_version_string) &&
+                             list_value->GetString(1, &stored_country) &&
+                             base::Version(stored_version_string).IsValid();
+
+  // Determine if the version from the saved pref matches |version|.
+  const bool does_version_match =
+      is_pref_valid && version == base::Version(stored_version_string);
+
+  // Determine if the country in the saved pref matches the country in
+  // |latest_country|.
+  const bool does_country_match = is_pref_valid && !latest_country.empty() &&
+                                  stored_country == latest_country;
+
+  // Record a histogram for how the saved pref value compares to the current
+  // version and the country code in the variations seed.
+  LoadPermanentConsistencyCountryResult result;
+  if (is_pref_empty) {
+    result = !latest_country.empty() ? LOAD_COUNTRY_NO_PREF_HAS_SEED
+                                     : LOAD_COUNTRY_NO_PREF_NO_SEED;
+  } else if (!is_pref_valid) {
+    result = !latest_country.empty() ? LOAD_COUNTRY_INVALID_PREF_HAS_SEED
+                                     : LOAD_COUNTRY_INVALID_PREF_NO_SEED;
+  } else if (latest_country.empty()) {
+    result = does_version_match ? LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_EQ
+                                : LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_NEQ;
+  } else if (does_version_match) {
+    result = does_country_match ? LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_EQ
+                                : LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_NEQ;
+  } else {
+    result = does_country_match ? LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_EQ
+                                : LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_NEQ;
+  }
+  UMA_HISTOGRAM_ENUMERATION("Variations.LoadPermanentConsistencyCountryResult",
+                            result, LOAD_COUNTRY_MAX);
+
+  // Use the stored country if one is available and was fetched since the last
+  // time Chrome was updated.
+  if (does_version_match)
+    return stored_country;
+
+  if (latest_country.empty()) {
+    if (!is_pref_valid)
+      local_state_->ClearPref(prefs::kVariationsPermanentConsistencyCountry);
+    // If we've never received a country code from the server, use an empty
+    // country so that it won't pass any filters that specifically include
+    // countries, but so that it will pass any filters that specifically exclude
+    // countries.
+    return std::string();
+  }
+
+  // Otherwise, update the pref with the current Chrome version and country.
+  StorePermanentCountry(version, latest_country);
+  return latest_country;
+}
+
+void VariationsFieldTrialCreator::StorePermanentCountry(
+    const base::Version& version,
+    const std::string& country) {
+  base::ListValue new_list_value;
+  new_list_value.AppendString(version.GetString());
+  new_list_value.AppendString(country);
+  local_state_->Set(prefs::kVariationsPermanentConsistencyCountry,
+                    new_list_value);
+}
+
+void VariationsFieldTrialCreator::RecordLastFetchTime() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  local_state_->SetInt64(prefs::kVariationsLastFetchTime,
+                         base::Time::Now().ToInternalValue());
+}
+
+bool VariationsFieldTrialCreator::LoadSeed(VariationsSeed* seed) {
+  return seed_store_.LoadSeed(seed);
+}
+
+}  // namespace variations
diff --git a/components/variations/service/variations_field_trial_creator.h b/components/variations/service/variations_field_trial_creator.h
new file mode 100644
index 0000000..5a72a3a
--- /dev/null
+++ b/components/variations/service/variations_field_trial_creator.h
@@ -0,0 +1,122 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VARIATIONS_FIELD_TRIAL_CREATOR_H_
+#define COMPONENTS_VARIATIONS_FIELD_TRIAL_CREATOR_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/metrics/field_trial.h"
+#include "components/variations/client_filterable_state.h"
+#include "components/variations/service/ui_string_overrider.h"
+#include "components/variations/variations_seed_store.h"
+
+namespace variations {
+class VariationsServiceClient;
+}
+
+namespace variations {
+
+// Used to setup field trials based on stored variations seed data.
+class VariationsFieldTrialCreator {
+ public:
+  // Caller is responsible for ensuring that objects passed to the constructor
+  // stay valid for the lifetime of this object.
+  VariationsFieldTrialCreator(PrefService* local_state,
+                              VariationsServiceClient* client,
+                              const UIStringOverrider& ui_string_overrider);
+  ~VariationsFieldTrialCreator();
+
+  // Returns what variations will consider to be the latest country. Returns
+  // empty if it is not available.
+  std::string GetLatestCountry() const;
+
+  // Creates field trials based on the variations seed loaded from local state.
+  // If there is a problem loading the seed data, all trials specified by the
+  // seed may not be created. Some field trials are configured to override or
+  // associate with (for reporting) specific features. These associations are
+  // registered with |feature_list|.
+  bool CreateTrialsFromSeed(
+      std::unique_ptr<const base::FieldTrial::EntropyProvider>
+          low_entropy_provider,
+      base::FeatureList* feature_list);
+
+  VariationsSeedStore& seed_store() { return seed_store_; }
+
+  const VariationsSeedStore& seed_store() const { return seed_store_; }
+
+  bool create_trials_from_seed_called() const {
+    return create_trials_from_seed_called_;
+  }
+
+  // Exposed for testing.
+  void SetCreateTrialsFromSeedCalledForTesting(bool called);
+
+  // Returns all of the client state used for filtering studies.
+  // As a side-effect, may update the stored permanent consistency country.
+  std::unique_ptr<ClientFilterableState> GetClientFilterableStateForVersion(
+      const base::Version& version);
+
+  // Loads the country code to use for filtering permanent consistency studies,
+  // updating the stored country code if the stored value was for a different
+  // Chrome version. The country used for permanent consistency studies is kept
+  // consistent between Chrome upgrades in order to avoid annoying the user due
+  // to experiment churn while traveling.
+  std::string LoadPermanentConsistencyCountry(
+      const base::Version& version,
+      const std::string& latest_country);
+
+  // Sets the stored permanent country pref for this client.
+  void StorePermanentCountry(const base::Version& version,
+                             const std::string& country);
+
+  // Records the time of the most recent successful fetch.
+  void RecordLastFetchTime();
+
+  // Loads the seed from the variations store into |seed|. If successfull,
+  // |seed| will contain the loaded data and true is returned. Set as virtual
+  // so that it can be overridden by tests.
+  virtual bool LoadSeed(VariationsSeed* seed);
+
+ private:
+  // Set of different possible values to report for the
+  // Variations.LoadPermanentConsistencyCountryResult histogram. This enum must
+  // be kept consistent with its counterpart in histograms.xml.
+  enum LoadPermanentConsistencyCountryResult {
+    LOAD_COUNTRY_NO_PREF_NO_SEED = 0,
+    LOAD_COUNTRY_NO_PREF_HAS_SEED,
+    LOAD_COUNTRY_INVALID_PREF_NO_SEED,
+    LOAD_COUNTRY_INVALID_PREF_HAS_SEED,
+    LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_EQ,
+    LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_NEQ,
+    LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_EQ,
+    LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_NEQ,
+    LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_EQ,
+    LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_NEQ,
+    LOAD_COUNTRY_MAX,
+  };
+
+  VariationsServiceClient* client_;
+
+  UIStringOverrider ui_string_overrider_;
+
+  // The pref service used to store persist the variations seed.
+  PrefService* local_state_;
+
+  VariationsSeedStore seed_store_;
+
+  // Tracks whether |CreateTrialsFromSeed| has been called, to ensure that
+  // it gets called prior to |StartRepeatedVariationsSeedFetch|.
+  bool create_trials_from_seed_called_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(VariationsFieldTrialCreator);
+};
+
+}  // namespace variations
+
+#endif  // COMPONENTS_VARIATIONS_FIELD_TRIAL_CREATOR_H_
diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc
index acdf7ef..74eccf9c 100644
--- a/components/variations/service/variations_service.cc
+++ b/components/variations/service/variations_service.cc
@@ -32,6 +32,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/variations/pref_names.h"
 #include "components/variations/proto/variations_seed.pb.h"
+#include "components/variations/service/variations_field_trial_creator.h"
 #include "components/variations/variations_seed_processor.h"
 #include "components/variations/variations_seed_simulator.h"
 #include "components/variations/variations_switches.h"
@@ -56,46 +57,10 @@
 // For the HTTP date headers, the resolution of the server time is 1 second.
 const int64_t kServerTimeResolutionMs = 1000;
 
-// Maximum age permitted for a variations seed, in days.
-const int kMaxVariationsSeedAgeDays = 30;
-
 // Whether the VariationsService should always be created, even in Chromium
 // builds.
 bool g_enabled_for_testing = false;
 
-// Wrapper around channel checking, used to enable channel mocking for
-// testing. If the current browser channel is not UNKNOWN, this will return
-// that channel value. Otherwise, if the fake channel flag is provided, this
-// will return the fake channel. Failing that, this will return the UNKNOWN
-// channel.
-Study::Channel GetChannelForVariations(version_info::Channel product_channel) {
-  switch (product_channel) {
-    case version_info::Channel::CANARY:
-      return Study::CANARY;
-    case version_info::Channel::DEV:
-      return Study::DEV;
-    case version_info::Channel::BETA:
-      return Study::BETA;
-    case version_info::Channel::STABLE:
-      return Study::STABLE;
-    case version_info::Channel::UNKNOWN:
-      break;
-  }
-  const std::string forced_channel =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          switches::kFakeVariationsChannel);
-  if (forced_channel == "stable")
-    return Study::STABLE;
-  if (forced_channel == "beta")
-    return Study::BETA;
-  if (forced_channel == "dev")
-    return Study::DEV;
-  if (forced_channel == "canary")
-    return Study::CANARY;
-  DVLOG(1) << "Invalid channel provided: " << forced_channel;
-  return Study::UNKNOWN;
-}
-
 // Returns a string that will be used for the value of the 'osname' URL param
 // to the variations server.
 std::string GetPlatformString() {
@@ -151,13 +116,6 @@
   VARIATIONS_SEED_EXPIRY_ENUM_SIZE,
 };
 
-// Records UMA histogram with the result of the variations seed expiry check.
-void RecordCreateTrialsSeedExpiry(VariationsSeedExpiry expiry_check_result) {
-  UMA_HISTOGRAM_ENUMERATION("Variations.CreateTrials.SeedExpiry",
-                            expiry_check_result,
-                            VARIATIONS_SEED_EXPIRY_ENUM_SIZE);
-}
-
 // Converts ResourceRequestAllowedNotifier::State to the corresponding
 // ResourceRequestsAllowedState value.
 ResourceRequestsAllowedState ResourceRequestStateToHistogramValue(
@@ -177,45 +135,6 @@
   return RESOURCE_REQUESTS_NOT_ALLOWED;
 }
 
-
-// Gets current form factor and converts it from enum DeviceFormFactor to enum
-// Study_FormFactor.
-Study::FormFactor GetCurrentFormFactor() {
-  switch (ui::GetDeviceFormFactor()) {
-    case ui::DEVICE_FORM_FACTOR_PHONE:
-      return Study::PHONE;
-    case ui::DEVICE_FORM_FACTOR_TABLET:
-      return Study::TABLET;
-    case ui::DEVICE_FORM_FACTOR_DESKTOP:
-      return Study::DESKTOP;
-  }
-  NOTREACHED();
-  return Study::DESKTOP;
-}
-
-// Gets the hardware class and returns it as a string. This returns an empty
-// string if the client is not ChromeOS.
-std::string GetHardwareClass() {
-#if defined(OS_CHROMEOS)
-  return base::SysInfo::GetLsbReleaseBoard();
-#endif  // OS_CHROMEOS
-  return std::string();
-}
-
-// Returns the date that should be used by the VariationsSeedProcessor to do
-// expiry and start date checks.
-base::Time GetReferenceDateForExpiryChecks(PrefService* local_state) {
-  const int64_t date_value = local_state->GetInt64(prefs::kVariationsSeedDate);
-  const base::Time seed_date = base::Time::FromInternalValue(date_value);
-  const base::Time build_time = base::GetBuildTime();
-  // Use the build time for date checks if either the seed date is invalid or
-  // the build time is newer than the seed date.
-  base::Time reference_date = seed_date;
-  if (seed_date.is_null() || seed_date < build_time)
-    reference_date = build_time;
-  return reference_date;
-}
-
 // Returns the header value for |name| from |headers| or an empty string if not
 // set.
 std::string GetHeaderValue(const net::HttpResponseHeaders* headers,
@@ -283,16 +202,14 @@
     metrics::MetricsStateManager* state_manager,
     const UIStringOverrider& ui_string_overrider)
     : client_(std::move(client)),
-      ui_string_overrider_(ui_string_overrider),
       local_state_(local_state),
       state_manager_(state_manager),
       policy_pref_service_(local_state),
-      seed_store_(local_state),
-      create_trials_from_seed_called_(false),
       initial_request_completed_(false),
       disable_deltas_for_next_request_(false),
       resource_request_allowed_notifier_(std::move(notifier)),
       request_count_(0),
+      field_trial_creator_(local_state, client.get(), ui_string_overrider),
       weak_ptr_factory_(this) {
   DCHECK(client_.get());
   DCHECK(resource_request_allowed_notifier_.get());
@@ -303,77 +220,14 @@
 VariationsService::~VariationsService() {
 }
 
-bool VariationsService::CreateTrialsFromSeed(base::FeatureList* feature_list) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  CHECK(!create_trials_from_seed_called_);
-
-  create_trials_from_seed_called_ = true;
-
-  VariationsSeed seed;
-  if (!LoadSeed(&seed))
-    return false;
-
-  const int64_t last_fetch_time_internal =
-      local_state_->GetInt64(prefs::kVariationsLastFetchTime);
-  const base::Time last_fetch_time =
-      base::Time::FromInternalValue(last_fetch_time_internal);
-  if (last_fetch_time.is_null()) {
-    // If the last fetch time is missing and we have a seed, then this must be
-    // the first run of Chrome. Store the current time as the last fetch time.
-    RecordLastFetchTime();
-    RecordCreateTrialsSeedExpiry(VARIATIONS_SEED_EXPIRY_FETCH_TIME_MISSING);
-  } else {
-    // Reject the seed if it is more than 30 days old.
-    const base::TimeDelta seed_age = base::Time::Now() - last_fetch_time;
-    if (seed_age.InDays() > kMaxVariationsSeedAgeDays) {
-      RecordCreateTrialsSeedExpiry(VARIATIONS_SEED_EXPIRY_EXPIRED);
-      return false;
-    }
-    RecordCreateTrialsSeedExpiry(VARIATIONS_SEED_EXPIRY_NOT_EXPIRED);
-  }
-
-  const base::Version current_version(version_info::GetVersionNumber());
-  if (!current_version.IsValid())
-    return false;
-
-  std::unique_ptr<ClientFilterableState> client_state =
-      GetClientFilterableStateForVersion(current_version);
-  UMA_HISTOGRAM_SPARSE_SLOWLY("Variations.UserChannel", client_state->channel);
-
-  std::unique_ptr<const base::FieldTrial::EntropyProvider> low_entropy_provider(
-      CreateLowEntropyProvider());
-  // Note that passing |&ui_string_overrider_| via base::Unretained below is
-  // safe because the callback is executed synchronously. It is not possible
-  // to pass UIStringOverrider itself to VariationSeedProcessor as variations
-  // components should not depends on //ui/base.
-  VariationsSeedProcessor().CreateTrialsFromSeed(
-      seed, *client_state,
-      base::Bind(&UIStringOverrider::OverrideUIString,
-                 base::Unretained(&ui_string_overrider_)),
-      low_entropy_provider.get(), feature_list);
-
-  const base::Time now = base::Time::Now();
-
-  // Log the "freshness" of the seed that was just used. The freshness is the
-  // time between the last successful seed download and now.
-  if (!last_fetch_time.is_null()) {
-    const base::TimeDelta delta = now - last_fetch_time;
-    // Log the value in number of minutes.
-    UMA_HISTOGRAM_CUSTOM_COUNTS("Variations.SeedFreshness", delta.InMinutes(),
-        1, base::TimeDelta::FromDays(30).InMinutes(), 50);
-  }
-
-  return true;
-}
-
 void VariationsService::PerformPreMainMessageLoopStartup() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   StartRepeatedVariationsSeedFetch();
 }
 
 void VariationsService::StartRepeatedVariationsSeedFetch() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Initialize the Variations server URL.
   variations_server_url_ =
@@ -381,7 +235,7 @@
 
   // Check that |CreateTrialsFromSeed| was called, which is necessary to
   // retrieve the serial number that will be sent to the server.
-  DCHECK(create_trials_from_seed_called_);
+  DCHECK(field_trial_creator_.create_trials_from_seed_called());
 
   DCHECK(!request_scheduler_.get());
   request_scheduler_.reset(VariationsRequestScheduler::Create(
@@ -393,18 +247,25 @@
   request_scheduler_->Start();
 }
 
+std::string VariationsService::LoadPermanentConsistencyCountry(
+    const base::Version& version,
+    const std::string& latest_country) {
+  return field_trial_creator_.LoadPermanentConsistencyCountry(version,
+                                                              latest_country);
+}
+
 void VariationsService::AddObserver(Observer* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   observer_list_.AddObserver(observer);
 }
 
 void VariationsService::RemoveObserver(Observer* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   observer_list_.RemoveObserver(observer);
 }
 
 void VariationsService::OnAppEnterForeground() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // On mobile platforms, initialize the fetch scheduler when we receive the
   // first app foreground notification.
@@ -414,7 +275,7 @@
 }
 
 void VariationsService::SetRestrictMode(const std::string& restrict_mode) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // This should be called before the server URL has been computed.
   DCHECK(variations_server_url_.is_empty());
@@ -422,8 +283,8 @@
 }
 
 void VariationsService::SetCreateTrialsFromSeedCalledForTesting(bool called) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  create_trials_from_seed_called_ = called;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  field_trial_creator_.SetCreateTrialsFromSeedCalledForTesting(called);
 }
 
 GURL VariationsService::GetVariationsServerURL(
@@ -513,7 +374,7 @@
 }
 
 void VariationsService::DoActualFetch() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Normally, there shouldn't be a |pending_request_| when this fires. However
   // it's not impossible - for example if Chrome was paused (e.g. in a debugger
@@ -552,14 +413,15 @@
                                       net::LOAD_DO_NOT_SAVE_COOKIES);
   pending_seed_request_->SetRequestContext(client_->GetURLRequestContext());
   bool enable_deltas = false;
-  if (!seed_store_.variations_serial_number().empty() &&
+  if (!field_trial_creator_.seed_store().variations_serial_number().empty() &&
       !disable_deltas_for_next_request_) {
     // Tell the server that delta-compressed seeds are supported.
     enable_deltas = true;
 
     // Get the seed only if its serial number doesn't match what we have.
     pending_seed_request_->AddExtraRequestHeader(
-        "If-None-Match:" + seed_store_.variations_serial_number());
+        "If-None-Match:" +
+        field_trial_creator_.seed_store().variations_serial_number());
   }
   // Tell the server that delta-compressed and gzipped seeds are supported.
   const char* supported_im = enable_deltas ? "A-IM:x-bm,gzip" : "A-IM:gzip";
@@ -587,15 +449,15 @@
                                   const base::Time& date_fetched,
                                   bool is_delta_compressed,
                                   bool is_gzip_compressed) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   std::unique_ptr<VariationsSeed> seed(new VariationsSeed);
-  if (!seed_store_.StoreSeedData(seed_data, seed_signature, country_code,
-                                 date_fetched, is_delta_compressed,
-                                 is_gzip_compressed, seed.get())) {
+  if (!field_trial_creator_.seed_store().StoreSeedData(
+          seed_data, seed_signature, country_code, date_fetched,
+          is_delta_compressed, is_gzip_compressed, seed.get())) {
     return false;
   }
-  RecordLastFetchTime();
+  field_trial_creator_.RecordLastFetchTime();
 
   base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
@@ -610,37 +472,8 @@
   return state_manager_->CreateLowEntropyProvider();
 }
 
-bool VariationsService::LoadSeed(VariationsSeed* seed) {
-  return seed_store_.LoadSeed(seed);
-}
-
-std::unique_ptr<ClientFilterableState>
-VariationsService::GetClientFilterableStateForVersion(
-    const base::Version& version) {
-  std::unique_ptr<ClientFilterableState> state =
-      base::MakeUnique<ClientFilterableState>();
-  state->locale = client_->GetApplicationLocale();
-  state->reference_date = GetReferenceDateForExpiryChecks(local_state_);
-  state->version = version;
-  state->channel = GetChannelForVariations(client_->GetChannel());
-  state->form_factor = GetCurrentFormFactor();
-  state->platform = ClientFilterableState::GetCurrentPlatform();
-  state->hardware_class = GetHardwareClass();
-#if defined(OS_ANDROID)
-  // This is set on Android only currently, because the IsLowEndDevice() API
-  // on other platforms has no intrinsic meaning outside of a field trial that
-  // controls its value. Since this is before server-side field trials are
-  // evaluated, that field trial would not be able to apply for this case.
-  state->is_low_end_device = base::SysInfo::IsLowEndDevice();
-#endif
-  state->session_consistency_country = GetLatestCountry();
-  state->permanent_consistency_country = LoadPermanentConsistencyCountry(
-      version, state->session_consistency_country);
-  return state;
-}
-
 void VariationsService::FetchVariationsSeed() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   const web_resource::ResourceRequestAllowedNotifier::State state =
       resource_request_allowed_notifier_->GetResourceRequestsAllowedState();
@@ -655,7 +488,7 @@
 
 void VariationsService::NotifyObservers(
     const VariationsSeedSimulator::Result& result) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (result.kill_critical_group_change_count > 0) {
     for (auto& observer : observer_list_)
@@ -667,7 +500,7 @@
 }
 
 void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(pending_seed_request_.get(), source);
 
   const bool is_first_request = !initial_request_completed_;
@@ -714,10 +547,11 @@
     DVLOG(1) << "Variations server request returned non-HTTP_OK response code: "
              << response_code;
     if (response_code == net::HTTP_NOT_MODIFIED) {
-      RecordLastFetchTime();
+      field_trial_creator_.RecordLastFetchTime();
       // Update the seed date value in local state (used for expiry check on
       // next start up), since 304 is a successful response.
-      seed_store_.UpdateSeedDateAndLogDayChange(response_date);
+      field_trial_creator_.seed_store().UpdateSeedDateAndLogDayChange(
+          response_date);
     }
     return;
   }
@@ -733,7 +567,7 @@
                                 &is_gzip_compressed)) {
     // The header does not specify supported instance manipulations, unable to
     // process data. Details of errors were logged by GetInstanceManipulations.
-    seed_store_.ReportUnsupportedSeedFormatError();
+    field_trial_creator_.seed_store().ReportUnsupportedSeedFormatError();
     return;
   }
 
@@ -749,7 +583,7 @@
 }
 
 void VariationsService::OnResourceRequestsAllowed() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Note that this only attempts to fetch the seed at most once per period
   // (kSeedFetchPeriodHours). This works because
@@ -769,7 +603,7 @@
 void VariationsService::PerformSimulationWithVersion(
     std::unique_ptr<VariationsSeed> seed,
     const base::Version& version) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!version.IsValid())
     return;
@@ -783,7 +617,7 @@
   VariationsSeedSimulator seed_simulator(*default_provider, *low_provider);
 
   std::unique_ptr<ClientFilterableState> client_state =
-      GetClientFilterableStateForVersion(version);
+      field_trial_creator_.GetClientFilterableStateForVersion(version);
   const VariationsSeedSimulator::Result result =
       seed_simulator.SimulateSeedStudies(*seed, *client_state);
 
@@ -799,100 +633,18 @@
   NotifyObservers(result);
 }
 
-void VariationsService::RecordLastFetchTime() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  local_state_->SetInt64(prefs::kVariationsLastFetchTime,
-                         base::Time::Now().ToInternalValue());
-}
-
 std::string VariationsService::GetInvalidVariationsSeedSignature() const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return seed_store_.GetInvalidSignature();
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return field_trial_creator_.seed_store().GetInvalidSignature();
 }
 
-std::string VariationsService::LoadPermanentConsistencyCountry(
-    const base::Version& version,
-    const std::string& latest_country) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(version.IsValid());
-
-  const std::string override_country =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          switches::kVariationsOverrideCountry);
-  if (!override_country.empty())
-    return override_country;
-
-  const base::ListValue* list_value =
-      local_state_->GetList(prefs::kVariationsPermanentConsistencyCountry);
-  std::string stored_version_string;
-  std::string stored_country;
-
-  // Determine if the saved pref value is present and valid.
-  const bool is_pref_empty = list_value->empty();
-  const bool is_pref_valid = list_value->GetSize() == 2 &&
-                             list_value->GetString(0, &stored_version_string) &&
-                             list_value->GetString(1, &stored_country) &&
-                             base::Version(stored_version_string).IsValid();
-
-  // Determine if the version from the saved pref matches |version|.
-  const bool does_version_match =
-      is_pref_valid && version == base::Version(stored_version_string);
-
-  // Determine if the country in the saved pref matches the country in
-  // |latest_country|.
-  const bool does_country_match = is_pref_valid && !latest_country.empty() &&
-                                  stored_country == latest_country;
-
-  // Record a histogram for how the saved pref value compares to the current
-  // version and the country code in the variations seed.
-  LoadPermanentConsistencyCountryResult result;
-  if (is_pref_empty) {
-    result = !latest_country.empty() ? LOAD_COUNTRY_NO_PREF_HAS_SEED
-                                     : LOAD_COUNTRY_NO_PREF_NO_SEED;
-  } else if (!is_pref_valid) {
-    result = !latest_country.empty() ? LOAD_COUNTRY_INVALID_PREF_HAS_SEED
-                                     : LOAD_COUNTRY_INVALID_PREF_NO_SEED;
-  } else if (latest_country.empty()) {
-    result = does_version_match ? LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_EQ
-                                : LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_NEQ;
-  } else if (does_version_match) {
-    result = does_country_match ? LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_EQ
-                                : LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_NEQ;
-  } else {
-    result = does_country_match ? LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_EQ
-                                : LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_NEQ;
-  }
-  UMA_HISTOGRAM_ENUMERATION("Variations.LoadPermanentConsistencyCountryResult",
-                            result, LOAD_COUNTRY_MAX);
-
-  // Use the stored country if one is available and was fetched since the last
-  // time Chrome was updated.
-  if (does_version_match)
-    return stored_country;
-
-  if (latest_country.empty()) {
-    if (!is_pref_valid)
-      local_state_->ClearPref(prefs::kVariationsPermanentConsistencyCountry);
-    // If we've never received a country code from the server, use an empty
-    // country so that it won't pass any filters that specifically include
-    // countries, but so that it will pass any filters that specifically exclude
-    // countries.
-    return std::string();
-  }
-
-  // Otherwise, update the pref with the current Chrome version and country.
-  StorePermanentCountry(version, latest_country);
-  return latest_country;
+std::string VariationsService::GetLatestCountry() const {
+  return field_trial_creator_.GetLatestCountry();
 }
 
-void VariationsService::StorePermanentCountry(const base::Version& version,
-                                              const std::string& country) {
-  base::ListValue new_list_value;
-  new_list_value.AppendString(version.GetString());
-  new_list_value.AppendString(country);
-  local_state_->Set(prefs::kVariationsPermanentConsistencyCountry,
-                    new_list_value);
+bool VariationsService::CreateTrialsFromSeed(base::FeatureList* feature_list) {
+  return field_trial_creator_.CreateTrialsFromSeed(CreateLowEntropyProvider(),
+                                                   feature_list);
 }
 
 std::string VariationsService::GetStoredPermanentCountry() {
@@ -909,7 +661,7 @@
 
 bool VariationsService::OverrideStoredPermanentCountry(
     const std::string& country_override) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (country_override.empty())
     return false;
@@ -925,17 +677,8 @@
     return false;
 
   base::Version version(version_info::GetVersionNumber());
-  StorePermanentCountry(version, country_override);
+  field_trial_creator_.StorePermanentCountry(version, country_override);
   return true;
 }
 
-std::string VariationsService::GetLatestCountry() const {
-  const std::string override_country =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          switches::kVariationsOverrideCountry);
-  return !override_country.empty()
-             ? override_country
-             : local_state_->GetString(prefs::kVariationsCountry);
-}
-
 }  // namespace variations
diff --git a/components/variations/service/variations_service.h b/components/variations/service/variations_service.h
index f3bf46b..bcadced 100644
--- a/components/variations/service/variations_service.h
+++ b/components/variations/service/variations_service.h
@@ -14,10 +14,10 @@
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/field_trial.h"
 #include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "components/variations/client_filterable_state.h"
 #include "components/variations/service/ui_string_overrider.h"
+#include "components/variations/service/variations_field_trial_creator.h"
 #include "components/variations/service/variations_service_client.h"
 #include "components/variations/variations_request_scheduler.h"
 #include "components/variations/variations_seed_simulator.h"
@@ -230,20 +230,6 @@
     LOAD_COUNTRY_MAX,
   };
 
-  // Loads the seed from the variations store into |seed|. If successfull,
-  // |seed| will contain the loaded data and true is returned. Set as virtual
-  // so that it can be overridden by tests.
-  virtual bool LoadSeed(VariationsSeed* seed);
-
-  // Returns all of the client state used for filtering studies.
-  // As a side-effect, may update the stored permanent consistency country.
-  std::unique_ptr<ClientFilterableState> GetClientFilterableStateForVersion(
-      const base::Version& version);
-
-  // Sets the stored permanent country pref for this client.
-  void StorePermanentCountry(const base::Version& version,
-                             const std::string& country);
-
   // Checks if prerequisites for fetching the Variations seed are met, and if
   // so, performs the actual fetch using |DoActualFetch|.
   void FetchVariationsSeed();
@@ -264,9 +250,6 @@
       std::unique_ptr<variations::VariationsSeed> seed,
       const base::Version& version);
 
-  // Record the time of the most recent successful fetch.
-  void RecordLastFetchTime();
-
   // Loads the country code to use for filtering permanent consistency studies,
   // updating the stored country code if the stored value was for a different
   // Chrome version. The country used for permanent consistency studies is kept
@@ -277,7 +260,6 @@
       const std::string& latest_country);
 
   std::unique_ptr<VariationsServiceClient> client_;
-  UIStringOverrider ui_string_overrider_;
 
   // The pref service used to store persist the variations seed.
   PrefService* local_state_;
@@ -290,8 +272,6 @@
   // either be Local State or Profile prefs.
   PrefService* policy_pref_service_;
 
-  VariationsSeedStore seed_store_;
-
   // Contains the scheduler instance that handles timing for requests to the
   // server. Initially NULL and instantiated when the initial fetch is
   // requested.
@@ -309,10 +289,6 @@
   // The URL to use for querying the variations server.
   GURL variations_server_url_;
 
-  // Tracks whether |CreateTrialsFromSeed| has been called, to ensure that
-  // it gets called prior to |StartRepeatedVariationsSeedFetch|.
-  bool create_trials_from_seed_called_;
-
   // Tracks whether the initial request to the variations server had completed.
   bool initial_request_completed_;
 
@@ -336,7 +312,10 @@
   // List of observers of the VariationsService.
   base::ObserverList<Observer> observer_list_;
 
-  base::ThreadChecker thread_checker_;
+  // Member responsible for creating trials from a variations seed.
+  VariationsFieldTrialCreator field_trial_creator_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<VariationsService> weak_ptr_factory_;
 
diff --git a/components/variations/service/variations_service_unittest.cc b/components/variations/service/variations_service_unittest.cc
index 181a1926..df770eb 100644
--- a/components/variations/service/variations_service_unittest.cc
+++ b/components/variations/service/variations_service_unittest.cc
@@ -149,11 +149,6 @@
   }
 
  private:
-  bool LoadSeed(VariationsSeed* seed) override {
-    if (!seed_stored_)
-      return false;
-    return seed->ParseFromString(stored_seed_data_);
-  }
 
   bool intercepts_fetch_;
   bool fetch_attempted_;
@@ -298,77 +293,6 @@
   DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest);
 };
 
-TEST_F(VariationsServiceTest, CreateTrialsFromSeed) {
-  // Create a local base::FieldTrialList, to hold the field trials created in
-  // this test.
-  base::FieldTrialList field_trial_list(nullptr);
-
-  // Create a variations service.
-  TestVariationsService service(
-      base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs_),
-      &prefs_, GetMetricsStateManager());
-  service.SetCreateTrialsFromSeedCalledForTesting(false);
-
-  // Store a seed.
-  service.StoreSeed(SerializeSeed(CreateTestSeed()), std::string(),
-                    std::string(), base::Time::Now(), false, false);
-  prefs_.SetInt64(prefs::kVariationsLastFetchTime,
-                  base::Time::Now().ToInternalValue());
-
-  // Check that field trials are created from the seed. Since the test study has
-  // only 1 experiment with 100% probability weight, we must be part of it.
-  EXPECT_TRUE(service.CreateTrialsFromSeed(base::FeatureList::GetInstance()));
-  EXPECT_EQ(kTestSeedExperimentName,
-            base::FieldTrialList::FindFullName(kTestSeedStudyName));
-}
-
-TEST_F(VariationsServiceTest, CreateTrialsFromSeedNoLastFetchTime) {
-  // Create a local base::FieldTrialList, to hold the field trials created in
-  // this test.
-  base::FieldTrialList field_trial_list(nullptr);
-
-  // Create a variations service
-  TestVariationsService service(
-      base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs_),
-      &prefs_, GetMetricsStateManager());
-  service.SetCreateTrialsFromSeedCalledForTesting(false);
-
-  // Store a seed. To simulate a first run, |prefs::kVariationsLastFetchTime|
-  // is left empty.
-  service.StoreSeed(SerializeSeed(CreateTestSeed()), std::string(),
-                    std::string(), base::Time::Now(), false, false);
-  EXPECT_EQ(0, prefs_.GetInt64(prefs::kVariationsLastFetchTime));
-
-  // Check that field trials are created from the seed. Since the test study has
-  // only 1 experiment with 100% probability weight, we must be part of it.
-  EXPECT_TRUE(service.CreateTrialsFromSeed(base::FeatureList::GetInstance()));
-  EXPECT_EQ(base::FieldTrialList::FindFullName(kTestSeedStudyName),
-            kTestSeedExperimentName);
-}
-
-TEST_F(VariationsServiceTest, CreateTrialsFromOutdatedSeed) {
-  // Create a local base::FieldTrialList, to hold the field trials created in
-  // this test.
-  base::FieldTrialList field_trial_list(nullptr);
-
-  // Create a variations service.
-  TestVariationsService service(
-      base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs_),
-      &prefs_, GetMetricsStateManager());
-  service.SetCreateTrialsFromSeedCalledForTesting(false);
-
-  // Store a seed, with a fetch time 31 days in the past.
-  const base::Time seed_date =
-      base::Time::Now() - base::TimeDelta::FromDays(31);
-  service.StoreSeed(SerializeSeed(CreateTestSeed()), std::string(),
-                    std::string(), seed_date, false, false);
-  prefs_.SetInt64(prefs::kVariationsLastFetchTime, seed_date.ToInternalValue());
-
-  // Check that field trials are not created from the seed.
-  EXPECT_FALSE(service.CreateTrialsFromSeed(base::FeatureList::GetInstance()));
-  EXPECT_TRUE(base::FieldTrialList::FindFullName(kTestSeedStudyName).empty());
-}
-
 TEST_F(VariationsServiceTest, GetVariationsServerURL) {
   const std::string default_variations_url =
       VariationsService::GetDefaultVariationsServerURLForTesting();
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index dc76086..8a9cd856 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -33,9 +33,16 @@
     "surfaces/local_surface_id.h",
     "surfaces/local_surface_id_allocator.cc",
     "surfaces/local_surface_id_allocator.h",
+    "surfaces/sequence_surface_reference_factory.cc",
+    "surfaces/sequence_surface_reference_factory.h",
     "surfaces/surface_id.cc",
     "surfaces/surface_id.h",
     "surfaces/surface_info.h",
+    "surfaces/surface_reference_factory.h",
+    "surfaces/surface_reference_owner.h",
+    "surfaces/surface_sequence.h",
+    "surfaces/surface_sequence_generator.cc",
+    "surfaces/surface_sequence_generator.h",
   ]
 
   deps = [
diff --git a/cc/surfaces/sequence_surface_reference_factory.cc b/components/viz/common/surfaces/sequence_surface_reference_factory.cc
similarity index 71%
rename from cc/surfaces/sequence_surface_reference_factory.cc
rename to components/viz/common/surfaces/sequence_surface_reference_factory.cc
index c24abf6..7faf30e 100644
--- a/cc/surfaces/sequence_surface_reference_factory.cc
+++ b/components/viz/common/surfaces/sequence_surface_reference_factory.cc
@@ -2,22 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/surfaces/sequence_surface_reference_factory.h"
+#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 
-#include "cc/surfaces/surface_sequence.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 
-namespace cc {
+namespace viz {
 
 base::Closure SequenceSurfaceReferenceFactory::CreateReference(
     SurfaceReferenceOwner* owner,
-    const viz::SurfaceId& surface_id) const {
+    const SurfaceId& surface_id) const {
   auto seq = owner->GetSurfaceSequenceGenerator()->CreateSurfaceSequence();
   RequireSequence(surface_id, seq);
   return base::Bind(&SequenceSurfaceReferenceFactory::SatisfySequence, this,
                     seq);
 }
 
-}  // namespace cc
+}  // namespace viz
diff --git a/components/viz/common/surfaces/sequence_surface_reference_factory.h b/components/viz/common/surfaces/sequence_surface_reference_factory.h
new file mode 100644
index 0000000..9c2096b
--- /dev/null
+++ b/components/viz/common/surfaces/sequence_surface_reference_factory.h
@@ -0,0 +1,36 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_COMMON_SURFACES_SEQUENCE_SURFACE_REFERENCE_FACTORY_H_
+#define COMPONENTS_VIZ_COMMON_SURFACES_SEQUENCE_SURFACE_REFERENCE_FACTORY_H_
+
+#include "components/viz/common/surfaces/surface_reference_factory.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
+
+namespace viz {
+
+// A surface reference factory that uses SurfaceSequence.
+class SequenceSurfaceReferenceFactory
+    : public NON_EXPORTED_BASE(SurfaceReferenceFactory) {
+ public:
+  SequenceSurfaceReferenceFactory() = default;
+
+  // SurfaceReferenceFactory implementation:
+  base::Closure CreateReference(SurfaceReferenceOwner* owner,
+                                const SurfaceId& surface_id) const override;
+
+ protected:
+  ~SequenceSurfaceReferenceFactory() override = default;
+
+ private:
+  virtual void RequireSequence(const SurfaceId& surface_id,
+                               const SurfaceSequence& sequence) const = 0;
+  virtual void SatisfySequence(const SurfaceSequence& sequence) const = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(SequenceSurfaceReferenceFactory);
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SEQUENCE_SURFACE_REFERENCE_FACTORY_H_
diff --git a/cc/surfaces/surface_reference_factory.h b/components/viz/common/surfaces/surface_reference_factory.h
similarity index 68%
rename from cc/surfaces/surface_reference_factory.h
rename to components/viz/common/surfaces/surface_reference_factory.h
index 4bf38180..03e5808 100644
--- a/cc/surfaces/surface_reference_factory.h
+++ b/components/viz/common/surfaces/surface_reference_factory.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_SURFACES_SURFACE_REFERENCE_FACTORY_H_
-#define CC_SURFACES_SURFACE_REFERENCE_FACTORY_H_
+#ifndef COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_FACTORY_H_
+#define COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_FACTORY_H_
 
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
-#include "cc/surfaces/surface_reference_owner.h"
 #include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_reference_owner.h"
 
-namespace cc {
+namespace viz {
 
 // Confusingly, SurfaceReferenceFactory is only used to create SurfaceSequences.
 // TODO(kylechar): Delete all usage of SurfaceReferenceFactory when surface
@@ -20,9 +20,8 @@
  public:
   // Creates a reference to the surface with the given surface id and returns
   // a closure that must be called exactly once to remove the reference.
-  virtual base::Closure CreateReference(
-      SurfaceReferenceOwner* owner,
-      const viz::SurfaceId& surface_id) const = 0;
+  virtual base::Closure CreateReference(SurfaceReferenceOwner* owner,
+                                        const SurfaceId& surface_id) const = 0;
 
   SurfaceReferenceFactory() = default;
 
@@ -35,6 +34,6 @@
   DISALLOW_COPY_AND_ASSIGN(SurfaceReferenceFactory);
 };
 
-}  // namespace cc
+}  // namespace viz
 
-#endif  // CC_SURFACES_SURFACE_REFERENCE_FACTORY_H_
+#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_FACTORY_H_
diff --git a/components/viz/common/surfaces/surface_reference_owner.h b/components/viz/common/surfaces/surface_reference_owner.h
new file mode 100644
index 0000000..c966fb9
--- /dev/null
+++ b/components/viz/common/surfaces/surface_reference_owner.h
@@ -0,0 +1,23 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_OWNER_H_
+#define COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_OWNER_H_
+
+#include "components/viz/common/surfaces/surface_sequence_generator.h"
+
+namespace viz {
+
+// Implementations of this interface can be passed to
+// SurfaceReferenceFactory::CreateReference as the reference owner.
+class SurfaceReferenceOwner {
+ public:
+  virtual ~SurfaceReferenceOwner() {}
+
+  virtual SurfaceSequenceGenerator* GetSurfaceSequenceGenerator() = 0;
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_OWNER_H_
diff --git a/cc/surfaces/surface_sequence.h b/components/viz/common/surfaces/surface_sequence.h
similarity index 80%
rename from cc/surfaces/surface_sequence.h
rename to components/viz/common/surfaces/surface_sequence.h
index 07697fd..1b5bda9 100644
--- a/cc/surfaces/surface_sequence.h
+++ b/components/viz/common/surfaces/surface_sequence.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_SURFACES_SURFACE_SEQUENCE_H_
-#define CC_SURFACES_SURFACE_SEQUENCE_H_
+#ifndef COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_H_
+#define COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -13,18 +13,18 @@
 #include "base/hash.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 
-namespace cc {
+namespace viz {
 
 // A per-surface-namespace sequence number that's used to coordinate
 // dependencies between frames. A sequence number may be satisfied once, and
 // may be depended on once.
 struct SurfaceSequence {
   SurfaceSequence() : sequence(0u) {}
-  SurfaceSequence(const viz::FrameSinkId& frame_sink_id, uint32_t sequence)
+  SurfaceSequence(const FrameSinkId& frame_sink_id, uint32_t sequence)
       : frame_sink_id(frame_sink_id), sequence(sequence) {}
   bool is_valid() const { return frame_sink_id.is_valid() && sequence > 0u; }
 
-  viz::FrameSinkId frame_sink_id;
+  FrameSinkId frame_sink_id;
   uint32_t sequence;
 };
 
@@ -48,6 +48,6 @@
   }
 };
 
-}  // namespace cc
+}  // namespace viz
 
-#endif  // CC_SURFACES_SURFACE_SEQUENCE_H_
+#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_H_
diff --git a/cc/surfaces/surface_sequence_generator.cc b/components/viz/common/surfaces/surface_sequence_generator.cc
similarity index 73%
rename from cc/surfaces/surface_sequence_generator.cc
rename to components/viz/common/surfaces/surface_sequence_generator.cc
index 3244841..f3c351e 100644
--- a/cc/surfaces/surface_sequence_generator.cc
+++ b/components/viz/common/surfaces/surface_sequence_generator.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/surfaces/surface_sequence_generator.h"
-#include "cc/surfaces/surface_sequence.h"
+#include "components/viz/common/surfaces/surface_sequence_generator.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 
-namespace cc {
+namespace viz {
 
 SurfaceSequenceGenerator::SurfaceSequenceGenerator()
     : next_surface_sequence_(1u) {}
@@ -16,4 +16,4 @@
   return SurfaceSequence(frame_sink_id_, next_surface_sequence_++);
 }
 
-}  // namespace cc
+}  // namespace viz
diff --git a/cc/surfaces/surface_sequence_generator.h b/components/viz/common/surfaces/surface_sequence_generator.h
similarity index 61%
rename from cc/surfaces/surface_sequence_generator.h
rename to components/viz/common/surfaces/surface_sequence_generator.h
index 6e591f9..c9e104b 100644
--- a/cc/surfaces/surface_sequence_generator.h
+++ b/components/viz/common/surfaces/surface_sequence_generator.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_SURFACES_SURFACE_SEQUENCE_GENERATOR_H_
-#define CC_SURFACES_SURFACE_SEQUENCE_GENERATOR_H_
+#ifndef COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_GENERATOR_H_
+#define COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_GENERATOR_H_
 
 #include <stdint.h>
 
@@ -12,10 +12,9 @@
 #include "base/macros.h"
 
 #include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 
-namespace cc {
-
-struct SurfaceSequence;
+namespace viz {
 
 // Generates unique surface sequences for a surface client id.
 class SurfaceSequenceGenerator {
@@ -23,19 +22,19 @@
   SurfaceSequenceGenerator();
   ~SurfaceSequenceGenerator();
 
-  void set_frame_sink_id(const viz::FrameSinkId& frame_sink_id) {
+  void set_frame_sink_id(const FrameSinkId& frame_sink_id) {
     frame_sink_id_ = frame_sink_id;
   }
 
   SurfaceSequence CreateSurfaceSequence();
 
  private:
-  viz::FrameSinkId frame_sink_id_;
+  FrameSinkId frame_sink_id_;
   uint32_t next_surface_sequence_;
 
   DISALLOW_COPY_AND_ASSIGN(SurfaceSequenceGenerator);
 };
 
-}  // namespace cc
+}  // namespace viz
 
-#endif  // CC_SURFACES_SURFACE_SEQUENCE_GENERATOR_H_
+#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_GENERATOR_H_
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index 6019d3c..52f64483 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -554,7 +554,7 @@
   SurfaceId surface_id(kAnotherArbitraryFrameSinkId, local_surface_id);
   cc::Surface* surface = GetSurfaceForId(surface_id);
   surface->AddDestructionDependency(
-      cc::SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
+      SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
 
   std::vector<cc::ReturnedResource> returned_resource = {
       resource.ToReturnedResource()};
@@ -591,7 +591,7 @@
   SurfaceId surface_id(kAnotherArbitraryFrameSinkId, local_surface_id);
   cc::Surface* surface = GetSurfaceForId(surface_id);
   surface->AddDestructionDependency(
-      cc::SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
+      SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
 
   std::vector<cc::ReturnedResource> returned_resources;
   EXPECT_TRUE(GetSurfaceForId(surface_id));
@@ -603,7 +603,7 @@
   EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resources))
       .Times(1);
   manager_.surface_manager()->SatisfySequence(
-      cc::SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
+      SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
   EXPECT_FALSE(GetSurfaceForId(surface_id));
 }
 
@@ -618,14 +618,14 @@
 
   // Check that waiting before the sequence is satisfied works.
   GetSurfaceForId(id2)->AddDestructionDependency(
-      cc::SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
+      SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
   support2->EvictCurrentSurface();
 
   DCHECK(GetSurfaceForId(id2));
   manager_.surface_manager()->SatisfySequence(
-      cc::SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
+      SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
   manager_.surface_manager()->SatisfySequence(
-      cc::SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 6));
+      SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 6));
   DCHECK(!GetSurfaceForId(id2));
 
   // Check that waiting after the sequence is satisfied works.
@@ -633,7 +633,7 @@
                                   cc::test::MakeCompositorFrame());
   DCHECK(GetSurfaceForId(id2));
   GetSurfaceForId(id2)->AddDestructionDependency(
-      cc::SurfaceSequence(kAnotherArbitraryFrameSinkId, 6));
+      SurfaceSequence(kAnotherArbitraryFrameSinkId, 6));
   support2->EvictCurrentSurface();
   DCHECK(!GetSurfaceForId(id2));
 }
@@ -650,7 +650,7 @@
 
   manager_.RegisterFrameSinkId(frame_sink_id);
   GetSurfaceForId(id)->AddDestructionDependency(
-      cc::SurfaceSequence(frame_sink_id, 4));
+      SurfaceSequence(frame_sink_id, 4));
 
   support_->EvictCurrentSurface();
 
@@ -687,7 +687,7 @@
               local_surface_id2);
   }
   GetSurfaceForId(id2)->AddDestructionDependency(
-      cc::SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
+      SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
   support2->EvictCurrentSurface();
   // Give local_surface_id_ a frame that references id2.
   {
@@ -703,7 +703,7 @@
 
   // Satisfy last destruction dependency for id2.
   manager_.surface_manager()->SatisfySequence(
-      cc::SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
+      SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
 
   // id2 and local_surface_id_ are in a reference cycle that has no surface
   // sequences holding on to it, so they should be destroyed.
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 1dddb59..0b7c64f03 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -368,10 +368,8 @@
            RenderProcessHost::AllHostsIterator();
        !host_iterator.IsAtEnd(); host_iterator.Advance()) {
     RenderProcessHost* host = host_iterator.GetCurrentValue();
-    if (host->GetBrowserContext() == browser_context) {
-      // This will also clean up spare RPH references.
+    if (host->GetBrowserContext() == browser_context)
       host->ForceReleaseWorkerRefCounts();
-    }
   }
 }
 
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index 7615c06..cf3c4ca 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -431,7 +431,7 @@
 
 void BrowserPluginGuest::SetChildFrameSurface(
     const viz::SurfaceInfo& surface_info,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   has_attached_since_surface_set_ = false;
   SendMessageToEmbedder(base::MakeUnique<BrowserPluginMsg_SetChildFrameSurface>(
       browser_plugin_instance_id(), surface_info, sequence));
@@ -439,14 +439,14 @@
 
 void BrowserPluginGuest::OnSatisfySequence(
     int instance_id,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   GetFrameSinkManager()->surface_manager()->SatisfySequence(sequence);
 }
 
 void BrowserPluginGuest::OnRequireSequence(
     int instance_id,
     const viz::SurfaceId& id,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   GetFrameSinkManager()->surface_manager()->RequireSequence(id, sequence);
 }
 
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index f933bf881..725b77d 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -51,10 +51,6 @@
 struct FrameHostMsg_ShowPopup_Params;
 #endif
 
-namespace cc {
-struct SurfaceSequence;
-}  // namespace cc
-
 namespace gfx {
 class Range;
 }  // namespace gfx
@@ -62,6 +58,7 @@
 namespace viz {
 class SurfaceId;
 class SurfaceInfo;
+struct SurfaceSequence;
 }  // namespace viz
 
 namespace content {
@@ -242,7 +239,7 @@
 
   // The next function is virtual for test purposes.
   virtual void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                                    const cc::SurfaceSequence& sequence);
+                                    const viz::SurfaceSequence& sequence);
 
   void ResendEventToEmbedder(const blink::WebInputEvent& event);
 
@@ -281,10 +278,10 @@
   void InitInternal(const BrowserPluginHostMsg_Attach_Params& params,
                     WebContentsImpl* owner_web_contents);
 
-  void OnSatisfySequence(int instance_id, const cc::SurfaceSequence& sequence);
+  void OnSatisfySequence(int instance_id, const viz::SurfaceSequence& sequence);
   void OnRequireSequence(int instance_id,
                          const viz::SurfaceId& id,
-                         const cc::SurfaceSequence& sequence);
+                         const viz::SurfaceSequence& sequence);
   // Message handlers for messages from embedder.
   void OnDetach(int instance_id);
   // Handles drag events from the embedder.
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index 19580422..a5d7db8 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -1171,11 +1171,11 @@
                         // the download and don't expect to receive any more
                         // data.
 
-  if (received_bytes_at_length_mismatch > 0) {
-    if (total_bytes > received_bytes_at_length_mismatch) {
+  if (received_bytes_at_length_mismatch_ > 0) {
+    if (total_bytes > received_bytes_at_length_mismatch_) {
       RecordDownloadCount(
           MORE_BYTES_RECEIVED_AFTER_CONTENT_LENGTH_MISMATCH_COUNT);
-    } else if (total_bytes == received_bytes_at_length_mismatch) {
+    } else if (total_bytes == received_bytes_at_length_mismatch_) {
       RecordDownloadCount(
           NO_BYTES_RECEIVED_AFTER_CONTENT_LENGTH_MISMATCH_COUNT);
     } else {
@@ -1852,7 +1852,7 @@
                             job_ && job_->IsParallelizable(),
                             IsParallelDownloadEnabled());
   if (reason == DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH)
-    received_bytes_at_length_mismatch = GetReceivedBytes();
+    received_bytes_at_length_mismatch_ = GetReceivedBytes();
 
   if (!GetWebContents())
     RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
diff --git a/content/browser/download/download_item_impl.h b/content/browser/download/download_item_impl.h
index 369d336..6d91f344 100644
--- a/content/browser/download/download_item_impl.h
+++ b/content/browser/download/download_item_impl.h
@@ -748,7 +748,7 @@
 
   // Value of |received_bytes_| at the time the download was interrupted with
   // CONTENT_LENGTH_MISMATCH.
-  int64_t received_bytes_at_length_mismatch = -1;
+  int64_t received_bytes_at_length_mismatch_ = -1;
 
   base::WeakPtrFactory<DownloadItemImpl> weak_ptr_factory_;
 
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 52a9d1eb..d69a4312 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -491,12 +491,6 @@
     item_created.Run(download_item);
 }
 
-void DownloadManagerImpl::OnSavePackageSuccessfullyFinished(
-    DownloadItem* download_item) {
-  for (auto& observer : observers_)
-    observer.OnSavePackageSuccessfullyFinished(this, download_item);
-}
-
 // Resume a download of a specific URL. We send the request to the
 // ResourceDispatcherHost, and let it send us responses like a regular
 // download.
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index e9b13f6..67c48e3 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -62,9 +62,6 @@
       std::unique_ptr<DownloadRequestHandleInterface> request_handle,
       const DownloadItemImplCreated& item_created);
 
-  // Notifies DownloadManager about a successful completion of |download_item|.
-  void OnSavePackageSuccessfullyFinished(DownloadItem* download_item);
-
   // DownloadManager functions.
   void SetDelegate(DownloadManagerDelegate* delegate) override;
   DownloadManagerDelegate* GetDelegate() const override;
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
index 4c587480..b6b6bd4 100644
--- a/content/browser/download/save_package.cc
+++ b/content/browser/download/save_package.cc
@@ -1467,7 +1467,6 @@
 void SavePackage::FinalizeDownloadEntry() {
   DCHECK(download_);
   DCHECK(download_manager_);
-  download_manager_->OnSavePackageSuccessfullyFinished(download_);
   download_ = nullptr;
   download_manager_ = nullptr;
 }
diff --git a/content/browser/download/save_package.h b/content/browser/download/save_package.h
index b78c35e..7a4fb8c 100644
--- a/content/browser/download/save_package.h
+++ b/content/browser/download/save_package.h
@@ -62,7 +62,6 @@
 class CONTENT_EXPORT SavePackage
     : public base::RefCountedThreadSafe<SavePackage>,
       public WebContentsObserver,
-      public DownloadItem::Observer,
       public base::SupportsWeakPtr<SavePackage> {
  public:
   enum WaitState {
diff --git a/content/browser/download/save_package_browsertest.cc b/content/browser/download/save_package_browsertest.cc
index ac393bbb..c8ad8b4 100644
--- a/content/browser/download/save_package_browsertest.cc
+++ b/content/browser/download/save_package_browsertest.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/download_test_observer.h"
 #include "content/shell/browser/shell.h"
 #include "content/shell/browser/shell_download_manager_delegate.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -72,15 +73,6 @@
   bool remove_download_;
 };
 
-class SavePackageCompletionWaiter : public DownloadManager::Observer {
- public:
-  void OnSavePackageSuccessfullyFinished(DownloadManager* m,
-                                         DownloadItem* d) override {
-    quit_closure_.Run();
-  }
-  base::Closure quit_closure_;
-};
-
 class SavePackageBrowserTest : public ContentBrowserTest {
  protected:
   void SetUp() override {
@@ -133,12 +125,10 @@
     // download item.
     {
       base::RunLoop run_loop;
-      SavePackageCompletionWaiter completion_waiter;
-      completion_waiter.quit_closure_ = run_loop.QuitClosure();
-      download_manager->AddObserver(&completion_waiter);
+      SavePackageFinishedObserver finished_observer(download_manager,
+                                                    run_loop.QuitClosure());
       shell()->web_contents()->OnSavePage();
       run_loop.Run();
-      download_manager->RemoveObserver(&completion_waiter);
     }
     download_manager->SetDelegate(old_delegate);
   }
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc
index 261efa0..b7f4c994 100644
--- a/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -95,19 +95,19 @@
 
 void CrossProcessFrameConnector::SetChildFrameSurface(
     const viz::SurfaceInfo& surface_info,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   frame_proxy_in_parent_renderer_->Send(new FrameMsg_SetChildFrameSurface(
       frame_proxy_in_parent_renderer_->GetRoutingID(), surface_info, sequence));
 }
 
 void CrossProcessFrameConnector::OnSatisfySequence(
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   GetFrameSinkManager()->surface_manager()->SatisfySequence(sequence);
 }
 
 void CrossProcessFrameConnector::OnRequireSequence(
     const viz::SurfaceId& id,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   GetFrameSinkManager()->surface_manager()->RequireSequence(id, sequence);
 }
 
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h
index f01c699..46d6f9e 100644
--- a/content/browser/frame_host/cross_process_frame_connector.h
+++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -17,10 +17,6 @@
 class WebGestureEvent;
 }
 
-namespace cc {
-struct SurfaceSequence;
-}
-
 namespace IPC {
 class Message;
 }
@@ -28,6 +24,7 @@
 namespace viz {
 class SurfaceId;
 class SurfaceInfo;
+struct SurfaceSequence;
 }  // namespace viz
 
 namespace content {
@@ -89,7 +86,7 @@
   void RenderProcessGone();
 
   virtual void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                                    const cc::SurfaceSequence& sequence);
+                                    const viz::SurfaceSequence& sequence);
 
   gfx::Rect ChildFrameRect();
   void UpdateCursor(const WebCursor& cursor);
@@ -155,9 +152,9 @@
   void OnUpdateViewportIntersection(const gfx::Rect& viewport_intersection);
   void OnVisibilityChanged(bool visible);
   void OnSetIsInert(bool);
-  void OnSatisfySequence(const cc::SurfaceSequence& sequence);
+  void OnSatisfySequence(const viz::SurfaceSequence& sequence);
   void OnRequireSequence(const viz::SurfaceId& id,
-                         const cc::SurfaceSequence& sequence);
+                         const viz::SurfaceSequence& sequence);
 
   void SetRect(const gfx::Rect& frame_rect);
 
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index af7ba90..f66dac33 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -1200,12 +1200,6 @@
   if (force_swap)
     CHECK_NE(new_instance, current_instance);
 
-  if (new_instance == current_instance) {
-    // If we're navigating to the same site instance, we won't need to use any
-    // spare RenderProcessHost.
-    RenderProcessHostImpl::CleanupSpareRenderProcessHost();
-  }
-
   // Double-check that the new SiteInstance is associated with the right
   // BrowserContext.
   DCHECK_EQ(new_instance->GetBrowserContext(), browser_context);
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc
index 14858aa..804d5ef 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -477,8 +477,8 @@
 void RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedder() {
   if (service_manager::ServiceManagerIsRemote())
     return;
-  cc::SurfaceSequence sequence =
-      cc::SurfaceSequence(frame_sink_id_, next_surface_sequence_++);
+  viz::SurfaceSequence sequence =
+      viz::SurfaceSequence(frame_sink_id_, next_surface_sequence_++);
   cc::SurfaceManager* manager = GetFrameSinkManager()->surface_manager();
   viz::SurfaceId surface_id(frame_sink_id_, local_surface_id_);
   // The renderer process will satisfy this dependency when it creates a
@@ -491,7 +491,7 @@
 
 void RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedderImpl(
     const viz::SurfaceInfo& surface_info,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   frame_connector_->SetChildFrameSurface(surface_info, sequence);
 }
 
@@ -513,7 +513,7 @@
 
 void RenderWidgetHostViewChildFrame::OnSurfaceChanged(
     const viz::SurfaceInfo& surface_info) {
-  cc::SurfaceSequence sequence(frame_sink_id_, next_surface_sequence_++);
+  viz::SurfaceSequence sequence(frame_sink_id_, next_surface_sequence_++);
   SendSurfaceInfoToEmbedderImpl(surface_info, sequence);
 }
 
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h
index a4c58cc..b0a77cb 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.h
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -18,8 +18,8 @@
 #include "build/build_config.h"
 #include "cc/resources/returned_resource.h"
 #include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface_sequence.h"
 #include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support_client.h"
 #include "content/browser/compositor/image_transport_factory.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
@@ -259,7 +259,7 @@
  private:
   virtual void SendSurfaceInfoToEmbedderImpl(
       const viz::SurfaceInfo& surface_info,
-      const cc::SurfaceSequence& sequence);
+      const viz::SurfaceSequence& sequence);
 
   void SubmitSurfaceCopyRequest(const gfx::Rect& src_subrect,
                                 const gfx::Size& dst_size,
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc
index c024f2cd..12a0d80 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/macros.h"
-#include "cc/surfaces/surface_sequence.h"
 #include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
@@ -147,7 +147,8 @@
     return false;
   }
 
-  void OnRequire(const viz::SurfaceId& id, const cc::SurfaceSequence sequence) {
+  void OnRequire(const viz::SurfaceId& id,
+                 const viz::SurfaceSequence sequence) {
     content::BrowserThread::PostTask(
         content::BrowserThread::UI, FROM_HERE,
         base::Bind(&SurfaceRefMessageFilter::OnRequireOnUI, this));
@@ -159,7 +160,7 @@
     require_message_loop_runner_->Quit();
   }
 
-  void OnSatisfy(const cc::SurfaceSequence sequence) {
+  void OnSatisfy(const viz::SurfaceSequence sequence) {
     content::BrowserThread::PostTask(
         content::BrowserThread::UI, FROM_HERE,
         base::Bind(&SurfaceRefMessageFilter::OnSatisfyOnUI, this));
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc b/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc
index cad2a59..4f6f571f 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc
@@ -17,9 +17,9 @@
 #include "build/build_config.h"
 #include "cc/surfaces/surface.h"
 #include "cc/surfaces/surface_manager.h"
-#include "cc/surfaces/surface_sequence.h"
 #include "cc/test/begin_frame_args_test.h"
 #include "cc/test/fake_external_begin_frame_source.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
 #include "content/browser/compositor/test/no_transport_image_transport_factory.h"
 #include "content/browser/frame_host/cross_process_frame_connector.h"
@@ -65,7 +65,7 @@
   ~MockCrossProcessFrameConnector() override {}
 
   void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                            const cc::SurfaceSequence& sequence) override {
+                            const viz::SurfaceSequence& sequence) override {
     last_surface_info_ = surface_info;
   }
 
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc
index 0cec6b5..d221c6c 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -14,7 +14,7 @@
 #include "build/build_config.h"
 #include "cc/surfaces/surface.h"
 #include "cc/surfaces/surface_manager.h"
-#include "cc/surfaces/surface_sequence.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "content/browser/browser_plugin/browser_plugin_guest.h"
 #include "content/browser/compositor/surface_utils.h"
 #include "content/browser/renderer_host/input/input_router.h"
@@ -283,7 +283,7 @@
 
 void RenderWidgetHostViewGuest::SendSurfaceInfoToEmbedderImpl(
     const viz::SurfaceInfo& surface_info,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   if (guest_ && !guest_->is_in_destruction())
     guest_->SetChildFrameSurface(surface_info, sequence);
 }
diff --git a/content/browser/frame_host/render_widget_host_view_guest.h b/content/browser/frame_host/render_widget_host_view_guest.h
index aaa26f4..e5361f1 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.h
+++ b/content/browser/frame_host/render_widget_host_view_guest.h
@@ -138,7 +138,7 @@
 
   void SendSurfaceInfoToEmbedderImpl(
       const viz::SurfaceInfo& surface_info,
-      const cc::SurfaceSequence& sequence) override;
+      const viz::SurfaceSequence& sequence) override;
 
   RenderWidgetHostViewGuest(
       RenderWidgetHost* widget,
diff --git a/content/browser/frame_host/render_widget_host_view_guest_unittest.cc b/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
index bd997d0..31c5f789 100644
--- a/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
@@ -15,7 +15,7 @@
 #include "build/build_config.h"
 #include "cc/surfaces/surface.h"
 #include "cc/surfaces/surface_manager.h"
-#include "cc/surfaces/surface_sequence.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "content/browser/browser_plugin/browser_plugin_guest.h"
 #include "content/browser/compositor/test/no_transport_image_transport_factory.h"
 #include "content/browser/gpu/compositor_util.h"
@@ -134,7 +134,7 @@
   }
 
   void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                            const cc::SurfaceSequence& sequence) override {
+                            const viz::SurfaceSequence& sequence) override {
     last_surface_info_ = surface_info;
   }
 
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
index 99f1dff..d5dc6681 100644
--- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -17,13 +17,13 @@
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/test_simple_task_runner.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/indexed_db/indexed_db_factory_impl.h"
 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
 #include "content/browser/indexed_db/indexed_db_value.h"
 #include "content/browser/indexed_db/leveldb/leveldb_factory.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
 #include "net/url_request/url_request_test_util.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/quota/special_storage_policy.h"
@@ -232,27 +232,94 @@
 
 class IndexedDBBackingStoreTest : public testing::Test {
  public:
-  IndexedDBBackingStoreTest() {}
+  IndexedDBBackingStoreTest()
+      : url_request_context_getter_(
+            base::MakeRefCounted<net::TestURLRequestContextGetter>(
+                BrowserThread::GetTaskRunnerForThread(BrowserThread::UI))),
+        special_storage_policy_(
+            base::MakeRefCounted<MockSpecialStoragePolicy>()),
+        quota_manager_proxy_(
+            base::MakeRefCounted<MockQuotaManagerProxy>(nullptr, nullptr)) {}
+
   void SetUp() override {
-    const Origin origin(GURL("http://localhost:81"));
-    task_runner_ = new base::TestSimpleTaskRunner();
-    url_request_context_getter_ =
-        new net::TestURLRequestContextGetter(task_runner_);
-    special_storage_policy_ = new MockSpecialStoragePolicy();
-    quota_manager_proxy_ = new MockQuotaManagerProxy(nullptr, nullptr);
     special_storage_policy_->SetAllUnlimited(true);
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    idb_context_ = new IndexedDBContextImpl(
-        temp_dir_.GetPath(), special_storage_policy_.get(),
-        quota_manager_proxy_.get(), task_runner_.get());
-    idb_factory_ = new TestIDBFactory(idb_context_.get());
-    backing_store_ = idb_factory_->OpenBackingStoreForTest(
-        origin, url_request_context_getter_);
+    idb_context_ = base::MakeRefCounted<IndexedDBContextImpl>(
+        temp_dir_.GetPath(), special_storage_policy_, quota_manager_proxy_);
+
+    // Factory and backing store must be created on IDB task runner.
+    idb_context_->TaskRunner()->PostTask(
+        FROM_HERE, base::BindOnce(
+                       [](IndexedDBBackingStoreTest* test) {
+                         const Origin origin(GURL("http://localhost:81"));
+                         test->idb_factory_ =
+                             base::MakeRefCounted<TestIDBFactory>(
+                                 test->idb_context_.get());
+                         test->backing_store_ =
+                             test->idb_factory_->OpenBackingStoreForTest(
+                                 origin, test->url_request_context_getter_);
+                       },
+                       base::Unretained(this)));
+    RunAllBlockingPoolTasksUntilIdle();
 
     // useful keys and values during tests
     value1_ = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>());
     value2_ = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>());
 
+    key1_ = IndexedDBKey(99, blink::kWebIDBKeyTypeNumber);
+    key2_ = IndexedDBKey(ASCIIToUTF16("key2"));
+  }
+
+  void TearDown() override {
+    // Factory and backing store must be destroyed on IDB task runner.
+    idb_context_->TaskRunner()->PostTask(
+        FROM_HERE, base::BindOnce(
+                       [](IndexedDBBackingStoreTest* test) {
+                         test->idb_factory_ = nullptr;
+                         test->backing_store_ = nullptr;
+                       },
+                       base::Unretained(this)));
+    RunAllBlockingPoolTasksUntilIdle();
+
+    quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+  }
+
+  TestableIndexedDBBackingStore* backing_store() const {
+    return backing_store_.get();
+  }
+
+  // Sample keys and values that are consistent. Public so that posted lambdas
+  // passed |this| can access them.
+  IndexedDBKey key1_;
+  IndexedDBKey key2_;
+  IndexedDBValue value1_;
+  IndexedDBValue value2_;
+
+ protected:
+  // Must be initialized before url_request_context_getter_
+  TestBrowserThreadBundle thread_bundle_;
+
+  base::ScopedTempDir temp_dir_;
+  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+  scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+  scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
+  scoped_refptr<IndexedDBContextImpl> idb_context_;
+  scoped_refptr<TestIDBFactory> idb_factory_;
+
+  scoped_refptr<TestableIndexedDBBackingStore> backing_store_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest);
+};
+
+class IndexedDBBackingStoreTestWithBlobs : public IndexedDBBackingStoreTest {
+ public:
+  IndexedDBBackingStoreTestWithBlobs() {}
+
+  void SetUp() override {
+    IndexedDBBackingStoreTest::SetUp();
+
+    // useful keys and values during tests
     blob_info_.push_back(
         IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1));
     blob_info_.push_back(IndexedDBBlobInfo(
@@ -263,18 +330,14 @@
                                            base::UTF8ToUTF16("file type")));
     value3_ = IndexedDBValue("value3", blob_info_);
 
-    key1_ = IndexedDBKey(99, blink::kWebIDBKeyTypeNumber);
-    key2_ = IndexedDBKey(ASCIIToUTF16("key2"));
     key3_ = IndexedDBKey(ASCIIToUTF16("key3"));
   }
 
-  void TearDown() override {
-    quota_manager_proxy_->SimulateQuotaManagerDestroyed();
-  }
-
   // This just checks the data that survive getting stored and recalled, e.g.
   // the file path and UUID will change and thus aren't verified.
   bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const {
+    DCHECK(idb_context_->TaskRunner()->RunsTasksInCurrentSequence());
+
     if (blob_info_.size() != reads.size())
       return false;
     for (size_t i = 0; i < blob_info_.size(); ++i) {
@@ -297,6 +360,8 @@
 
   bool CheckBlobReadsMatchWrites(
       const std::vector<IndexedDBBlobInfo>& reads) const {
+    DCHECK(idb_context_->TaskRunner()->RunsTasksInCurrentSequence());
+
     if (backing_store_->writes().size() != reads.size())
       return false;
     std::set<int64_t> ids;
@@ -312,6 +377,8 @@
   }
 
   bool CheckBlobWrites() const {
+    DCHECK(idb_context_->TaskRunner()->RunsTasksInCurrentSequence());
+
     if (backing_store_->writes().size() != blob_info_.size())
       return false;
     for (size_t i = 0; i < backing_store_->writes().size(); ++i) {
@@ -333,6 +400,8 @@
   }
 
   bool CheckBlobRemovals() const {
+    DCHECK(idb_context_->TaskRunner()->RunsTasksInCurrentSequence());
+
     if (backing_store_->removals().size() != backing_store_->writes().size())
       return false;
     for (size_t i = 0; i < backing_store_->writes().size(); ++i) {
@@ -342,31 +411,17 @@
     return true;
   }
 
- protected:
-  // Must be initialized before url_request_context_getter_
-  TestBrowserThreadBundle thread_bundle_;
-
-  base::ScopedTempDir temp_dir_;
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
-  scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
-  scoped_refptr<IndexedDBContextImpl> idb_context_;
-  scoped_refptr<TestIDBFactory> idb_factory_;
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
-
-  scoped_refptr<TestableIndexedDBBackingStore> backing_store_;
-
-  // Sample keys and values that are consistent.
-  IndexedDBKey key1_;
-  IndexedDBKey key2_;
+  // Sample keys and values that are consistent. Public so that posted lambdas
+  // passed |this| can access them.
   IndexedDBKey key3_;
-  IndexedDBValue value1_;
-  IndexedDBValue value2_;
   IndexedDBValue value3_;
-  std::vector<IndexedDBBlobInfo> blob_info_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest);
+  // Blob details referenced by |value3_|. The various CheckBlob*() methods
+  // can be used to verify the state as a test progresses.
+  std::vector<IndexedDBBlobInfo> blob_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTestWithBlobs);
 };
 
 class TestCallback : public IndexedDBBackingStore::BlobWriteCallback {
@@ -396,630 +451,847 @@
 };
 
 TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
-  {
-    IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
-    transaction1.Begin();
-    std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
-    IndexedDBBackingStore::RecordIdentifier record;
-    leveldb::Status s = backing_store_->PutRecord(&transaction1, 1, 1, key1_,
-                                                  &value1_, &handles, &record);
-    EXPECT_TRUE(s.ok());
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
-  }
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStore* backing_store, IndexedDBKey key,
+             IndexedDBValue value) {
+            {
+              IndexedDBBackingStore::Transaction transaction1(backing_store);
+              transaction1.Begin();
+              std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
+              IndexedDBBackingStore::RecordIdentifier record;
+              leveldb::Status s = backing_store->PutRecord(
+                  &transaction1, 1, 1, key, &value, &handles, &record);
+              EXPECT_TRUE(s.ok());
+              scoped_refptr<TestCallback> callback(
+                  base::MakeRefCounted<TestCallback>());
+              EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
+              EXPECT_TRUE(callback->called);
+              EXPECT_TRUE(callback->succeeded);
+              EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
+            }
 
-  {
-    IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
-    transaction2.Begin();
-    IndexedDBValue result_value;
-    EXPECT_TRUE(
-        backing_store_->GetRecord(&transaction2, 1, 1, key1_, &result_value)
-            .ok());
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
-    EXPECT_EQ(value1_.bits, result_value.bits);
-  }
+            {
+              IndexedDBBackingStore::Transaction transaction2(backing_store);
+              transaction2.Begin();
+              IndexedDBValue result_value;
+              EXPECT_TRUE(
+                  backing_store
+                      ->GetRecord(&transaction2, 1, 1, key, &result_value)
+                      .ok());
+              scoped_refptr<TestCallback> callback(
+                  base::MakeRefCounted<TestCallback>());
+              EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
+              EXPECT_TRUE(callback->called);
+              EXPECT_TRUE(callback->succeeded);
+              EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
+              EXPECT_EQ(value.bits, result_value.bits);
+            }
+          },
+          base::Unretained(backing_store()), key1_, value1_));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
-TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) {
-  {
-    IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
-    transaction1.Begin();
-    std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
-    IndexedDBBackingStore::RecordIdentifier record;
-    EXPECT_TRUE(
-        backing_store_
-            ->PutRecord(&transaction1, 1, 1, key3_, &value3_, &handles, &record)
-            .ok());
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
-    task_runner_->RunUntilIdle();
-    EXPECT_TRUE(CheckBlobWrites());
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
-  }
+TEST_F(IndexedDBBackingStoreTestWithBlobs, PutGetConsistencyWithBlobs) {
+  struct TestState {
+    std::unique_ptr<IndexedDBBackingStore::Transaction> transaction1;
+    scoped_refptr<TestCallback> callback1;
+    std::unique_ptr<IndexedDBBackingStore::Transaction> transaction3;
+    scoped_refptr<TestCallback> callback3;
+  } state;
 
-  {
-    IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
-    transaction2.Begin();
-    IndexedDBValue result_value;
-    EXPECT_TRUE(
-        backing_store_->GetRecord(&transaction2, 1, 1, key3_, &result_value)
-            .ok());
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
-    EXPECT_EQ(value3_.bits, result_value.bits);
-    EXPECT_TRUE(CheckBlobInfoMatches(result_value.blob_info));
-    EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value.blob_info));
-  }
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStoreTestWithBlobs* test, TestState* state) {
+            // Initiate transaction1 - writing blobs.
+            state->transaction1 =
+                base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                    test->backing_store());
+            state->transaction1->Begin();
+            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
+            IndexedDBBackingStore::RecordIdentifier record;
+            EXPECT_TRUE(test->backing_store()
+                            ->PutRecord(state->transaction1.get(), 1, 1,
+                                        test->key3_, &test->value3_, &handles,
+                                        &record)
+                            .ok());
+            state->callback1 = base::MakeRefCounted<TestCallback>();
+            EXPECT_TRUE(
+                state->transaction1->CommitPhaseOne(state->callback1).ok());
+          },
+          base::Unretained(this), base::Unretained(&state)));
+  RunAllBlockingPoolTasksUntilIdle();
 
-  {
-    IndexedDBBackingStore::Transaction transaction3(backing_store_.get());
-    transaction3.Begin();
-    IndexedDBValue result_value;
-    EXPECT_TRUE(backing_store_
-                    ->DeleteRange(&transaction3, 1, 1, IndexedDBKeyRange(key3_))
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStoreTestWithBlobs* test, TestState* state) {
+            // Finish up transaction1, verifying blob writes.
+            EXPECT_TRUE(state->callback1->called);
+            EXPECT_TRUE(state->callback1->succeeded);
+            EXPECT_TRUE(test->CheckBlobWrites());
+            EXPECT_TRUE(state->transaction1->CommitPhaseTwo().ok());
+
+            // Initiate transaction2, reading blobs.
+            IndexedDBBackingStore::Transaction transaction2(
+                test->backing_store());
+            transaction2.Begin();
+            IndexedDBValue result_value;
+            EXPECT_TRUE(
+                test->backing_store()
+                    ->GetRecord(&transaction2, 1, 1, test->key3_, &result_value)
                     .ok());
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok());
-    task_runner_->RunUntilIdle();
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    EXPECT_TRUE(transaction3.CommitPhaseTwo().ok());
-    EXPECT_TRUE(CheckBlobRemovals());
-  }
+
+            // Finish up transaction2, verifying blob reads.
+            scoped_refptr<TestCallback> callback(
+                base::MakeRefCounted<TestCallback>());
+            EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
+            EXPECT_TRUE(callback->called);
+            EXPECT_TRUE(callback->succeeded);
+            EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
+            EXPECT_EQ(test->value3_.bits, result_value.bits);
+            EXPECT_TRUE(test->CheckBlobInfoMatches(result_value.blob_info));
+            EXPECT_TRUE(
+                test->CheckBlobReadsMatchWrites(result_value.blob_info));
+
+            // Initiate transaction3, deleting blobs.
+            state->transaction3 =
+                base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                    test->backing_store());
+            state->transaction3->Begin();
+            EXPECT_TRUE(test->backing_store()
+                            ->DeleteRange(state->transaction3.get(), 1, 1,
+                                          IndexedDBKeyRange(test->key3_))
+                            .ok());
+            state->callback3 = base::MakeRefCounted<TestCallback>();
+            EXPECT_TRUE(
+                state->transaction3->CommitPhaseOne(state->callback3).ok());
+
+          },
+          base::Unretained(this), base::Unretained(&state)));
+  RunAllBlockingPoolTasksUntilIdle();
+
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStoreTestWithBlobs* test, TestState* state) {
+            // Finish up transaction 3, verifying blob deletes.
+            EXPECT_TRUE(state->transaction3->CommitPhaseTwo().ok());
+            EXPECT_TRUE(test->CheckBlobRemovals());
+          },
+          base::Unretained(this), base::Unretained(&state)));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
-  IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0"));
-  IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1"));
-  IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2"));
-  IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3"));
-  IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
-  IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
-  IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
-  IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
-  IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key1, key2, false, false),
-                                IndexedDBKeyRange(key1, key2, false, false),
-                                IndexedDBKeyRange(key0, key2, true, false),
-                                IndexedDBKeyRange(key1, key3, false, true),
-                                IndexedDBKeyRange(key0, key3, true, true)};
+  const std::vector<IndexedDBKey> keys = {
+      IndexedDBKey(ASCIIToUTF16("key0")), IndexedDBKey(ASCIIToUTF16("key1")),
+      IndexedDBKey(ASCIIToUTF16("key2")), IndexedDBKey(ASCIIToUTF16("key3"))};
+  const IndexedDBKeyRange ranges[] = {
+      IndexedDBKeyRange(keys[1], keys[2], false, false),
+      IndexedDBKeyRange(keys[1], keys[2], false, false),
+      IndexedDBKeyRange(keys[0], keys[2], true, false),
+      IndexedDBKeyRange(keys[1], keys[3], false, true),
+      IndexedDBKeyRange(keys[0], keys[3], true, true)};
 
-  for (unsigned i = 0; i < sizeof(ranges) / sizeof(IndexedDBKeyRange); ++i) {
-    backing_store_->ClearWrites();
-    backing_store_->ClearRemovals();
+  for (size_t i = 0; i < arraysize(ranges); ++i) {
+    const int64_t database_id = 1;
+    const int64_t object_store_id = i + 1;
+    const IndexedDBKeyRange& range = ranges[i];
 
-    {
-      std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2,
-          blob_info3;
-      blob_info0.push_back(blob0);
-      blob_info1.push_back(blob1);
-      blob_info2.push_back(blob2);
-      blob_info3.push_back(blob3);
-      IndexedDBValue value0 = IndexedDBValue("value0", blob_info0);
-      IndexedDBValue value1 = IndexedDBValue("value1", blob_info1);
-      IndexedDBValue value2 = IndexedDBValue("value2", blob_info2);
-      IndexedDBValue value3 = IndexedDBValue("value3", blob_info3);
-      IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
-      transaction1.Begin();
-      std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
-      IndexedDBBackingStore::RecordIdentifier record;
-      EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
-                                            1,
-                                            i + 1,
-                                            key0,
-                                            &value0,
-                                            &handles,
-                                            &record).ok());
-      EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
-                                            1,
-                                            i + 1,
-                                            key1,
-                                            &value1,
-                                            &handles,
-                                            &record).ok());
-      EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
-                                            1,
-                                            i + 1,
-                                            key2,
-                                            &value2,
-                                            &handles,
-                                            &record).ok());
-      EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
-                                            1,
-                                            i + 1,
-                                            key3,
-                                            &value3,
-                                            &handles,
-                                            &record).ok());
-      scoped_refptr<TestCallback> callback(new TestCallback());
-      EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
-      task_runner_->RunUntilIdle();
-      EXPECT_TRUE(callback->called);
-      EXPECT_TRUE(callback->succeeded);
-      EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
-    }
+    struct TestState {
+      std::unique_ptr<IndexedDBBackingStore::Transaction> transaction1;
+      scoped_refptr<TestCallback> callback1;
+      std::unique_ptr<IndexedDBBackingStore::Transaction> transaction2;
+      scoped_refptr<TestCallback> callback2;
+    } state;
 
-    {
-      IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
-      transaction2.Begin();
-      IndexedDBValue result_value;
-      EXPECT_TRUE(
-          backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok());
-      scoped_refptr<TestCallback> callback(new TestCallback());
-      EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
-      task_runner_->RunUntilIdle();
-      EXPECT_TRUE(callback->called);
-      EXPECT_TRUE(callback->succeeded);
-      EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
-      ASSERT_EQ(2UL, backing_store_->removals().size());
-      EXPECT_EQ(backing_store_->writes()[1].key(),
-                backing_store_->removals()[0]);
-      EXPECT_EQ(backing_store_->writes()[2].key(),
-                backing_store_->removals()[1]);
-    }
+    idb_context_->TaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](TestableIndexedDBBackingStore* backing_store, TestState* state,
+               const std::vector<IndexedDBKey>& keys, int64_t database_id,
+               int64_t object_store_id) {
+              // Reset from previous iteration.
+              backing_store->ClearWrites();
+              backing_store->ClearRemovals();
+
+              std::vector<IndexedDBValue> values = {
+                  IndexedDBValue(
+                      "value0", {IndexedDBBlobInfo(
+                                    "uuid 0", base::UTF8ToUTF16("type 0"), 1)}),
+                  IndexedDBValue(
+                      "value1", {IndexedDBBlobInfo(
+                                    "uuid 1", base::UTF8ToUTF16("type 1"), 1)}),
+                  IndexedDBValue(
+                      "value2", {IndexedDBBlobInfo(
+                                    "uuid 2", base::UTF8ToUTF16("type 2"), 1)}),
+                  IndexedDBValue(
+                      "value3",
+                      {IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("type 3"),
+                                         1)})};
+              ASSERT_GE(keys.size(), values.size());
+
+              // Initiate transaction1 - write records.
+              state->transaction1 =
+                  base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                      backing_store);
+              state->transaction1->Begin();
+              std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
+              IndexedDBBackingStore::RecordIdentifier record;
+              for (size_t i = 0; i < values.size(); ++i) {
+                EXPECT_TRUE(backing_store
+                                ->PutRecord(state->transaction1.get(),
+                                            database_id, object_store_id,
+                                            keys[i], &values[i], &handles,
+                                            &record)
+                                .ok());
+              }
+
+              // Start committing transaction1.
+              state->callback1 = base::MakeRefCounted<TestCallback>();
+              EXPECT_TRUE(
+                  state->transaction1->CommitPhaseOne(state->callback1).ok());
+            },
+            base::Unretained(backing_store()), base::Unretained(&state),
+            base::ConstRef(keys), database_id, object_store_id));
+    RunAllBlockingPoolTasksUntilIdle();
+
+    idb_context_->TaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](TestableIndexedDBBackingStore* backing_store, TestState* state,
+               IndexedDBKeyRange range, int64_t database_id,
+               int64_t object_store_id) {
+              // Finish committing transaction1.
+              EXPECT_TRUE(state->callback1->called);
+              EXPECT_TRUE(state->callback1->succeeded);
+              EXPECT_TRUE(state->transaction1->CommitPhaseTwo().ok());
+
+              // Initiate transaction 2 - delete range.
+              state->transaction2 =
+                  base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                      backing_store);
+              state->transaction2->Begin();
+              IndexedDBValue result_value;
+              EXPECT_TRUE(backing_store
+                              ->DeleteRange(state->transaction2.get(),
+                                            database_id, object_store_id, range)
+                              .ok());
+
+              // Start committing transaction2.
+              state->callback2 = base::MakeRefCounted<TestCallback>();
+              EXPECT_TRUE(
+                  state->transaction2->CommitPhaseOne(state->callback2).ok());
+            },
+            base::Unretained(backing_store()), base::Unretained(&state), range,
+            database_id, object_store_id));
+    RunAllBlockingPoolTasksUntilIdle();
+
+    idb_context_->TaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](TestableIndexedDBBackingStore* backing_store, TestState* state) {
+              // Finish committing transaction2.
+              EXPECT_TRUE(state->callback2->called);
+              EXPECT_TRUE(state->callback2->succeeded);
+              EXPECT_TRUE(state->transaction2->CommitPhaseTwo().ok());
+
+              // Verify blob removals.
+              ASSERT_EQ(2UL, backing_store->removals().size());
+              EXPECT_EQ(backing_store->writes()[1].key(),
+                        backing_store->removals()[0]);
+              EXPECT_EQ(backing_store->writes()[2].key(),
+                        backing_store->removals()[1]);
+            },
+            base::Unretained(backing_store()), base::Unretained(&state)));
+    RunAllBlockingPoolTasksUntilIdle();
   }
 }
 
 TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
-  IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0"));
-  IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1"));
-  IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2"));
-  IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3"));
-  IndexedDBKey key4 = IndexedDBKey(ASCIIToUTF16("key4"));
-  IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
-  IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
-  IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
-  IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
-  IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key3, key4, true, false),
-                                IndexedDBKeyRange(key2, key1, false, false),
-                                IndexedDBKeyRange(key2, key1, true, true)};
+  const std::vector<IndexedDBKey> keys = {
+      IndexedDBKey(ASCIIToUTF16("key0")), IndexedDBKey(ASCIIToUTF16("key1")),
+      IndexedDBKey(ASCIIToUTF16("key2")), IndexedDBKey(ASCIIToUTF16("key3")),
+      IndexedDBKey(ASCIIToUTF16("key4"))};
+  const IndexedDBKeyRange ranges[] = {
+      IndexedDBKeyRange(keys[3], keys[4], true, false),
+      IndexedDBKeyRange(keys[2], keys[1], false, false),
+      IndexedDBKeyRange(keys[2], keys[1], true, true)};
 
-  for (unsigned i = 0; i < arraysize(ranges); ++i) {
-    backing_store_->ClearWrites();
-    backing_store_->ClearRemovals();
+  for (size_t i = 0; i < arraysize(ranges); ++i) {
+    const int64_t database_id = 1;
+    const int64_t object_store_id = i + 1;
+    const IndexedDBKeyRange& range = ranges[i];
 
-    {
-      std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2,
-          blob_info3;
-      blob_info0.push_back(blob0);
-      blob_info1.push_back(blob1);
-      blob_info2.push_back(blob2);
-      blob_info3.push_back(blob3);
-      IndexedDBValue value0 = IndexedDBValue("value0", blob_info0);
-      IndexedDBValue value1 = IndexedDBValue("value1", blob_info1);
-      IndexedDBValue value2 = IndexedDBValue("value2", blob_info2);
-      IndexedDBValue value3 = IndexedDBValue("value3", blob_info3);
-      IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
-      transaction1.Begin();
-      std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
-      IndexedDBBackingStore::RecordIdentifier record;
-      EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
-                                            1,
-                                            i + 1,
-                                            key0,
-                                            &value0,
-                                            &handles,
-                                            &record).ok());
-      EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
-                                            1,
-                                            i + 1,
-                                            key1,
-                                            &value1,
-                                            &handles,
-                                            &record).ok());
-      EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
-                                            1,
-                                            i + 1,
-                                            key2,
-                                            &value2,
-                                            &handles,
-                                            &record).ok());
-      EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
-                                            1,
-                                            i + 1,
-                                            key3,
-                                            &value3,
-                                            &handles,
-                                            &record).ok());
-      scoped_refptr<TestCallback> callback(new TestCallback());
-      EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
-      task_runner_->RunUntilIdle();
-      EXPECT_TRUE(callback->called);
-      EXPECT_TRUE(callback->succeeded);
-      EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
-    }
+    struct TestState {
+      std::unique_ptr<IndexedDBBackingStore::Transaction> transaction1;
+      scoped_refptr<TestCallback> callback1;
+      std::unique_ptr<IndexedDBBackingStore::Transaction> transaction2;
+      scoped_refptr<TestCallback> callback2;
+    } state;
 
-    {
-      IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
-      transaction2.Begin();
-      IndexedDBValue result_value;
-      EXPECT_TRUE(
-          backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok());
-      scoped_refptr<TestCallback> callback(new TestCallback());
-      EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
-      task_runner_->RunUntilIdle();
-      EXPECT_TRUE(callback->called);
-      EXPECT_TRUE(callback->succeeded);
-      EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
-      EXPECT_EQ(0UL, backing_store_->removals().size());
-    }
+    idb_context_->TaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](TestableIndexedDBBackingStore* backing_store, TestState* state,
+               const std::vector<IndexedDBKey>& keys, int64_t database_id,
+               int64_t object_store_id) {
+              // Reset from previous iteration.
+              backing_store->ClearWrites();
+              backing_store->ClearRemovals();
+
+              std::vector<IndexedDBValue> values = {
+                  IndexedDBValue(
+                      "value0", {IndexedDBBlobInfo(
+                                    "uuid 0", base::UTF8ToUTF16("type 0"), 1)}),
+                  IndexedDBValue(
+                      "value1", {IndexedDBBlobInfo(
+                                    "uuid 1", base::UTF8ToUTF16("type 1"), 1)}),
+                  IndexedDBValue(
+                      "value2", {IndexedDBBlobInfo(
+                                    "uuid 2", base::UTF8ToUTF16("type 2"), 1)}),
+                  IndexedDBValue(
+                      "value3",
+                      {IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("type 3"),
+                                         1)})};
+              ASSERT_GE(keys.size(), values.size());
+
+              // Initiate transaction1 - write records.
+              state->transaction1 =
+                  base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                      backing_store);
+              state->transaction1->Begin();
+
+              std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
+              IndexedDBBackingStore::RecordIdentifier record;
+              for (size_t i = 0; i < values.size(); ++i) {
+                EXPECT_TRUE(backing_store
+                                ->PutRecord(state->transaction1.get(),
+                                            database_id, object_store_id,
+                                            keys[i], &values[i], &handles,
+                                            &record)
+                                .ok());
+              }
+              // Start committing transaction1.
+              state->callback1 = base::MakeRefCounted<TestCallback>();
+              EXPECT_TRUE(
+                  state->transaction1->CommitPhaseOne(state->callback1).ok());
+            },
+            base::Unretained(backing_store()), base::Unretained(&state),
+            base::ConstRef(keys), database_id, object_store_id));
+    RunAllBlockingPoolTasksUntilIdle();
+
+    idb_context_->TaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](TestableIndexedDBBackingStore* backing_store, TestState* state,
+               IndexedDBKeyRange range, int64_t database_id,
+               int64_t object_store_id) {
+              // Finish committing transaction1.
+              EXPECT_TRUE(state->callback1->called);
+              EXPECT_TRUE(state->callback1->succeeded);
+              EXPECT_TRUE(state->transaction1->CommitPhaseTwo().ok());
+
+              // Initiate transaction 2 - delete range.
+              state->transaction2 =
+                  base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                      backing_store);
+              state->transaction2->Begin();
+              IndexedDBValue result_value;
+              EXPECT_TRUE(backing_store
+                              ->DeleteRange(state->transaction2.get(),
+                                            database_id, object_store_id, range)
+                              .ok());
+
+              // Start committing transaction2.
+              state->callback2 = base::MakeRefCounted<TestCallback>();
+              EXPECT_TRUE(
+                  state->transaction2->CommitPhaseOne(state->callback2).ok());
+            },
+            base::Unretained(backing_store()), base::Unretained(&state), range,
+            database_id, object_store_id));
+    RunAllBlockingPoolTasksUntilIdle();
+
+    idb_context_->TaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](TestableIndexedDBBackingStore* backing_store, TestState* state) {
+              // Finish committing transaction2.
+              EXPECT_TRUE(state->callback2->called);
+              EXPECT_TRUE(state->callback2->succeeded);
+              EXPECT_TRUE(state->transaction2->CommitPhaseTwo().ok());
+
+              // Verify blob removals.
+              EXPECT_EQ(0UL, backing_store->removals().size());
+            },
+            base::Unretained(backing_store()), base::Unretained(&state)));
+    RunAllBlockingPoolTasksUntilIdle();
   }
 }
 
-TEST_F(IndexedDBBackingStoreTest, BlobJournalInterleavedTransactions) {
-  IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
-  transaction1.Begin();
-  std::vector<std::unique_ptr<storage::BlobDataHandle>> handles1;
-  IndexedDBBackingStore::RecordIdentifier record1;
-  EXPECT_TRUE(
-      backing_store_
-          ->PutRecord(&transaction1, 1, 1, key3_, &value3_, &handles1, &record1)
-          .ok());
-  scoped_refptr<TestCallback> callback1(new TestCallback());
-  EXPECT_TRUE(transaction1.CommitPhaseOne(callback1).ok());
-  task_runner_->RunUntilIdle();
-  EXPECT_TRUE(CheckBlobWrites());
-  EXPECT_TRUE(callback1->called);
-  EXPECT_TRUE(callback1->succeeded);
-  EXPECT_EQ(0U, backing_store_->removals().size());
+TEST_F(IndexedDBBackingStoreTestWithBlobs, BlobJournalInterleavedTransactions) {
+  struct TestState {
+    std::unique_ptr<IndexedDBBackingStore::Transaction> transaction1;
+    scoped_refptr<TestCallback> callback1;
+    std::unique_ptr<IndexedDBBackingStore::Transaction> transaction2;
+    scoped_refptr<TestCallback> callback2;
+  } state;
 
-  IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
-  transaction2.Begin();
-  std::vector<std::unique_ptr<storage::BlobDataHandle>> handles2;
-  IndexedDBBackingStore::RecordIdentifier record2;
-  EXPECT_TRUE(
-      backing_store_
-          ->PutRecord(&transaction2, 1, 1, key1_, &value1_, &handles2, &record2)
-          .ok());
-  scoped_refptr<TestCallback> callback2(new TestCallback());
-  EXPECT_TRUE(transaction2.CommitPhaseOne(callback2).ok());
-  task_runner_->RunUntilIdle();
-  EXPECT_TRUE(CheckBlobWrites());
-  EXPECT_TRUE(callback2->called);
-  EXPECT_TRUE(callback2->succeeded);
-  EXPECT_EQ(0U, backing_store_->removals().size());
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStoreTestWithBlobs* test, TestState* state) {
+            // Initiate transaction1.
+            state->transaction1 =
+                base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                    test->backing_store());
+            state->transaction1->Begin();
+            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles1;
+            IndexedDBBackingStore::RecordIdentifier record1;
+            EXPECT_TRUE(test->backing_store()
+                            ->PutRecord(state->transaction1.get(), 1, 1,
+                                        test->key3_, &test->value3_, &handles1,
+                                        &record1)
+                            .ok());
+            state->callback1 = base::MakeRefCounted<TestCallback>();
+            EXPECT_TRUE(
+                state->transaction1->CommitPhaseOne(state->callback1).ok());
+          },
+          base::Unretained(this), base::Unretained(&state)));
+  RunAllBlockingPoolTasksUntilIdle();
 
-  EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
-  EXPECT_EQ(0U, backing_store_->removals().size());
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStoreTestWithBlobs* test, TestState* state) {
+            // Verify transaction1 phase one completed.
+            EXPECT_TRUE(state->callback1->called);
+            EXPECT_TRUE(state->callback1->succeeded);
+            EXPECT_TRUE(test->CheckBlobWrites());
+            EXPECT_EQ(0U, test->backing_store()->removals().size());
 
-  EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
-  EXPECT_EQ(0U, backing_store_->removals().size());
+            // Initiate transaction2.
+            state->transaction2 =
+                base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                    test->backing_store());
+            state->transaction2->Begin();
+            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles2;
+            IndexedDBBackingStore::RecordIdentifier record2;
+            EXPECT_TRUE(test->backing_store()
+                            ->PutRecord(state->transaction2.get(), 1, 1,
+                                        test->key1_, &test->value1_, &handles2,
+                                        &record2)
+                            .ok());
+            state->callback2 = base::MakeRefCounted<TestCallback>();
+            EXPECT_TRUE(
+                state->transaction2->CommitPhaseOne(state->callback2).ok());
+          },
+          base::Unretained(this), base::Unretained(&state)));
+  RunAllBlockingPoolTasksUntilIdle();
+
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStoreTestWithBlobs* test, TestState* state) {
+            // Verify transaction2 phase one completed.
+            EXPECT_TRUE(state->callback2->called);
+            EXPECT_TRUE(state->callback2->succeeded);
+            EXPECT_TRUE(test->CheckBlobWrites());
+            EXPECT_EQ(0U, test->backing_store()->removals().size());
+
+            // Finalize both transactions.
+            EXPECT_TRUE(state->transaction1->CommitPhaseTwo().ok());
+            EXPECT_EQ(0U, test->backing_store()->removals().size());
+
+            EXPECT_TRUE(state->transaction2->CommitPhaseTwo().ok());
+            EXPECT_EQ(0U, test->backing_store()->removals().size());
+          },
+          base::Unretained(this), base::Unretained(&state)));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
-TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) {
-  {
-    IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
-    transaction1.Begin();
-    std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
-    IndexedDBBackingStore::RecordIdentifier record;
-    EXPECT_TRUE(
-        backing_store_
-            ->PutRecord(&transaction1, 1, 1, key3_, &value3_, &handles, &record)
-            .ok());
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
-    task_runner_->RunUntilIdle();
-    EXPECT_TRUE(CheckBlobWrites());
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
-  }
+TEST_F(IndexedDBBackingStoreTestWithBlobs, LiveBlobJournal) {
+  struct TestState {
+    std::unique_ptr<IndexedDBBackingStore::Transaction> transaction1;
+    scoped_refptr<TestCallback> callback1;
+    std::unique_ptr<IndexedDBBackingStore::Transaction> transaction3;
+    scoped_refptr<TestCallback> callback3;
+    IndexedDBValue read_result_value;
+  } state;
 
-  IndexedDBValue read_result_value;
-  {
-    IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
-    transaction2.Begin();
-    EXPECT_TRUE(backing_store_
-                    ->GetRecord(&transaction2, 1, 1, key3_, &read_result_value)
-                    .ok());
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
-    EXPECT_EQ(value3_.bits, read_result_value.bits);
-    EXPECT_TRUE(CheckBlobInfoMatches(read_result_value.blob_info));
-    EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value.blob_info));
-    for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) {
-      read_result_value.blob_info[i].mark_used_callback().Run();
-    }
-  }
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStoreTestWithBlobs* test, TestState* state) {
+            state->transaction1 =
+                base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                    test->backing_store());
+            state->transaction1->Begin();
+            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
+            IndexedDBBackingStore::RecordIdentifier record;
+            EXPECT_TRUE(test->backing_store()
+                            ->PutRecord(state->transaction1.get(), 1, 1,
+                                        test->key3_, &test->value3_, &handles,
+                                        &record)
+                            .ok());
+            state->callback1 = base::MakeRefCounted<TestCallback>();
+            EXPECT_TRUE(
+                state->transaction1->CommitPhaseOne(state->callback1).ok());
+          },
+          base::Unretained(this), base::Unretained(&state)));
+  RunAllBlockingPoolTasksUntilIdle();
 
-  {
-    IndexedDBBackingStore::Transaction transaction3(backing_store_.get());
-    transaction3.Begin();
-    EXPECT_TRUE(backing_store_
-                    ->DeleteRange(&transaction3, 1, 1, IndexedDBKeyRange(key3_))
-                    .ok());
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok());
-    task_runner_->RunUntilIdle();
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    EXPECT_TRUE(transaction3.CommitPhaseTwo().ok());
-    EXPECT_EQ(0U, backing_store_->removals().size());
-    for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) {
-      read_result_value.blob_info[i].release_callback().Run(
-          read_result_value.blob_info[i].file_path());
-    }
-    task_runner_->RunUntilIdle();
-    EXPECT_NE(0U, backing_store_->removals().size());
-    EXPECT_TRUE(CheckBlobRemovals());
-  }
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStoreTestWithBlobs* test, TestState* state) {
+            EXPECT_TRUE(state->callback1->called);
+            EXPECT_TRUE(state->callback1->succeeded);
+            EXPECT_TRUE(test->CheckBlobWrites());
+            EXPECT_TRUE(state->transaction1->CommitPhaseTwo().ok());
+
+            IndexedDBBackingStore::Transaction transaction2(
+                test->backing_store());
+            transaction2.Begin();
+            EXPECT_TRUE(test->backing_store()
+                            ->GetRecord(&transaction2, 1, 1, test->key3_,
+                                        &state->read_result_value)
+                            .ok());
+            scoped_refptr<TestCallback> callback(
+                base::MakeRefCounted<TestCallback>());
+            EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
+            EXPECT_TRUE(callback->called);
+            EXPECT_TRUE(callback->succeeded);
+            EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
+            EXPECT_EQ(test->value3_.bits, state->read_result_value.bits);
+            EXPECT_TRUE(
+                test->CheckBlobInfoMatches(state->read_result_value.blob_info));
+            EXPECT_TRUE(test->CheckBlobReadsMatchWrites(
+                state->read_result_value.blob_info));
+            for (size_t i = 0; i < state->read_result_value.blob_info.size();
+                 ++i) {
+              state->read_result_value.blob_info[i].mark_used_callback().Run();
+            }
+
+            state->transaction3 =
+                base::MakeUnique<IndexedDBBackingStore::Transaction>(
+                    test->backing_store());
+            state->transaction3->Begin();
+            EXPECT_TRUE(test->backing_store()
+                            ->DeleteRange(state->transaction3.get(), 1, 1,
+                                          IndexedDBKeyRange(test->key3_))
+                            .ok());
+            state->callback3 = base::MakeRefCounted<TestCallback>();
+            EXPECT_TRUE(
+                state->transaction3->CommitPhaseOne(state->callback3).ok());
+          },
+          base::Unretained(this), base::Unretained(&state)));
+  RunAllBlockingPoolTasksUntilIdle();
+
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStoreTestWithBlobs* test, TestState* state) {
+            EXPECT_TRUE(state->callback3->called);
+            EXPECT_TRUE(state->callback3->succeeded);
+            EXPECT_TRUE(state->transaction3->CommitPhaseTwo().ok());
+            EXPECT_EQ(0U, test->backing_store()->removals().size());
+            for (size_t i = 0; i < state->read_result_value.blob_info.size();
+                 ++i) {
+              state->read_result_value.blob_info[i].release_callback().Run(
+                  state->read_result_value.blob_info[i].file_path());
+            }
+          },
+          base::Unretained(this), base::Unretained(&state)));
+  RunAllBlockingPoolTasksUntilIdle();
+
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(
+                     [](IndexedDBBackingStoreTestWithBlobs* test) {
+                       EXPECT_NE(0U, test->backing_store()->removals().size());
+                       EXPECT_TRUE(test->CheckBlobRemovals());
+                     },
+                     base::Unretained(this)));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 // Make sure that using very high ( more than 32 bit ) values for database_id
 // and object_store_id still work.
 TEST_F(IndexedDBBackingStoreTest, HighIds) {
-  const int64_t high_database_id = 1ULL << 35;
-  const int64_t high_object_store_id = 1ULL << 39;
-  // index_ids are capped at 32 bits for storage purposes.
-  const int64_t high_index_id = 1ULL << 29;
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStore* backing_store, IndexedDBKey key1,
+             IndexedDBKey key2, IndexedDBValue value1) {
+            const int64_t high_database_id = 1ULL << 35;
+            const int64_t high_object_store_id = 1ULL << 39;
+            // index_ids are capped at 32 bits for storage purposes.
+            const int64_t high_index_id = 1ULL << 29;
 
-  const int64_t invalid_high_index_id = 1ULL << 37;
+            const int64_t invalid_high_index_id = 1ULL << 37;
 
-  const IndexedDBKey& index_key = key2_;
-  std::string index_key_raw;
-  EncodeIDBKey(index_key, &index_key_raw);
-  {
-    IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
-    transaction1.Begin();
-    std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
-    IndexedDBBackingStore::RecordIdentifier record;
-    leveldb::Status s = backing_store_->PutRecord(
-        &transaction1, high_database_id, high_object_store_id, key1_, &value1_,
-        &handles, &record);
-    EXPECT_TRUE(s.ok());
+            const IndexedDBKey& index_key = key2;
+            std::string index_key_raw;
+            EncodeIDBKey(index_key, &index_key_raw);
+            {
+              IndexedDBBackingStore::Transaction transaction1(backing_store);
+              transaction1.Begin();
+              std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
+              IndexedDBBackingStore::RecordIdentifier record;
+              leveldb::Status s = backing_store->PutRecord(
+                  &transaction1, high_database_id, high_object_store_id, key1,
+                  &value1, &handles, &record);
+              EXPECT_TRUE(s.ok());
 
-    s = backing_store_->PutIndexDataForRecord(&transaction1,
-                                              high_database_id,
-                                              high_object_store_id,
-                                              invalid_high_index_id,
-                                              index_key,
-                                              record);
-    EXPECT_FALSE(s.ok());
+              s = backing_store->PutIndexDataForRecord(
+                  &transaction1, high_database_id, high_object_store_id,
+                  invalid_high_index_id, index_key, record);
+              EXPECT_FALSE(s.ok());
 
-    s = backing_store_->PutIndexDataForRecord(&transaction1,
-                                              high_database_id,
-                                              high_object_store_id,
-                                              high_index_id,
-                                              index_key,
-                                              record);
-    EXPECT_TRUE(s.ok());
+              s = backing_store->PutIndexDataForRecord(
+                  &transaction1, high_database_id, high_object_store_id,
+                  high_index_id, index_key, record);
+              EXPECT_TRUE(s.ok());
 
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    s = transaction1.CommitPhaseOne(callback);
-    EXPECT_TRUE(s.ok());
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    s = transaction1.CommitPhaseTwo();
-    EXPECT_TRUE(s.ok());
-  }
+              scoped_refptr<TestCallback> callback(
+                  base::MakeRefCounted<TestCallback>());
+              EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
+              EXPECT_TRUE(callback->called);
+              EXPECT_TRUE(callback->succeeded);
+              EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
+            }
 
-  {
-    IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
-    transaction2.Begin();
-    IndexedDBValue result_value;
-    leveldb::Status s =
-        backing_store_->GetRecord(&transaction2, high_database_id,
-                                  high_object_store_id, key1_, &result_value);
-    EXPECT_TRUE(s.ok());
-    EXPECT_EQ(value1_.bits, result_value.bits);
+            {
+              IndexedDBBackingStore::Transaction transaction2(backing_store);
+              transaction2.Begin();
+              IndexedDBValue result_value;
+              leveldb::Status s = backing_store->GetRecord(
+                  &transaction2, high_database_id, high_object_store_id, key1,
+                  &result_value);
+              EXPECT_TRUE(s.ok());
+              EXPECT_EQ(value1.bits, result_value.bits);
 
-    std::unique_ptr<IndexedDBKey> new_primary_key;
-    s = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
-                                              high_database_id,
-                                              high_object_store_id,
-                                              invalid_high_index_id,
-                                              index_key,
-                                              &new_primary_key);
-    EXPECT_FALSE(s.ok());
+              std::unique_ptr<IndexedDBKey> new_primary_key;
+              s = backing_store->GetPrimaryKeyViaIndex(
+                  &transaction2, high_database_id, high_object_store_id,
+                  invalid_high_index_id, index_key, &new_primary_key);
+              EXPECT_FALSE(s.ok());
 
-    s = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
-                                              high_database_id,
-                                              high_object_store_id,
-                                              high_index_id,
-                                              index_key,
-                                              &new_primary_key);
-    EXPECT_TRUE(s.ok());
-    EXPECT_TRUE(new_primary_key->Equals(key1_));
+              s = backing_store->GetPrimaryKeyViaIndex(
+                  &transaction2, high_database_id, high_object_store_id,
+                  high_index_id, index_key, &new_primary_key);
+              EXPECT_TRUE(s.ok());
+              EXPECT_TRUE(new_primary_key->Equals(key1));
 
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    s = transaction2.CommitPhaseOne(callback);
-    EXPECT_TRUE(s.ok());
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    s = transaction2.CommitPhaseTwo();
-    EXPECT_TRUE(s.ok());
-  }
+              scoped_refptr<TestCallback> callback(
+                  base::MakeRefCounted<TestCallback>());
+              EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
+              EXPECT_TRUE(callback->called);
+              EXPECT_TRUE(callback->succeeded);
+              EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
+            }
+          },
+          base::Unretained(backing_store()), key1_, key2_, value1_));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 // Make sure that other invalid ids do not crash.
 TEST_F(IndexedDBBackingStoreTest, InvalidIds) {
-  // valid ids for use when testing invalid ids
-  const int64_t database_id = 1;
-  const int64_t object_store_id = 1;
-  const int64_t index_id = kMinimumIndexId;
-  const int64_t invalid_low_index_id =
-      19;  // index_ids must be > kMinimumIndexId
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStore* backing_store, IndexedDBKey key,
+             IndexedDBValue value) {
+            // valid ids for use when testing invalid ids
+            const int64_t database_id = 1;
+            const int64_t object_store_id = 1;
+            const int64_t index_id = kMinimumIndexId;
+            // index_ids must be > kMinimumIndexId
+            const int64_t invalid_low_index_id = 19;
+            IndexedDBValue result_value;
 
-  IndexedDBValue result_value;
+            IndexedDBBackingStore::Transaction transaction1(backing_store);
+            transaction1.Begin();
 
-  IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
-  transaction1.Begin();
+            std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
+            IndexedDBBackingStore::RecordIdentifier record;
+            leveldb::Status s = backing_store->PutRecord(
+                &transaction1, database_id, KeyPrefix::kInvalidId, key, &value,
+                &handles, &record);
+            EXPECT_FALSE(s.ok());
+            s = backing_store->PutRecord(&transaction1, database_id, 0, key,
+                                         &value, &handles, &record);
+            EXPECT_FALSE(s.ok());
+            s = backing_store->PutRecord(&transaction1, KeyPrefix::kInvalidId,
+                                         object_store_id, key, &value, &handles,
+                                         &record);
+            EXPECT_FALSE(s.ok());
+            s = backing_store->PutRecord(&transaction1, 0, object_store_id, key,
+                                         &value, &handles, &record);
+            EXPECT_FALSE(s.ok());
 
-  std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
-  IndexedDBBackingStore::RecordIdentifier record;
-  leveldb::Status s = backing_store_->PutRecord(&transaction1, database_id,
-                                                KeyPrefix::kInvalidId, key1_,
-                                                &value1_, &handles, &record);
-  EXPECT_FALSE(s.ok());
-  s = backing_store_->PutRecord(&transaction1, database_id, 0, key1_, &value1_,
-                                &handles, &record);
-  EXPECT_FALSE(s.ok());
-  s = backing_store_->PutRecord(&transaction1, KeyPrefix::kInvalidId,
-                                object_store_id, key1_, &value1_, &handles,
-                                &record);
-  EXPECT_FALSE(s.ok());
-  s = backing_store_->PutRecord(&transaction1, 0, object_store_id, key1_,
-                                &value1_, &handles, &record);
-  EXPECT_FALSE(s.ok());
+            s = backing_store->GetRecord(&transaction1, database_id,
+                                         KeyPrefix::kInvalidId, key,
+                                         &result_value);
+            EXPECT_FALSE(s.ok());
+            s = backing_store->GetRecord(&transaction1, database_id, 0, key,
+                                         &result_value);
+            EXPECT_FALSE(s.ok());
+            s = backing_store->GetRecord(&transaction1, KeyPrefix::kInvalidId,
+                                         object_store_id, key, &result_value);
+            EXPECT_FALSE(s.ok());
+            s = backing_store->GetRecord(&transaction1, 0, object_store_id, key,
+                                         &result_value);
+            EXPECT_FALSE(s.ok());
 
-  s = backing_store_->GetRecord(&transaction1, database_id,
-                                KeyPrefix::kInvalidId, key1_, &result_value);
-  EXPECT_FALSE(s.ok());
-  s = backing_store_->GetRecord(&transaction1, database_id, 0, key1_,
-                                &result_value);
-  EXPECT_FALSE(s.ok());
-  s = backing_store_->GetRecord(&transaction1, KeyPrefix::kInvalidId,
-                                object_store_id, key1_, &result_value);
-  EXPECT_FALSE(s.ok());
-  s = backing_store_->GetRecord(&transaction1, 0, object_store_id, key1_,
-                                &result_value);
-  EXPECT_FALSE(s.ok());
+            std::unique_ptr<IndexedDBKey> new_primary_key;
+            s = backing_store->GetPrimaryKeyViaIndex(
+                &transaction1, database_id, object_store_id,
+                KeyPrefix::kInvalidId, key, &new_primary_key);
+            EXPECT_FALSE(s.ok());
+            s = backing_store->GetPrimaryKeyViaIndex(
+                &transaction1, database_id, object_store_id,
+                invalid_low_index_id, key, &new_primary_key);
+            EXPECT_FALSE(s.ok());
+            s = backing_store->GetPrimaryKeyViaIndex(&transaction1, database_id,
+                                                     object_store_id, 0, key,
+                                                     &new_primary_key);
+            EXPECT_FALSE(s.ok());
 
-  std::unique_ptr<IndexedDBKey> new_primary_key;
-  s = backing_store_->GetPrimaryKeyViaIndex(
-      &transaction1, database_id, object_store_id, KeyPrefix::kInvalidId, key1_,
-      &new_primary_key);
-  EXPECT_FALSE(s.ok());
-  s = backing_store_->GetPrimaryKeyViaIndex(
-      &transaction1, database_id, object_store_id, invalid_low_index_id, key1_,
-      &new_primary_key);
-  EXPECT_FALSE(s.ok());
-  s = backing_store_->GetPrimaryKeyViaIndex(
-      &transaction1, database_id, object_store_id, 0, key1_, &new_primary_key);
-  EXPECT_FALSE(s.ok());
-
-  s = backing_store_->GetPrimaryKeyViaIndex(
-      &transaction1, KeyPrefix::kInvalidId, object_store_id, index_id, key1_,
-      &new_primary_key);
-  EXPECT_FALSE(s.ok());
-  s = backing_store_->GetPrimaryKeyViaIndex(&transaction1, database_id,
-                                            KeyPrefix::kInvalidId, index_id,
-                                            key1_, &new_primary_key);
-  EXPECT_FALSE(s.ok());
+            s = backing_store->GetPrimaryKeyViaIndex(
+                &transaction1, KeyPrefix::kInvalidId, object_store_id, index_id,
+                key, &new_primary_key);
+            EXPECT_FALSE(s.ok());
+            s = backing_store->GetPrimaryKeyViaIndex(
+                &transaction1, database_id, KeyPrefix::kInvalidId, index_id,
+                key, &new_primary_key);
+            EXPECT_FALSE(s.ok());
+          },
+          base::Unretained(backing_store()), key1_, value1_));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
-  const base::string16 database_name(ASCIIToUTF16("db1"));
-  int64_t database_id;
-  const int64_t version = 9;
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBBackingStore* backing_store) {
+            const base::string16 database_name(ASCIIToUTF16("db1"));
+            int64_t database_id;
+            const int64_t version = 9;
 
-  const int64_t object_store_id = 99;
-  const base::string16 object_store_name(ASCIIToUTF16("object_store1"));
-  const bool auto_increment = true;
-  const IndexedDBKeyPath object_store_key_path(
-      ASCIIToUTF16("object_store_key"));
+            const int64_t object_store_id = 99;
+            const base::string16 object_store_name(
+                ASCIIToUTF16("object_store1"));
+            const bool auto_increment = true;
+            const IndexedDBKeyPath object_store_key_path(
+                ASCIIToUTF16("object_store_key"));
 
-  const int64_t index_id = 999;
-  const base::string16 index_name(ASCIIToUTF16("index1"));
-  const bool unique = true;
-  const bool multi_entry = true;
-  const IndexedDBKeyPath index_key_path(ASCIIToUTF16("index_key"));
+            const int64_t index_id = 999;
+            const base::string16 index_name(ASCIIToUTF16("index1"));
+            const bool unique = true;
+            const bool multi_entry = true;
+            const IndexedDBKeyPath index_key_path(ASCIIToUTF16("index_key"));
 
-  {
-    leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
-        database_name, version, &database_id);
-    EXPECT_TRUE(s.ok());
-    EXPECT_GT(database_id, 0);
+            {
+              leveldb::Status s = backing_store->CreateIDBDatabaseMetaData(
+                  database_name, version, &database_id);
+              EXPECT_TRUE(s.ok());
+              EXPECT_GT(database_id, 0);
 
-    IndexedDBBackingStore::Transaction transaction(backing_store_.get());
-    transaction.Begin();
+              IndexedDBBackingStore::Transaction transaction(backing_store);
+              transaction.Begin();
 
-    s = backing_store_->CreateObjectStore(&transaction,
-                                          database_id,
-                                          object_store_id,
-                                          object_store_name,
-                                          object_store_key_path,
-                                          auto_increment);
-    EXPECT_TRUE(s.ok());
+              s = backing_store->CreateObjectStore(
+                  &transaction, database_id, object_store_id, object_store_name,
+                  object_store_key_path, auto_increment);
+              EXPECT_TRUE(s.ok());
 
-    s = backing_store_->CreateIndex(&transaction,
-                                    database_id,
-                                    object_store_id,
-                                    index_id,
-                                    index_name,
-                                    index_key_path,
-                                    unique,
-                                    multi_entry);
-    EXPECT_TRUE(s.ok());
+              s = backing_store->CreateIndex(
+                  &transaction, database_id, object_store_id, index_id,
+                  index_name, index_key_path, unique, multi_entry);
+              EXPECT_TRUE(s.ok());
 
-    scoped_refptr<TestCallback> callback(new TestCallback());
-    s = transaction.CommitPhaseOne(callback);
-    EXPECT_TRUE(s.ok());
-    EXPECT_TRUE(callback->called);
-    EXPECT_TRUE(callback->succeeded);
-    s = transaction.CommitPhaseTwo();
-    EXPECT_TRUE(s.ok());
-  }
+              scoped_refptr<TestCallback> callback(
+                  base::MakeRefCounted<TestCallback>());
+              EXPECT_TRUE(transaction.CommitPhaseOne(callback).ok());
+              EXPECT_TRUE(callback->called);
+              EXPECT_TRUE(callback->succeeded);
+              EXPECT_TRUE(transaction.CommitPhaseTwo().ok());
+            }
 
-  {
-    IndexedDBDatabaseMetadata database;
-    bool found;
-    leveldb::Status s = backing_store_->GetIDBDatabaseMetaData(
-        database_name, &database, &found);
-    EXPECT_TRUE(s.ok());
-    EXPECT_TRUE(found);
+            {
+              IndexedDBDatabaseMetadata database;
+              bool found;
+              leveldb::Status s = backing_store->GetIDBDatabaseMetaData(
+                  database_name, &database, &found);
+              EXPECT_TRUE(s.ok());
+              EXPECT_TRUE(found);
 
-    // database.name is not filled in by the implementation.
-    EXPECT_EQ(version, database.version);
-    EXPECT_EQ(database_id, database.id);
+              // database.name is not filled in by the implementation.
+              EXPECT_EQ(version, database.version);
+              EXPECT_EQ(database_id, database.id);
 
-    s = backing_store_->GetObjectStores(database.id, &database.object_stores);
-    EXPECT_TRUE(s.ok());
+              s = backing_store->GetObjectStores(database.id,
+                                                 &database.object_stores);
+              EXPECT_TRUE(s.ok());
 
-    EXPECT_EQ(1UL, database.object_stores.size());
-    IndexedDBObjectStoreMetadata object_store =
-        database.object_stores[object_store_id];
-    EXPECT_EQ(object_store_name, object_store.name);
-    EXPECT_EQ(object_store_key_path, object_store.key_path);
-    EXPECT_EQ(auto_increment, object_store.auto_increment);
+              EXPECT_EQ(1UL, database.object_stores.size());
+              IndexedDBObjectStoreMetadata object_store =
+                  database.object_stores[object_store_id];
+              EXPECT_EQ(object_store_name, object_store.name);
+              EXPECT_EQ(object_store_key_path, object_store.key_path);
+              EXPECT_EQ(auto_increment, object_store.auto_increment);
 
-    EXPECT_EQ(1UL, object_store.indexes.size());
-    IndexedDBIndexMetadata index = object_store.indexes[index_id];
-    EXPECT_EQ(index_name, index.name);
-    EXPECT_EQ(index_key_path, index.key_path);
-    EXPECT_EQ(unique, index.unique);
-    EXPECT_EQ(multi_entry, index.multi_entry);
-  }
+              EXPECT_EQ(1UL, object_store.indexes.size());
+              IndexedDBIndexMetadata index = object_store.indexes[index_id];
+              EXPECT_EQ(index_name, index.name);
+              EXPECT_EQ(index_key_path, index.key_path);
+              EXPECT_EQ(unique, index.unique);
+              EXPECT_EQ(multi_entry, index.multi_entry);
+            }
+          },
+          base::Unretained(backing_store())));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBBackingStoreTest, GetDatabaseNames) {
-  const base::string16 db1_name(ASCIIToUTF16("db1"));
-  const int64_t db1_version = 1LL;
-  int64_t db1_id;
+  idb_context_->TaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(
+                     [](IndexedDBBackingStore* backing_store) {
+                       const base::string16 db1_name(ASCIIToUTF16("db1"));
+                       const int64_t db1_version = 1LL;
+                       int64_t db1_id;
 
-  // Database records with DEFAULT_VERSION represent stale data,
-  // and should not be enumerated.
-  const base::string16 db2_name(ASCIIToUTF16("db2"));
-  const int64_t db2_version = IndexedDBDatabaseMetadata::DEFAULT_VERSION;
-  int64_t db2_id;
+                       // Database records with DEFAULT_VERSION represent
+                       // stale data, and should not be enumerated.
+                       const base::string16 db2_name(ASCIIToUTF16("db2"));
+                       const int64_t db2_version =
+                           IndexedDBDatabaseMetadata::DEFAULT_VERSION;
+                       int64_t db2_id;
 
-  leveldb::Status s =
-      backing_store_->CreateIDBDatabaseMetaData(db1_name, db1_version, &db1_id);
-  EXPECT_TRUE(s.ok());
-  EXPECT_GT(db1_id, 0LL);
+                       leveldb::Status s =
+                           backing_store->CreateIDBDatabaseMetaData(
+                               db1_name, db1_version, &db1_id);
+                       EXPECT_TRUE(s.ok());
+                       EXPECT_GT(db1_id, 0LL);
 
-  s = backing_store_->CreateIDBDatabaseMetaData(db2_name, db2_version, &db2_id);
-  EXPECT_TRUE(s.ok());
-  EXPECT_GT(db2_id, db1_id);
+                       s = backing_store->CreateIDBDatabaseMetaData(
+                           db2_name, db2_version, &db2_id);
+                       EXPECT_TRUE(s.ok());
+                       EXPECT_GT(db2_id, db1_id);
 
-  std::vector<base::string16> names = backing_store_->GetDatabaseNames(&s);
-  EXPECT_TRUE(s.ok());
-  ASSERT_EQ(1U, names.size());
-  EXPECT_EQ(db1_name, names[0]);
+                       std::vector<base::string16> names =
+                           backing_store->GetDatabaseNames(&s);
+                       EXPECT_TRUE(s.ok());
+                       ASSERT_EQ(1U, names.size());
+                       EXPECT_EQ(db1_name, names[0]);
+                     },
+                     base::Unretained(backing_store())));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 }  // namespace
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc
index c64f52e..b687171 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -17,6 +17,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
@@ -33,8 +34,6 @@
 #include "content/public/browser/indexed_db_info.h"
 #include "content/public/common/content_switches.h"
 #include "storage/browser/database/database_util.h"
-#include "storage/browser/quota/quota_manager_proxy.h"
-#include "storage/browser/quota/special_storage_policy.h"
 #include "storage/common/database/database_identifier.h"
 #include "ui/base/text/bytes_formatting.h"
 #include "url/origin.h"
@@ -108,13 +107,15 @@
 
 IndexedDBContextImpl::IndexedDBContextImpl(
     const base::FilePath& data_path,
-    storage::SpecialStoragePolicy* special_storage_policy,
-    storage::QuotaManagerProxy* quota_manager_proxy,
-    scoped_refptr<base::SequencedTaskRunner> task_runner)
+    scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+    scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy)
     : force_keep_session_state_(false),
       special_storage_policy_(special_storage_policy),
       quota_manager_proxy_(quota_manager_proxy),
-      task_runner_(std::move(task_runner)) {
+      task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::WithBaseSyncPrimitives(),
+           base::TaskPriority::USER_VISIBLE,
+           base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {
   IDB_TRACE("init");
   if (!data_path.empty())
     data_path_ = data_path.Append(kIndexedDBDirectory);
@@ -426,9 +427,13 @@
 }
 
 void IndexedDBContextImpl::SetTaskRunnerForTesting(
-    base::SequencedTaskRunner* task_runner) {
-  DCHECK(!task_runner_.get());
-  task_runner_ = task_runner;
+    scoped_refptr<base::SequencedTaskRunner> task_runner) {
+  task_runner_ = std::move(task_runner);
+}
+
+void IndexedDBContextImpl::ResetCachesForTesting() {
+  origin_set_.reset();
+  origin_size_map_.clear();
 }
 
 void IndexedDBContextImpl::ConnectionOpened(const Origin& origin,
@@ -559,12 +564,8 @@
   return origin_set_.get();
 }
 
-void IndexedDBContextImpl::ResetCaches() {
-  origin_set_.reset();
-  origin_size_map_.clear();
-}
-
 base::SequencedTaskRunner* IndexedDBContextImpl::TaskRunner() const {
+  DCHECK(task_runner_.get());
   return task_runner_.get();
 }
 
diff --git a/content/browser/indexed_db/indexed_db_context_impl.h b/content/browser/indexed_db/indexed_db_context_impl.h
index 47e5774..30948886 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.h
+++ b/content/browser/indexed_db/indexed_db_context_impl.h
@@ -21,6 +21,8 @@
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/indexed_db/indexed_db_factory.h"
 #include "content/public/browser/indexed_db_context.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/browser/quota/special_storage_policy.h"
 #include "storage/common/quota/quota_types.h"
 #include "url/gurl.h"
 
@@ -30,11 +32,6 @@
 class SequencedTaskRunner;
 }
 
-namespace storage {
-class QuotaManagerProxy;
-class SpecialStoragePolicy;
-}
-
 namespace url {
 class Origin;
 }
@@ -59,10 +56,10 @@
   static const base::FilePath::CharType kIndexedDBDirectory[];
 
   // If |data_path| is empty, nothing will be saved to disk.
-  IndexedDBContextImpl(const base::FilePath& data_path,
-                       storage::SpecialStoragePolicy* special_storage_policy,
-                       storage::QuotaManagerProxy* quota_manager_proxy,
-                       scoped_refptr<base::SequencedTaskRunner> task_runner);
+  IndexedDBContextImpl(
+      const base::FilePath& data_path,
+      scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+      scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy);
 
   IndexedDBFactory* GetIDBFactory();
 
@@ -77,7 +74,7 @@
   void CopyOriginData(const GURL& origin_url,
                       IndexedDBContext* dest_context) override;
   base::FilePath GetFilePathForTesting(const GURL& origin_url) const override;
-  void SetTaskRunnerForTesting(base::SequencedTaskRunner* task_runner) override;
+  void ResetCachesForTesting() override;
 
   // TODO(jsbell): Replace IndexedDBContext members with these.
   int64_t GetOriginDiskUsage(const url::Origin& origin);
@@ -118,6 +115,10 @@
   size_t GetConnectionCount(const url::Origin& origin);
   int GetOriginBlobFileCount(const url::Origin& origin);
 
+  // TODO(jsbell): Update tests to eliminate the need for this.
+  void SetTaskRunnerForTesting(
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
+
   // For unit tests allow to override the |data_path_|.
   void set_data_path_for_testing(const base::FilePath& data_path) {
     data_path_ = data_path;
@@ -153,9 +154,6 @@
     GetOriginSet()->erase(origin);
   }
 
-  // Only for testing.
-  void ResetCaches();
-
   scoped_refptr<IndexedDBFactory> factory_;
   base::FilePath data_path_;
   // If true, nothing (not even session-only data) should be deleted on exit.
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index 85df1d00..4e5299f6 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -132,21 +132,16 @@
     scoped_refptr<ChromeBlobStorageContext> blob_storage_context)
     : indexed_db_context_(std::move(indexed_db_context)),
       blob_storage_context_(std::move(blob_storage_context)),
-      idb_runner_(indexed_db_context_->TaskRunner()),
       ipc_process_id_(ipc_process_id),
+      idb_helper_(new IDBSequenceHelper(ipc_process_id_,
+                                        std::move(request_context_getter),
+                                        indexed_db_context_)),
       weak_factory_(this) {
-  // Can be null in unittests.
-  idb_helper_ = idb_runner_
-                    ? new IDBSequenceHelper(ipc_process_id_,
-                                            std::move(request_context_getter),
-                                            indexed_db_context_)
-                    : nullptr;
   DCHECK(indexed_db_context_.get());
 }
 
 IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
-  if (idb_helper_)
-    idb_runner_->DeleteSoon(FROM_HERE, idb_helper_);
+  IDBTaskRunner()->DeleteSoon(FROM_HERE, idb_helper_);
 }
 
 void IndexedDBDispatcherHost::AddBinding(
@@ -230,8 +225,8 @@
   }
 
   scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
-      this->AsWeakPtr(), origin, std::move(callbacks_info), idb_runner_));
-  idb_runner_->PostTask(
+      this->AsWeakPtr(), origin, std::move(callbacks_info), IDBTaskRunner()));
+  IDBTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(&IDBSequenceHelper::GetDatabaseNamesOnIDBThread,
                                 base::Unretained(idb_helper_),
                                 base::Passed(&callbacks), origin));
@@ -253,11 +248,11 @@
   }
 
   scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
-      this->AsWeakPtr(), origin, std::move(callbacks_info), idb_runner_));
+      this->AsWeakPtr(), origin, std::move(callbacks_info), IDBTaskRunner()));
   scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks(
       new IndexedDBDatabaseCallbacks(indexed_db_context_,
                                      std::move(database_callbacks_info)));
-  idb_runner_->PostTask(
+  IDBTaskRunner()->PostTask(
       FROM_HERE,
       base::BindOnce(&IDBSequenceHelper::OpenOnIDBThread,
                      base::Unretained(idb_helper_), base::Passed(&callbacks),
@@ -278,8 +273,8 @@
   }
 
   scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
-      this->AsWeakPtr(), origin, std::move(callbacks_info), idb_runner_));
-  idb_runner_->PostTask(
+      this->AsWeakPtr(), origin, std::move(callbacks_info), IDBTaskRunner()));
+  IDBTaskRunner()->PostTask(
       FROM_HERE,
       base::BindOnce(&IDBSequenceHelper::DeleteDatabaseOnIDBThread,
                      base::Unretained(idb_helper_), base::Passed(&callbacks),
@@ -299,7 +294,7 @@
   base::OnceCallback<void(leveldb::Status)> callback_on_io = base::BindOnce(
       &CallCompactionStatusCallbackOnIOThread,
       base::ThreadTaskRunnerHandle::Get(), std::move(mojo_callback));
-  idb_runner_->PostTask(
+  IDBTaskRunner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           &IDBSequenceHelper::AbortTransactionsAndCompactDatabaseOnIDBThread,
@@ -320,7 +315,7 @@
   base::OnceCallback<void(leveldb::Status)> callback_on_io = base::BindOnce(
       &CallAbortStatusCallbackOnIOThread, base::ThreadTaskRunnerHandle::Get(),
       std::move(mojo_callback));
-  idb_runner_->PostTask(
+  IDBTaskRunner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           &IDBSequenceHelper::AbortTransactionsForDatabaseOnIDBThread,
@@ -334,6 +329,10 @@
   database_bindings_.CloseAllBindings();
 }
 
+base::SequencedTaskRunner* IndexedDBDispatcherHost::IDBTaskRunner() const {
+  return indexed_db_context_->TaskRunner();
+}
+
 void IndexedDBDispatcherHost::IDBSequenceHelper::GetDatabaseNamesOnIDBThread(
     scoped_refptr<IndexedDBCallbacks> callbacks,
     const url::Origin& origin) {
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.h b/content/browser/indexed_db/indexed_db_dispatcher_host.h
index 582fe63..8bbe91f7 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.h
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.h
@@ -115,9 +115,10 @@
 
   void InvalidateWeakPtrsAndClearBindings();
 
+  base::SequencedTaskRunner* IDBTaskRunner() const;
+
   scoped_refptr<IndexedDBContextImpl> indexed_db_context_;
   scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
-  scoped_refptr<base::SequencedTaskRunner> idb_runner_;
 
   // Maps blob uuid to a pair (handle, ref count). Entry is added and/or count
   // is incremented in HoldBlobData(), and count is decremented and/or entry
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
index 50d4856..060c2a5 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
@@ -25,6 +25,7 @@
 #include "content/common/indexed_db/indexed_db.mojom.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "net/url_request/url_request_test_util.h"
@@ -83,7 +84,6 @@
 static const char kOrigin[] = "https://www.example.com";
 static const int kFakeProcessId = 2;
 static const int64_t kTemporaryQuota = 50 * 1024 * 1024;
-static const int64_t kPersistantQuota = 50 * 1024 * 1024;
 
 base::FilePath CreateAndReturnTempDir(base::ScopedTempDir* temp_dir) {
   CHECK(temp_dir->CreateUniqueTempDir());
@@ -138,57 +138,38 @@
  public:
   IndexedDBDispatcherHostTest()
       : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
-        idb_thread_(new base::Thread("IndexedDB")),
-        io_task_runner_(
-            BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)),
-        idb_task_runner_(idb_thread_->Start() ? idb_thread_->task_runner()
-                                              : nullptr),
-        request_context_getter_(
-            new net::TestURLRequestContextGetter(io_task_runner_)),
-        special_storage_policy_(new MockSpecialStoragePolicy()),
-        quota_manager_(new MockQuotaManager(false,
-                                            browser_context_.GetPath(),
-                                            io_task_runner_,
-                                            idb_task_runner_,
-                                            special_storage_policy_)),
-        quota_manager_proxy_(quota_manager_->proxy()),
-        context_impl_(
-            new IndexedDBContextImpl(CreateAndReturnTempDir(&temp_dir_),
-                                     special_storage_policy_.get(),
-                                     quota_manager_proxy_.get(),
-                                     idb_task_runner_.get())),
-        blob_storage_(ChromeBlobStorageContext::GetFor(&browser_context_)),
-        host_(new IndexedDBDispatcherHost(kFakeProcessId,
-                                          request_context_getter_.get(),
-                                          context_impl_.get(),
-                                          blob_storage_.get())) {
-    quota_manager_->SetQuota(GURL(kOrigin), storage::kStorageTypePersistent,
-                             kTemporaryQuota);
+        special_storage_policy_(
+            base::MakeRefCounted<MockSpecialStoragePolicy>()),
+        quota_manager_(base::MakeRefCounted<MockQuotaManager>(
+            false /*is_incognito*/,
+            browser_context_.GetPath(),
+            BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
+            base::ThreadTaskRunnerHandle::Get().get(),
+            special_storage_policy_)),
+        context_impl_(base::MakeRefCounted<IndexedDBContextImpl>(
+            CreateAndReturnTempDir(&temp_dir_),
+            special_storage_policy_,
+            quota_manager_->proxy())),
+        host_(new IndexedDBDispatcherHost(
+            kFakeProcessId,
+            base::MakeRefCounted<net::TestURLRequestContextGetter>(
+                BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)),
+            context_impl_,
+            ChromeBlobStorageContext::GetFor(&browser_context_))) {
     quota_manager_->SetQuota(GURL(kOrigin), storage::kStorageTypeTemporary,
-                             kPersistantQuota);
+                             kTemporaryQuota);
   }
 
   void TearDown() override {
     host_.reset();
-    // In order for idb_thread_.Stop() to not cause thread/taskrunner checking
-    // errors, the handles must be deref'd before we join threads. This ensures
-    // classes that require destruction on the idb thread can be destructed
-    // correctly before scheduling on the the idb thread task runner turns into
-    // a no-op after thread join.
-    blob_storage_ = nullptr;
     context_impl_ = nullptr;
-    quota_manager_proxy_ = nullptr;
     quota_manager_ = nullptr;
-    special_storage_policy_ = nullptr;
-    request_context_getter_ = nullptr;
-    // This will run the idb task runner until idle, then join the threads.
-    idb_thread_->Stop();
+    RunAllBlockingPoolTasksUntilIdle();
     // File are leaked if this doesn't return true.
     ASSERT_TRUE(temp_dir_.Delete());
   }
 
   void SetUp() override {
-    ASSERT_TRUE(idb_task_runner_);
     FactoryAssociatedRequest request =
         ::mojo::MakeIsolatedRequest(&idb_mojo_factory_);
     host_->AddBinding(std::move(request));
@@ -199,15 +180,9 @@
   TestBrowserContext browser_context_;
 
   base::ScopedTempDir temp_dir_;
-  std::unique_ptr<base::Thread> idb_thread_;
-  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-  scoped_refptr<base::SingleThreadTaskRunner> idb_task_runner_;
-  scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
   scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
   scoped_refptr<MockQuotaManager> quota_manager_;
-  scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
   scoped_refptr<IndexedDBContextImpl> context_impl_;
-  scoped_refptr<ChromeBlobStorageContext> blob_storage_;
   std::unique_ptr<IndexedDBDispatcherHost, BrowserThread::DeleteOnIOThread>
       host_;
   FactoryAssociatedPtr idb_mojo_factory_;
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc
index 374143a..1c87281 100644
--- a/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -14,7 +14,7 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "content/browser/indexed_db/indexed_db_connection.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/indexed_db/indexed_db_data_format_version.h"
@@ -22,6 +22,7 @@
 #include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
 #include "storage/browser/test/mock_quota_manager_proxy.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
@@ -72,14 +73,15 @@
 
 class IndexedDBFactoryTest : public testing::Test {
  public:
+  IndexedDBFactoryTest()
+      : quota_manager_proxy_(
+            base::MakeRefCounted<MockQuotaManagerProxy>(nullptr, nullptr)) {}
+
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    task_runner_ = new base::TestSimpleTaskRunner();
-    quota_manager_proxy_ = new MockQuotaManagerProxy(nullptr, nullptr);
-    context_ = new IndexedDBContextImpl(
+    context_ = base::MakeRefCounted<IndexedDBContextImpl>(
         temp_dir_.GetPath(), nullptr /* special_storage_policy */,
-        quota_manager_proxy_.get(), task_runner_.get());
-    idb_factory_ = new MockIDBFactory(context_.get());
+        quota_manager_proxy_.get());
   }
 
   void TearDown() override {
@@ -87,127 +89,164 @@
   }
 
  protected:
-  IndexedDBFactoryTest() {}
-  MockIDBFactory* factory() const { return idb_factory_.get(); }
-  void clear_factory() { idb_factory_ = nullptr; }
   IndexedDBContextImpl* context() const { return context_.get(); }
 
  private:
-  base::ScopedTempDir temp_dir_;
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  scoped_refptr<IndexedDBContextImpl> context_;
-  scoped_refptr<MockIDBFactory> idb_factory_;
-  scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
   TestBrowserThreadBundle thread_bundle_;
 
+  base::ScopedTempDir temp_dir_;
+  scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
+  scoped_refptr<IndexedDBContextImpl> context_;
+
   DISALLOW_COPY_AND_ASSIGN(IndexedDBFactoryTest);
 };
 
 TEST_F(IndexedDBFactoryTest, BackingStoreLifetime) {
-  const Origin origin1(GURL("http://localhost:81"));
-  const Origin origin2(GURL("http://localhost:82"));
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context) {
+            scoped_refptr<MockIDBFactory> factory =
+                base::MakeRefCounted<MockIDBFactory>(context);
 
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
-  scoped_refptr<IndexedDBBackingStore> disk_store1 =
-      factory()->TestOpenBackingStore(origin1, temp_directory.GetPath());
+            const Origin origin1(GURL("http://localhost:81"));
+            const Origin origin2(GURL("http://localhost:82"));
 
-  scoped_refptr<IndexedDBBackingStore> disk_store2 =
-      factory()->TestOpenBackingStore(origin1, temp_directory.GetPath());
-  EXPECT_EQ(disk_store1.get(), disk_store2.get());
+            scoped_refptr<IndexedDBBackingStore> disk_store1 =
+                factory->TestOpenBackingStore(origin1, context->data_path());
 
-  scoped_refptr<IndexedDBBackingStore> disk_store3 =
-      factory()->TestOpenBackingStore(origin2, temp_directory.GetPath());
+            scoped_refptr<IndexedDBBackingStore> disk_store2 =
+                factory->TestOpenBackingStore(origin1, context->data_path());
+            EXPECT_EQ(disk_store1.get(), disk_store2.get());
 
-  factory()->TestCloseBackingStore(disk_store1.get());
-  factory()->TestCloseBackingStore(disk_store3.get());
+            scoped_refptr<IndexedDBBackingStore> disk_store3 =
+                factory->TestOpenBackingStore(origin2, context->data_path());
 
-  EXPECT_FALSE(disk_store1->HasOneRef());
-  EXPECT_FALSE(disk_store2->HasOneRef());
-  EXPECT_TRUE(disk_store3->HasOneRef());
+            factory->TestCloseBackingStore(disk_store1.get());
+            factory->TestCloseBackingStore(disk_store3.get());
 
-  disk_store2 = nullptr;
-  EXPECT_TRUE(disk_store1->HasOneRef());
+            EXPECT_FALSE(disk_store1->HasOneRef());
+            EXPECT_FALSE(disk_store2->HasOneRef());
+            EXPECT_TRUE(disk_store3->HasOneRef());
+
+            disk_store2 = nullptr;
+            EXPECT_TRUE(disk_store1->HasOneRef());
+          },
+          base::Unretained(context())));
+
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBFactoryTest, BackingStoreLazyClose) {
-  const Origin origin(GURL("http://localhost:81"));
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context) {
 
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
-  scoped_refptr<IndexedDBBackingStore> store =
-      factory()->TestOpenBackingStore(origin, temp_directory.GetPath());
+            scoped_refptr<MockIDBFactory> factory =
+                base::MakeRefCounted<MockIDBFactory>(context);
 
-  // Give up the local refptr so that the factory has the only
-  // outstanding reference.
-  IndexedDBBackingStore* store_ptr = store.get();
-  store = nullptr;
-  EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
-  factory()->TestReleaseBackingStore(store_ptr, false);
-  EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
+            const Origin origin(GURL("http://localhost:81"));
 
-  factory()->TestOpenBackingStore(origin, temp_directory.GetPath());
-  EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
-  factory()->TestReleaseBackingStore(store_ptr, false);
-  EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
+            scoped_refptr<IndexedDBBackingStore> store =
+                factory->TestOpenBackingStore(origin, context->data_path());
 
-  // Take back a ref ptr and ensure that the actual close
-  // stops a running timer.
-  store = store_ptr;
-  factory()->TestCloseBackingStore(store_ptr);
-  EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
+            // Give up the local refptr so that the factory has the only
+            // outstanding reference.
+            IndexedDBBackingStore* store_ptr = store.get();
+            store = nullptr;
+            EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
+            factory->TestReleaseBackingStore(store_ptr, false);
+            EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
+
+            factory->TestOpenBackingStore(origin, context->data_path());
+            EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
+            factory->TestReleaseBackingStore(store_ptr, false);
+            EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
+
+            // Take back a ref ptr and ensure that the actual close
+            // stops a running timer.
+            store = store_ptr;
+            factory->TestCloseBackingStore(store_ptr);
+            EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
+          },
+          base::Unretained(context())));
+
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBFactoryTest, MemoryBackingStoreLifetime) {
-  const Origin origin1(GURL("http://localhost:81"));
-  const Origin origin2(GURL("http://localhost:82"));
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context) {
 
-  scoped_refptr<IndexedDBBackingStore> mem_store1 =
-      factory()->TestOpenBackingStore(origin1, base::FilePath());
+            scoped_refptr<MockIDBFactory> factory =
+                base::MakeRefCounted<MockIDBFactory>(context);
 
-  scoped_refptr<IndexedDBBackingStore> mem_store2 =
-      factory()->TestOpenBackingStore(origin1, base::FilePath());
-  EXPECT_EQ(mem_store1.get(), mem_store2.get());
+            const Origin origin1(GURL("http://localhost:81"));
+            const Origin origin2(GURL("http://localhost:82"));
 
-  scoped_refptr<IndexedDBBackingStore> mem_store3 =
-      factory()->TestOpenBackingStore(origin2, base::FilePath());
+            scoped_refptr<IndexedDBBackingStore> mem_store1 =
+                factory->TestOpenBackingStore(origin1, base::FilePath());
 
-  factory()->TestCloseBackingStore(mem_store1.get());
-  factory()->TestCloseBackingStore(mem_store3.get());
+            scoped_refptr<IndexedDBBackingStore> mem_store2 =
+                factory->TestOpenBackingStore(origin1, base::FilePath());
+            EXPECT_EQ(mem_store1.get(), mem_store2.get());
 
-  EXPECT_FALSE(mem_store1->HasOneRef());
-  EXPECT_FALSE(mem_store2->HasOneRef());
-  EXPECT_FALSE(mem_store3->HasOneRef());
+            scoped_refptr<IndexedDBBackingStore> mem_store3 =
+                factory->TestOpenBackingStore(origin2, base::FilePath());
 
-  clear_factory();
-  EXPECT_FALSE(mem_store1->HasOneRef());  // mem_store1 and 2
-  EXPECT_FALSE(mem_store2->HasOneRef());  // mem_store1 and 2
-  EXPECT_TRUE(mem_store3->HasOneRef());
+            factory->TestCloseBackingStore(mem_store1.get());
+            factory->TestCloseBackingStore(mem_store3.get());
 
-  mem_store2 = nullptr;
-  EXPECT_TRUE(mem_store1->HasOneRef());
+            EXPECT_FALSE(mem_store1->HasOneRef());
+            EXPECT_FALSE(mem_store2->HasOneRef());
+            EXPECT_FALSE(mem_store3->HasOneRef());
+
+            factory = nullptr;
+            EXPECT_FALSE(mem_store1->HasOneRef());  // mem_store1 and 2
+            EXPECT_FALSE(mem_store2->HasOneRef());  // mem_store1 and 2
+            EXPECT_TRUE(mem_store3->HasOneRef());
+
+            mem_store2 = nullptr;
+            EXPECT_TRUE(mem_store1->HasOneRef());
+          },
+          base::Unretained(context())));
+
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBFactoryTest, RejectLongOrigins) {
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
-  const base::FilePath base_path = temp_directory.GetPath();
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context) {
+            base::FilePath temp_dir = context->data_path().DirName();
+            int limit = base::GetMaximumPathComponentLength(temp_dir);
+            EXPECT_GT(limit, 0);
 
-  int limit = base::GetMaximumPathComponentLength(base_path);
-  EXPECT_GT(limit, 0);
+            scoped_refptr<MockIDBFactory> factory =
+                base::MakeRefCounted<MockIDBFactory>(context);
 
-  std::string origin(limit + 1, 'x');
-  Origin too_long_origin(GURL("http://" + origin + ":81/"));
-  scoped_refptr<IndexedDBBackingStore> diskStore1 =
-      factory()->TestOpenBackingStore(too_long_origin, base_path);
-  EXPECT_FALSE(diskStore1.get());
+            std::string origin(limit + 1, 'x');
+            Origin too_long_origin(GURL("http://" + origin + ":81/"));
+            scoped_refptr<IndexedDBBackingStore> diskStore1 =
+                factory->TestOpenBackingStore(too_long_origin,
+                                              context->data_path());
+            EXPECT_FALSE(diskStore1.get());
 
-  Origin ok_origin(GURL("http://someorigin.com:82/"));
-  scoped_refptr<IndexedDBBackingStore> diskStore2 =
-      factory()->TestOpenBackingStore(ok_origin, base_path);
-  EXPECT_TRUE(diskStore2.get());
-  // We need a manual close or Windows can't delete the temp directory.
-  factory()->TestCloseBackingStore(diskStore2.get());
+            Origin ok_origin(GURL("http://someorigin.com:82/"));
+            scoped_refptr<IndexedDBBackingStore> diskStore2 =
+                factory->TestOpenBackingStore(ok_origin, context->data_path());
+            EXPECT_TRUE(diskStore2.get());
+            // We need a manual close or Windows can't delete the temp
+            // directory.
+            factory->TestCloseBackingStore(diskStore2.get());
+          },
+          base::Unretained(context())));
+
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 class DiskFullFactory : public IndexedDBFactoryImpl {
@@ -238,7 +277,7 @@
       : IndexedDBCallbacks(nullptr,
                            url::Origin(),
                            nullptr,
-                           base::ThreadTaskRunnerHandle::Get()),
+                           base::SequencedTaskRunnerHandle::Get()),
         error_called_(false) {}
   void OnError(const IndexedDBDatabaseError& error) override {
     error_called_ = true;
@@ -254,177 +293,232 @@
 };
 
 TEST_F(IndexedDBFactoryTest, QuotaErrorOnDiskFull) {
-  const Origin origin(GURL("http://localhost:81"));
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
-
-  scoped_refptr<DiskFullFactory> factory = new DiskFullFactory(context());
   scoped_refptr<LookingForQuotaErrorMockCallbacks> callbacks =
-      new LookingForQuotaErrorMockCallbacks;
+      base::MakeRefCounted<LookingForQuotaErrorMockCallbacks>();
   scoped_refptr<IndexedDBDatabaseCallbacks> dummy_database_callbacks =
-      new IndexedDBDatabaseCallbacks(nullptr, nullptr);
-  const base::string16 name(ASCIIToUTF16("name"));
-  std::unique_ptr<IndexedDBPendingConnection> connection(
-      base::MakeUnique<IndexedDBPendingConnection>(
-          callbacks, dummy_database_callbacks, 0 /* child_process_id */,
-          2 /* transaction_id */, 1 /* version */));
-  factory->Open(name, std::move(connection), nullptr /* request_context */,
-                origin, temp_directory.GetPath());
-  EXPECT_TRUE(callbacks->error_called());
+      base::MakeRefCounted<IndexedDBDatabaseCallbacks>(nullptr, nullptr);
+
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context,
+             scoped_refptr<LookingForQuotaErrorMockCallbacks> callbacks,
+             scoped_refptr<IndexedDBDatabaseCallbacks>
+                 dummy_database_callbacks) {
+
+            const Origin origin(GURL("http://localhost:81"));
+            scoped_refptr<DiskFullFactory> factory =
+                base::MakeRefCounted<DiskFullFactory>(context);
+            const base::string16 name(ASCIIToUTF16("name"));
+            std::unique_ptr<IndexedDBPendingConnection> connection(
+                base::MakeUnique<IndexedDBPendingConnection>(
+                    callbacks, dummy_database_callbacks,
+                    0 /* child_process_id */, 2 /* transaction_id */,
+                    1 /* version */));
+            factory->Open(name, std::move(connection),
+                          nullptr /* request_context */, origin,
+                          context->data_path());
+            EXPECT_TRUE(callbacks->error_called());
+          },
+          base::Unretained(context()), std::move(callbacks),
+          std::move(dummy_database_callbacks)));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBFactoryTest, BackingStoreReleasedOnForcedClose) {
-  const Origin origin(GURL("http://localhost:81"));
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context,
+             scoped_refptr<MockIndexedDBCallbacks> callbacks,
+             scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks) {
 
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+            scoped_refptr<MockIDBFactory> factory =
+                base::MakeRefCounted<MockIDBFactory>(context);
 
-  scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
-  scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
-      new MockIndexedDBDatabaseCallbacks());
-  const int64_t transaction_id = 1;
-  std::unique_ptr<IndexedDBPendingConnection> connection(
-      base::MakeUnique<IndexedDBPendingConnection>(
-          callbacks, db_callbacks, 0 /* child_process_id */, transaction_id,
-          IndexedDBDatabaseMetadata::DEFAULT_VERSION));
-  factory()->Open(ASCIIToUTF16("db"), std::move(connection),
-                  nullptr /* request_context */, origin,
-                  temp_directory.GetPath());
+            const Origin origin(GURL("http://localhost:81"));
+            const int64_t transaction_id = 1;
+            std::unique_ptr<IndexedDBPendingConnection> connection(
+                base::MakeUnique<IndexedDBPendingConnection>(
+                    callbacks, db_callbacks, 0 /* child_process_id */,
+                    transaction_id,
+                    IndexedDBDatabaseMetadata::DEFAULT_VERSION));
+            factory->Open(ASCIIToUTF16("db"), std::move(connection),
+                          nullptr /* request_context */, origin,
+                          context->data_path());
 
-  EXPECT_TRUE(callbacks->connection());
+            EXPECT_TRUE(callbacks->connection());
 
-  EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
+            EXPECT_TRUE(factory->IsBackingStoreOpen(origin));
+            EXPECT_FALSE(factory->IsBackingStorePendingClose(origin));
 
-  callbacks->connection()->ForceClose();
+            callbacks->connection()->ForceClose();
 
-  EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
+            EXPECT_FALSE(factory->IsBackingStoreOpen(origin));
+            EXPECT_FALSE(factory->IsBackingStorePendingClose(origin));
+          },
+          base::Unretained(context()),
+          base::MakeRefCounted<MockIndexedDBCallbacks>(),
+          base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>()));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBFactoryTest, BackingStoreReleaseDelayedOnClose) {
-  const Origin origin(GURL("http://localhost:81"));
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context,
+             scoped_refptr<MockIndexedDBCallbacks> callbacks,
+             scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks) {
 
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+            scoped_refptr<MockIDBFactory> factory =
+                base::MakeRefCounted<MockIDBFactory>(context);
 
-  scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
-  scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
-      new MockIndexedDBDatabaseCallbacks());
-  const int64_t transaction_id = 1;
-  std::unique_ptr<IndexedDBPendingConnection> connection(
-      base::MakeUnique<IndexedDBPendingConnection>(
-          callbacks, db_callbacks, 0 /* child_process_id */, transaction_id,
-          IndexedDBDatabaseMetadata::DEFAULT_VERSION));
-  factory()->Open(ASCIIToUTF16("db"), std::move(connection),
-                  nullptr /* request_context */, origin,
-                  temp_directory.GetPath());
+            const Origin origin(GURL("http://localhost:81"));
+            const int64_t transaction_id = 1;
+            std::unique_ptr<IndexedDBPendingConnection> connection(
+                base::MakeUnique<IndexedDBPendingConnection>(
+                    callbacks, db_callbacks, 0 /* child_process_id */,
+                    transaction_id,
+                    IndexedDBDatabaseMetadata::DEFAULT_VERSION));
+            factory->Open(ASCIIToUTF16("db"), std::move(connection),
+                          nullptr /* request_context */, origin,
+                          context->data_path());
 
-  EXPECT_TRUE(callbacks->connection());
-  IndexedDBBackingStore* store =
-      callbacks->connection()->database()->backing_store();
-  EXPECT_FALSE(store->HasOneRef());  // Factory and database.
+            EXPECT_TRUE(callbacks->connection());
+            IndexedDBBackingStore* store =
+                callbacks->connection()->database()->backing_store();
+            EXPECT_FALSE(store->HasOneRef());  // Factory and database.
 
-  EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
-  callbacks->connection()->Close();
-  EXPECT_TRUE(store->HasOneRef());  // Factory.
-  EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
-  EXPECT_TRUE(store->close_timer()->IsRunning());
+            EXPECT_TRUE(factory->IsBackingStoreOpen(origin));
+            callbacks->connection()->Close();
+            EXPECT_TRUE(store->HasOneRef());  // Factory.
+            EXPECT_TRUE(factory->IsBackingStoreOpen(origin));
+            EXPECT_TRUE(factory->IsBackingStorePendingClose(origin));
+            EXPECT_TRUE(store->close_timer()->IsRunning());
 
-  // Take a ref so it won't be destroyed out from under the test.
-  scoped_refptr<IndexedDBBackingStore> store_ref = store;
-  // Now simulate shutdown, which should stop the timer.
-  factory()->ContextDestroyed();
-  EXPECT_TRUE(store->HasOneRef());  // Local.
-  EXPECT_FALSE(store->close_timer()->IsRunning());
-  EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
+            // Take a ref so it won't be destroyed out from under the test.
+            scoped_refptr<IndexedDBBackingStore> store_ref = store;
+            // Now simulate shutdown, which should stop the timer.
+            factory->ContextDestroyed();
+            EXPECT_TRUE(store->HasOneRef());  // Local.
+            EXPECT_FALSE(store->close_timer()->IsRunning());
+            EXPECT_FALSE(factory->IsBackingStoreOpen(origin));
+            EXPECT_FALSE(factory->IsBackingStorePendingClose(origin));
+          },
+          base::Unretained(context()),
+          base::MakeRefCounted<MockIndexedDBCallbacks>(),
+          base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>()));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBFactoryTest, DeleteDatabaseClosesBackingStore) {
-  const Origin origin(GURL("http://localhost:81"));
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context,
+             scoped_refptr<MockIndexedDBCallbacks> callbacks) {
 
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+            scoped_refptr<MockIDBFactory> factory =
+                base::MakeRefCounted<MockIDBFactory>(context);
 
-  EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
+            const Origin origin(GURL("http://localhost:81"));
+            EXPECT_FALSE(factory->IsBackingStoreOpen(origin));
 
-  const bool expect_connection = false;
-  scoped_refptr<MockIndexedDBCallbacks> callbacks(
-      new MockIndexedDBCallbacks(expect_connection));
-  factory()->DeleteDatabase(ASCIIToUTF16("db"), nullptr /* request_context */,
-                            callbacks, origin, temp_directory.GetPath(),
-                            false /* force_close */);
+            factory->DeleteDatabase(
+                ASCIIToUTF16("db"), nullptr /* request_context */, callbacks,
+                origin, context->data_path(), false /* force_close */);
 
-  EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
+            EXPECT_TRUE(factory->IsBackingStoreOpen(origin));
+            EXPECT_TRUE(factory->IsBackingStorePendingClose(origin));
 
-  // Now simulate shutdown, which should stop the timer.
-  factory()->ContextDestroyed();
+            // Now simulate shutdown, which should stop the timer.
+            factory->ContextDestroyed();
 
-  EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
+            EXPECT_FALSE(factory->IsBackingStoreOpen(origin));
+            EXPECT_FALSE(factory->IsBackingStorePendingClose(origin));
+
+          },
+          base::Unretained(context()),
+          base::MakeRefCounted<MockIndexedDBCallbacks>(
+              false /*expect_connection*/)));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBFactoryTest, GetDatabaseNamesClosesBackingStore) {
-  const Origin origin(GURL("http://localhost:81"));
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context,
+             scoped_refptr<MockIndexedDBCallbacks> callbacks) {
+            scoped_refptr<MockIDBFactory> factory =
+                base::MakeRefCounted<MockIDBFactory>(context);
 
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+            const Origin origin(GURL("http://localhost:81"));
+            EXPECT_FALSE(factory->IsBackingStoreOpen(origin));
 
-  EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
+            factory->GetDatabaseNames(callbacks, origin, context->data_path(),
+                                      nullptr /* request_context */);
 
-  const bool expect_connection = false;
-  scoped_refptr<MockIndexedDBCallbacks> callbacks(
-      new MockIndexedDBCallbacks(expect_connection));
-  factory()->GetDatabaseNames(callbacks, origin, temp_directory.GetPath(),
-                              nullptr /* request_context */);
+            EXPECT_TRUE(factory->IsBackingStoreOpen(origin));
+            EXPECT_TRUE(factory->IsBackingStorePendingClose(origin));
 
-  EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
+            // Now simulate shutdown, which should stop the timer.
+            factory->ContextDestroyed();
 
-  // Now simulate shutdown, which should stop the timer.
-  factory()->ContextDestroyed();
+            EXPECT_FALSE(factory->IsBackingStoreOpen(origin));
+            EXPECT_FALSE(factory->IsBackingStorePendingClose(origin));
 
-  EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
+          },
+          base::Unretained(context()),
+          base::MakeRefCounted<MockIndexedDBCallbacks>(
+              false /*expect_connection*/)));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBFactoryTest, ForceCloseReleasesBackingStore) {
-  const Origin origin(GURL("http://localhost:81"));
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context,
+             scoped_refptr<MockIndexedDBCallbacks> callbacks,
+             scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks) {
+            scoped_refptr<MockIDBFactory> factory =
+                base::MakeRefCounted<MockIDBFactory>(context);
 
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+            const Origin origin(GURL("http://localhost:81"));
+            const int64_t transaction_id = 1;
+            std::unique_ptr<IndexedDBPendingConnection> connection(
+                base::MakeUnique<IndexedDBPendingConnection>(
+                    callbacks, db_callbacks, 0 /* child_process_id */,
+                    transaction_id,
+                    IndexedDBDatabaseMetadata::DEFAULT_VERSION));
+            factory->Open(ASCIIToUTF16("db"), std::move(connection),
+                          nullptr /* request_context */, origin,
+                          context->data_path());
 
-  scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
-  scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
-      new MockIndexedDBDatabaseCallbacks());
-  const int64_t transaction_id = 1;
-  std::unique_ptr<IndexedDBPendingConnection> connection(
-      base::MakeUnique<IndexedDBPendingConnection>(
-          callbacks, db_callbacks, 0 /* child_process_id */, transaction_id,
-          IndexedDBDatabaseMetadata::DEFAULT_VERSION));
-  factory()->Open(ASCIIToUTF16("db"), std::move(connection),
-                  nullptr /* request_context */, origin,
-                  temp_directory.GetPath());
+            EXPECT_TRUE(callbacks->connection());
+            EXPECT_TRUE(factory->IsBackingStoreOpen(origin));
+            EXPECT_FALSE(factory->IsBackingStorePendingClose(origin));
 
-  EXPECT_TRUE(callbacks->connection());
-  EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
+            callbacks->connection()->Close();
 
-  callbacks->connection()->Close();
+            EXPECT_TRUE(factory->IsBackingStoreOpen(origin));
+            EXPECT_TRUE(factory->IsBackingStorePendingClose(origin));
 
-  EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
+            factory->ForceClose(origin);
 
-  factory()->ForceClose(origin);
+            EXPECT_FALSE(factory->IsBackingStoreOpen(origin));
+            EXPECT_FALSE(factory->IsBackingStorePendingClose(origin));
 
-  EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
-  EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
+            // Ensure it is safe if the store is not open.
+            factory->ForceClose(origin);
 
-  // Ensure it is safe if the store is not open.
-  factory()->ForceClose(origin);
+          },
+          base::Unretained(context()),
+          base::MakeRefCounted<MockIndexedDBCallbacks>(),
+          base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>()));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 class UpgradeNeededCallbacks : public MockIndexedDBCallbacks {
@@ -469,56 +563,93 @@
 
 TEST_F(IndexedDBFactoryTest, DatabaseFailedOpen) {
   const Origin origin(GURL("http://localhost:81"));
-
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
-
   const base::string16 db_name(ASCIIToUTF16("db"));
-  const int64_t db_version = 2;
   const int64_t transaction_id = 1;
-  scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks(
-      new MockIndexedDBDatabaseCallbacks());
 
-  // Open at version 2, then close.
-  {
-    scoped_refptr<UpgradeNeededCallbacks> callbacks(
-        new UpgradeNeededCallbacks());
-    std::unique_ptr<IndexedDBPendingConnection> connection(
-        base::MakeUnique<IndexedDBPendingConnection>(
-            callbacks, db_callbacks, 0 /* child_process_id */, transaction_id,
-            db_version));
-    factory()->Open(db_name, std::move(connection),
-                    nullptr /* request_context */, origin,
-                    temp_directory.GetPath());
-    EXPECT_TRUE(factory()->IsDatabaseOpen(origin, db_name));
+  // These objects are retained across posted tasks, so despite being used
+  // exclusively on the IDB sequence.
 
-    // Pump the message loop so the upgrade transaction can run.
-    base::RunLoop().RunUntilIdle();
-    EXPECT_TRUE(callbacks->connection());
-    callbacks->connection()->database()->Commit(
-        callbacks->connection()->GetTransaction(transaction_id));
+  // Created and used on IDB sequence.
+  scoped_refptr<MockIDBFactory> factory;
+  // Created on IO thread, used on IDB sequence.
+  scoped_refptr<UpgradeNeededCallbacks> upgrade_callbacks =
+      base::MakeRefCounted<UpgradeNeededCallbacks>();
 
-    callbacks->connection()->Close();
-    EXPECT_FALSE(factory()->IsDatabaseOpen(origin, db_name));
-  }
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context,
+             scoped_refptr<MockIDBFactory>* factory,
+             scoped_refptr<UpgradeNeededCallbacks>* upgrade_callbacks,
+             scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks,
+             const base::string16& db_name, int64_t transaction_id,
+             const Origin& origin) {
 
-  // Open at version < 2, which will fail; ensure factory doesn't retain
-  // the database object.
-  {
-    scoped_refptr<ErrorCallbacks> callbacks(new ErrorCallbacks());
-    std::unique_ptr<IndexedDBPendingConnection> connection(
-        base::MakeUnique<IndexedDBPendingConnection>(
-            callbacks, db_callbacks, 0 /* child_process_id */, transaction_id,
-            db_version - 1));
-    factory()->Open(db_name, std::move(connection),
-                    nullptr /* request_context */, origin,
-                    temp_directory.GetPath());
-    EXPECT_TRUE(callbacks->saw_error());
-    EXPECT_FALSE(factory()->IsDatabaseOpen(origin, db_name));
-  }
+            *factory = base::MakeRefCounted<MockIDBFactory>(context);
 
-  // Terminate all pending-close timers.
-  factory()->ForceClose(origin);
+            // Open at version 2.
+            const int64_t db_version = 2;
+            (*factory)->Open(
+                db_name,
+                base::MakeUnique<IndexedDBPendingConnection>(
+                    *upgrade_callbacks, db_callbacks, 0 /* child_process_id */,
+                    transaction_id, db_version),
+                nullptr /* request_context */, origin, context->data_path());
+
+            EXPECT_TRUE((*factory)->IsDatabaseOpen(origin, db_name));
+          },
+          base::Unretained(context()), base::Unretained(&factory),
+          base::Unretained(&upgrade_callbacks),
+          base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>(), db_name,
+          transaction_id, origin));
+
+  // Pump the message loop so the upgrade transaction can run.
+  RunAllBlockingPoolTasksUntilIdle();
+
+  context()->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* context,
+             scoped_refptr<MockIDBFactory> factory,
+             scoped_refptr<UpgradeNeededCallbacks> upgrade_callbacks,
+             scoped_refptr<ErrorCallbacks> failed_open_callbacks,
+             scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks,
+             const base::string16& db_name, int64_t transaction_id,
+             const Origin& origin) {
+            // Close the connection.
+            {
+              EXPECT_TRUE(upgrade_callbacks->connection());
+              upgrade_callbacks->connection()->database()->Commit(
+                  upgrade_callbacks->connection()->GetTransaction(
+                      transaction_id));
+              upgrade_callbacks->connection()->Close();
+              EXPECT_FALSE(factory->IsDatabaseOpen(origin, db_name));
+            }
+
+            // Open at version < 2, which will fail; ensure factory doesn't
+            // retain the database object.
+            {
+              const int64_t db_version = 1;
+              std::unique_ptr<IndexedDBPendingConnection> connection(
+                  base::MakeUnique<IndexedDBPendingConnection>(
+                      failed_open_callbacks, db_callbacks,
+                      0 /* child_process_id */, transaction_id, db_version));
+              factory->Open(db_name, std::move(connection),
+                            nullptr /* request_context */, origin,
+                            context->data_path());
+              EXPECT_TRUE(failed_open_callbacks->saw_error());
+              EXPECT_FALSE(factory->IsDatabaseOpen(origin, db_name));
+            }
+
+            // Terminate all pending-close timers.
+            factory->ForceClose(origin);
+          },
+          base::Unretained(context()), std::move(factory),
+          std::move(upgrade_callbacks), base::MakeRefCounted<ErrorCallbacks>(),
+          base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>(), db_name,
+          transaction_id, origin));
+
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 namespace {
@@ -552,22 +683,58 @@
                          const IndexedDBDataFormatVersion& version) {
     base::AutoReset<IndexedDBDataFormatVersion> override_version(
         &IndexedDBDataFormatVersion::GetMutableCurrentForTesting(), version);
-    auto db_callbacks = base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>();
-    auto callbacks = base::MakeRefCounted<DataLossCallbacks>();
+
+    // These objects are retained across posted tasks, so despite being used
+    // exclusively on the IDB sequence.
+
+    // Created and used on IDB sequence.
+    scoped_refptr<MockIDBFactory> factory;
+    // Created on IO thread, used on IDB sequence.
+    scoped_refptr<DataLossCallbacks> callbacks =
+        base::MakeRefCounted<DataLossCallbacks>();
+
     const int64_t transaction_id = 1;
-    factory()->Open(ASCIIToUTF16("test_db"),
-                    base::MakeUnique<IndexedDBPendingConnection>(
-                        callbacks, db_callbacks, 0 /* child_process_id */,
-                        transaction_id, 1 /* version */),
-                    nullptr /* request_context */, origin,
-                    context()->data_path());
-    base::RunLoop().RunUntilIdle();
-    auto* connection = callbacks->connection();
-    EXPECT_TRUE(connection);
-    connection->database()->Commit(connection->GetTransaction(transaction_id));
-    connection->Close();
-    factory()->ForceClose(origin);
-    return callbacks->data_loss();
+    blink::WebIDBDataLoss result;
+
+    context()->TaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](IndexedDBContextImpl* context,
+               scoped_refptr<MockIDBFactory>* factory,
+               scoped_refptr<DataLossCallbacks>* callbacks,
+               scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks,
+               const Origin& origin, int64_t transaction_id) {
+              *factory = base::MakeRefCounted<MockIDBFactory>(context);
+              (*factory)->Open(
+                  ASCIIToUTF16("test_db"),
+                  base::MakeUnique<IndexedDBPendingConnection>(
+                      *callbacks, db_callbacks, 0 /* child_process_id */,
+                      transaction_id, 1 /* version */),
+                  nullptr /* request_context */, origin, context->data_path());
+            },
+            base::Unretained(context()), base::Unretained(&factory),
+            base::Unretained(&callbacks),
+            base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>(), origin,
+            transaction_id));
+    RunAllBlockingPoolTasksUntilIdle();
+    context()->TaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](scoped_refptr<MockIDBFactory> factory,
+               scoped_refptr<DataLossCallbacks> callbacks, const Origin& origin,
+               int64_t transaction_id, blink::WebIDBDataLoss* result) {
+              auto* connection = callbacks->connection();
+              EXPECT_TRUE(connection);
+              connection->database()->Commit(
+                  connection->GetTransaction(transaction_id));
+              connection->Close();
+              factory->ForceClose(origin);
+              *result = callbacks->data_loss();
+            },
+            std::move(factory), std::move(callbacks), origin, transaction_id,
+            base::Unretained(&result)));
+    RunAllBlockingPoolTasksUntilIdle();
+    return result;
   };
 
   using blink::kWebIDBDataLossNone;
diff --git a/content/browser/indexed_db/indexed_db_quota_client.cc b/content/browser/indexed_db/indexed_db_quota_client.cc
index c43d672..3d50c3a 100644
--- a/content/browser/indexed_db/indexed_db_quota_client.cc
+++ b/content/browser/indexed_db/indexed_db_quota_client.cc
@@ -84,12 +84,6 @@
     return;
   }
 
-  // No task runner means unit test; no cleanup necessary.
-  if (!indexed_db_context_->TaskRunner()) {
-    callback.Run(0);
-    return;
-  }
-
   base::PostTaskAndReplyWithResult(
       indexed_db_context_->TaskRunner(), FROM_HERE,
       base::Bind(&GetOriginUsageOnIndexedDBThread,
@@ -109,12 +103,6 @@
     return;
   }
 
-  // No task runner means unit test; no cleanup necessary.
-  if (!indexed_db_context_->TaskRunner()) {
-    callback.Run(std::set<GURL>());
-    return;
-  }
-
   std::set<GURL>* origins_to_return = new std::set<GURL>();
   indexed_db_context_->TaskRunner()->PostTaskAndReply(
       FROM_HERE,
@@ -137,12 +125,6 @@
     return;
   }
 
-  // No task runner means unit test; no cleanup necessary.
-  if (!indexed_db_context_->TaskRunner()) {
-    callback.Run(std::set<GURL>());
-    return;
-  }
-
   std::set<GURL>* origins_to_return = new std::set<GURL>();
   indexed_db_context_->TaskRunner()->PostTaskAndReply(
       FROM_HERE,
@@ -160,12 +142,6 @@
     return;
   }
 
-  // No task runner means unit test; no cleanup necessary.
-  if (!indexed_db_context_->TaskRunner()) {
-    callback.Run(storage::kQuotaStatusOk);
-    return;
-  }
-
   base::PostTaskAndReplyWithResult(
       indexed_db_context_->TaskRunner(), FROM_HERE,
       base::Bind(&DeleteOriginDataOnIndexedDBThread,
diff --git a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
index a5a11ce..8474e39 100644
--- a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "base/test/test_simple_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/browser_thread_impl.h"
@@ -21,6 +21,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
 #include "storage/browser/test/mock_quota_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -42,27 +43,22 @@
         kOriginB("http://host:8000"),
         kOriginOther("http://other"),
         usage_(0),
-        task_runner_(new base::TestSimpleTaskRunner),
         weak_factory_(this) {
     browser_context_.reset(new TestBrowserContext());
 
     scoped_refptr<storage::QuotaManager> quota_manager =
         new MockQuotaManager(false /*in_memory*/, browser_context_->GetPath(),
                              base::ThreadTaskRunnerHandle::Get(),
-                             base::ThreadTaskRunnerHandle::Get(),
+                             base::SequencedTaskRunnerHandle::Get(),
                              browser_context_->GetSpecialStoragePolicy());
 
-    idb_context_ =
-        new IndexedDBContextImpl(browser_context_->GetPath(),
-                                 browser_context_->GetSpecialStoragePolicy(),
-                                 quota_manager->proxy(),
-                                 task_runner_.get());
+    idb_context_ = new IndexedDBContextImpl(
+        browser_context_->GetPath(),
+        browser_context_->GetSpecialStoragePolicy(), quota_manager->proxy());
     base::RunLoop().RunUntilIdle();
     setup_temp_dir();
   }
 
-  void FlushIndexedDBTaskRunner() { task_runner_->RunUntilIdle(); }
-
   void setup_temp_dir() {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     base::FilePath indexeddb_dir =
@@ -72,7 +68,7 @@
   }
 
   ~IndexedDBQuotaClientTest() override {
-    FlushIndexedDBTaskRunner();
+    RunAllBlockingPoolTasksUntilIdle();
     idb_context_ = NULL;
     browser_context_.reset();
     base::RunLoop().RunUntilIdle();
@@ -87,8 +83,7 @@
         type,
         base::Bind(&IndexedDBQuotaClientTest::OnGetOriginUsageComplete,
                    weak_factory_.GetWeakPtr()));
-    FlushIndexedDBTaskRunner();
-    base::RunLoop().RunUntilIdle();
+    RunAllBlockingPoolTasksUntilIdle();
     EXPECT_GT(usage_, -1);
     return usage_;
   }
@@ -100,8 +95,7 @@
         type,
         base::Bind(&IndexedDBQuotaClientTest::OnGetOriginsComplete,
                    weak_factory_.GetWeakPtr()));
-    FlushIndexedDBTaskRunner();
-    base::RunLoop().RunUntilIdle();
+    RunAllBlockingPoolTasksUntilIdle();
     return origins_;
   }
 
@@ -114,8 +108,7 @@
         host,
         base::Bind(&IndexedDBQuotaClientTest::OnGetOriginsComplete,
                    weak_factory_.GetWeakPtr()));
-    FlushIndexedDBTaskRunner();
-    base::RunLoop().RunUntilIdle();
+    RunAllBlockingPoolTasksUntilIdle();
     return origins_;
   }
 
@@ -127,8 +120,7 @@
         kTemp,
         base::Bind(&IndexedDBQuotaClientTest::OnDeleteOriginComplete,
                    weak_factory_.GetWeakPtr()));
-    FlushIndexedDBTaskRunner();
-    base::RunLoop().RunUntilIdle();
+    RunAllBlockingPoolTasksUntilIdle();
     return delete_status_;
   }
 
@@ -148,7 +140,7 @@
     }
     file_path_origin = file_path_origin.Append(FILE_PATH_LITERAL("fake_file"));
     SetFileSizeTo(file_path_origin, size);
-    idb_context()->ResetCaches();
+    idb_context()->ResetCachesForTesting();
   }
 
  private:
@@ -162,12 +154,11 @@
     delete_status_ = code;
   }
 
+  content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
   int64_t usage_;
   std::set<GURL> origins_;
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   scoped_refptr<IndexedDBContextImpl> idb_context_;
-  content::TestBrowserThreadBundle thread_bundle_;
   std::unique_ptr<TestBrowserContext> browser_context_;
   storage::QuotaStatusCode delete_status_;
   base::WeakPtrFactory<IndexedDBQuotaClientTest> weak_factory_;
diff --git a/content/browser/indexed_db/indexed_db_unittest.cc b/content/browser/indexed_db/indexed_db_unittest.cc
index 21a1aa5..ceece31fcc 100644
--- a/content/browser/indexed_db/indexed_db_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_unittest.cc
@@ -10,9 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "content/browser/indexed_db/indexed_db_connection.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/indexed_db/indexed_db_factory_impl.h"
@@ -20,8 +18,8 @@
 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/url_constants.h"
-#include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
 #include "storage/browser/quota/quota_manager.h"
 #include "storage/browser/quota/special_storage_policy.h"
 #include "storage/browser/test/mock_quota_manager_proxy.h"
@@ -41,9 +39,10 @@
   IndexedDBTest()
       : kNormalOrigin(GURL("http://normal/")),
         kSessionOnlyOrigin(GURL("http://session-only/")),
-        task_runner_(new base::TestSimpleTaskRunner),
-        special_storage_policy_(new MockSpecialStoragePolicy),
-        quota_manager_proxy_(new MockQuotaManagerProxy(nullptr, nullptr)) {
+        special_storage_policy_(
+            base::MakeRefCounted<MockSpecialStoragePolicy>()),
+        quota_manager_proxy_(
+            base::MakeRefCounted<MockQuotaManagerProxy>(nullptr, nullptr)) {
     special_storage_policy_->AddSessionOnly(kSessionOnlyOrigin.GetURL());
   }
   ~IndexedDBTest() override {
@@ -51,9 +50,6 @@
   }
 
  protected:
-  void FlushIndexedDBTaskRunner() { task_runner_->RunUntilIdle(); }
-
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
   scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
 
@@ -73,21 +69,20 @@
   // Create the scope which will ensure we run the destructor of the context
   // which should trigger the clean up.
   {
-    scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
-        temp_dir.GetPath(), special_storage_policy_.get(),
-        quota_manager_proxy_.get(), task_runner_.get());
+    scoped_refptr<IndexedDBContextImpl> idb_context =
+        base::MakeRefCounted<IndexedDBContextImpl>(
+            temp_dir.GetPath(), special_storage_policy_.get(),
+            quota_manager_proxy_.get());
 
     normal_path = idb_context->GetFilePathForTesting(kNormalOrigin);
     session_only_path = idb_context->GetFilePathForTesting(kSessionOnlyOrigin);
     ASSERT_TRUE(base::CreateDirectory(normal_path));
     ASSERT_TRUE(base::CreateDirectory(session_only_path));
-    FlushIndexedDBTaskRunner();
-    base::RunLoop().RunUntilIdle();
+    RunAllBlockingPoolTasksUntilIdle();
     quota_manager_proxy_->SimulateQuotaManagerDestroyed();
   }
 
-  FlushIndexedDBTaskRunner();
-  base::RunLoop().RunUntilIdle();
+  RunAllBlockingPoolTasksUntilIdle();
 
   EXPECT_TRUE(base::DirectoryExists(normal_path));
   EXPECT_FALSE(base::DirectoryExists(session_only_path));
@@ -104,9 +99,10 @@
   {
     // Create some indexedDB paths.
     // With the levelDB backend, these are directories.
-    scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
-        temp_dir.GetPath(), special_storage_policy_.get(),
-        quota_manager_proxy_.get(), task_runner_.get());
+    scoped_refptr<IndexedDBContextImpl> idb_context =
+        base::MakeRefCounted<IndexedDBContextImpl>(
+            temp_dir.GetPath(), special_storage_policy_.get(),
+            quota_manager_proxy_.get());
 
     // Save session state. This should bypass the destruction-time deletion.
     idb_context->SetForceKeepSessionState();
@@ -130,10 +126,7 @@
  public:
   ForceCloseDBCallbacks(scoped_refptr<IndexedDBContextImpl> idb_context,
                         const Origin& origin)
-      : IndexedDBCallbacks(nullptr,
-                           origin,
-                           nullptr,
-                           base::ThreadTaskRunnerHandle::Get()),
+      : IndexedDBCallbacks(nullptr, origin, nullptr, idb_context->TaskRunner()),
         idb_context_(idb_context),
         origin_(origin) {}
 
@@ -161,67 +154,60 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  scoped_refptr<MockIndexedDBDatabaseCallbacks> open_db_callbacks(
-      new MockIndexedDBDatabaseCallbacks());
-  scoped_refptr<MockIndexedDBDatabaseCallbacks> closed_db_callbacks(
-      new MockIndexedDBDatabaseCallbacks());
+  scoped_refptr<IndexedDBContextImpl> idb_context =
+      base::MakeRefCounted<IndexedDBContextImpl>(temp_dir.GetPath(),
+                                                 special_storage_policy_.get(),
+                                                 quota_manager_proxy_.get());
 
-  base::FilePath test_path;
+  const Origin kTestOrigin(GURL("http://test/"));
+  idb_context->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* idb_context,
+             scoped_refptr<MockIndexedDBDatabaseCallbacks> open_db_callbacks,
+             scoped_refptr<MockIndexedDBDatabaseCallbacks> closed_db_callbacks,
+             scoped_refptr<ForceCloseDBCallbacks> open_callbacks,
+             scoped_refptr<ForceCloseDBCallbacks> closed_callbacks,
+             const Origin& origin) {
 
-  // Create the scope which will ensure we run the destructor of the context.
-  {
-    TestBrowserContext browser_context;
+            const int child_process_id = 0;
+            const int64_t host_transaction_id = 0;
+            const int64_t version = 0;
+            const scoped_refptr<net::URLRequestContextGetter> request_context;
 
-    const Origin kTestOrigin(GURL("http://test/"));
+            IndexedDBFactory* factory = idb_context->GetIDBFactory();
 
-    scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
-        temp_dir.GetPath(), special_storage_policy_.get(),
-        quota_manager_proxy_.get(), task_runner_.get());
+            base::FilePath test_path =
+                idb_context->GetFilePathForTesting(origin);
 
-    scoped_refptr<ForceCloseDBCallbacks> open_callbacks =
-        new ForceCloseDBCallbacks(idb_context, kTestOrigin);
+            factory->Open(base::ASCIIToUTF16("opendb"),
+                          base::MakeUnique<IndexedDBPendingConnection>(
+                              open_callbacks, open_db_callbacks,
+                              child_process_id, host_transaction_id, version),
+                          request_context, origin, idb_context->data_path());
+            EXPECT_TRUE(base::DirectoryExists(test_path));
 
-    scoped_refptr<ForceCloseDBCallbacks> closed_callbacks =
-        new ForceCloseDBCallbacks(idb_context, kTestOrigin);
+            factory->Open(base::ASCIIToUTF16("closeddb"),
+                          base::MakeUnique<IndexedDBPendingConnection>(
+                              closed_callbacks, closed_db_callbacks,
+                              child_process_id, host_transaction_id, version),
+                          request_context, origin, idb_context->data_path());
 
-    IndexedDBFactory* factory = idb_context->GetIDBFactory();
+            closed_callbacks->connection()->Close();
 
-    test_path = idb_context->GetFilePathForTesting(kTestOrigin);
+            idb_context->DeleteForOrigin(origin);
 
-    std::unique_ptr<IndexedDBPendingConnection> open_connection(
-        base::MakeUnique<IndexedDBPendingConnection>(
-            open_callbacks, open_db_callbacks, 0 /* child_process_id */,
-            0 /* host_transaction_id */, 0 /* version */));
-    factory->Open(base::ASCIIToUTF16("opendb"), std::move(open_connection),
-                  nullptr /* request_context */, Origin(kTestOrigin),
-                  idb_context->data_path());
-    std::unique_ptr<IndexedDBPendingConnection> closed_connection(
-        base::MakeUnique<IndexedDBPendingConnection>(
-            closed_callbacks, closed_db_callbacks, 0 /* child_process_id */,
-            0 /* host_transaction_id */, 0 /* version */));
-    factory->Open(base::ASCIIToUTF16("closeddb"), std::move(closed_connection),
-                  nullptr /* request_context */, Origin(kTestOrigin),
-                  idb_context->data_path());
-
-    closed_callbacks->connection()->Close();
-
-    // TODO(jsbell): Remove static_cast<> when overloads are eliminated.
-    idb_context->TaskRunner()->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            static_cast<void (IndexedDBContextImpl::*)(const Origin&)>(
-                &IndexedDBContextImpl::DeleteForOrigin),
-            idb_context, kTestOrigin));
-    FlushIndexedDBTaskRunner();
-    base::RunLoop().RunUntilIdle();
-  }
-
-  // Make sure we wait until the destructor has run.
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(open_db_callbacks->forced_close_called());
-  EXPECT_FALSE(closed_db_callbacks->forced_close_called());
-  EXPECT_FALSE(base::DirectoryExists(test_path));
+            EXPECT_TRUE(open_db_callbacks->forced_close_called());
+            EXPECT_FALSE(closed_db_callbacks->forced_close_called());
+            EXPECT_FALSE(base::DirectoryExists(test_path));
+          },
+          base::Unretained(idb_context.get()),
+          base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>(),
+          base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>(),
+          base::MakeRefCounted<ForceCloseDBCallbacks>(idb_context, kTestOrigin),
+          base::MakeRefCounted<ForceCloseDBCallbacks>(idb_context, kTestOrigin),
+          kTestOrigin));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(IndexedDBTest, DeleteFailsIfDirectoryLocked) {
@@ -229,9 +215,10 @@
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   const Origin kTestOrigin(GURL("http://test/"));
 
-  scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
-      temp_dir.GetPath(), special_storage_policy_.get(),
-      quota_manager_proxy_.get(), task_runner_.get());
+  scoped_refptr<IndexedDBContextImpl> idb_context =
+      base::MakeRefCounted<IndexedDBContextImpl>(temp_dir.GetPath(),
+                                                 special_storage_policy_.get(),
+                                                 quota_manager_proxy_.get());
 
   base::FilePath test_path = idb_context->GetFilePathForTesting(kTestOrigin);
   ASSERT_TRUE(base::CreateDirectory(test_path));
@@ -245,49 +232,64 @@
       &IndexedDBContextImpl::DeleteForOrigin;
   idb_context->TaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(delete_for_origin, idb_context, kTestOrigin));
-  FlushIndexedDBTaskRunner();
+  RunAllBlockingPoolTasksUntilIdle();
 
   EXPECT_TRUE(base::DirectoryExists(test_path));
 }
 
 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
-  const Origin kTestOrigin(GURL("http://test/"));
-
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  scoped_refptr<IndexedDBContextImpl> context = new IndexedDBContextImpl(
-      temp_dir.GetPath(), special_storage_policy_.get(),
-      quota_manager_proxy_.get(), task_runner_.get());
+  scoped_refptr<IndexedDBContextImpl> idb_context =
+      base::MakeRefCounted<IndexedDBContextImpl>(temp_dir.GetPath(),
+                                                 special_storage_policy_.get(),
+                                                 quota_manager_proxy_.get());
 
-  scoped_refptr<IndexedDBFactoryImpl> factory =
-      static_cast<IndexedDBFactoryImpl*>(context->GetIDBFactory());
+  idb_context->TaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](IndexedDBContextImpl* idb_context, const base::FilePath temp_path,
+             scoped_refptr<MockIndexedDBCallbacks> callbacks,
+             scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks) {
+            const Origin kTestOrigin(GURL("http://test/"));
 
-  scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
-  scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
-      new MockIndexedDBDatabaseCallbacks());
-  const int64_t transaction_id = 1;
-  std::unique_ptr<IndexedDBPendingConnection> connection(
-      base::MakeUnique<IndexedDBPendingConnection>(
-          callbacks, db_callbacks, 0 /* child_process_id */, transaction_id,
-          IndexedDBDatabaseMetadata::DEFAULT_VERSION));
-  factory->Open(base::ASCIIToUTF16("db"), std::move(connection),
-                nullptr /* request_context */, Origin(kTestOrigin),
-                temp_dir.GetPath());
+            scoped_refptr<IndexedDBFactoryImpl> factory =
+                static_cast<IndexedDBFactoryImpl*>(
+                    idb_context->GetIDBFactory());
 
-  EXPECT_TRUE(callbacks->connection());
+            const int child_process_id = 0;
+            const int64_t transaction_id = 1;
+            const scoped_refptr<net::URLRequestContextGetter> request_context;
 
-  // ConnectionOpened() is usually called by the dispatcher.
-  context->ConnectionOpened(kTestOrigin, callbacks->connection());
+            std::unique_ptr<IndexedDBPendingConnection> connection(
+                base::MakeUnique<IndexedDBPendingConnection>(
+                    callbacks, db_callbacks, child_process_id, transaction_id,
+                    IndexedDBDatabaseMetadata::DEFAULT_VERSION));
+            factory->Open(base::ASCIIToUTF16("db"), std::move(connection),
+                          request_context, Origin(kTestOrigin), temp_path);
 
-  EXPECT_TRUE(factory->IsBackingStoreOpen(kTestOrigin));
+            EXPECT_TRUE(callbacks->connection());
 
-  // Simulate the write failure.
-  leveldb::Status status = leveldb::Status::IOError("Simulated failure");
-  context->GetIDBFactory()->HandleBackingStoreFailure(kTestOrigin);
+            // ConnectionOpened() is usually called by the dispatcher.
+            idb_context->ConnectionOpened(kTestOrigin, callbacks->connection());
 
-  EXPECT_TRUE(db_callbacks->forced_close_called());
-  EXPECT_FALSE(factory->IsBackingStoreOpen(kTestOrigin));
+            EXPECT_TRUE(factory->IsBackingStoreOpen(kTestOrigin));
+
+            // Simulate the write failure.
+            leveldb::Status status =
+                leveldb::Status::IOError("Simulated failure");
+            idb_context->GetIDBFactory()->HandleBackingStoreFailure(
+                kTestOrigin);
+
+            EXPECT_TRUE(db_callbacks->forced_close_called());
+            EXPECT_FALSE(factory->IsBackingStoreOpen(kTestOrigin));
+          },
+          base::Unretained(idb_context.get()), temp_dir.GetPath(),
+
+          base::MakeRefCounted<MockIndexedDBCallbacks>(),
+          base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>()));
+  RunAllBlockingPoolTasksUntilIdle();
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/input_router_client.h b/content/browser/renderer_host/input/input_router_client.h
index 5c7573ee..d7f018a 100644
--- a/content/browser/renderer_host/input/input_router_client.h
+++ b/content/browser/renderer_host/input/input_router_client.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_CLIENT_H_
 #define CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_CLIENT_H_
 
+#include "cc/input/touch_action.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
 #include "content/common/content_export.h"
 #include "content/common/input/input_event_ack_source.h"
@@ -46,6 +47,10 @@
   // renderer.
   virtual void DidOverscroll(const ui::DidOverscrollParams& params) = 0;
 
+  // Called when the router has received a whitelisted touch action notification
+  // from the renderer.
+  virtual void OnSetWhiteListedTouchAction(cc::TouchAction touch_action) = 0;
+
   // Called when a renderer fling has terminated.
   virtual void DidStopFlinging() = 0;
 
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl.cc b/content/browser/renderer_host/input/legacy_input_router_impl.cc
index 823f4c6..98df9a4 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl.cc
+++ b/content/browser/renderer_host/input/legacy_input_router_impl.cc
@@ -254,6 +254,8 @@
     IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
                         OnHasTouchEventHandlers)
     IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction, OnSetTouchAction)
+    IPC_MESSAGE_HANDLER(InputHostMsg_SetWhiteListedTouchAction,
+                        OnSetWhiteListedTouchAction)
     IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging, OnDidStopFlinging)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
@@ -511,6 +513,12 @@
   UpdateTouchAckTimeoutEnabled();
 }
 
+void LegacyInputRouterImpl::OnSetWhiteListedTouchAction(
+    cc::TouchAction white_listed_touch_action) {
+  touch_action_filter_.OnSetWhiteListedTouchAction(white_listed_touch_action);
+  client_->OnSetWhiteListedTouchAction(white_listed_touch_action);
+}
+
 void LegacyInputRouterImpl::OnDidStopFlinging() {
   DCHECK_GT(active_renderer_fling_count_, 0);
   // Note that we're only guaranteed to get a fling end notification from the
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl.h b/content/browser/renderer_host/input/legacy_input_router_impl.h
index bd3189b..fe456f42 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl.h
+++ b/content/browser/renderer_host/input/legacy_input_router_impl.h
@@ -150,6 +150,7 @@
   void OnSelectMessageAck();
   void OnHasTouchEventHandlers(bool has_handlers);
   void OnSetTouchAction(cc::TouchAction touch_action);
+  void OnSetWhiteListedTouchAction(cc::TouchAction white_listed_touch_action);
   void OnDidStopFlinging();
 
   // Indicates the source of an ack provided to |ProcessInputEventAck()|.
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl_perftest.cc b/content/browser/renderer_host/input/legacy_input_router_impl_perftest.cc
index 157bac3..b723d20 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl_perftest.cc
+++ b/content/browser/renderer_host/input/legacy_input_router_impl_perftest.cc
@@ -91,6 +91,8 @@
   void DecrementInFlightEventCount(InputEventAckSource ack_source) override {}
   void OnHasTouchEventHandlers(bool has_handlers) override {}
   void DidOverscroll(const ui::DidOverscrollParams& params) override {}
+  void OnSetWhiteListedTouchAction(
+      cc::TouchAction white_listed_touch_action) override {}
   void DidStopFlinging() override {}
   void ForwardGestureEventWithLatencyInfo(
       const blink::WebGestureEvent& event,
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc b/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc
index e29ca61..71c5e14 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc
@@ -414,6 +414,11 @@
         InputHostMsg_SetTouchAction(0, touch_action));
   }
 
+  void OnSetWhiteListedTouchAction(cc::TouchAction white_listed_touch_action) {
+    input_router_->OnMessageReceived(
+        InputHostMsg_SetWhiteListedTouchAction(0, white_listed_touch_action));
+  }
+
   size_t GetSentMessageCountAndResetSink() {
     size_t count = process_->sink().message_count();
     process_->sink().ClearMessages();
@@ -2050,6 +2055,17 @@
   OverscrollDispatch();
 }
 
+// Test proper routing of whitelisted touch action notifications received from
+// |SetWhiteListedTouchAction| IPC messages.
+TEST_F(LegacyInputRouterImplTest, OnSetWhiteListedTouchAction) {
+  cc::TouchAction touch_action = cc::kTouchActionPanY;
+  input_router_->OnMessageReceived(
+      InputHostMsg_SetWhiteListedTouchAction(0, touch_action));
+  cc::TouchAction white_listed_touch_action =
+      client_->GetAndResetWhiteListedTouchAction();
+  EXPECT_EQ(touch_action, white_listed_touch_action);
+}
+
 // Tests that touch event stream validation passes when events are filtered
 // out. See crbug.com/581231 for details.
 TEST_F(LegacyInputRouterImplTest,
diff --git a/content/browser/renderer_host/input/mock_input_router_client.cc b/content/browser/renderer_host/input/mock_input_router_client.cc
index 50fcf50..9df4633 100644
--- a/content/browser/renderer_host/input/mock_input_router_client.cc
+++ b/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -23,7 +23,8 @@
       in_flight_event_count_(0),
       has_touch_handler_(false),
       filter_state_(INPUT_EVENT_ACK_STATE_NOT_CONSUMED),
-      filter_input_event_called_(false) {}
+      filter_input_event_called_(false),
+      white_listed_touch_action_(cc::kTouchActionAuto) {}
 
 MockInputRouterClient::~MockInputRouterClient() {}
 
@@ -55,6 +56,11 @@
   overscroll_ = params;
 }
 
+void MockInputRouterClient::OnSetWhiteListedTouchAction(
+    cc::TouchAction white_listed_touch_action) {
+  white_listed_touch_action_ = white_listed_touch_action;
+}
+
 void MockInputRouterClient::DidStopFlinging() {
 }
 
@@ -78,4 +84,10 @@
   return overscroll;
 }
 
+cc::TouchAction MockInputRouterClient::GetAndResetWhiteListedTouchAction() {
+  cc::TouchAction white_listed_touch_action = white_listed_touch_action_;
+  white_listed_touch_action_ = cc::kTouchActionAuto;
+  return white_listed_touch_action;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/input/mock_input_router_client.h b/content/browser/renderer_host/input/mock_input_router_client.h
index ed1072e..b65e04e 100644
--- a/content/browser/renderer_host/input/mock_input_router_client.h
+++ b/content/browser/renderer_host/input/mock_input_router_client.h
@@ -31,6 +31,7 @@
   void DecrementInFlightEventCount(InputEventAckSource ack_source) override;
   void OnHasTouchEventHandlers(bool has_handlers) override;
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
+  void OnSetWhiteListedTouchAction(cc::TouchAction touch_action) override;
   void DidStopFlinging() override;
   void ForwardGestureEventWithLatencyInfo(
       const blink::WebGestureEvent& gesture_event,
@@ -38,6 +39,7 @@
 
   bool GetAndResetFilterEventCalled();
   ui::DidOverscrollParams GetAndResetOverscroll();
+  cc::TouchAction GetAndResetWhiteListedTouchAction();
 
   void set_input_router(InputRouter* input_router) {
     input_router_ = input_router;
@@ -68,6 +70,8 @@
   std::unique_ptr<InputEvent> last_filter_event_;
 
   ui::DidOverscrollParams overscroll_;
+
+  cc::TouchAction white_listed_touch_action_;
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_mac.mm b/content/browser/renderer_host/input/synthetic_gesture_target_mac.mm
index e9513715..83a8792d 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_mac.mm
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_mac.mm
@@ -17,6 +17,7 @@
 @property CGFloat magnification;
 @property NSPoint locationInWindow;
 @property NSEventType type;
+@property NSEventPhase phase;
 
 // Filled with default values.
 @property(readonly) CGFloat deltaX;
@@ -31,6 +32,7 @@
 @synthesize magnification = magnification_;
 @synthesize locationInWindow = locationInWindow_;
 @synthesize type = type_;
+@synthesize phase = phase_;
 @synthesize deltaX = deltaX_;
 @synthesize deltaY = deltaY_;
 @synthesize modifierFlags = modifierFlags_;
@@ -41,6 +43,7 @@
   self = [super init];
   if (self) {
     type_ = NSEventTypeMagnify;
+    phase_ = NSEventPhaseChanged;
     magnification_ = magnification;
     locationInWindow_ = location;
 
@@ -56,10 +59,12 @@
 }
 
 + (id)eventWithMagnification:(float)magnification
-            locationInWindow:(NSPoint)location {
+            locationInWindow:(NSPoint)location
+                       phase:(NSEventPhase)phase {
   SyntheticPinchEvent* event =
       [[SyntheticPinchEvent alloc] initWithMagnification:magnification
                                         locationInWindow:location];
+  event.phase = phase;
   return [event autorelease];
 }
 
@@ -90,7 +95,8 @@
         id event = [SyntheticPinchEvent
             eventWithMagnification:0.0f
                   locationInWindow:NSMakePoint(gesture_event->x,
-                                               gesture_event->y)];
+                                               gesture_event->y)
+                             phase:NSEventPhaseBegan];
         [cocoa_view_ handleBeginGestureWithEvent:event];
         return;
       }
@@ -98,7 +104,8 @@
         id event = [SyntheticPinchEvent
             eventWithMagnification:0.0f
                   locationInWindow:NSMakePoint(gesture_event->x,
-                                               gesture_event->y)];
+                                               gesture_event->y)
+                             phase:NSEventPhaseEnded];
         [cocoa_view_ handleEndGestureWithEvent:event];
         return;
       }
@@ -106,7 +113,8 @@
         id event = [SyntheticPinchEvent
             eventWithMagnification:gesture_event->data.pinch_update.scale - 1.0f
                   locationInWindow:NSMakePoint(gesture_event->x,
-                                               gesture_event->y)];
+                                               gesture_event->y)
+                             phase:NSEventPhaseChanged];
         [cocoa_view_ magnifyWithEvent:event];
         return;
       }
diff --git a/content/browser/renderer_host/input/touch_action_filter.cc b/content/browser/renderer_host/input/touch_action_filter.cc
index f9304b8..d7b5d46 100644
--- a/content/browser/renderer_host/input/touch_action_filter.cc
+++ b/content/browser/renderer_host/input/touch_action_filter.cc
@@ -31,7 +31,8 @@
     : suppress_manipulation_events_(false),
       drop_current_tap_ending_event_(false),
       allow_current_double_tap_event_(true),
-      allowed_touch_action_(cc::kTouchActionAuto) {}
+      allowed_touch_action_(cc::kTouchActionAuto),
+      white_listed_touch_action_(cc::kTouchActionAuto) {}
 
 bool TouchActionFilter::FilterGestureEvent(WebGestureEvent* gesture_event) {
   if (gesture_event->source_device != blink::kWebGestureDeviceTouchscreen)
@@ -167,6 +168,22 @@
   // Note that resetting the action mid-sequence is tolerated. Gestures that had
   // their begin event(s) suppressed will be suppressed until the next sequence.
   allowed_touch_action_ = cc::kTouchActionAuto;
+  white_listed_touch_action_ = cc::kTouchActionAuto;
+}
+
+void TouchActionFilter::OnSetWhiteListedTouchAction(
+    cc::TouchAction white_listed_touch_action) {
+  // For multiple fingers, we take the intersection of the touch actions for all
+  // fingers that have gone down during this action.  In the majority of
+  // real-world scenarios the touch action for all fingers will be the same.
+  // This is left as implementation because of the relationship of gestures
+  // (which are off limits for the spec).  We believe the following are
+  // desirable properties of this choice:
+  // 1. Not sensitive to finger touch order.  Behavior of putting two fingers
+  //    down "at once" will be deterministic.
+  // 2. Only subtractive - eg. can't trigger scrolling on an element that
+  //    otherwise has scrolling disabling by the addition of a finger.
+  white_listed_touch_action_ &= white_listed_touch_action;
 }
 
 bool TouchActionFilter::ShouldSuppressManipulation(
diff --git a/content/browser/renderer_host/input/touch_action_filter.h b/content/browser/renderer_host/input/touch_action_filter.h
index 3fd52b9..4231c7b9 100644
--- a/content/browser/renderer_host/input/touch_action_filter.h
+++ b/content/browser/renderer_host/input/touch_action_filter.h
@@ -39,6 +39,10 @@
   // renderer. It may be called multiple times during this interval.
   void ResetTouchAction();
 
+  // Called when a set-white-listed-touch-action message is received from the
+  // renderer for a touch start event that is currently in flight.
+  void OnSetWhiteListedTouchAction(cc::TouchAction white_listed_touch_action);
+
   cc::TouchAction allowed_touch_action() const { return allowed_touch_action_; }
 
  private:
@@ -61,6 +65,9 @@
   // What touch actions are currently permitted.
   cc::TouchAction allowed_touch_action_;
 
+  // Whitelisted touch action received from the compositor.
+  cc::TouchAction white_listed_touch_action_;
+
   DISALLOW_COPY_AND_ASSIGN(TouchActionFilter);
 };
 
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
index ffb9dfd..20d64595 100644
--- a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
+++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
@@ -69,12 +69,12 @@
 }
 
 void OffscreenCanvasSurfaceImpl::Require(const viz::SurfaceId& surface_id,
-                                         const cc::SurfaceSequence& sequence) {
+                                         const viz::SurfaceSequence& sequence) {
   GetFrameSinkManager()->surface_manager()->RequireSequence(surface_id,
                                                             sequence);
 }
 
-void OffscreenCanvasSurfaceImpl::Satisfy(const cc::SurfaceSequence& sequence) {
+void OffscreenCanvasSurfaceImpl::Satisfy(const viz::SurfaceSequence& sequence) {
   GetFrameSinkManager()->surface_manager()->SatisfySequence(sequence);
 }
 
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.h b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
index 6ea40cbb..16759c9 100644
--- a/content/browser/renderer_host/offscreen_canvas_surface_impl.h
+++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
@@ -56,8 +56,8 @@
 
   // blink::mojom::OffscreenCanvasSurface implementation.
   void Require(const viz::SurfaceId& surface_id,
-               const cc::SurfaceSequence& sequence) override;
-  void Satisfy(const cc::SurfaceSequence& sequence) override;
+               const viz::SurfaceSequence& sequence) override;
+  void Satisfy(const viz::SurfaceSequence& sequence) override;
 
  private:
   // Registered as a callback for when |binding_| is closed. Will call
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc
index 686c62a..866e829 100644
--- a/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -17,10 +17,6 @@
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/test_service.mojom.h"
 #include "content/shell/browser/shell.h"
-#include "content/shell/browser/shell_browser_context.h"
-#include "content/shell/browser/shell_browser_main_parts.h"
-#include "content/shell/browser/shell_content_browser_client.h"
-#include "content/test/test_content_browser_client.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/media_switches.h"
 #include "media/base/test_data_util.h"
@@ -77,36 +73,6 @@
   base::Closure process_exit_callback_;
 };
 
-// A mock ContentBrowserClient that only considers a spare renderer to be a
-// suitable host.
-class SpareRendererContentBrowserClient : public TestContentBrowserClient {
- public:
-  bool IsSuitableHost(RenderProcessHost* process_host,
-                      const GURL& site_url) override {
-    if (RenderProcessHostImpl::GetSpareRenderProcessHostForTesting()) {
-      return process_host ==
-             RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
-    }
-    return true;
-  }
-};
-
-// A mock ContentBrowserClient that only considers a non-spare renderer to be a
-// suitable host, but otherwise tries to reuse processes.
-class NonSpareRendererContentBrowserClient : public TestContentBrowserClient {
- public:
-  bool IsSuitableHost(RenderProcessHost* process_host,
-                      const GURL& site_url) override {
-    return RenderProcessHostImpl::GetSpareRenderProcessHostForTesting() !=
-           process_host;
-  }
-
-  bool ShouldTryToUseExistingProcessHost(BrowserContext* context,
-                                         const GURL& url) override {
-    return true;
-  }
-};
-
 // Sometimes the renderer process's ShutdownRequest (corresponding to the
 // ViewMsg_WasSwappedOut from a previous navigation) doesn't arrive until after
 // the browser process decides to re-use the renderer for a new purpose.  This
@@ -164,144 +130,6 @@
   EXPECT_EQ(2, RenderProcessHostCount());
 }
 
-IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, SpareRenderProcessHostTaken) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  RenderProcessHost::WarmupSpareRenderProcessHost(
-      ShellContentBrowserClient::Get()->browser_context());
-  RenderProcessHost* spare_renderer =
-      RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
-  EXPECT_NE(nullptr, spare_renderer);
-
-  GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
-  Shell* window = CreateBrowser();
-  NavigateToURL(window, test_url);
-
-  EXPECT_EQ(spare_renderer,
-            window->web_contents()->GetMainFrame()->GetProcess());
-
-  // The spare render process host should no longer be available.
-  EXPECT_EQ(nullptr,
-            RenderProcessHostImpl::GetSpareRenderProcessHostForTesting());
-}
-
-IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, SpareRenderProcessHostNotTaken) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  RenderProcessHost::WarmupSpareRenderProcessHost(
-      ShellContentBrowserClient::Get()->off_the_record_browser_context());
-  RenderProcessHost* spare_renderer =
-      RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
-  GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
-  Shell* window = CreateBrowser();
-  NavigateToURL(window, test_url);
-
-  // There should have been another process created for the navigation.
-  EXPECT_NE(spare_renderer,
-            window->web_contents()->GetMainFrame()->GetProcess());
-
-  // The spare RenderProcessHost should have been cleaned up. Note this
-  // behavior is identical to what would have happened if the RenderProcessHost
-  // were taken.
-  EXPECT_EQ(nullptr,
-            RenderProcessHostImpl::GetSpareRenderProcessHostForTesting());
-}
-
-IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, SpareRenderProcessHostKilled) {
-  RenderProcessHost::WarmupSpareRenderProcessHost(
-      ShellContentBrowserClient::Get()->browser_context());
-
-  RenderProcessHost* spare_renderer =
-      RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
-  mojom::TestServicePtr service;
-  ASSERT_NE(nullptr, spare_renderer);
-  BindInterface(spare_renderer, &service);
-
-  base::RunLoop run_loop;
-  set_process_exit_callback(run_loop.QuitClosure());
-  spare_renderer->AddObserver(this);  // For process_exit_callback.
-
-  // Should reply with a bad message and cause process death.
-  service->DoSomething(base::Bind(&base::DoNothing));
-  run_loop.Run();
-
-  // The spare RenderProcessHost should disappear when its process dies.
-  EXPECT_EQ(nullptr,
-            RenderProcessHostImpl::GetSpareRenderProcessHostForTesting());
-}
-
-// Test that the spare renderer works correctly when the limit on the maximum
-// number of processes is small.
-IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
-                       SpareRendererSurpressedMaxProcesses) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  SpareRendererContentBrowserClient browser_client;
-  ContentBrowserClient* old_client =
-      SetBrowserClientForTesting(&browser_client);
-
-  RenderProcessHost::SetMaxRendererProcessCount(1);
-
-  // A process is created with shell startup, so with a maximum of one renderer
-  // process the spare RPH should not be created.
-  RenderProcessHost::WarmupSpareRenderProcessHost(
-      ShellContentBrowserClient::Get()->browser_context());
-  EXPECT_EQ(nullptr,
-            RenderProcessHostImpl::GetSpareRenderProcessHostForTesting());
-
-  // A spare RPH should be created with a max of 2 renderer processes.
-  RenderProcessHost::SetMaxRendererProcessCount(2);
-  RenderProcessHost::WarmupSpareRenderProcessHost(
-      ShellContentBrowserClient::Get()->browser_context());
-  RenderProcessHost* spare_renderer =
-      RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
-  EXPECT_NE(nullptr, spare_renderer);
-
-  // Thanks to the injected SpareRendererContentBrowserClient and the limit on
-  // processes, the spare RPH will always be used via GetExistingProcessHost()
-  // rather than picked up via MaybeTakeSpareRenderProcessHost().
-  GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
-  Shell* new_window = CreateBrowser();
-  NavigateToURL(new_window, test_url);
-  // The spare RPH should have been dropped during CreateBrowser() and given to
-  // the new window.
-  EXPECT_EQ(nullptr,
-            RenderProcessHostImpl::GetSpareRenderProcessHostForTesting());
-  EXPECT_EQ(spare_renderer,
-            new_window->web_contents()->GetMainFrame()->GetProcess());
-
-  // Revert to the default process limit and original ContentBrowserClient.
-  RenderProcessHost::SetMaxRendererProcessCount(0);
-  SetBrowserClientForTesting(old_client);
-}
-
-// Check that the spare renderer is dropped if an existing process is reused.
-IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, SpareRendererOnProcessReuse) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  NonSpareRendererContentBrowserClient browser_client;
-  ContentBrowserClient* old_client =
-      SetBrowserClientForTesting(&browser_client);
-
-  RenderProcessHost::WarmupSpareRenderProcessHost(
-      ShellContentBrowserClient::Get()->browser_context());
-  RenderProcessHost* spare_renderer =
-      RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
-  EXPECT_NE(nullptr, spare_renderer);
-
-  // This should resuse the existing process and cause the spare renderer to be
-  // dropped.
-  Shell* new_browser = CreateBrowser();
-  EXPECT_EQ(shell()->web_contents()->GetMainFrame()->GetProcess(),
-            new_browser->web_contents()->GetMainFrame()->GetProcess());
-  EXPECT_NE(spare_renderer,
-            new_browser->web_contents()->GetMainFrame()->GetProcess());
-  EXPECT_EQ(nullptr,
-            RenderProcessHostImpl::GetSpareRenderProcessHostForTesting());
-
-  SetBrowserClientForTesting(old_client);
-}
-
 class ShellCloser : public RenderProcessHostObserver {
  public:
   ShellCloser(Shell* shell, std::string* logging_string)
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 2f201f9..0f7c807 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -463,159 +463,6 @@
   DISALLOW_COPY_AND_ASSIGN(SessionStorageHolder);
 };
 
-// This class manages spare RenderProcessHosts.
-//
-// There is a singleton instance of this class which manages a single spare
-// renderer (g_spare_render_process_host_manager, below). This class
-// encapsulates the implementation of
-// RenderProcessHost::WarmupSpareRenderProcessHost()
-//
-// RenderProcessHostImpl should call
-// SpareRenderProcessHostManager::MaybeTakeSpareRenderProcessHost when creating
-// a new RPH. In this implementation, the spare renderer is bound to a
-// BrowserContext and its default StoragePartition. If
-// MaybeTakeSpareRenderProcessHost is called with a BrowserContext and
-// StoragePartition that does not match, the spare renderer is discarded. In
-// particular, only the default StoragePartition will be able to use a spare
-// renderer. The spare renderer will also not be used as a guest renderer
-// (is_for_guests_ == true).
-//
-// It is safe to call WarmupSpareRenderProcessHost multiple times, although if
-// called in a context where the spare renderer is not likely to be used
-// performance may suffer due to the unnecessary RPH creation.
-class SpareRenderProcessHostManager : public RenderProcessHostObserver {
- public:
-  SpareRenderProcessHostManager() {}
-
-  void WarmupSpareRenderProcessHost(BrowserContext* browser_context) {
-    StoragePartitionImpl* current_partition =
-        static_cast<StoragePartitionImpl*>(
-            BrowserContext::GetStoragePartition(browser_context, nullptr));
-
-    if (spare_render_process_host_ &&
-        matching_browser_context_ == browser_context &&
-        matching_storage_partition_ == current_partition)
-      return;  // Nothing to warm up.
-
-    CleanupSpareRenderProcessHost();
-
-    // Don't create a spare renderer if we're using --single-process or if we've
-    // got too many processes. See also ShouldTryToUseExistingProcessHost in
-    // this file.
-    if (RenderProcessHost::run_renderer_in_process() ||
-        g_all_hosts.Get().size() >=
-            RenderProcessHostImpl::GetMaxRendererProcessCount())
-      return;
-
-    matching_browser_context_ = browser_context;
-    matching_storage_partition_ = current_partition;
-
-    spare_render_process_host_ = RenderProcessHostImpl::CreateRenderProcessHost(
-        browser_context, current_partition, nullptr,
-        false /* is_for_guests_only */);
-    spare_render_process_host_->AddObserver(this);
-    spare_render_process_host_->Init();
-  }
-
-  // If |partition| is null, this gets the default partition from the browser
-  // context.
-  RenderProcessHost* MaybeTakeSpareRenderProcessHost(
-      BrowserContext* browser_context,
-      StoragePartition* partition,
-      SiteInstance* site_instance,
-      bool is_for_guests_only) {
-    if (spare_render_process_host_ &&
-        browser_context == matching_browser_context_ && !is_for_guests_only &&
-        !partition) {
-      // If the spare renderer matches for everything but possibly the storage
-      // partition, and the passed-in partition is null, get the default storage
-      // partition. If this is the case, the default storage partition will
-      // already have been created and there is no possibility of breaking tests
-      // by GetDefaultStoragePartition prematurely creating one.
-      partition =
-          BrowserContext::GetStoragePartition(browser_context, site_instance);
-    }
-
-    if (!spare_render_process_host_ ||
-        browser_context != matching_browser_context_ ||
-        partition != matching_storage_partition_ || is_for_guests_only) {
-      // As a new RenderProcessHost will almost certainly be created, we cleanup
-      // the non-matching one so as not to waste resources.
-      CleanupSpareRenderProcessHost();
-      return nullptr;
-    }
-
-    CHECK(spare_render_process_host_->HostHasNotBeenUsed());
-    RenderProcessHost* rph = spare_render_process_host_;
-    DropSpareRenderProcessHost(spare_render_process_host_);
-    return rph;
-  }
-
-  // Remove |host| as a possible spare renderer. Does not shut it down cleanly;
-  // the assumption is that the host was shutdown somewhere else and has
-  // notifying the SpareRenderProcessHostManager.
-  void DropSpareRenderProcessHost(RenderProcessHost* host) {
-    if (spare_render_process_host_ && spare_render_process_host_ == host) {
-      spare_render_process_host_->RemoveObserver(this);
-      spare_render_process_host_ = nullptr;
-    }
-  }
-
-  // Remove |host| as a possible spare renderer. If |host| is not the spare
-  // renderer, then shut down the spare renderer. The idea is that a navigation
-  // was just made to |host|, and we do not expect another immediate navigation,
-  // so that the spare renderer can be dropped in order to free up resources.
-  void DropSpareOnProcessCreation(RenderProcessHost* new_host) {
-    if (spare_render_process_host_ == new_host) {
-      DropSpareRenderProcessHost(new_host);
-    } else {
-      CleanupSpareRenderProcessHost();
-    }
-  }
-
-  // Gracefully remove and cleanup a spare RenderProcessHost if it exists.
-  void CleanupSpareRenderProcessHost() {
-    if (spare_render_process_host_) {
-      spare_render_process_host_->Cleanup();
-      DropSpareRenderProcessHost(spare_render_process_host_);
-    }
-  }
-
-  RenderProcessHost* spare_render_process_host() {
-    return spare_render_process_host_;
-  }
-
- private:
-  // RenderProcessHostObserver
-  void RenderProcessWillExit(RenderProcessHost* host) override {
-    DropSpareRenderProcessHost(host);
-  }
-
-  void RenderProcessExited(RenderProcessHost* host,
-                           base::TerminationStatus unused_status,
-                           int unused_exit_code) override {
-    DropSpareRenderProcessHost(host);
-  }
-
-  void RenderProcessHostDestroyed(RenderProcessHost* host) override {
-    DropSpareRenderProcessHost(host);
-  }
-
-  // This is a bare pointer, because RenderProcessHost manages the lifetime of
-  // all its instances; see g_all_hosts, above.
-  RenderProcessHost* spare_render_process_host_ = nullptr;
-
-  // Used only to check if a creation request matches the spare, and not
-  // accessed.
-  const BrowserContext* matching_browser_context_ = nullptr;
-  const StoragePartition* matching_storage_partition_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(SpareRenderProcessHostManager);
-};
-
-base::LazyInstance<SpareRenderProcessHostManager>::Leaky
-    g_spare_render_process_host_manager = LAZY_INSTANCE_INITIALIZER;
-
 const void* const kDefaultSubframeProcessHostHolderKey =
     &kDefaultSubframeProcessHostHolderKey;
 
@@ -629,17 +476,17 @@
   // Gets the correct render process to use for this SiteInstance.
   RenderProcessHost* GetProcessHost(SiteInstance* site_instance,
                                     bool is_for_guests_only) {
-    StoragePartitionImpl* default_partition =
-        static_cast<StoragePartitionImpl*>(
-            BrowserContext::GetDefaultStoragePartition(browser_context_));
-    StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
-        BrowserContext::GetStoragePartition(browser_context_, site_instance));
+    StoragePartition* default_partition =
+        BrowserContext::GetDefaultStoragePartition(browser_context_);
+    StoragePartition* partition =
+        BrowserContext::GetStoragePartition(browser_context_, site_instance);
 
     // Is this the default storage partition? If it isn't, then just give it its
     // own non-shared process.
     if (partition != default_partition || is_for_guests_only) {
-      RenderProcessHost* host = RenderProcessHostImpl::CreateRenderProcessHost(
-          browser_context_, partition, site_instance, is_for_guests_only);
+      RenderProcessHostImpl* host = new RenderProcessHostImpl(
+          browser_context_, static_cast<StoragePartitionImpl*>(partition),
+          is_for_guests_only);
       host->SetIsNeverSuitableForReuse();
       return host;
     }
@@ -649,9 +496,9 @@
     if (host_)
       return host_;
 
-    host_ = RenderProcessHostImpl::CreateOrUseSpareRenderProcessHost(
-        browser_context_, partition, site_instance,
-        false /* is for guests only */);
+    host_ = new RenderProcessHostImpl(
+        browser_context_, static_cast<StoragePartitionImpl*>(partition),
+        false /* for guests only */);
     host_->SetIsNeverSuitableForReuse();
     host_->AddObserver(this);
 
@@ -670,7 +517,7 @@
 
   // The default subframe render process used for the default storage partition
   // of this BrowserContext.
-  RenderProcessHost* host_ = nullptr;
+  RenderProcessHostImpl* host_ = nullptr;
 };
 
 void CreateMemoryCoordinatorHandle(
@@ -1190,47 +1037,6 @@
   g_max_renderer_count_override = count;
 }
 
-// static
-RenderProcessHost* RenderProcessHostImpl::CreateRenderProcessHost(
-    BrowserContext* browser_context,
-    StoragePartitionImpl* storage_partition_impl,
-    SiteInstance* site_instance,
-    bool is_for_guests_only) {
-  if (g_render_process_host_factory_) {
-    return g_render_process_host_factory_->CreateRenderProcessHost(
-        browser_context);
-  }
-
-  if (!storage_partition_impl) {
-    storage_partition_impl = static_cast<StoragePartitionImpl*>(
-        BrowserContext::GetStoragePartition(browser_context, site_instance));
-  }
-
-  return new RenderProcessHostImpl(browser_context, storage_partition_impl,
-                                   is_for_guests_only);
-}
-
-// static
-RenderProcessHost* RenderProcessHostImpl::CreateOrUseSpareRenderProcessHost(
-    BrowserContext* browser_context,
-    StoragePartitionImpl* storage_partition_impl,
-    SiteInstance* site_instance,
-    bool is_for_guests_only) {
-  RenderProcessHost* render_process_host =
-      g_spare_render_process_host_manager.Get().MaybeTakeSpareRenderProcessHost(
-          browser_context, storage_partition_impl, site_instance,
-          is_for_guests_only);
-
-  if (!render_process_host) {
-    render_process_host =
-        CreateRenderProcessHost(browser_context, storage_partition_impl,
-                                site_instance, is_for_guests_only);
-  }
-
-  DCHECK(render_process_host);
-  return render_process_host;
-}
-
 RenderProcessHostImpl::RenderProcessHostImpl(
     BrowserContext* browser_context,
     StoragePartitionImpl* storage_partition_impl,
@@ -2090,7 +1896,6 @@
     return;
   service_worker_ref_count_ = 0;
   shared_worker_ref_count_ = 0;
-  // Cleaning up will also remove this from the SpareRenderProcessHostManager.
   Cleanup();
 }
 
@@ -2322,22 +2127,6 @@
   tracker->DecrementSiteProcessCount(site_url, render_process_host->GetID());
 }
 
-// static
-void RenderProcessHostImpl::CleanupSpareRenderProcessHost() {
-  g_spare_render_process_host_manager.Get().CleanupSpareRenderProcessHost();
-}
-
-// static
-RenderProcessHost*
-RenderProcessHostImpl::GetSpareRenderProcessHostForTesting() {
-  return g_spare_render_process_host_manager.Get().spare_render_process_host();
-}
-
-bool RenderProcessHostImpl::HostHasNotBeenUsed() {
-  return IsUnused() && listeners_.IsEmpty() && GetWorkerRefCount() == 0 &&
-         pending_views_ == 0;
-}
-
 bool RenderProcessHostImpl::IsForGuestsOnly() const {
   return is_for_guests_only_;
 }
@@ -3283,13 +3072,6 @@
 }
 
 // static
-void RenderProcessHost::WarmupSpareRenderProcessHost(
-    content::BrowserContext* browser_context) {
-  g_spare_render_process_host_manager.Get().WarmupSpareRenderProcessHost(
-      browser_context);
-}
-
-// static
 bool RenderProcessHost::run_renderer_in_process() {
   return g_run_renderer_in_process_;
 }
@@ -3367,10 +3149,6 @@
   if (!suitable_renderers.empty()) {
     int suitable_count = static_cast<int>(suitable_renderers.size());
     int random_index = base::RandInt(0, suitable_count - 1);
-    // If the process chosen was the spare RenderProcessHost, ensure it won't be
-    // used as a spare in the future, or drop the spare if it wasn't used.
-    g_spare_render_process_host_manager.Get().DropSpareOnProcessCreation(
-        suitable_renderers[random_index]);
     return suitable_renderers[random_index];
   }
 
@@ -3497,14 +3275,18 @@
     render_process_host = GetExistingProcessHost(browser_context, site_url);
   }
 
-  // Otherwise, use the spare RenderProcessHost or create a new one.
+  // Otherwise (or if that fails), create a new one.
   if (!render_process_host) {
-    // Pass a null StoragePartition. Tests with TestBrowserContext using a
-    // RenderProcessHostFactory may not instantiate a StoragePartition, and
-    // creating one here with GetStoragePartition() can run into cross-thread
-    // issues as TestBrowserContext initialization is done on the main thread.
-    render_process_host = CreateOrUseSpareRenderProcessHost(
-        browser_context, nullptr, site_instance, is_for_guests_only);
+    if (g_render_process_host_factory_) {
+      render_process_host =
+          g_render_process_host_factory_->CreateRenderProcessHost(
+              browser_context);
+    } else {
+      StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
+          BrowserContext::GetStoragePartition(browser_context, site_instance));
+      render_process_host = new RenderProcessHostImpl(
+          browser_context, partition, is_for_guests_only);
+    }
   }
 
   if (is_unmatched_service_worker) {
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 189b64c..52320c0 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -80,7 +80,6 @@
 class RenderWidgetHost;
 class RenderWidgetHostImpl;
 class ResourceMessageFilter;
-class SiteInstance;
 class SiteInstanceImpl;
 class StoragePartition;
 class StoragePartitionImpl;
@@ -115,29 +114,9 @@
       public NON_EXPORTED_BASE(mojom::AssociatedInterfaceProvider),
       public NON_EXPORTED_BASE(mojom::RendererHost) {
  public:
-  // Use the spare RenderProcessHost if it exists, or create a new one. This
-  // should be the usual way to get a new RenderProcessHost.
-  // If |storage_partition_impl| is null, the default partition from the
-  // browser_context is used, using |site_instance| (for which a null value is
-  // legal).
-  static RenderProcessHost* CreateOrUseSpareRenderProcessHost(
-      BrowserContext* browser_context,
-      StoragePartitionImpl* storage_partition_impl,
-      SiteInstance* site_instance,
-      bool is_for_guests_only);
-
-  // Create a new RenderProcessHost. In most cases
-  // CreateOrUseSpareRenderProcessHost, above, should be used instead.
-  // If |storage_partition_impl| is null, the default partition from the
-  // browser_context is used, using |site_instance| (for which a null value is
-  // legal). |site_instance| is not used if |storage_partition_impl| is not
-  // null.
-  static RenderProcessHost* CreateRenderProcessHost(
-      BrowserContext* browser_context,
-      StoragePartitionImpl* storage_partition_impl,
-      SiteInstance* site_instance,
-      bool is_for_guests_only);
-
+  RenderProcessHostImpl(BrowserContext* browser_context,
+                        StoragePartitionImpl* storage_partition_impl,
+                        bool is_for_guests_only);
   ~RenderProcessHostImpl() override;
 
   // RenderProcessHost implementation (public portion).
@@ -217,8 +196,6 @@
   bool IsUnused() override;
   void SetIsUsed() override;
 
-  bool HostHasNotBeenUsed() override;
-
   mojom::RouteProvider* GetRemoteRouteProvider();
 
   // IPC::Sender via RenderProcessHost.
@@ -292,11 +269,6 @@
       BrowserContext* browser_context,
       SiteInstanceImpl* site_instance);
 
-  // Cleanup and remove any spare renderer. This should be used when a
-  // navigation has occurred or will be occurring that will not use the spare
-  // renderer and resources should be cleaned up.
-  static void CleanupSpareRenderProcessHost();
-
   static base::MessageLoop* GetInProcessRendererThreadForTesting();
 
   // This forces a renderer that is running "in process" to shut down.
@@ -365,10 +337,6 @@
       RenderProcessHost* render_process_host,
       const GURL& site_url);
 
-  // Return the spare RenderProcessHost, if it exists. There is at most one
-  // globally-used spare RenderProcessHost at any time.
-  static RenderProcessHost* GetSpareRenderProcessHostForTesting();
-
  protected:
   // A proxy for our IPC::Channel that lives on the IO thread.
   std::unique_ptr<IPC::ChannelProxy> channel_;
@@ -395,12 +363,6 @@
   class ConnectionFilterController;
   class ConnectionFilterImpl;
 
-  // Use CreateRenderProcessHost() instead of calling this constructor
-  // directly.
-  RenderProcessHostImpl(BrowserContext* browser_context,
-                        StoragePartitionImpl* storage_partition_impl,
-                        bool is_for_guests_only);
-
   // Initializes a new IPC::ChannelProxy in |channel_|, which will be connected
   // to the next child process launched for this host, if any.
   void InitializeChannelProxy();
diff --git a/content/browser/renderer_host/render_process_host_unittest.cc b/content/browser/renderer_host/render_process_host_unittest.cc
index 4753d921..267eb83d 100644
--- a/content/browser/renderer_host/render_process_host_unittest.cc
+++ b/content/browser/renderer_host/render_process_host_unittest.cc
@@ -12,13 +12,11 @@
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "content/common/frame_messages.h"
-#include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/mock_render_process_host.h"
-#include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_utils.h"
 #include "content/test/test_render_frame_host.h"
 #include "content/test/test_render_view_host.h"
@@ -751,46 +749,4 @@
   EXPECT_EQ(main_test_rfh()->GetProcess(), site_instance->GetProcess());
 }
 
-class SpareRenderProcessHostUnitTest : public RenderViewHostImplTestHarness {
- protected:
-  void SetUp() override {
-    SetRenderProcessHostFactory(&rph_factory_);
-    RenderViewHostImplTestHarness::SetUp();
-    SetContents(NULL);  // Start with no renderers.
-    while (!rph_factory_.GetProcesses()->empty()) {
-      rph_factory_.Remove(rph_factory_.GetProcesses()->back().get());
-    }
-  }
-
-  MockRenderProcessHostFactory rph_factory_;
-};
-
-TEST_F(SpareRenderProcessHostUnitTest, TestRendererTaken) {
-  RenderProcessHost::WarmupSpareRenderProcessHost(browser_context());
-  ASSERT_EQ(1U, rph_factory_.GetProcesses()->size());
-  RenderProcessHost* spare_rph =
-      RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
-  EXPECT_EQ(spare_rph, rph_factory_.GetProcesses()->at(0).get());
-
-  const GURL kUrl1("http://foo.com");
-  SetContents(CreateTestWebContents());
-  NavigateAndCommit(kUrl1);
-  EXPECT_EQ(spare_rph, main_test_rfh()->GetProcess());
-  ASSERT_EQ(1U, rph_factory_.GetProcesses()->size());
-}
-
-TEST_F(SpareRenderProcessHostUnitTest, TestRendererNotTaken) {
-  std::unique_ptr<BrowserContext> alternate_context(new TestBrowserContext());
-  RenderProcessHost::WarmupSpareRenderProcessHost(alternate_context.get());
-  ASSERT_EQ(1U, rph_factory_.GetProcesses()->size());
-  RenderProcessHost* spare_rph =
-      RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
-  EXPECT_EQ(spare_rph, rph_factory_.GetProcesses()->at(0).get());
-
-  const GURL kUrl1("http://foo.com");
-  SetContents(CreateTestWebContents());
-  NavigateAndCommit(kUrl1);
-  EXPECT_NE(spare_rph, main_test_rfh()->GetProcess());
-}
-
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 169e069f..035b6b7 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -697,6 +697,8 @@
   void OnHasTouchEventHandlers(bool has_handlers) override;
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
   void DidStopFlinging() override;
+  void OnSetWhiteListedTouchAction(
+      cc::TouchAction white_listed_touch_action) override {}
 
   // Dispatch input events with latency information
   void DispatchInputEventWithLatencyInfo(const blink::WebInputEvent& event,
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 5ab3510..639e259 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -942,7 +942,10 @@
       BrowserThread::IO, FROM_HERE,
       base::Bind(
           &ServiceWorkerContextWrapper::StartServiceWorkerForNavigationHintOnIO,
-          this, document_url, callback));
+          this, document_url,
+          base::Bind(&ServiceWorkerContextWrapper::
+                         RecordStartServiceWorkerForNavigationHintResult,
+                     this, callback)));
 }
 
 void ServiceWorkerContextWrapper::StartServiceWorkerForNavigationHintOnIO(
@@ -952,10 +955,7 @@
                "document_url", document_url.spec());
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (!context_core_) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(callback,
-                   StartServiceWorkerForNavigationHintResult::FAILED));
+    callback.Run(StartServiceWorkerForNavigationHintResult::FAILED);
     return;
   }
   context_core_->storage()->FindRegistrationForDocument(
@@ -974,34 +974,23 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (!registration) {
     DCHECK_NE(status, SERVICE_WORKER_OK);
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(callback, StartServiceWorkerForNavigationHintResult::
-                                 NO_SERVICE_WORKER_REGISTRATION));
+    callback.Run(StartServiceWorkerForNavigationHintResult::
+                     NO_SERVICE_WORKER_REGISTRATION);
     return;
   }
   if (!registration->active_version()) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(callback, StartServiceWorkerForNavigationHintResult::
-                                 NO_ACTIVE_SERVICE_WORKER_VERSION));
+    callback.Run(StartServiceWorkerForNavigationHintResult::
+                     NO_ACTIVE_SERVICE_WORKER_VERSION);
     return;
   }
   if (registration->active_version()->fetch_handler_existence() ==
       ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(
-            callback,
-            StartServiceWorkerForNavigationHintResult::NO_FETCH_HANDLER));
+    callback.Run(StartServiceWorkerForNavigationHintResult::NO_FETCH_HANDLER);
     return;
   }
   if (registration->active_version()->running_status() ==
       EmbeddedWorkerStatus::RUNNING) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(callback,
-                   StartServiceWorkerForNavigationHintResult::ALREADY_RUNNING));
+    callback.Run(StartServiceWorkerForNavigationHintResult::ALREADY_RUNNING);
     return;
   }
 
@@ -1019,13 +1008,19 @@
   TRACE_EVENT2("ServiceWorker", "DidStartServiceWorkerForNavigationHint", "url",
                pattern.spec(), "code", ServiceWorkerStatusToString(code));
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  callback.Run(code == SERVICE_WORKER_OK
+                   ? StartServiceWorkerForNavigationHintResult::STARTED
+                   : StartServiceWorkerForNavigationHintResult::FAILED);
+}
 
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(callback,
-                 code == SERVICE_WORKER_OK
-                     ? StartServiceWorkerForNavigationHintResult::STARTED
-                     : StartServiceWorkerForNavigationHintResult::FAILED));
+void ServiceWorkerContextWrapper::
+    RecordStartServiceWorkerForNavigationHintResult(
+        const StartServiceWorkerForNavigationHintCallback& callback,
+        StartServiceWorkerForNavigationHintResult result) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  ServiceWorkerMetrics::RecordStartServiceWorkerForNavigationHintResult(result);
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(callback, result));
 }
 
 void ServiceWorkerContextWrapper::BindWorkerFetchContext(
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h
index 5d871cd4..ecce8e1 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -320,6 +320,10 @@
       const StartServiceWorkerForNavigationHintCallback& callback,
       ServiceWorkerStatusCode code);
 
+  void RecordStartServiceWorkerForNavigationHintResult(
+      const StartServiceWorkerForNavigationHintCallback& callback,
+      StartServiceWorkerForNavigationHintResult result);
+
   // The core context is only for use on the IO thread.
   // Can be null before/during init, during/after shutdown, and after
   // DeleteAndStartOver fails.
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc
index 7b276eb..d42abfd 100644
--- a/content/browser/service_worker/service_worker_metrics.cc
+++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -1036,4 +1036,11 @@
                  url));
 }
 
+void ServiceWorkerMetrics::RecordStartServiceWorkerForNavigationHintResult(
+    StartServiceWorkerForNavigationHintResult result) {
+  UMA_HISTOGRAM_ENUMERATION(
+      "ServiceWorker.StartForNavigationHint.Result", result,
+      StartServiceWorkerForNavigationHintResult::NUM_TYPES);
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h
index 431ef53..a9eb085 100644
--- a/content/browser/service_worker/service_worker_metrics.h
+++ b/content/browser/service_worker/service_worker_metrics.h
@@ -15,6 +15,7 @@
 #include "content/browser/service_worker/service_worker_database.h"
 #include "content/common/service_worker/embedded_worker.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/service_worker_context.h"
 #include "content/public/common/service_worker_modes.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerResponseError.h"
 #include "ui/base/page_transition_types.h"
@@ -395,6 +396,10 @@
   // TODO(falken): Remove after this is deprecated. https://crbug.com/737044
   static void RecordUninstalledScriptImport(const GURL& url);
 
+  // Records the result of starting service worker for a navigation hint.
+  static void RecordStartServiceWorkerForNavigationHintResult(
+      StartServiceWorkerForNavigationHintResult result);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics);
 };
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 9b1e53ea..32a960d 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -16,7 +16,6 @@
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
 #include "content/browser/blob_storage/blob_registry_wrapper.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/browser_main_loop.h"
@@ -472,25 +471,9 @@
       in_memory ? base::FilePath() : context->GetPath(),
       relative_partition_path, context->GetSpecialStoragePolicy());
 
-  // BrowserMainLoop may not be initialized in unit tests. Tests will
-  // need to inject their own task runner into the IndexedDBContext.
-  // TODO(jsbell): This is no longer true, update tests to provide use a
-  // base::test::ScopedTaskEnvironment instead of injecting a test task
-  // runner.
-  scoped_refptr<base::SequencedTaskRunner> idb_task_runner =
-      BrowserThread::CurrentlyOn(BrowserThread::UI) &&
-              BrowserMainLoop::GetInstance()
-          ? base::CreateSequencedTaskRunnerWithTraits({
-                base::MayBlock(), base::WithBaseSyncPrimitives(),
-                base::TaskPriority::USER_VISIBLE,
-                base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
-            })
-          : nullptr;
-
   base::FilePath path = in_memory ? base::FilePath() : partition_path;
-  partition->indexed_db_context_ =
-      new IndexedDBContextImpl(path, context->GetSpecialStoragePolicy(),
-                               quota_manager_proxy.get(), idb_task_runner);
+  partition->indexed_db_context_ = new IndexedDBContextImpl(
+      path, context->GetSpecialStoragePolicy(), quota_manager_proxy);
 
   partition->cache_storage_context_ = new CacheStorageContextImpl(context);
   partition->cache_storage_context_->Init(path, quota_manager_proxy);
diff --git a/content/browser/web_contents/aura/gesture_nav_simple.cc b/content/browser/web_contents/aura/gesture_nav_simple.cc
index 4375307..2b24730 100644
--- a/content/browser/web_contents/aura/gesture_nav_simple.cc
+++ b/content/browser/web_contents/aura/gesture_nav_simple.cc
@@ -105,6 +105,9 @@
   // Returns the root layer of the affordance.
   ui::Layer* root_layer() const { return root_layer_.get(); }
 
+  // Returns whether the affordance is performing abort or complete animation.
+  bool IsFinishing() const { return state_ != State::DRAGGING; }
+
  private:
   enum class State { DRAGGING, ABORTING, COMPLETING };
 
@@ -373,7 +376,7 @@
 }
 
 bool GestureNavSimple::OnOverscrollUpdate(float delta_x, float delta_y) {
-  if (!affordance_)
+  if (!affordance_ || affordance_->IsFinishing())
     return false;
   affordance_->SetDragProgress(
       std::min(1.f, std::abs(delta_x) / completion_threshold_));
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc
index 95393e8..280db4bc 100644
--- a/content/browser/webauth/authenticator_impl.cc
+++ b/content/browser/webauth/authenticator_impl.cc
@@ -17,13 +17,13 @@
 
 namespace {
 
-const char kGetAssertionType[] = "navigator.id.getAssertion";
+constexpr char kMakeCredentialType[] = "navigator.id.makeCredential";
 
 // JSON key values
-const char kTypeKey[] = "type";
-const char kChallengeKey[] = "challenge";
-const char kOriginKey[] = "origin";
-const char kCidPubkeyKey[] = "cid_pubkey";
+constexpr char kTypeKey[] = "type";
+constexpr char kChallengeKey[] = "challenge";
+constexpr char kOriginKey[] = "origin";
+constexpr char kCidPubkeyKey[] = "cid_pubkey";
 
 }  // namespace
 
@@ -53,10 +53,7 @@
 
 // mojom:Authenticator
 void AuthenticatorImpl::MakeCredential(
-    webauth::mojom::RelyingPartyAccountPtr account,
-    std::vector<webauth::mojom::ScopedCredentialParametersPtr> parameters,
-    const std::vector<uint8_t>& challenge,
-    webauth::mojom::ScopedCredentialOptionsPtr options,
+    webauth::mojom::MakeCredentialOptionsPtr options,
     MakeCredentialCallback callback) {
   std::string effective_domain;
   std::string relying_party_id;
@@ -71,7 +68,7 @@
     return;
   }
 
-  if (!options->relying_party_id) {
+  if (options->relying_party->id.empty()) {
     relying_party_id = caller_origin_.Serialize();
   } else {
     effective_domain = caller_origin_.host();
@@ -80,18 +77,17 @@
     // TODO(kpaulhamus): Check if relyingPartyId is a registrable domain
     // suffix of and equal to effectiveDomain and set relyingPartyId
     // appropriately.
-    relying_party_id = options->relying_party_id.value_or(std::string());
+    relying_party_id = options->relying_party->id;
   }
 
   // TODO(kpaulhamus): Check ScopedCredentialParameter's type and
   // algorithmIdentifier after algorithmIdentifier is added to mojom to
   // make sure it is U2F_V2.
-
-  client_data.SetString(kTypeKey, kGetAssertionType);
-  client_data.SetString(
-      kChallengeKey,
-      base::StringPiece(reinterpret_cast<const char*>(challenge.data()),
-                        challenge.size()));
+  client_data.SetString(kTypeKey, kMakeCredentialType);
+  client_data.SetString(kChallengeKey,
+                        base::StringPiece(reinterpret_cast<const char*>(
+                                              options->challenge.data()),
+                                          options->challenge.size()));
   client_data.SetString(kOriginKey, relying_party_id);
   // Channel ID is optional, and missing if the browser doesn't support it.
   // It is present and set to the constant "unused" if the browser
diff --git a/content/browser/webauth/authenticator_impl.h b/content/browser/webauth/authenticator_impl.h
index b2689b7..bcd589c 100644
--- a/content/browser/webauth/authenticator_impl.h
+++ b/content/browser/webauth/authenticator_impl.h
@@ -40,12 +40,8 @@
   explicit AuthenticatorImpl(RenderFrameHost* render_frame_host);
 
   // mojom:Authenticator
-  void MakeCredential(
-      webauth::mojom::RelyingPartyAccountPtr account,
-      std::vector<webauth::mojom::ScopedCredentialParametersPtr> parameters,
-      const std::vector<uint8_t>& challenge,
-      webauth::mojom::ScopedCredentialOptionsPtr options,
-      MakeCredentialCallback callback) override;
+  void MakeCredential(webauth::mojom::MakeCredentialOptionsPtr options,
+                      MakeCredentialCallback callback) override;
 
   base::Closure connection_error_handler_;
   base::CancelableClosure timeout_callback_;
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 168ec03..2ebef756 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -23,15 +23,15 @@
 
 using ::testing::_;
 
-using webauth::mojom::RelyingPartyAccount;
-using webauth::mojom::ScopedCredentialOptions;
-using webauth::mojom::ScopedCredentialParameters;
 using webauth::mojom::AuthenticatorPtr;
 using webauth::mojom::AuthenticatorStatus;
-using webauth::mojom::RelyingPartyAccountPtr;
-using webauth::mojom::ScopedCredentialInfoPtr;
-using webauth::mojom::ScopedCredentialOptionsPtr;
-using webauth::mojom::ScopedCredentialParametersPtr;
+using webauth::mojom::MakeCredentialOptions;
+using webauth::mojom::MakeCredentialOptionsPtr;
+using webauth::mojom::PublicKeyCredentialEntity;
+using webauth::mojom::PublicKeyCredentialEntityPtr;
+using webauth::mojom::PublicKeyCredentialInfoPtr;
+using webauth::mojom::PublicKeyCredentialParameters;
+using webauth::mojom::PublicKeyCredentialParametersPtr;
 
 const char* kOrigin1 = "https://google.com";
 
@@ -64,54 +64,66 @@
   ~TestMakeCredentialCallback() {}
 
   void ReceivedCallback(AuthenticatorStatus status,
-                        ScopedCredentialInfoPtr credential) {
+                        PublicKeyCredentialInfoPtr credential) {
     response_ = std::make_pair(status, std::move(credential));
     closure_.Run();
   }
 
-  std::pair<AuthenticatorStatus, ScopedCredentialInfoPtr>& WaitForCallback() {
+  std::pair<AuthenticatorStatus, PublicKeyCredentialInfoPtr>&
+  WaitForCallback() {
     closure_ = run_loop_.QuitClosure();
     run_loop_.Run();
     return response_;
   }
 
   const base::Callback<void(AuthenticatorStatus status,
-                            ScopedCredentialInfoPtr credential)>&
+                            PublicKeyCredentialInfoPtr credential)>&
   callback() {
     return callback_;
   }
 
  private:
-  std::pair<AuthenticatorStatus, ScopedCredentialInfoPtr> response_;
+  std::pair<AuthenticatorStatus, PublicKeyCredentialInfoPtr> response_;
   base::Closure closure_;
   base::Callback<void(AuthenticatorStatus status,
-                      ScopedCredentialInfoPtr credential)>
+                      PublicKeyCredentialInfoPtr credential)>
       callback_;
   base::RunLoop run_loop_;
 };
 
-RelyingPartyAccountPtr GetTestRelyingPartyAccount() {
-  RelyingPartyAccountPtr account = RelyingPartyAccount::New();
-  account->relying_party_display_name = std::string("TestRP");
-  account->display_name = std::string("Test A. Name");
-  account->id = std::string("1098237235409872");
-  account->name = std::string("Testname@example.com");
-  account->image_url = std::string("fakeurl.png");
-  return account;
+PublicKeyCredentialEntityPtr GetTestPublicKeyCredentialRPEntity() {
+  auto entity = PublicKeyCredentialEntity::New();
+  entity->id = std::string("localhost");
+  entity->name = std::string("TestRP@example.com");
+  return entity;
 }
 
-std::vector<ScopedCredentialParametersPtr> GetTestScopedCredentialParameters() {
-  std::vector<ScopedCredentialParametersPtr> parameters;
-  auto fake_parameter = ScopedCredentialParameters::New();
-  fake_parameter->type = webauth::mojom::ScopedCredentialType::SCOPEDCRED;
+PublicKeyCredentialEntityPtr GetTestPublicKeyCredentialUserEntity() {
+  auto entity = PublicKeyCredentialEntity::New();
+  entity->display_name = std::string("User A. Name");
+  entity->id = std::string("1098237235409872");
+  entity->name = std::string("TestRP@example.com");
+  entity->icon = GURL("fakeurl2.png");
+  return entity;
+}
+
+std::vector<PublicKeyCredentialParametersPtr>
+GetTestPublicKeyCredentialParameters() {
+  std::vector<PublicKeyCredentialParametersPtr> parameters;
+  auto fake_parameter = PublicKeyCredentialParameters::New();
+  fake_parameter->type = webauth::mojom::PublicKeyCredentialType::PUBLIC_KEY;
   parameters.push_back(std::move(fake_parameter));
   return parameters;
 }
 
-ScopedCredentialOptionsPtr GetTestScopedCredentialOptions() {
-  ScopedCredentialOptionsPtr opts = ScopedCredentialOptions::New();
-  opts->adjusted_timeout = 60;
-  opts->relying_party_id = std::string("localhost");
+MakeCredentialOptionsPtr GetTestMakeCredentialOptions() {
+  auto opts = MakeCredentialOptions::New();
+  std::vector<uint8_t> buffer(32, 0x0A);
+  opts->relying_party = GetTestPublicKeyCredentialRPEntity();
+  opts->user = GetTestPublicKeyCredentialUserEntity();
+  opts->crypto_parameters = GetTestPublicKeyCredentialParameters();
+  opts->challenge = std::move(buffer);
+  opts->adjusted_timeout = base::TimeDelta::FromMinutes(1);
   return opts;
 }
 
@@ -119,20 +131,12 @@
 TEST_F(AuthenticatorImplTest, MakeCredentialNotImplemented) {
   SimulateNavigation(GURL(kOrigin1));
   AuthenticatorPtr authenticator = ConnectToAuthenticator();
-
-  RelyingPartyAccountPtr account = GetTestRelyingPartyAccount();
-
-  std::vector<ScopedCredentialParametersPtr> parameters =
-      GetTestScopedCredentialParameters();
-
-  std::vector<uint8_t> buffer(32, 0x0A);
-  ScopedCredentialOptionsPtr opts = GetTestScopedCredentialOptions();
+  MakeCredentialOptionsPtr opts = GetTestMakeCredentialOptions();
 
   TestMakeCredentialCallback cb;
-  authenticator->MakeCredential(std::move(account), std::move(parameters),
-                                buffer, std::move(opts), cb.callback());
+  authenticator->MakeCredential(std::move(opts), cb.callback());
   std::pair<webauth::mojom::AuthenticatorStatus,
-            webauth::mojom::ScopedCredentialInfoPtr>& response =
+            webauth::mojom::PublicKeyCredentialInfoPtr>& response =
       cb.WaitForCallback();
   EXPECT_EQ(webauth::mojom::AuthenticatorStatus::NOT_IMPLEMENTED,
             response.first);
@@ -143,19 +147,13 @@
 TEST_F(AuthenticatorImplTest, MakeCredentialOpaqueOrigin) {
   NavigateAndCommit(GURL("data:text/html,opaque"));
   AuthenticatorPtr authenticator = ConnectToAuthenticator();
-  RelyingPartyAccountPtr account = GetTestRelyingPartyAccount();
 
-  std::vector<ScopedCredentialParametersPtr> parameters =
-      GetTestScopedCredentialParameters();
-
-  std::vector<uint8_t> buffer(32, 0x0A);
-  ScopedCredentialOptionsPtr opts = GetTestScopedCredentialOptions();
+  MakeCredentialOptionsPtr opts = GetTestMakeCredentialOptions();
 
   TestMakeCredentialCallback cb;
-  authenticator->MakeCredential(std::move(account), std::move(parameters),
-                                buffer, std::move(opts), cb.callback());
+  authenticator->MakeCredential(std::move(opts), cb.callback());
   std::pair<webauth::mojom::AuthenticatorStatus,
-            webauth::mojom::ScopedCredentialInfoPtr>& response =
+            webauth::mojom::PublicKeyCredentialInfoPtr>& response =
       cb.WaitForCallback();
   EXPECT_EQ(webauth::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR,
             response.first);
diff --git a/content/common/browser_plugin/browser_plugin_messages.h b/content/common/browser_plugin/browser_plugin_messages.h
index f7037f9e..4459d0f 100644
--- a/content/common/browser_plugin/browser_plugin_messages.h
+++ b/content/common/browser_plugin/browser_plugin_messages.h
@@ -159,12 +159,12 @@
 
 IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_SatisfySequence,
                     int /* browser_plugin_instance_id */,
-                    cc::SurfaceSequence /* sequence */)
+                    viz::SurfaceSequence /* sequence */)
 
 IPC_MESSAGE_ROUTED3(BrowserPluginHostMsg_RequireSequence,
                     int /* browser_plugin_instance_id */,
                     viz::SurfaceId /* surface_id */,
-                    cc::SurfaceSequence /* sequence */)
+                    viz::SurfaceSequence /* sequence */)
 
 // -----------------------------------------------------------------------------
 // These messages are from the browser process to the embedder.
@@ -197,7 +197,7 @@
 IPC_MESSAGE_CONTROL3(BrowserPluginMsg_SetChildFrameSurface,
                      int /* browser_plugin_instance_id */,
                      viz::SurfaceInfo /* surface_info */,
-                     cc::SurfaceSequence /* sequence */)
+                     viz::SurfaceSequence /* sequence */)
 
 // Forwards a PointerLock Unlock request to the BrowserPlugin.
 IPC_MESSAGE_CONTROL2(BrowserPluginMsg_SetMouseLock,
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 4e408c9..e2788736 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -14,9 +14,9 @@
 #include <vector>
 
 #include "build/build_config.h"
-#include "cc/surfaces/surface_sequence.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "content/common/content_export.h"
 #include "content/common/content_param_traits.h"
 #include "content/common/content_security_policy/csp_context.h"
@@ -700,7 +700,7 @@
 
 IPC_MESSAGE_ROUTED2(FrameMsg_SetChildFrameSurface,
                     viz::SurfaceInfo /* surface_info */,
-                    cc::SurfaceSequence /* sequence */)
+                    viz::SurfaceSequence /* sequence */)
 
 // Notifies the embedding frame that the process rendering the child frame's
 // contents has terminated.
@@ -1422,13 +1422,13 @@
 
 // Satisfies a Surface destruction dependency associated with |sequence|.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_SatisfySequence,
-                    cc::SurfaceSequence /* sequence */)
+                    viz::SurfaceSequence /* sequence */)
 
 // Creates a destruction dependency for the Surface specified by the given
 // |surface_id|.
 IPC_MESSAGE_ROUTED2(FrameHostMsg_RequireSequence,
                     viz::SurfaceId /* surface_id */,
-                    cc::SurfaceSequence /* sequence */)
+                    viz::SurfaceSequence /* sequence */)
 
 // Provides the result from handling BeforeUnload.  |proceed| matches the return
 // value of the frame's beforeunload handler: true if the user decided to
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index a28a307..30ecc094 100644
--- a/content/common/input_messages.h
+++ b/content/common/input_messages.h
@@ -332,6 +332,10 @@
 IPC_MESSAGE_ROUTED1(InputHostMsg_SetTouchAction,
                     cc::TouchAction /* touch_action */)
 
+// The whitelisted touch action for a new touch point sent by the compositor.
+IPC_MESSAGE_ROUTED1(InputHostMsg_SetWhiteListedTouchAction,
+                    cc::TouchAction /* white_listed_touch_action */)
+
 // Sent by the compositor when input scroll events are dropped due to bounds
 // restrictions on the root scroll offset.
 IPC_MESSAGE_ROUTED1(InputHostMsg_DidOverscroll,
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index ed1b6769..90520e2 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -111,6 +111,7 @@
     "java/src/org/chromium/content/browser/BindingManager.java",
     "java/src/org/chromium/content/browser/BindingManagerImpl.java",
     "java/src/org/chromium/content/browser/BrowserStartupController.java",
+    "java/src/org/chromium/content/browser/ChildProcessCreationParams.java",
     "java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java",
     "java/src/org/chromium/content/browser/ContentChildProcessConstants.java",
     "java/src/org/chromium/content/browser/ContentClassFactory.java",
diff --git a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
index c55cc361..fcb2726b 100644
--- a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
+++ b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
@@ -23,8 +23,8 @@
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.Linker;
 import org.chromium.base.library_loader.ProcessInitException;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.process_launcher.ChildProcessServiceDelegate;
+import org.chromium.content.browser.ChildProcessCreationParams;
 import org.chromium.content.browser.ContentChildProcessConstants;
 import org.chromium.content.common.ContentSwitches;
 import org.chromium.content.common.IGpuProcessCallback;
@@ -65,7 +65,7 @@
     @Override
     public void onServiceBound(Intent intent) {
         mLinkerParams = ChromiumLinkerParams.create(intent.getExtras());
-        mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessType(intent);
+        mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessType(intent.getExtras());
     }
 
     @Override
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessCreationParams.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessCreationParams.java
similarity index 90%
rename from base/android/java/src/org/chromium/base/process_launcher/ChildProcessCreationParams.java
rename to content/public/android/java/src/org/chromium/content/browser/ChildProcessCreationParams.java
index 1c33600a..49eb76f4 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessCreationParams.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessCreationParams.java
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.base.process_launcher;
+package org.chromium.content.browser;
 
-import android.content.Intent;
+import android.os.Bundle;
 import android.util.SparseArray;
 
 import org.chromium.base.library_loader.LibraryProcessType;
@@ -95,11 +95,11 @@
         return mBindToCallerCheck;
     }
 
-    public void addIntentExtras(Intent intent) {
-        intent.putExtra(EXTRA_LIBRARY_PROCESS_TYPE, mLibraryProcessType);
+    public void addIntentExtras(Bundle extras) {
+        extras.putInt(EXTRA_LIBRARY_PROCESS_TYPE, mLibraryProcessType);
     }
 
-    public static int getLibraryProcessType(Intent intent) {
-        return intent.getIntExtra(EXTRA_LIBRARY_PROCESS_TYPE, LibraryProcessType.PROCESS_CHILD);
+    public static int getLibraryProcessType(Bundle extras) {
+        return extras.getInt(EXTRA_LIBRARY_PROCESS_TYPE, LibraryProcessType.PROCESS_CHILD);
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
index b4a64b7..237f043 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
@@ -23,7 +23,6 @@
 import org.chromium.base.process_launcher.ChildConnectionAllocator;
 import org.chromium.base.process_launcher.ChildProcessConnection;
 import org.chromium.base.process_launcher.ChildProcessConstants;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.process_launcher.ChildProcessLauncher;
 import org.chromium.base.process_launcher.FileDescriptorInfo;
 import org.chromium.content.app.ChromiumLinkerParams;
@@ -231,6 +230,11 @@
         return sandboxed && params != null && params.getIsSandboxedServiceExternal();
     }
 
+    public static boolean isServiceBoundToCallerFromCreationParams(
+            ChildProcessCreationParams params) {
+        return params == null ? false : params.getBindToCallerCheck();
+    }
+
     /**
      * Starts the moderate binding management that adjust a process priority in response to various
      * signals (app sent to background/foreground for example).
@@ -311,15 +315,16 @@
         assert LauncherThread.runningOnLauncherThread();
         final String packageName =
                 getPackageNameFromCreationParams(context, creationParams, sandboxed);
+        boolean bindToCaller = isServiceBoundToCallerFromCreationParams(creationParams);
         boolean bindAsExternalService =
                 isServiceExternalFromCreationParams(creationParams, sandboxed);
 
         if (!sandboxed) {
             if (sPrivilegedChildConnectionAllocator == null) {
                 sPrivilegedChildConnectionAllocator = ChildConnectionAllocator.create(context,
-                        LauncherThread.getHandler(), creationParams, packageName,
-                        PRIVILEGED_SERVICES_NAME_KEY, NUM_PRIVILEGED_SERVICES_KEY,
-                        bindAsExternalService, true /* useStrongBinding */);
+                        LauncherThread.getHandler(), packageName, PRIVILEGED_SERVICES_NAME_KEY,
+                        NUM_PRIVILEGED_SERVICES_KEY, bindToCaller, bindAsExternalService,
+                        true /* useStrongBinding */);
             }
             return sPrivilegedChildConnectionAllocator;
         }
@@ -335,14 +340,14 @@
                 String serviceName = !TextUtils.isEmpty(sSandboxedServicesNameForTesting)
                         ? sSandboxedServicesNameForTesting
                         : SandboxedProcessService.class.getName();
-                connectionAllocator = ChildConnectionAllocator.createForTest(creationParams,
-                        packageName, serviceName, sSandboxedServicesCountForTesting,
+                connectionAllocator = ChildConnectionAllocator.createForTest(packageName,
+                        serviceName, sSandboxedServicesCountForTesting, bindToCaller,
                         bindAsExternalService, false /* useStrongBinding */);
             } else {
                 connectionAllocator = ChildConnectionAllocator.create(context,
-                        LauncherThread.getHandler(), creationParams, packageName,
-                        SANDBOXED_SERVICES_NAME_KEY, NUM_SANDBOXED_SERVICES_KEY,
-                        bindAsExternalService, false /* useStrongBinding */);
+                        LauncherThread.getHandler(), packageName, SANDBOXED_SERVICES_NAME_KEY,
+                        NUM_SANDBOXED_SERVICES_KEY, bindToCaller, bindAsExternalService,
+                        false /* useStrongBinding */);
             }
             if (sSandboxedServiceFactoryForTesting != null) {
                 connectionAllocator.setConnectionFactoryForTesting(
@@ -518,8 +523,11 @@
 
     private static Bundle populateServiceBundle(
             Bundle bundle, ChildProcessCreationParams creationParams) {
-        boolean bindToCallerCheck =
-                creationParams == null ? false : creationParams.getBindToCallerCheck();
+        boolean bindToCallerCheck = false;
+        if (creationParams != null) {
+            bindToCallerCheck = creationParams.getBindToCallerCheck();
+            creationParams.addIntentExtras(bundle);
+        }
         bundle.putBoolean(ChildProcessConstants.EXTRA_BIND_TO_CALLER, bindToCallerCheck);
         ChromiumLinkerParams linkerParams = getLinkerParamsForNewConnection();
         if (linkerParams != null) linkerParams.populateBundle(bundle);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java
index d868525..59ba40df 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java
@@ -28,7 +28,6 @@
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.process_launcher.ChildConnectionAllocator;
 import org.chromium.base.process_launcher.ChildProcessConnection;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.process_launcher.FileDescriptorInfo;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.test.ChildProcessAllocatorSettings;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java
index d1d5dcb..639af9f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java
@@ -17,7 +17,6 @@
 
 import org.chromium.base.process_launcher.ChildConnectionAllocator;
 import org.chromium.base.process_launcher.ChildProcessConnection;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
@@ -46,10 +45,9 @@
 
         @Override
         public ChildProcessConnection createConnection(Context context, ComponentName serviceName,
-                boolean bindAsExternalService, Bundle serviceBundle,
-                ChildProcessCreationParams creationParams) {
+                boolean bindToCaller, boolean bindAsExternalService, Bundle serviceBundle) {
             TestChildProcessConnection connection = new TestChildProcessConnection(
-                    context, serviceName, bindAsExternalService, serviceBundle, creationParams);
+                    context, serviceName, bindToCaller, bindAsExternalService, serviceBundle);
             mConnections.add(connection);
             return connection;
         }
@@ -63,10 +61,10 @@
         private RuntimeException mRemovedBothInitialAndStrongBinding;
 
         public TestChildProcessConnection(Context context, ComponentName serviceName,
-                boolean bindAsExternalService, Bundle childProcessCommonParameters,
-                ChildProcessCreationParams creationParams) {
-            super(context, serviceName, bindAsExternalService, childProcessCommonParameters,
-                    creationParams);
+                boolean bindToCaller, boolean bindAsExternalService,
+                Bundle childProcessCommonParameters) {
+            super(context, serviceName, bindToCaller, bindAsExternalService,
+                    childProcessCommonParameters);
         }
 
         @Override
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
index 35b6fd14..fede1e0 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
@@ -105,8 +105,8 @@
                         Context context =
                                 InstrumentationRegistry.getInstrumentation().getTargetContext();
                         return ChildConnectionAllocator.create(context, LauncherThread.getHandler(),
-                                null /* creationParams */, SERVICE_PACKAGE_NAME,
-                                SERVICE_NAME_META_DATA_KEY, SERVICE_COUNT_META_DATA_KEY,
+                                SERVICE_PACKAGE_NAME, SERVICE_NAME_META_DATA_KEY,
+                                SERVICE_COUNT_META_DATA_KEY, false /* bindToCaller */,
                                 false /* bindAsExternalService */, false /* useStrongBinding */);
                     }
                 });
@@ -334,9 +334,10 @@
                                 InstrumentationRegistry.getInstrumentation().getTargetContext();
                         ComponentName serviceName =
                                 new ComponentName(SERVICE_PACKAGE_NAME, SERVICE0_FULL_NAME);
-                        ChildProcessConnection connection = new ChildProcessConnection(context,
-                                serviceName, false /* bindAsExternalService */,
-                                new Bundle() /* serviceBundle */, null /* creationParams */);
+                        ChildProcessConnection connection =
+                                new ChildProcessConnection(context, serviceName,
+                                        false /* bindToCaller */, false /* bindAsExternalService */,
+                                        new Bundle() /* serviceBundle */);
                         connection.start(false /* useStrongBinding */,
                                 new ChildProcessConnection.ServiceCallback() {
                                     @Override
@@ -414,8 +415,8 @@
                             @Override
                             public ChildConnectionAllocator call() {
                                 return ChildConnectionAllocator.createForTest(
-                                        null /* creationParams */, "org.chromium.wrong_package",
-                                        "WrongService", 2 /* serviceCount */,
+                                        "org.chromium.wrong_package", "WrongService",
+                                        2 /* serviceCount */, false /* bindToCaller */,
                                         false /* bindAsExternalService */,
                                         false /* useStrongBinding */);
                             }
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 969b12c..29fc5fe 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
@@ -23,7 +23,6 @@
 import org.robolectric.shadows.ShadowLooper;
 
 import org.chromium.base.process_launcher.ChildProcessConnection;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.test.util.Feature;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
@@ -42,13 +41,10 @@
     // Creates a mocked ChildProcessConnection that is optionally added to a BindingManager.
     private static ChildProcessConnection createTestChildProcessConnection(
             int pid, BindingManager manager) {
-        String packageName = "org.chromium.test";
-        ChildProcessCreationParams creationParams =
-                new ChildProcessCreationParams(packageName, false /* isExternalService */,
-                        0 /* libraryProcessType */, false /* bindToCallerCheck */);
         TestChildProcessConnection connection = new TestChildProcessConnection(
-                new ComponentName(packageName, "TestService"), false /* bindAsExternalService */,
-                null /* serviceBundle */, creationParams);
+                new ComponentName("org.chromium.test", "TestService"),
+                false /* bindToCallerCheck */, false /* bindAsExternalService */,
+                null /* serviceBundle */);
         connection.setPid(pid);
         connection.start(false /* useStrongBinding */, null /* serviceCallback */,
                 false /* retryOnTimeout */);
diff --git a/content/public/android/junit/src/org/chromium/content/browser/ChildProcessConnectionTest.java b/content/public/android/junit/src/org/chromium/content/browser/ChildProcessConnectionTest.java
index ed85b1e..e0b9559 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/ChildProcessConnectionTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/ChildProcessConnectionTest.java
@@ -36,8 +36,8 @@
         String packageName = "org.chromium.test";
         String serviceName = "TestService";
         return new TestChildProcessConnection(new ComponentName(packageName, serviceName),
-                false /* bindAsExternalService */, null /* serviceBundle */,
-                null /* creationParams */);
+                false /* bindToCaller */, false /* bindAsExternalService */,
+                null /* serviceBundle */);
     }
 
     @Test
diff --git a/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java b/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
index 01eca4f8..e89cc02 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
@@ -27,7 +27,6 @@
 
 import org.chromium.base.process_launcher.ChildConnectionAllocator;
 import org.chromium.base.process_launcher.ChildProcessConnection;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.test.util.Feature;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
@@ -40,9 +39,9 @@
 
     // A connection allocator not used to create connections.
     private final ChildConnectionAllocator mWrongConnectionAllocator =
-            ChildConnectionAllocator.createForTest(null /* creationParams */, "org.chromium.test",
-                    "TestServiceName", 3 /* serviceCount */, false /* bindAsExternalService */,
-                    false /* useStrongBinding */);
+            ChildConnectionAllocator.createForTest("org.chromium.test", "TestServiceName",
+                    3 /* serviceCount */, false /* bindToCaller */,
+                    false /* bindAsExternalService */, false /* useStrongBinding */);
 
     // The allocator used to allocate the actual connection.
     private ChildConnectionAllocator mConnectionAllocator;
@@ -53,12 +52,11 @@
 
         @Override
         public ChildProcessConnection createConnection(Context context, ComponentName serviceName,
-                boolean bindAsExternalService, Bundle serviceBundle,
-                ChildProcessCreationParams creationParams) {
+                boolean bindToCaller, boolean bindAsExternalService, Bundle serviceBundle) {
             // We expect to create only one connection in these tests.
             assert mConnection == null;
             mConnection = new TestChildProcessConnection(
-                    serviceName, bindAsExternalService, serviceBundle, creationParams);
+                    serviceName, bindToCaller, bindAsExternalService, serviceBundle);
             mConnection.setPostOnServiceConnected(false);
             return mConnection;
         }
@@ -78,12 +76,6 @@
 
     private final TestConnectionFactory mTestConnectionFactory = new TestConnectionFactory();
 
-    // For some reason creating ChildProcessCreationParams from a static context makes the launcher
-    // unhappy. (some Dalvik native library is not found when initializing a SparseArray)
-    private final ChildProcessCreationParams mCreationParams = new ChildProcessCreationParams(
-            "org.chromium.test,.spare_connection", true /* isExternalService */,
-            0 /* libraryProcessType */, true /* bindToCallerCheck */);
-
     private SpareChildConnection mSpareConnection;
 
     @Before
@@ -94,10 +86,10 @@
         // asserts are not triggered.
         LauncherThread.setCurrentThreadAsLauncherThread();
 
-        mConnectionAllocator = ChildConnectionAllocator.createForTest(mCreationParams,
-                mCreationParams.getPackageNameForSandboxedService(), "TestServiceName",
-                5 /* serviceCount */, false /* bindAsExternalService */,
-                false /* useStrongBinding */);
+        mConnectionAllocator =
+                ChildConnectionAllocator.createForTest("org.chromium.test.spare_connection",
+                        "TestServiceName", 5 /* serviceCount */, false /* bindToCaller */,
+                        false /* bindAsExternalService */, false /* useStrongBinding */);
         mConnectionAllocator.setConnectionFactoryForTesting(mTestConnectionFactory);
         mSpareConnection = new SpareChildConnection(
                 null /* context */, mConnectionAllocator, null /* serviceBundle */);
diff --git a/content/public/android/junit/src/org/chromium/content/browser/TestChildProcessConnection.java b/content/public/android/junit/src/org/chromium/content/browser/TestChildProcessConnection.java
index 2f7baa8c..2f925e9 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/TestChildProcessConnection.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/TestChildProcessConnection.java
@@ -9,7 +9,6 @@
 import android.os.IBinder;
 
 import org.chromium.base.process_launcher.ChildProcessConnection;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.process_launcher.ICallbackInt;
 import org.chromium.base.process_launcher.IChildProcessService;
 
@@ -74,10 +73,9 @@
      * Creates a mock binding corresponding to real ManagedChildProcessConnection after the
      * connection is established: with initial binding bound and no strong binding.
      */
-    TestChildProcessConnection(ComponentName serviceName, boolean bindAsExternalService,
-            Bundle serviceBundle, ChildProcessCreationParams creationParams) {
-        super(null /* context */, serviceName, bindAsExternalService, serviceBundle,
-                creationParams);
+    TestChildProcessConnection(ComponentName serviceName, boolean bindToCaller,
+            boolean bindAsExternalService, Bundle serviceBundle) {
+        super(null /* context */, serviceName, bindToCaller, bindAsExternalService, serviceBundle);
         mPostOnServiceConnected = true;
     }
 
diff --git a/content/public/browser/download_manager.h b/content/public/browser/download_manager.h
index f6080fe5..eecfe7a 100644
--- a/content/public/browser/download_manager.h
+++ b/content/public/browser/download_manager.h
@@ -80,10 +80,6 @@
     virtual void OnDownloadCreated(
         DownloadManager* manager, DownloadItem* item) {}
 
-    // A SavePackage has successfully finished.
-    virtual void OnSavePackageSuccessfullyFinished(
-        DownloadManager* manager, DownloadItem* item) {}
-
     // Called when the download manager has finished loading the data.
     virtual void OnManagerInitialized() {}
 
diff --git a/content/public/browser/indexed_db_context.h b/content/public/browser/indexed_db_context.h
index ef9d61f4..61a9146 100644
--- a/content/public/browser/indexed_db_context.h
+++ b/content/public/browser/indexed_db_context.h
@@ -44,9 +44,8 @@
   virtual base::FilePath GetFilePathForTesting(
       const GURL& origin_url) const = 0;
 
-  // Set the task runner for tests if browser main loop is not initialized.
-  virtual void SetTaskRunnerForTesting(
-      base::SequencedTaskRunner* task_runner) = 0;
+  // Forget the origins/sizes read from disk.
+  virtual void ResetCachesForTesting() = 0;
 
  protected:
   friend class base::RefCountedThreadSafe<IndexedDBContext>;
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 0a44d0aa..e42a39f9 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -378,14 +378,6 @@
   virtual bool IsUnused() = 0;
   virtual void SetIsUsed() = 0;
 
-  // Return true if the host has not been used. This is stronger than IsUnused()
-  // in that it checks if this RPH has ever been used to render at all, rather
-  // than just no being suitable to host a URL that requires a dedicated
-  // process.
-  // TODO(alexmos): can this be unified with IsUnused()? See also
-  // crbug.com/738634.
-  virtual bool HostHasNotBeenUsed() = 0;
-
   // Returns the current number of active views in this process.  Excludes
   // any RenderViewHosts that are swapped out.
   size_t GetActiveViewCount();
@@ -399,23 +391,6 @@
 
   // Static management functions -----------------------------------------------
 
-  // Possibly start an unbound, spare RenderProcessHost. A subsequent creation
-  // of a RenderProcessHost with a matching browser_context may use this
-  // preinitialized RenderProcessHost, improving performance.
-  //
-  // It is safe to call this multiple times or when it is not certain that the
-  // spare renderer will be used, although calling this too eagerly may reduce
-  // performance as unnecessary RenderProcessHosts are created. The spare
-  // renderer will only be used if it using the default StoragePartition of a
-  // matching BrowserContext.
-  //
-  // The spare RenderProcessHost is meant to be created in a situation where a
-  // navigation is imminent and it is unlikely an existing RenderProcessHost
-  // will be used, for example in a cross-site navigation when a Service Worker
-  // will need to be started.
-  static void WarmupSpareRenderProcessHost(
-      content::BrowserContext* browser_context);
-
   // Flag to run the renderer in process.  This is primarily
   // for debugging purposes.  When running "in process", the
   // browser maintains a single RenderProcessHost which communicates
diff --git a/content/public/browser/service_worker_context.h b/content/public/browser/service_worker_context.h
index 5a105ad..1371beb 100644
--- a/content/public/browser/service_worker_context.h
+++ b/content/public/browser/service_worker_context.h
@@ -22,19 +22,22 @@
   SERVICE_WORKER_WITH_FETCH_HANDLER,
 };
 
+// Used for UMA. Append only.
 enum class StartServiceWorkerForNavigationHintResult {
   // The service worker started successfully.
-  STARTED,
+  STARTED = 0,
   // The service worker was already running.
-  ALREADY_RUNNING,
+  ALREADY_RUNNING = 1,
   // There was no service worker registration for the given URL.
-  NO_SERVICE_WORKER_REGISTRATION,
+  NO_SERVICE_WORKER_REGISTRATION = 2,
   // There was no active service worker for the given URL.
-  NO_ACTIVE_SERVICE_WORKER_VERSION,
+  NO_ACTIVE_SERVICE_WORKER_VERSION = 3,
   // The service worker for the given URL had no fetch event handler.
-  NO_FETCH_HANDLER,
+  NO_FETCH_HANDLER = 4,
   // Something failed.
-  FAILED,
+  FAILED = 5,
+  // Add new result to record here.
+  NUM_TYPES
 };
 
 // Represents the per-StoragePartition ServiceWorker data.
diff --git a/content/public/test/download_test_observer.cc b/content/public/test/download_test_observer.cc
index bf3b158..9262642 100644
--- a/content/public/test/download_test_observer.cc
+++ b/content/public/test/download_test_observer.cc
@@ -452,4 +452,44 @@
       &DownloadTestItemCreationObserver::DownloadItemCreationCallback, this);
 }
 
+SavePackageFinishedObserver::SavePackageFinishedObserver(
+    DownloadManager* manager,
+    const base::Closure& callback)
+    : download_manager_(manager), download_(nullptr), callback_(callback) {
+  download_manager_->AddObserver(this);
+}
+
+SavePackageFinishedObserver::~SavePackageFinishedObserver() {
+  if (download_manager_)
+    download_manager_->RemoveObserver(this);
+
+  if (download_)
+    download_->RemoveObserver(this);
+}
+
+void SavePackageFinishedObserver::OnDownloadUpdated(DownloadItem* download) {
+  if (download->GetState() == DownloadItem::COMPLETE ||
+      download->GetState() == DownloadItem::CANCELLED) {
+    callback_.Run();
+  }
+}
+
+void SavePackageFinishedObserver::OnDownloadDestroyed(DownloadItem* download) {
+  download_->RemoveObserver(this);
+  download_ = NULL;
+}
+
+void SavePackageFinishedObserver::OnDownloadCreated(DownloadManager* manager,
+                                                    DownloadItem* download) {
+  download_ = download;
+  download->AddObserver(this);
+}
+
+void SavePackageFinishedObserver::ManagerGoingDown(DownloadManager* manager) {
+  download_->RemoveObserver(this);
+  download_ = NULL;
+  download_manager_->RemoveObserver(this);
+  download_manager_ = NULL;
+}
+
 }  // namespace content
diff --git a/content/public/test/download_test_observer.h b/content/public/test/download_test_observer.h
index c7e209588..1e87631 100644
--- a/content/public/test/download_test_observer.h
+++ b/content/public/test/download_test_observer.h
@@ -311,6 +311,31 @@
   DISALLOW_COPY_AND_ASSIGN(DownloadTestItemCreationObserver);
 };
 
+// Class for mornitoring whether a save package download finishes.
+class SavePackageFinishedObserver : public DownloadItem::Observer,
+                                    public DownloadManager::Observer {
+ public:
+  SavePackageFinishedObserver(DownloadManager* manager,
+                              const base::Closure& callback);
+  ~SavePackageFinishedObserver() override;
+
+  // DownloadItem::Observer:
+  void OnDownloadUpdated(DownloadItem* download) override;
+  void OnDownloadDestroyed(DownloadItem* download) override;
+
+  // DownloadManager::Observer:
+  void OnDownloadCreated(DownloadManager* manager,
+                         DownloadItem* download) override;
+  void ManagerGoingDown(DownloadManager* manager) override;
+
+ private:
+  DownloadManager* download_manager_;
+  DownloadItem* download_;
+  base::Closure callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(SavePackageFinishedObserver);
+};
+
 }  // namespace content`
 
 #endif  // CONTENT_PUBLIC_TEST_DOWNLOAD_TEST_OBSERVER_H_
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index c82fac6..efabfce4 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -367,10 +367,6 @@
   is_unused_ = false;
 }
 
-bool MockRenderProcessHost::HostHasNotBeenUsed() {
-  return IsUnused() && listeners_.IsEmpty() && GetWorkerRefCount() == 0;
-}
-
 void MockRenderProcessHost::FilterURL(bool empty_allowed, GURL* url) {
   RenderProcessHostImpl::FilterURL(this, empty_allowed, url);
 }
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 1a318ca..f2802c9 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -131,8 +131,6 @@
   bool IsUnused() override;
   void SetIsUsed() override;
 
-  bool HostHasNotBeenUsed() override;
-
   // IPC::Sender via RenderProcessHost.
   bool Send(IPC::Message* msg) override;
 
@@ -202,11 +200,6 @@
   // to remove it from |processes_| to prevent it from being deleted twice.
   void Remove(MockRenderProcessHost* host) const;
 
-  // Retrieve the current list of mock processes.
-  std::vector<std::unique_ptr<MockRenderProcessHost>>* GetProcesses() {
-    return &processes_;
-  }
-
  private:
   // A list of MockRenderProcessHosts created by this object. This list is used
   // for deleting all MockRenderProcessHosts that have not deleted by a test in
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index bc52c78..fd3e94b 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -438,7 +438,6 @@
     "//cc/ipc",
     "//cc/paint",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
     "//cc/surfaces:surfaces",
     "//components/discardable_memory/client",
     "//components/metrics",
@@ -446,6 +445,7 @@
     "//components/url_formatter",
     "//components/variations",
     "//components/viz/client",
+    "//components/viz/common",
     "//components/viz/service",
     "//content:resources",
     "//content/child",
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index 09231e2..3ff4c7d 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -127,7 +127,7 @@
 void BrowserPlugin::OnSetChildFrameSurface(
     int browser_plugin_instance_id,
     const viz::SurfaceInfo& surface_info,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   if (!attached())
     return;
 
@@ -136,7 +136,7 @@
   compositing_helper_->OnSetSurface(surface_info, sequence);
 }
 
-void BrowserPlugin::SendSatisfySequence(const cc::SurfaceSequence& sequence) {
+void BrowserPlugin::SendSatisfySequence(const viz::SurfaceSequence& sequence) {
   BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SatisfySequence(
       render_frame_routing_id_, browser_plugin_instance_id_, sequence));
 }
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index 5a9f099..637002e8 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -19,12 +19,9 @@
 #include "third_party/WebKit/public/web/WebInputMethodController.h"
 #include "third_party/WebKit/public/web/WebNode.h"
 
-namespace cc {
-struct SurfaceSequence;
-}
-
 namespace viz {
 class SurfaceInfo;
+struct SurfaceSequence;
 }
 
 namespace content {
@@ -63,7 +60,7 @@
   void EnableCompositing(bool enable);
 
   // Called by CompositingHelper to send current SurfaceSequence to browser.
-  void SendSatisfySequence(const cc::SurfaceSequence& sequence);
+  void SendSatisfySequence(const viz::SurfaceSequence& sequence);
 
   // Provided that a guest instance ID has been allocated, this method attaches
   // this BrowserPlugin instance to that guest.
@@ -161,7 +158,7 @@
   void OnGuestReady(int instance_id);
   void OnSetChildFrameSurface(int instance_id,
                               const viz::SurfaceInfo& surface_info,
-                              const cc::SurfaceSequence& sequence);
+                              const viz::SurfaceSequence& sequence);
   void OnSetContentsOpaque(int instance_id, bool opaque);
   void OnSetCursor(int instance_id, const WebCursor& cursor);
   void OnSetMouseLock(int instance_id, bool enable);
diff --git a/content/renderer/child_frame_compositing_helper.cc b/content/renderer/child_frame_compositing_helper.cc
index aade80d..3192c99e 100644
--- a/content/renderer/child_frame_compositing_helper.cc
+++ b/content/renderer/child_frame_compositing_helper.cc
@@ -15,7 +15,7 @@
 #include "cc/output/copy_output_result.h"
 #include "cc/paint/paint_image.h"
 #include "cc/resources/single_release_callback.h"
-#include "cc/surfaces/sequence_surface_reference_factory.h"
+#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "content/child/thread_safe_sender.h"
 #include "content/common/browser_plugin/browser_plugin_messages.h"
 #include "content/common/content_switches_internal.h"
@@ -43,13 +43,13 @@
 namespace {
 
 class IframeSurfaceReferenceFactory
-    : public cc::SequenceSurfaceReferenceFactory {
+    : public viz::SequenceSurfaceReferenceFactory {
  public:
   IframeSurfaceReferenceFactory(scoped_refptr<ThreadSafeSender> sender,
                                 int routing_id)
       : sender_(std::move(sender)), routing_id_(routing_id) {}
 
-  void AddPendingSequence(const cc::SurfaceSequence& sequence) {
+  void AddPendingSequence(const viz::SurfaceSequence& sequence) {
     ReleasePendingSequenceIfNecessary();
     pending_sequence_ = sequence;
   }
@@ -63,13 +63,13 @@
     if (pending_sequence_.is_valid()) {
       sender_->Send(
           new FrameHostMsg_SatisfySequence(routing_id_, pending_sequence_));
-      pending_sequence_ = cc::SurfaceSequence();
+      pending_sequence_ = viz::SurfaceSequence();
     }
   }
 
   // cc::SequenceSurfaceReferenceFactory implementation:
   void RequireSequence(const viz::SurfaceId& surface_id,
-                       const cc::SurfaceSequence& sequence) const override {
+                       const viz::SurfaceSequence& sequence) const override {
     sender_->Send(
         new FrameHostMsg_RequireSequence(routing_id_, surface_id, sequence));
     // If there is a temporary reference that was waiting on a new one to be
@@ -77,19 +77,19 @@
     ReleasePendingSequenceIfNecessary();
   }
 
-  void SatisfySequence(const cc::SurfaceSequence& sequence) const override {
+  void SatisfySequence(const viz::SurfaceSequence& sequence) const override {
     sender_->Send(new FrameHostMsg_SatisfySequence(routing_id_, sequence));
   }
 
   const scoped_refptr<ThreadSafeSender> sender_;
-  mutable cc::SurfaceSequence pending_sequence_;
+  mutable viz::SurfaceSequence pending_sequence_;
   const int routing_id_;
 
   DISALLOW_COPY_AND_ASSIGN(IframeSurfaceReferenceFactory);
 };
 
 class BrowserPluginSurfaceReferenceFactory
-    : public cc::SequenceSurfaceReferenceFactory {
+    : public viz::SequenceSurfaceReferenceFactory {
  public:
   BrowserPluginSurfaceReferenceFactory(scoped_refptr<ThreadSafeSender> sender,
                                        int routing_id,
@@ -98,7 +98,7 @@
         routing_id_(routing_id),
         browser_plugin_instance_id_(browser_plugin_instance_id) {}
 
-  void AddPendingSequence(const cc::SurfaceSequence& sequence) {
+  void AddPendingSequence(const viz::SurfaceSequence& sequence) {
     ReleasePendingSequenceIfNecessary();
     pending_sequence_ = sequence;
   }
@@ -112,18 +112,18 @@
     if (pending_sequence_.is_valid()) {
       sender_->Send(new BrowserPluginHostMsg_SatisfySequence(
           routing_id_, browser_plugin_instance_id_, pending_sequence_));
-      pending_sequence_ = cc::SurfaceSequence();
+      pending_sequence_ = viz::SurfaceSequence();
     }
   }
 
   // cc::SequenceSurfaceRefrenceFactory implementation:
-  void SatisfySequence(const cc::SurfaceSequence& seq) const override {
+  void SatisfySequence(const viz::SurfaceSequence& seq) const override {
     sender_->Send(new BrowserPluginHostMsg_SatisfySequence(
         routing_id_, browser_plugin_instance_id_, seq));
   }
 
   void RequireSequence(const viz::SurfaceId& surface_id,
-                       const cc::SurfaceSequence& sequence) const override {
+                       const viz::SurfaceSequence& sequence) const override {
     sender_->Send(new BrowserPluginHostMsg_RequireSequence(
         routing_id_, browser_plugin_instance_id_, surface_id, sequence));
     // If there is a temporary reference that was waiting on a new one to be
@@ -132,7 +132,7 @@
   }
 
   const scoped_refptr<ThreadSafeSender> sender_;
-  mutable cc::SurfaceSequence pending_sequence_;
+  mutable viz::SurfaceSequence pending_sequence_;
   const int routing_id_;
   const int browser_plugin_instance_id_;
 
@@ -250,7 +250,7 @@
 
 void ChildFrameCompositingHelper::OnSetSurface(
     const viz::SurfaceInfo& surface_info,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   float scale_factor = surface_info.device_scale_factor();
   surface_id_ = surface_info.id();
   scoped_refptr<cc::SurfaceLayer> surface_layer =
diff --git a/content/renderer/child_frame_compositing_helper.h b/content/renderer/child_frame_compositing_helper.h
index f324159..5f94c2c7 100644
--- a/content/renderer/child_frame_compositing_helper.h
+++ b/content/renderer/child_frame_compositing_helper.h
@@ -15,8 +15,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/shared_memory.h"
 #include "base/memory/weak_ptr.h"
-#include "cc/surfaces/surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
 #include "content/common/content_export.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -55,7 +55,7 @@
 
   void OnContainerDestroy();
   void OnSetSurface(const viz::SurfaceInfo& surface_info,
-                    const cc::SurfaceSequence& sequence);
+                    const viz::SurfaceSequence& sequence);
   void UpdateVisibility(bool);
   void ChildFrameGone();
 
@@ -95,7 +95,7 @@
   viz::SurfaceId surface_id_;
   blink::WebRemoteFrame* frame_;
 
-  scoped_refptr<cc::SurfaceReferenceFactory> surface_reference_factory_;
+  scoped_refptr<viz::SurfaceReferenceFactory> surface_reference_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ChildFrameCompositingHelper);
 };
diff --git a/content/renderer/input/input_event_filter.cc b/content/renderer/input/input_event_filter.cc
index 32ff75f03..1777365 100644
--- a/content/renderer/input/input_event_filter.cc
+++ b/content/renderer/input/input_event_filter.cc
@@ -130,6 +130,12 @@
   }
 }
 
+void InputEventFilter::SetWhiteListedTouchAction(int routing_id,
+                                                 cc::TouchAction touch_action) {
+  SendMessage(base::MakeUnique<InputHostMsg_SetWhiteListedTouchAction>(
+      routing_id, touch_action));
+}
+
 void InputEventFilter::OnFilterAdded(IPC::Channel* channel) {
   io_task_runner_ = base::ThreadTaskRunnerHandle::Get();
   sender_ = channel;
diff --git a/content/renderer/input/input_event_filter.h b/content/renderer/input/input_event_filter.h
index bd6e9432..bd366c4 100644
--- a/content/renderer/input/input_event_filter.h
+++ b/content/renderer/input/input_event_filter.h
@@ -77,6 +77,8 @@
       int routing_id,
       ui::WebScopedInputEvent event,
       const ui::LatencyInfo& latency_info) override;
+  void SetWhiteListedTouchAction(int routing_id,
+                                 cc::TouchAction touch_action) override;
 
   // IPC::MessageFilter methods:
   void OnFilterAdded(IPC::Channel* channel) override;
diff --git a/content/renderer/input/input_handler_manager.cc b/content/renderer/input/input_handler_manager.cc
index 05f5c06..1d17b4d 100644
--- a/content/renderer/input/input_handler_manager.cc
+++ b/content/renderer/input/input_handler_manager.cc
@@ -282,4 +282,10 @@
                                                 latency_info);
 }
 
+void InputHandlerManager::SetWhiteListedTouchAction(
+    int routing_id,
+    cc::TouchAction touch_action) {
+  client_->SetWhiteListedTouchAction(routing_id, touch_action);
+}
+
 }  // namespace content
diff --git a/content/renderer/input/input_handler_manager.h b/content/renderer/input/input_handler_manager.h
index ac9017b9..5f42198 100644
--- a/content/renderer/input/input_handler_manager.h
+++ b/content/renderer/input/input_handler_manager.h
@@ -112,6 +112,9 @@
       ui::WebScopedInputEvent event,
       const ui::LatencyInfo& latency_info);
 
+  // Called from the compositor's thread.
+  void SetWhiteListedTouchAction(int routing_id, cc::TouchAction touch_action);
+
  private:
   // Called from the compositor's thread.
   void AddInputHandlerOnCompositorThread(
diff --git a/content/renderer/input/input_handler_manager_client.h b/content/renderer/input/input_handler_manager_client.h
index ab1aebc..4c43c9a 100644
--- a/content/renderer/input/input_handler_manager_client.h
+++ b/content/renderer/input/input_handler_manager_client.h
@@ -8,6 +8,7 @@
 #include "base/callback.h"
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "cc/input/touch_action.h"
 #include "content/common/content_export.h"
 #include "content/common/input/input_event_ack_state.h"
 #include "third_party/WebKit/public/platform/WebInputEventResult.h"
@@ -53,6 +54,8 @@
       int routing_id,
       ui::WebScopedInputEvent event,
       const ui::LatencyInfo& latency_info) = 0;
+  virtual void SetWhiteListedTouchAction(int routing_id,
+                                         cc::TouchAction touch_action) = 0;
 
  protected:
   InputHandlerManagerClient() {}
diff --git a/content/renderer/input/input_handler_wrapper.cc b/content/renderer/input/input_handler_wrapper.cc
index 1605e40..bbe43cd 100644
--- a/content/renderer/input/input_handler_wrapper.cc
+++ b/content/renderer/input/input_handler_wrapper.cc
@@ -109,4 +109,9 @@
       ui::WebInputEventTraits::Clone(scroll_begin), ui::LatencyInfo());
 }
 
+void InputHandlerWrapper::SetWhiteListedTouchAction(
+    cc::TouchAction touch_action) {
+  input_handler_manager_->SetWhiteListedTouchAction(routing_id_, touch_action);
+}
+
 }  // namespace content
diff --git a/content/renderer/input/input_handler_wrapper.h b/content/renderer/input/input_handler_wrapper.h
index 178df26..3488039 100644
--- a/content/renderer/input/input_handler_wrapper.h
+++ b/content/renderer/input/input_handler_wrapper.h
@@ -57,6 +57,7 @@
   void DidAnimateForInput() override;
   void GenerateScrollBeginAndSendToMainThread(
       const blink::WebGestureEvent& update_event) override;
+  void SetWhiteListedTouchAction(cc::TouchAction touch_action) override;
 
  private:
   InputHandlerManager* input_handler_manager_;
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index a99aea8..7395813 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -326,7 +326,7 @@
 
 void RenderFrameProxy::OnSetChildFrameSurface(
     const viz::SurfaceInfo& surface_info,
-    const cc::SurfaceSequence& sequence) {
+    const viz::SurfaceSequence& sequence) {
   // If this WebFrame has already been detached, its parent will be null. This
   // can happen when swapping a WebRemoteFrame with a WebLocalFrame, where this
   // message may arrive after the frame was removed from the frame tree, but
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index bc7ef2a6..d6dc03c 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -21,12 +21,9 @@
 struct WebRect;
 }
 
-namespace cc {
-struct SurfaceSequence;
-}
-
 namespace viz {
 class SurfaceInfo;
+struct SurfaceSequence;
 }
 
 namespace content {
@@ -168,7 +165,7 @@
   void OnChildFrameProcessGone();
   void OnCompositorFrameSwapped(const IPC::Message& message);
   void OnSetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                              const cc::SurfaceSequence& sequence);
+                              const viz::SurfaceSequence& sequence);
   void OnUpdateOpener(int opener_routing_id);
   void OnDidStopLoading();
   void OnDidUpdateFramePolicy(
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java
index 152b48a..117a31b 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestHelperService.java
@@ -19,8 +19,8 @@
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.process_launcher.ChildProcessConnection;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.process_launcher.FileDescriptorInfo;
+import org.chromium.content.browser.ChildProcessCreationParams;
 import org.chromium.content.browser.ChildProcessLauncherHelper;
 
 /**
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestUtils.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestUtils.java
index 54f196f1..0998e19 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestUtils.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ChildProcessLauncherTestUtils.java
@@ -5,9 +5,9 @@
 package org.chromium.content_shell_apk;
 
 import org.chromium.base.process_launcher.ChildProcessConnection;
-import org.chromium.base.process_launcher.ChildProcessCreationParams;
 import org.chromium.base.process_launcher.FileDescriptorInfo;
 import org.chromium.base.process_launcher.IChildProcessService;
+import org.chromium.content.browser.ChildProcessCreationParams;
 import org.chromium.content.browser.ChildProcessLauncherHelper;
 import org.chromium.content.browser.LauncherThread;
 
diff --git a/device/bluetooth/dbus/bluetooth_device_client.cc b/device/bluetooth/dbus/bluetooth_device_client.cc
index 142a72b..c79cba4 100644
--- a/device/bluetooth/dbus/bluetooth_device_client.cc
+++ b/device/bluetooth/dbus/bluetooth_device_client.cc
@@ -444,11 +444,9 @@
       return;
     }
 
-    // TODO(crbug.com/725367): Use constants in cros_system_api once it is
-    // rolled.
     dbus::MethodCall method_call(
         bluetooth_plugin_device::kBluetoothPluginInterface,
-        "SetLEConnectionParameters");
+        bluetooth_plugin_device::kSetLEConnectionParameters);
 
     dbus::MessageWriter writer(&method_call);
     dbus::MessageWriter dict_writer(nullptr);
@@ -457,7 +455,9 @@
     {
       dbus::MessageWriter dict_entry_writer(nullptr);
       dict_writer.OpenDictEntry(&dict_entry_writer);
-      dict_entry_writer.AppendString("MinimumConnectionInterval");
+      dict_entry_writer.AppendString(
+          bluetooth_plugin_device::
+              kLEConnectionParameterMinimumConnectionInterval);
       dict_entry_writer.AppendUint16(conn_params.min_connection_interval);
       dict_writer.CloseContainer(&dict_entry_writer);
     }
@@ -465,7 +465,9 @@
     {
       dbus::MessageWriter dict_entry_writer(nullptr);
       dict_writer.OpenDictEntry(&dict_entry_writer);
-      dict_entry_writer.AppendString("MaximumConnectionInterval");
+      dict_entry_writer.AppendString(
+          bluetooth_plugin_device::
+              kLEConnectionParameterMaximumConnectionInterval);
       dict_entry_writer.AppendUint16(conn_params.max_connection_interval);
       dict_writer.CloseContainer(&dict_entry_writer);
     }
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 17301128..8a69dd9 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -589,6 +589,8 @@
   if (is_chromeos) {
     sources += [
       "api/audio/audio_device_id_calculator_unittest.cc",
+      "api/lock_screen_data/data_item_unittest.cc",
+      "api/lock_screen_data/lock_screen_item_storage_unittest.cc",
       "api/media_perception_private/conversion_utils_unittest.cc",
       "api/media_perception_private/media_perception_api_manager_unittest.cc",
       "api/webcam_private/visca_webcam_unittest.cc",
diff --git a/extensions/browser/api/BUILD.gn b/extensions/browser/api/BUILD.gn
index 700a17c0..f2a23a15 100644
--- a/extensions/browser/api/BUILD.gn
+++ b/extensions/browser/api/BUILD.gn
@@ -109,8 +109,13 @@
 
   if (is_chromeos) {
     sources += [
+      "lock_screen_data/data_item.cc",
+      "lock_screen_data/data_item.h",
       "lock_screen_data/lock_screen_data_api.cc",
       "lock_screen_data/lock_screen_data_api.h",
+      "lock_screen_data/lock_screen_item_storage.cc",
+      "lock_screen_data/lock_screen_item_storage.h",
+      "lock_screen_data/operation_result.h",
       "media_perception_private/conversion_utils.cc",
       "media_perception_private/conversion_utils.h",
       "media_perception_private/media_perception_api_manager.cc",
diff --git a/extensions/browser/api/execute_code_function.cc b/extensions/browser/api/execute_code_function.cc
index 0f2dd5f..bf04871e 100644
--- a/extensions/browser/api/execute_code_function.cc
+++ b/extensions/browser/api/execute_code_function.cc
@@ -7,6 +7,8 @@
 
 #include "extensions/browser/api/execute_code_function.h"
 
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_restrictions.h"
 #include "extensions/browser/component_extension_resource_manager.h"
 #include "extensions/browser/extension_api_frame_id_map.h"
 #include "extensions/browser/extensions_browser_client.h"
@@ -42,14 +44,17 @@
 ExecuteCodeFunction::~ExecuteCodeFunction() {
 }
 
-void ExecuteCodeFunction::GetFileURLAndMaybeLocalizeOnFileThread(
+void ExecuteCodeFunction::GetFileURLAndMaybeLocalizeInBackground(
     const std::string& extension_id,
     const base::FilePath& extension_path,
     const std::string& extension_default_locale,
     bool might_require_localization,
     std::string* data) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
+  // TODO(devlin): FilePathToFileURL() doesn't need to be done on a blocking
+  // task runner, so we could do that on the UI thread and then avoid the hop
+  // if we don't need localization.
   file_url_ = net::FilePathToFileURL(resource_.GetFilePath());
 
   if (!might_require_localization)
@@ -69,23 +74,19 @@
                                                        data, &error);
 }
 
-void ExecuteCodeFunction::GetFileURLAndLocalizeComponentResourceOnFileThread(
+std::unique_ptr<std::string>
+ExecuteCodeFunction::GetFileURLAndLocalizeComponentResourceInBackground(
     std::unique_ptr<std::string> data,
     const std::string& extension_id,
     const base::FilePath& extension_path,
     const std::string& extension_default_locale,
     bool might_require_localization) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
-  GetFileURLAndMaybeLocalizeOnFileThread(
+  base::ThreadRestrictions::AssertIOAllowed();
+  GetFileURLAndMaybeLocalizeInBackground(
       extension_id, extension_path, extension_default_locale,
       might_require_localization, data.get());
 
-  bool success = true;
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this,
-                 resource_.relative_path().AsUTF8Unsafe(), success,
-                 base::Passed(std::move(data))));
+  return data;
 }
 
 void ExecuteCodeFunction::DidLoadAndLocalizeFile(
@@ -223,16 +224,21 @@
         ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id);
     std::unique_ptr<std::string> data(
         new std::string(resource.data(), resource.size()));
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::Bind(&ExecuteCodeFunction::
-                       GetFileURLAndLocalizeComponentResourceOnFileThread,
-                   this, base::Passed(std::move(data)), extension_id,
-                   extension_path, extension_default_locale,
-                   might_require_localization));
+
+    base::PostTaskWithTraitsAndReplyWithResult(
+        FROM_HERE,
+        {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+        base::BindOnce(&ExecuteCodeFunction::
+                           GetFileURLAndLocalizeComponentResourceInBackground,
+                       this, base::Passed(std::move(data)), extension_id,
+                       extension_path, extension_default_locale,
+                       might_require_localization),
+        base::BindOnce(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this,
+                       resource_.relative_path().AsUTF8Unsafe(),
+                       true /* We assume this call always succeeds */));
   } else {
     FileReader::OptionalFileThreadTaskCallback get_file_and_l10n_callback =
-        base::Bind(&ExecuteCodeFunction::GetFileURLAndMaybeLocalizeOnFileThread,
+        base::Bind(&ExecuteCodeFunction::GetFileURLAndMaybeLocalizeInBackground,
                    this, extension_id, extension_path, extension_default_locale,
                    might_require_localization);
 
diff --git a/extensions/browser/api/execute_code_function.h b/extensions/browser/api/execute_code_function.h
index 13df3dd..330668f 100644
--- a/extensions/browser/api/execute_code_function.h
+++ b/extensions/browser/api/execute_code_function.h
@@ -84,7 +84,7 @@
   // localizes |data|.
   // Localization depends on whether |might_require_localization| was specified.
   // Only CSS file content needs to be localized.
-  void GetFileURLAndMaybeLocalizeOnFileThread(
+  void GetFileURLAndMaybeLocalizeInBackground(
       const std::string& extension_id,
       const base::FilePath& extension_path,
       const std::string& extension_default_locale,
@@ -93,9 +93,10 @@
 
   // Retrieves the file url for the given |extension_path| and optionally
   // localizes |data|.
-  // Similar to GetFileURLAndMaybeLocalizeOnFileThread, but only applies to
-  // component extension resource.
-  void GetFileURLAndLocalizeComponentResourceOnFileThread(
+  // Similar to GetFileURLAndMaybeLocalizeInBackground, but only applies
+  // to component extension resource.
+  std::unique_ptr<std::string>
+  GetFileURLAndLocalizeComponentResourceInBackground(
       std::unique_ptr<std::string> data,
       const std::string& extension_id,
       const base::FilePath& extension_path,
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index 764233d..f2e2790 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -108,6 +108,10 @@
   return nullptr;
 }
 
+FileSystemDelegate* ExtensionsAPIClient::GetFileSystemDelegate() {
+  return nullptr;
+}
+
 #if defined(OS_CHROMEOS)
 NonNativeFileSystemDelegate*
 ExtensionsAPIClient::GetNonNativeFileSystemDelegate() {
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index e629818b..3aff94b 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -35,6 +35,7 @@
 class DevicePermissionsPrompt;
 class ExtensionOptionsGuest;
 class ExtensionOptionsGuestDelegate;
+class FileSystemDelegate;
 class ManagementAPIDelegate;
 class MetricsPrivateDelegate;
 class MimeHandlerViewGuest;
@@ -137,6 +138,9 @@
   // Creates a delegate for networking.castPrivate's API behavior.
   virtual NetworkingCastPrivateDelegate* GetNetworkingCastPrivateDelegate();
 
+  // Returns a delegate for embedder-specific chrome.fileSystem behavior.
+  virtual FileSystemDelegate* GetFileSystemDelegate();
+
 #if defined(OS_CHROMEOS)
   // If supported by the embedder, returns a delegate for querying non-native
   // file systems.
diff --git a/extensions/browser/api/file_system/BUILD.gn b/extensions/browser/api/file_system/BUILD.gn
index 0e5fa0b..a352c48 100644
--- a/extensions/browser/api/file_system/BUILD.gn
+++ b/extensions/browser/api/file_system/BUILD.gn
@@ -9,12 +9,28 @@
 
 source_set("file_system") {
   sources = [
+    "file_system_api.cc",
+    "file_system_api.h",
+    "file_system_delegate.h",
     "saved_file_entry.cc",
     "saved_file_entry.h",
     "saved_files_service_interface.h",
   ]
 
   deps = [
-    "//base:base",
+    "//base",
+    "//content/public/browser",
+    "//extensions/browser/api/file_handlers",
+    "//extensions/common",
+    "//extensions/common/api",
+    "//net",
+    "//storage/browser",
+    "//storage/common",
+    "//ui/base",
+    "//ui/shell_dialogs",
+  ]
+
+  public_deps = [
+    "//extensions/browser:browser_sources",
   ]
 }
diff --git a/extensions/browser/api/file_system/DEPS b/extensions/browser/api/file_system/DEPS
new file mode 100644
index 0000000..00478bd4
--- /dev/null
+++ b/extensions/browser/api/file_system/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+ui/shell_dialogs",
+]
diff --git a/extensions/browser/api/file_system/OWNERS b/extensions/browser/api/file_system/OWNERS
new file mode 100644
index 0000000..ac81da7
--- /dev/null
+++ b/extensions/browser/api/file_system/OWNERS
@@ -0,0 +1,3 @@
+benwells@chromium.org
+mtomasz@chromium.org
+sammc@chromium.org
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/extensions/browser/api/file_system/file_system_api.cc
similarity index 66%
rename from chrome/browser/extensions/api/file_system/file_system_api.cc
rename to extensions/browser/api/file_system/file_system_api.cc
index 58f4803..5c4395f 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/extensions/browser/api/file_system/file_system_api.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
+#include "extensions/browser/api/file_system/file_system_api.h"
 
 #include <stddef.h>
 
@@ -11,58 +11,53 @@
 #include <utility>
 #include <vector>
 
-#include "apps/saved_files_service.h"
 #include "base/bind.h"
-#include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
+#include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/value_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/extensions/api/file_system/file_entry_picker.h"
-#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/apps/directory_access_confirmation_dialog.h"
-#include "chrome/browser/ui/chrome_select_file_policy.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/api/file_system.h"
-#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/api/file_handlers/app_file_handler_util.h"
+#include "extensions/browser/api/file_system/file_system_delegate.h"
 #include "extensions/browser/api/file_system/saved_file_entry.h"
+#include "extensions/browser/api/file_system/saved_files_service_interface.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_system.h"
 #include "extensions/browser/extension_util.h"
 #include "extensions/browser/granted_file_entry.h"
 #include "extensions/browser/path_util.h"
+#include "extensions/common/api/file_system.h"
 #include "extensions/common/permissions/api_permission.h"
 #include "extensions/common/permissions/permissions_data.h"
 #include "net/base/mime_util.h"
 #include "storage/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/fileapi/file_system_operation_runner.h"
 #include "storage/browser/fileapi/isolated_context.h"
 #include "storage/common/fileapi/file_system_types.h"
 #include "storage/common/fileapi/file_system_util.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/ui_base_types.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
-#include "ui/shell_dialogs/select_file_policy.h"
 
 #if defined(OS_MACOSX)
 #include <CoreFoundation/CoreFoundation.h>
@@ -70,16 +65,9 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#include "base/strings/string16.h"
-#include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
-#include "chrome/browser/chromeos/file_manager/volume_manager.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/common/constants.h"
-#include "url/url_constants.h"
+#include "extensions/browser/api/file_handlers/non_native_file_system_delegate.h"
 #endif
 
-using apps::SavedFilesService;
 using storage::IsolatedContext;
 
 const char kInvalidCallingPage[] =
@@ -94,17 +82,13 @@
 const char kMultipleUnsupportedError[] =
     "acceptsMultiple: true is only supported for 'openFile'";
 const char kUnknownIdError[] = "Unknown id";
-
-#if !defined(OS_CHROMEOS)
 const char kNotSupportedOnCurrentPlatformError[] =
     "Operation not supported on the current platform.";
-#else
+const char kRetainEntryError[] = "Could not retain file entry.";
+
+#if defined(OS_CHROMEOS)
 const char kNotSupportedOnNonKioskSessionError[] =
     "Operation only supported for kiosk apps running in a kiosk session.";
-const char kVolumeNotFoundError[] = "Volume not found.";
-const char kSecurityError[] = "Security error.";
-const char kConsentImpossible[] =
-    "Impossible to ask for user consent as there is no app window visible.";
 #endif
 
 namespace extensions {
@@ -142,15 +126,15 @@
       if (inner.empty())
         continue;
 
-      if (valid_type)
+      if (valid_type) {
         description_id = 0;  // We already have an accept type with label; if
                              // we find another, give up and use the default.
-      else if (accept_type == "image/*")
-        description_id = IDS_IMAGE_FILES;
-      else if (accept_type == "audio/*")
-        description_id = IDS_AUDIO_FILES;
-      else if (accept_type == "video/*")
-        description_id = IDS_VIDEO_FILES;
+      } else {
+        FileSystemDelegate* delegate =
+            ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+        DCHECK(delegate);
+        description_id = delegate->GetDescriptionIdForAcceptType(accept_type);
+      }
 
       extension_set.insert(inner.begin(), inner.end());
       valid_type = true;
@@ -223,59 +207,6 @@
              : nullptr;
 }
 
-#if defined(OS_CHROMEOS)
-// Fills a list of volumes mounted in the system.
-void FillVolumeList(Profile* profile,
-                    std::vector<api::file_system::Volume>* result) {
-  file_manager::VolumeManager* const volume_manager =
-      file_manager::VolumeManager::Get(profile);
-  DCHECK(volume_manager);
-
-  const auto& volume_list = volume_manager->GetVolumeList();
-  // Convert volume_list to result_volume_list.
-  for (const auto& volume : volume_list) {
-    api::file_system::Volume result_volume;
-    result_volume.volume_id = volume->volume_id();
-    result_volume.writable = !volume->is_read_only();
-    result->push_back(std::move(result_volume));
-  }
-}
-#endif
-
-// Creates and shows a SelectFileDialog, or returns false if the dialog could
-// not be created.
-bool ShowSelectFileDialog(
-    scoped_refptr<UIThreadExtensionFunction> extension_function,
-    ui::SelectFileDialog::Type type,
-    const base::FilePath& default_path,
-    const ui::SelectFileDialog::FileTypeInfo* file_types,
-    FileEntryPicker::FilesSelectedCallback files_selected_callback,
-    base::OnceClosure file_selection_canceled_callback) {
-  // TODO(asargent/benwells) - As a short term remediation for
-  // crbug.com/179010 we're adding the ability for a whitelisted extension to
-  // use this API since chrome.fileBrowserHandler.selectFile is ChromeOS-only.
-  // Eventually we'd like a better solution and likely this code will go back
-  // to being platform-app only.
-  content::WebContents* const web_contents =
-      extension_function->extension()->is_platform_app()
-          ? GetWebContentsForRenderFrameHost(
-                extension_function->browser_context(),
-                extension_function->render_frame_host())
-          : extension_function->GetAssociatedWebContents();
-  if (!web_contents)
-    return false;
-
-  // The file picker will hold a reference to the UIThreadExtensionFunction
-  // instance, preventing its destruction (and subsequent sending of the
-  // function response) until the user has selected a file or cancelled the
-  // picker. At that point, the picker will delete itself, which will also free
-  // the function instance.
-  new FileEntryPicker(web_contents, default_path, *file_types, type,
-                      std::move(files_selected_callback),
-                      std::move(file_selection_canceled_callback));
-  return true;
-}
-
 }  // namespace
 
 namespace file_system_api {
@@ -298,40 +229,8 @@
                              base::CreateFilePathValue(path));
 }
 
-#if defined(OS_CHROMEOS)
-void DispatchVolumeListChangeEvent(Profile* profile) {
-  DCHECK(profile);
-  EventRouter* const event_router = EventRouter::Get(profile);
-  if (!event_router)  // Possible on shutdown.
-    return;
-
-  ExtensionRegistry* const registry = ExtensionRegistry::Get(profile);
-  if (!registry)  // Possible on shutdown.
-    return;
-
-  ConsentProviderDelegate consent_provider_delegate(profile, nullptr);
-  ConsentProvider consent_provider(&consent_provider_delegate);
-  api::file_system::VolumeListChangedEvent event_args;
-  FillVolumeList(profile, &event_args.volumes);
-  for (const auto& extension : registry->enabled_extensions()) {
-    if (!consent_provider.IsGrantable(*extension.get()))
-      continue;
-    event_router->DispatchEventToExtension(
-        extension->id(),
-        base::MakeUnique<Event>(
-            events::FILE_SYSTEM_ON_VOLUME_LIST_CHANGED,
-            api::file_system::OnVolumeListChanged::kEventName,
-            api::file_system::OnVolumeListChanged::Create(event_args)));
-  }
-}
-#endif
-
 }  // namespace file_system_api
 
-#if defined(OS_CHROMEOS)
-using file_system_api::ConsentProvider;
-#endif
-
 ExtensionFunction::ResponseAction FileSystemGetDisplayPathFunction::Run() {
   std::string filesystem_name;
   std::string filesystem_path;
@@ -365,7 +264,7 @@
       is_directory_ ? std::set<base::FilePath>(paths.begin(), paths.end())
                     : std::set<base::FilePath>{};
   app_file_handler_util::PrepareFilesForWritableApp(
-      paths, GetProfile(), path_directory_set_,
+      paths, browser_context(), path_directory_set_,
       base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse,
                  this, paths),
       base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this));
@@ -380,8 +279,7 @@
   std::unique_ptr<base::DictionaryValue> result = CreateResult();
   for (const auto& path : paths)
     AddEntryToResult(path, std::string(), result.get());
-  SetResult(std::move(result));
-  SendResponse(true);
+  Respond(OneArgument(std::move(result)));
 }
 
 std::unique_ptr<base::DictionaryValue> FileSystemEntryFunction::CreateResult() {
@@ -395,8 +293,8 @@
                                                const std::string& id_override,
                                                base::DictionaryValue* result) {
   GrantedFileEntry file_entry = app_file_handler_util::CreateFileEntry(
-      GetProfile(), extension(), render_frame_host()->GetProcess()->GetID(),
-      path, is_directory_);
+      browser_context(), extension(),
+      render_frame_host()->GetProcess()->GetID(), path, is_directory_);
   base::ListValue* entries;
   bool success = result->GetList("entries", &entries);
   DCHECK(success);
@@ -415,26 +313,26 @@
 void FileSystemEntryFunction::HandleWritableFileError(
     const base::FilePath& error_path) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  error_ = base::StringPrintf(kWritableFileErrorFormat,
-                              error_path.BaseName().AsUTF8Unsafe().c_str());
-  SendResponse(false);
+  Respond(Error(base::StringPrintf(
+      kWritableFileErrorFormat, error_path.BaseName().AsUTF8Unsafe().c_str())));
 }
 
-bool FileSystemGetWritableEntryFunction::RunAsync() {
+ExtensionFunction::ResponseAction FileSystemGetWritableEntryFunction::Run() {
   std::string filesystem_name;
   std::string filesystem_path;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name));
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path));
 
   if (!app_file_handler_util::HasFileSystemWritePermission(extension_.get())) {
-    error_ = kRequiresFileSystemWriteError;
-    return false;
+    return RespondNow(Error(kRequiresFileSystemWriteError));
   }
 
+  std::string error;
   if (!app_file_handler_util::ValidateFileEntryAndGetPath(
           filesystem_name, filesystem_path,
-          render_frame_host()->GetProcess()->GetID(), &path_, &error_))
-    return false;
+          render_frame_host()->GetProcess()->GetID(), &path_, &error)) {
+    return RespondNow(Error(error));
+  }
 
   base::PostTaskWithTraitsAndReply(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
@@ -443,15 +341,15 @@
       base::BindOnce(
           &FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse,
           this));
-  return true;
+  return RespondLater();
 }
 
 void FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (is_directory_ && !extension_->permissions_data()->HasAPIPermission(
                            APIPermission::kFileSystemDirectory)) {
-    error_ = kRequiresFileSystemDirectoryError;
-    SendResponse(false);
+    Respond(Error(kRequiresFileSystemDirectoryError));
+    return;
   }
   std::vector<base::FilePath> paths;
   paths.push_back(path_);
@@ -485,6 +383,8 @@
 void FileSystemChooseEntryFunction::ShowPicker(
     const ui::SelectFileDialog::FileTypeInfo& file_type_info,
     ui::SelectFileDialog::Type picker_type) {
+  // TODO(michaelpg): Use the FileSystemDelegate to override functionality for
+  // tests instead of using global variables.
   if (g_skip_picker_for_test) {
     std::vector<base::FilePath> test_paths;
     if (g_use_suggested_path_for_test)
@@ -504,17 +404,20 @@
     return;
   }
 
+  FileSystemDelegate* delegate =
+      ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+  DCHECK(delegate);
+
   // The callbacks passed to the dialog will retain references to this
   // UIThreadExtenisonFunction, preventing its destruction (and subsequent
   // sending of the function response) until the user has selected a file or
   // cancelled the picker.
-  if (!ShowSelectFileDialog(
+  if (!delegate->ShowSelectFileDialog(
           this, picker_type, initial_path_, &file_type_info,
           base::BindOnce(&FileSystemChooseEntryFunction::FilesSelected, this),
           base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled,
                          this))) {
-    error_ = kInvalidCallingPage;
-    SendResponse(false);
+    Respond(Error(kInvalidCallingPage));
   }
 }
 
@@ -527,6 +430,7 @@
   g_paths_to_be_picked_for_test = NULL;
 }
 
+// static
 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathsForTest(
     std::vector<base::FilePath>* paths) {
   g_skip_picker_for_test = true;
@@ -594,24 +498,25 @@
     last_choose_directory = paths[0].DirName();
   }
   file_system_api::SetLastChooseEntryDirectory(
-      ExtensionPrefs::Get(GetProfile()), extension()->id(),
+      ExtensionPrefs::Get(browser_context()), extension()->id(),
       last_choose_directory);
   if (is_directory_) {
     // Get the WebContents for the app window to be the parent window of the
     // confirmation dialog if necessary.
-    content::WebContents* const web_contents =
-        GetWebContentsForRenderFrameHost(GetProfile(), render_frame_host());
+    content::WebContents* const web_contents = GetWebContentsForRenderFrameHost(
+        browser_context(), render_frame_host());
     if (!web_contents) {
-      error_ = kInvalidCallingPage;
-      SendResponse(false);
+      Respond(Error(kInvalidCallingPage));
       return;
     }
 
     DCHECK_EQ(paths.size(), 1u);
     bool non_native_path = false;
 #if defined(OS_CHROMEOS)
-    non_native_path =
-        file_manager::util::IsUnderNonNativeLocalPath(GetProfile(), paths[0]);
+    NonNativeFileSystemDelegate* delegate =
+        ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate();
+    non_native_path = delegate && delegate->IsUnderNonNativeLocalPath(
+                                      browser_context(), paths[0]);
 #endif
 
     base::PostTaskWithTraits(
@@ -626,8 +531,7 @@
 }
 
 void FileSystemChooseEntryFunction::FileSelectionCanceled() {
-  error_ = kUserCancelled;
-  SendResponse(false);
+  Respond(Error(kUserCancelled));
 }
 
 void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync(
@@ -646,35 +550,27 @@
 
   for (size_t i = 0; i < arraysize(kGraylistedPaths); i++) {
     base::FilePath graylisted_path;
-    if (PathService::Get(kGraylistedPaths[i], &graylisted_path) &&
-        (check_path == graylisted_path ||
-         check_path.IsParent(graylisted_path))) {
-      if (g_skip_directory_confirmation_for_test) {
-        if (g_allow_directory_access_for_test) {
-          break;
-        } else {
-          content::BrowserThread::PostTask(
-              content::BrowserThread::UI, FROM_HERE,
-              base::BindOnce(
-                  &FileSystemChooseEntryFunction::FileSelectionCanceled, this));
-        }
-        return;
-      }
+    if (!PathService::Get(kGraylistedPaths[i], &graylisted_path))
+      continue;
+    if (check_path != graylisted_path && !check_path.IsParent(graylisted_path))
+      continue;
 
+    if (g_skip_directory_confirmation_for_test) {
+      if (g_allow_directory_access_for_test)
+        break;
       content::BrowserThread::PostTask(
           content::BrowserThread::UI, FROM_HERE,
-          base::BindOnce(
-              CreateDirectoryAccessConfirmationDialog,
-              app_file_handler_util::HasFileSystemWritePermission(
-                  extension_.get()),
-              base::UTF8ToUTF16(extension_->name()), web_contents,
-              base::Bind(
-                  &FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed,
-                  this, paths),
-              base::Bind(&FileSystemChooseEntryFunction::FileSelectionCanceled,
-                         this)));
+          base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled,
+                         this));
       return;
     }
+
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::BindOnce(
+            &FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess,
+            this, paths, web_contents));
+    return;
   }
 
   content::BrowserThread::PostTask(
@@ -683,6 +579,29 @@
                      this, paths));
 }
 
+void FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess(
+    const std::vector<base::FilePath>& paths,
+    content::WebContents* web_contents) {
+  if (ExtensionsBrowserClient::Get()->IsShuttingDown()) {
+    FileSelectionCanceled();
+    return;
+  }
+
+  FileSystemDelegate* delegate =
+      ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+  if (!delegate) {
+    Respond(Error(kNotSupportedOnCurrentPlatformError));
+    return;
+  }
+
+  delegate->ConfirmSensitiveDirectoryAccess(
+      app_file_handler_util::HasFileSystemWritePermission(extension_.get()),
+      base::UTF8ToUTF16(extension_->name()), web_contents,
+      base::Bind(&FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed,
+                 this, paths),
+      base::Bind(&FileSystemChooseEntryFunction::FileSelectionCanceled, this));
+}
+
 void FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed(
     const std::vector<base::FilePath>& paths) {
   if (app_file_handler_util::HasFileSystemWritePermission(extension_.get())) {
@@ -762,17 +681,19 @@
   if (is_previous_path_directory) {
     initial_path_ = previous_path.Append(suggested_name);
   } else {
-    base::FilePath documents_dir;
-    if (PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir)) {
-      initial_path_ = documents_dir.Append(suggested_name);
-    } else {
+    FileSystemDelegate* delegate =
+        ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+    DCHECK(delegate);
+    const base::FilePath default_directory = delegate->GetDefaultDirectory();
+    if (!default_directory.empty())
+      initial_path_ = default_directory.Append(suggested_name);
+    else
       initial_path_ = suggested_name;
-    }
   }
   ShowPicker(file_type_info, picker_type);
 }
 
-bool FileSystemChooseEntryFunction::RunAsync() {
+ExtensionFunction::ResponseAction FileSystemChooseEntryFunction::Run() {
   std::unique_ptr<ChooseEntry::Params> params(
       ChooseEntry::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -791,29 +712,24 @@
     if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENWRITABLEFILE &&
         !app_file_handler_util::HasFileSystemWritePermission(
             extension_.get())) {
-      error_ = kRequiresFileSystemWriteError;
-      return false;
+      return RespondNow(Error(kRequiresFileSystemWriteError));
     } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) {
       if (!app_file_handler_util::HasFileSystemWritePermission(
               extension_.get())) {
-        error_ = kRequiresFileSystemWriteError;
-        return false;
+        return RespondNow(Error(kRequiresFileSystemWriteError));
       }
       if (multiple_) {
-        error_ = kMultipleUnsupportedError;
-        return false;
+        return RespondNow(Error(kMultipleUnsupportedError));
       }
       picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE;
     } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENDIRECTORY) {
       is_directory_ = true;
       if (!extension_->permissions_data()->HasAPIPermission(
               APIPermission::kFileSystemDirectory)) {
-        error_ = kRequiresFileSystemDirectoryError;
-        return false;
+        return RespondNow(Error(kRequiresFileSystemDirectoryError));
       }
       if (multiple_) {
-        error_ = kMultipleUnsupportedError;
-        return false;
+        return RespondNow(Error(kMultipleUnsupportedError));
       }
       picker_type = ui::SelectFileDialog::SELECT_FOLDER;
     }
@@ -829,12 +745,12 @@
   file_type_info.allowed_paths = ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
 
   base::FilePath previous_path = file_system_api::GetLastChooseEntryDirectory(
-      ExtensionPrefs::Get(GetProfile()), extension()->id());
+      ExtensionPrefs::Get(browser_context()), extension()->id());
 
   if (previous_path.empty()) {
     SetInitialPathAndShowPicker(previous_path, suggested_name, file_type_info,
                                 picker_type, false);
-    return true;
+    return RespondLater();
   }
 
   base::Callback<void(bool)> set_initial_path_callback = base::Bind(
@@ -843,11 +759,13 @@
 
 // Check whether the |previous_path| is a non-native directory.
 #if defined(OS_CHROMEOS)
-  if (file_manager::util::IsUnderNonNativeLocalPath(GetProfile(),
-                                                    previous_path)) {
-    file_manager::util::IsNonNativeLocalPathDirectory(
-        GetProfile(), previous_path, set_initial_path_callback);
-    return true;
+  NonNativeFileSystemDelegate* delegate =
+      ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate();
+  if (delegate &&
+      delegate->IsUnderNonNativeLocalPath(browser_context(), previous_path)) {
+    delegate->IsNonNativeLocalPathDirectory(browser_context(), previous_path,
+                                            set_initial_path_callback);
+    return RespondLater();
   }
 #endif
   base::PostTaskWithTraitsAndReplyWithResult(
@@ -855,13 +773,21 @@
       base::Bind(&base::DirectoryExists, previous_path),
       set_initial_path_callback);
 
-  return true;
+  return RespondLater();
 }
 
-bool FileSystemRetainEntryFunction::RunAsync() {
+ExtensionFunction::ResponseAction FileSystemRetainEntryFunction::Run() {
   std::string entry_id;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
-  SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile());
+
+  FileSystemDelegate* delegate =
+      ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+  DCHECK(delegate);
+
+  SavedFilesServiceInterface* saved_files_service =
+      delegate->GetSavedFilesService(browser_context());
+  DCHECK(saved_files_service);
+
   // Add the file to the retain list if it is not already on there.
   if (!saved_files_service->IsRegistered(extension_->id(), entry_id)) {
     std::string filesystem_name;
@@ -869,23 +795,26 @@
     base::FilePath path;
     EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name));
     EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path));
+    std::string error;
     if (!app_file_handler_util::ValidateFileEntryAndGetPath(
             filesystem_name, filesystem_path,
-            render_frame_host()->GetProcess()->GetID(), &path, &error_)) {
-      return false;
+            render_frame_host()->GetProcess()->GetID(), &path, &error)) {
+      return RespondNow(Error(error));
     }
 
     std::string filesystem_id;
     if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id))
-      return false;
+      return RespondNow(Error(kRetainEntryError));
 
-    const GURL site = util::GetSiteForExtensionId(extension_id(), GetProfile());
+    const GURL site =
+        util::GetSiteForExtensionId(extension_id(), browser_context());
     storage::FileSystemContext* const context =
-        content::BrowserContext::GetStoragePartitionForSite(GetProfile(), site)
+        content::BrowserContext::GetStoragePartitionForSite(browser_context(),
+                                                            site)
             ->GetFileSystemContext();
     const storage::FileSystemURL url = context->CreateCrackedFileSystemURL(
         site, storage::kFileSystemTypeIsolated,
-        IsolatedContext::GetInstance()
+        storage::IsolatedContext::GetInstance()
             ->CreateVirtualRootPath(filesystem_id)
             .Append(base::FilePath::FromUTF8Unsafe(filesystem_path)));
 
@@ -900,12 +829,11 @@
                 &PassFileInfoToUIThread,
                 base::Bind(&FileSystemRetainEntryFunction::RetainFileEntry,
                            this, entry_id, path))));
-    return true;
+    return RespondLater();
   }
 
   saved_files_service->EnqueueFileEntry(extension_->id(), entry_id);
-  SendResponse(true);
-  return true;
+  return RespondNow(NoArguments());
 }
 
 void FileSystemRetainEntryFunction::RetainFileEntry(
@@ -913,52 +841,68 @@
     const base::FilePath& path,
     std::unique_ptr<base::File::Info> file_info) {
   if (!file_info) {
-    SendResponse(false);
+    Respond(Error(kRetainEntryError));
     return;
   }
 
-  SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile());
+  FileSystemDelegate* delegate =
+      ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+  DCHECK(delegate);
+
+  SavedFilesServiceInterface* saved_files_service =
+      delegate->GetSavedFilesService(browser_context());
+  DCHECK(saved_files_service);
   saved_files_service->RegisterFileEntry(extension_->id(), entry_id, path,
                                          file_info->is_directory);
   saved_files_service->EnqueueFileEntry(extension_->id(), entry_id);
-  SendResponse(true);
+  Respond(NoArguments());
 }
 
 ExtensionFunction::ResponseAction FileSystemIsRestorableFunction::Run() {
   std::string entry_id;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
+
+  FileSystemDelegate* delegate =
+      ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+  DCHECK(delegate);
+
+  SavedFilesServiceInterface* saved_files_service =
+      delegate->GetSavedFilesService(browser_context());
+  DCHECK(saved_files_service);
+
   return RespondNow(OneArgument(base::MakeUnique<base::Value>(
-      SavedFilesService::Get(Profile::FromBrowserContext(browser_context()))
-          ->IsRegistered(extension_->id(), entry_id))));
+      saved_files_service->IsRegistered(extension_->id(), entry_id))));
 }
 
-bool FileSystemRestoreEntryFunction::RunAsync() {
+ExtensionFunction::ResponseAction FileSystemRestoreEntryFunction::Run() {
   std::string entry_id;
   bool needs_new_entry;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id));
   EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry));
-  const SavedFileEntry* file_entry =
-      SavedFilesService::Get(GetProfile())
-          ->GetFileEntry(extension_->id(), entry_id);
-  if (!file_entry) {
-    error_ = kUnknownIdError;
-    return false;
-  }
+  FileSystemDelegate* delegate =
+      ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+  DCHECK(delegate);
 
-  SavedFilesService::Get(GetProfile())
-      ->EnqueueFileEntry(extension_->id(), entry_id);
+  SavedFilesServiceInterface* saved_files_service =
+      delegate->GetSavedFilesService(browser_context());
+  DCHECK(saved_files_service);
+  const SavedFileEntry* file =
+      saved_files_service->GetFileEntry(extension_->id(), entry_id);
+  if (!file)
+    return RespondNow(Error(kUnknownIdError));
+
+  saved_files_service->EnqueueFileEntry(extension_->id(), entry_id);
 
   // Only create a new file entry if the renderer requests one.
   // |needs_new_entry| will be false if the renderer already has an Entry for
   // |entry_id|.
   if (needs_new_entry) {
-    is_directory_ = file_entry->is_directory;
+    is_directory_ = file->is_directory;
     std::unique_ptr<base::DictionaryValue> result = CreateResult();
-    AddEntryToResult(file_entry->path, file_entry->id, result.get());
-    SetResult(std::move(result));
+    AddEntryToResult(file->path, file->id, result.get());
+    return RespondNow(OneArgument(std::move(result)));
   }
-  SendResponse(true);
-  return true;
+  return RespondNow(NoArguments());
 }
 
 ExtensionFunction::ResponseAction FileSystemObserveDirectoryFunction::Run() {
@@ -978,7 +922,7 @@
 
 #if !defined(OS_CHROMEOS)
 ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() {
-  using api::file_system::RequestFileSystem::Params;
+  using file_system::RequestFileSystem::Params;
   const std::unique_ptr<Params> params(Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
@@ -992,190 +936,77 @@
 }
 #else
 
-FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction()
-    : chrome_details_(this) {}
+FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction() {}
 
 FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() {}
 
 ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() {
-  using api::file_system::RequestFileSystem::Params;
+  using file_system::RequestFileSystem::Params;
   const std::unique_ptr<Params> params(Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
+  FileSystemDelegate* delegate =
+      ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+  DCHECK(delegate);
   // Only kiosk apps in kiosk sessions can use this API.
   // Additionally it is enabled for whitelisted component extensions and apps.
-  file_system_api::ConsentProviderDelegate consent_provider_delegate(
-      chrome_details_.GetProfile(), render_frame_host());
-  file_system_api::ConsentProvider consent_provider(&consent_provider_delegate);
-
-  if (!consent_provider.IsGrantable(*extension()))
+  if (!delegate->IsGrantable(browser_context(), render_frame_host(),
+                             *extension())) {
     return RespondNow(Error(kNotSupportedOnNonKioskSessionError));
-
-  using file_manager::VolumeManager;
-  using file_manager::Volume;
-  VolumeManager* const volume_manager =
-      VolumeManager::Get(chrome_details_.GetProfile());
-  DCHECK(volume_manager);
-
-  const bool writable =
-      params->options.writable.get() && *params->options.writable.get();
-  if (writable &&
-      !app_file_handler_util::HasFileSystemWritePermission(extension_.get())) {
-    return RespondNow(Error(kRequiresFileSystemWriteError));
   }
 
-  base::WeakPtr<file_manager::Volume> volume =
-      volume_manager->FindVolumeById(params->options.volume_id);
-  if (!volume.get())
-    return RespondNow(Error(kVolumeNotFoundError));
+  delegate->RequestFileSystem(
+      browser_context(), this, *extension(), params->options.volume_id,
+      params->options.writable.get() && *params->options.writable.get(),
+      base::Bind(&FileSystemRequestFileSystemFunction::OnGotFileSystem, this),
+      base::Bind(&FileSystemRequestFileSystemFunction::OnError, this));
 
-  const GURL site =
-      util::GetSiteForExtensionId(extension_id(), chrome_details_.GetProfile());
-  scoped_refptr<storage::FileSystemContext> file_system_context =
-      content::BrowserContext::GetStoragePartitionForSite(
-          chrome_details_.GetProfile(), site)
-          ->GetFileSystemContext();
-  storage::ExternalFileSystemBackend* const backend =
-      file_system_context->external_backend();
-  DCHECK(backend);
-
-  base::FilePath virtual_path;
-  if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path))
-    return RespondNow(Error(kSecurityError));
-
-  if (writable && (volume->is_read_only()))
-    return RespondNow(Error(kSecurityError));
-
-  consent_provider.RequestConsent(
-      *extension(), volume, writable,
-      base::Bind(&FileSystemRequestFileSystemFunction::OnConsentReceived, this,
-                 volume, writable));
-  return RespondLater();
+  return did_respond() ? AlreadyResponded() : RespondLater();
 }
 
-void FileSystemRequestFileSystemFunction::OnConsentReceived(
-    const base::WeakPtr<file_manager::Volume>& volume,
-    bool writable,
-    ConsentProvider::Consent result) {
-  using file_manager::VolumeManager;
-  using file_manager::Volume;
-
-  // Render frame host can be gone before this callback method is executed.
-  if (!render_frame_host()) {
-    Respond(Error(""));
-    return;
-  }
-
-  switch (result) {
-    case ConsentProvider::CONSENT_REJECTED:
-      Respond(Error(kSecurityError));
-      return;
-
-    case ConsentProvider::CONSENT_IMPOSSIBLE:
-      Respond(Error(kConsentImpossible));
-      return;
-
-    case ConsentProvider::CONSENT_GRANTED:
-      break;
-  }
-
-  if (!volume.get()) {
-    Respond(Error(kVolumeNotFoundError));
-    return;
-  }
-
-  const GURL site =
-      util::GetSiteForExtensionId(extension_id(), chrome_details_.GetProfile());
-  scoped_refptr<storage::FileSystemContext> file_system_context =
-      content::BrowserContext::GetStoragePartitionForSite(
-          chrome_details_.GetProfile(), site)
-          ->GetFileSystemContext();
-  storage::ExternalFileSystemBackend* const backend =
-      file_system_context->external_backend();
-  DCHECK(backend);
-
-  base::FilePath virtual_path;
-  if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) {
-    Respond(Error(kSecurityError));
-    return;
-  }
-
-  storage::IsolatedContext* const isolated_context =
-      storage::IsolatedContext::GetInstance();
-  DCHECK(isolated_context);
-
-  const storage::FileSystemURL original_url =
-      file_system_context->CreateCrackedFileSystemURL(
-          GURL(std::string(kExtensionScheme) + url::kStandardSchemeSeparator +
-               extension_id()),
-          storage::kFileSystemTypeExternal, virtual_path);
-
-  // Set a fixed register name, as the automatic one would leak the mount point
-  // directory.
-  std::string register_name = "fs";
-  const std::string file_system_id =
-      isolated_context->RegisterFileSystemForPath(
-          storage::kFileSystemTypeNativeForPlatformApp,
-          std::string() /* file_system_id */, original_url.path(),
-          &register_name);
-  if (file_system_id.empty()) {
-    Respond(Error(kSecurityError));
-    return;
-  }
-
-  backend->GrantFileAccessToExtension(extension_->id(), virtual_path);
-
-  // Grant file permissions to the renderer hosting component.
-  content::ChildProcessSecurityPolicy* policy =
-      content::ChildProcessSecurityPolicy::GetInstance();
-  DCHECK(policy);
-
-  // Read-only permisisons.
-  policy->GrantReadFile(render_frame_host()->GetProcess()->GetID(),
-                        volume->mount_path());
-  policy->GrantReadFileSystem(render_frame_host()->GetProcess()->GetID(),
-                              file_system_id);
-
-  // Additional write permissions.
-  if (writable) {
-    policy->GrantCreateReadWriteFile(render_frame_host()->GetProcess()->GetID(),
-                                     volume->mount_path());
-    policy->GrantCopyInto(render_frame_host()->GetProcess()->GetID(),
-                          volume->mount_path());
-    policy->GrantWriteFileSystem(render_frame_host()->GetProcess()->GetID(),
-                                 file_system_id);
-    policy->GrantDeleteFromFileSystem(
-        render_frame_host()->GetProcess()->GetID(), file_system_id);
-    policy->GrantCreateFileForFileSystem(
-        render_frame_host()->GetProcess()->GetID(), file_system_id);
-  }
-
+void FileSystemRequestFileSystemFunction::OnGotFileSystem(
+    const std::string& id,
+    const std::string& path) {
   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-  dict->SetString("file_system_id", file_system_id);
-  dict->SetString("file_system_path", register_name);
-
+  dict->SetString("file_system_id", id);
+  dict->SetString("file_system_path", path);
   Respond(OneArgument(std::move(dict)));
 }
 
-FileSystemGetVolumeListFunction::FileSystemGetVolumeListFunction()
-    : chrome_details_(this) {}
+void FileSystemRequestFileSystemFunction::OnError(const std::string& error) {
+  Respond(Error(error));
+}
+
+FileSystemGetVolumeListFunction::FileSystemGetVolumeListFunction() {}
 
 FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() {}
 
 ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() {
+  FileSystemDelegate* delegate =
+      ExtensionsAPIClient::Get()->GetFileSystemDelegate();
+  DCHECK(delegate);
   // Only kiosk apps in kiosk sessions can use this API.
   // Additionally it is enabled for whitelisted component extensions and apps.
-  file_system_api::ConsentProviderDelegate consent_provider_delegate(
-      chrome_details_.GetProfile(), render_frame_host());
-  file_system_api::ConsentProvider consent_provider(&consent_provider_delegate);
-
-  if (!consent_provider.IsGrantable(*extension()))
+  if (!delegate->IsGrantable(browser_context(), render_frame_host(),
+                             *extension())) {
     return RespondNow(Error(kNotSupportedOnNonKioskSessionError));
-  std::vector<api::file_system::Volume> result_volume_list;
-  FillVolumeList(chrome_details_.GetProfile(), &result_volume_list);
+  }
 
-  return RespondNow(ArgumentList(
-      api::file_system::GetVolumeList::Results::Create(result_volume_list)));
+  delegate->GetVolumeList(
+      browser_context(),
+      base::Bind(&FileSystemGetVolumeListFunction::OnGotVolumeList, this),
+      base::Bind(&FileSystemGetVolumeListFunction::OnError, this));
+
+  return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void FileSystemGetVolumeListFunction::OnGotVolumeList(
+    const std::vector<file_system::Volume>& volumes) {
+  Respond(ArgumentList(file_system::GetVolumeList::Results::Create(volumes)));
+}
+
+void FileSystemGetVolumeListFunction::OnError(const std::string& error) {
+  Respond(Error(error));
 }
 #endif
 
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.h b/extensions/browser/api/file_system/file_system_api.h
similarity index 85%
rename from chrome/browser/extensions/api/file_system/file_system_api.h
rename to extensions/browser/api/file_system/file_system_api.h
index d43a8e2..efa3d0f8 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.h
+++ b/extensions/browser/api/file_system/file_system_api.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
+#ifndef EXTENSIONS_BROWSER_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
+#define EXTENSIONS_BROWSER_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
 
 #include <memory>
 #include <string>
@@ -12,19 +12,12 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/extensions/chrome_extension_function.h"
-#include "chrome/browser/extensions/chrome_extension_function_details.h"
-#include "chrome/common/extensions/api/file_system.h"
 #include "extensions/browser/extension_function.h"
+#include "extensions/common/api/file_system.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/extensions/api/file_system/consent_provider.h"
-#endif
-
 namespace content {
 class WebContents;
 }  // namespace content
@@ -46,12 +39,6 @@
                                  const std::string& extension_id,
                                  const base::FilePath& path);
 
-#if defined(OS_CHROMEOS)
-// Dispatches an event about a mounted on unmounted volume in the system to
-// each extension which can request it.
-void DispatchVolumeListChangeEvent(Profile* profile);
-#endif
-
 }  // namespace file_system_api
 
 class FileSystemGetDisplayPathFunction : public UIThreadExtensionFunction {
@@ -64,7 +51,7 @@
   ResponseAction Run() override;
 };
 
-class FileSystemEntryFunction : public ChromeAsyncExtensionFunction {
+class FileSystemEntryFunction : public UIThreadExtensionFunction {
  protected:
   FileSystemEntryFunction();
 
@@ -107,7 +94,7 @@
 
  protected:
   ~FileSystemGetWritableEntryFunction() override {}
-  bool RunAsync() override;
+  ResponseAction Run() override;
 
  private:
   void CheckPermissionAndSendResponse();
@@ -160,7 +147,7 @@
 
  protected:
   ~FileSystemChooseEntryFunction() override {}
-  bool RunAsync() override;
+  ResponseAction Run() override;
   void ShowPicker(const ui::SelectFileDialog::FileTypeInfo& file_type_info,
                   ui::SelectFileDialog::Type picker_type);
 
@@ -177,25 +164,29 @@
   void FileSelectionCanceled();
 
   // Check if the chosen directory is or is an ancestor of a sensitive
-  // directory. If so, show a dialog to confirm that the user wants to open the
-  // directory. Calls OnDirectoryAccessConfirmed if the directory isn't
-  // sensitive or the user chooses to open it. Otherwise, calls
-  // FileSelectionCanceled.
+  // directory. If so, calls ConfirmSensitiveDirectoryAccess. Otherwise, calls
+  // OnDirectoryAccessConfirmed.
   void ConfirmDirectoryAccessAsync(bool non_native_path,
                                    const std::vector<base::FilePath>& paths,
                                    content::WebContents* web_contents);
+
+  // Shows a dialog to confirm whether the user wants to open the directory.
+  // Calls OnDirectoryAccessConfirmed or FileSelectionCanceled.
+  void ConfirmSensitiveDirectoryAccess(const std::vector<base::FilePath>& paths,
+                                       content::WebContents* web_contents);
+
   void OnDirectoryAccessConfirmed(const std::vector<base::FilePath>& paths);
 
   base::FilePath initial_path_;
 };
 
-class FileSystemRetainEntryFunction : public ChromeAsyncExtensionFunction {
+class FileSystemRetainEntryFunction : public UIThreadExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileSystem.retainEntry", FILESYSTEM_RETAINENTRY)
 
  protected:
   ~FileSystemRetainEntryFunction() override {}
-  bool RunAsync() override;
+  ResponseAction Run() override;
 
  private:
   // Retains the file entry referenced by |entry_id| in apps::SavedFilesService.
@@ -222,7 +213,7 @@
 
  protected:
   ~FileSystemRestoreEntryFunction() override {}
-  bool RunAsync() override;
+  ResponseAction Run() override;
 };
 
 class FileSystemObserveDirectoryFunction : public UIThreadExtensionFunction {
@@ -299,11 +290,8 @@
  private:
   // Called when a user grants or rejects permissions for the file system
   // access.
-  void OnConsentReceived(const base::WeakPtr<file_manager::Volume>& volume,
-                         bool writable,
-                         file_system_api::ConsentProvider::Consent result);
-
-  ChromeExtensionFunctionDetails chrome_details_;
+  void OnGotFileSystem(const std::string& id, const std::string& path);
+  void OnError(const std::string& error);
 };
 
 // Requests a list of available volumes.
@@ -320,10 +308,11 @@
   ExtensionFunction::ResponseAction Run() override;
 
  private:
-  ChromeExtensionFunctionDetails chrome_details_;
+  void OnGotVolumeList(const std::vector<api::file_system::Volume>& volumes);
+  void OnError(const std::string& error);
 };
 #endif
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
+#endif  // EXTENSIONS_BROWSER_API_FILE_SYSTEM_FILE_SYSTEM_API_H_
diff --git a/extensions/browser/api/file_system/file_system_delegate.h b/extensions/browser/api/file_system/file_system_delegate.h
new file mode 100644
index 0000000..8e831454
--- /dev/null
+++ b/extensions/browser/api/file_system/file_system_delegate.h
@@ -0,0 +1,103 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_FILE_SYSTEM_FILE_SYSTEM_DELEGATE_H_
+#define EXTENSIONS_BROWSER_API_FILE_SYSTEM_FILE_SYSTEM_DELEGATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "build/build_config.h"
+#include "extensions/common/api/file_system.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+
+class UIThreadExtensionFunction;
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace content {
+class BrowserContext;
+class RenderFrameHost;
+class WebContents;
+}  // namespace content
+
+namespace extensions {
+
+class Extension;
+class SavedFilesServiceInterface;
+
+// Delegate class for embedder-specific file system access.
+class FileSystemDelegate {
+ public:
+  using ErrorCallback = base::Callback<void(const std::string&)>;
+  using FileSystemCallback =
+      base::Callback<void(const std::string& id, const std::string& path)>;
+  using FilesSelectedCallback =
+      base::OnceCallback<void(const std::vector<base::FilePath>& paths)>;
+  using VolumeListCallback =
+      base::Callback<void(const std::vector<api::file_system::Volume>&)>;
+
+  virtual ~FileSystemDelegate() {}
+
+  virtual base::FilePath GetDefaultDirectory() = 0;
+
+  // Shows a dialog to prompt the user to select files/directories. Returns
+  // false if the dialog cannot be shown, i.e. there is no valid WebContents.
+  virtual bool ShowSelectFileDialog(
+      scoped_refptr<UIThreadExtensionFunction> extension_function,
+      ui::SelectFileDialog::Type type,
+      const base::FilePath& default_path,
+      const ui::SelectFileDialog::FileTypeInfo* file_types,
+      FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+      base::OnceClosure file_selection_canceled_callback) = 0;
+
+  // Confirms (e.g. with a dialog) whether the user wants to open the directory
+  // for a given app.
+  virtual void ConfirmSensitiveDirectoryAccess(
+      bool has_write_permission,
+      const base::string16& app_name,
+      content::WebContents* web_contents,
+      const base::Closure& on_accept,
+      const base::Closure& on_cancel) = 0;
+
+  // Finds a string describing the accept type. Returns 0 if no applicable
+  // string ID is found.
+  virtual int GetDescriptionIdForAcceptType(const std::string& accept_type) = 0;
+
+#if defined(OS_CHROMEOS)
+  // Checks whether the extension can be granted access.
+  virtual bool IsGrantable(content::BrowserContext* browser_context,
+                           content::RenderFrameHost* render_frame_host,
+                           const Extension& extension) = 0;
+
+  // Grants or denies an extension's request for access to the named file
+  // system. May prompt the user for consent.
+  virtual void RequestFileSystem(
+      content::BrowserContext* browser_context,
+      scoped_refptr<UIThreadExtensionFunction> requester,
+      const Extension& extension,
+      std::string volume_id,
+      bool writable,
+      const FileSystemCallback& success_callback,
+      const ErrorCallback& error_callback) = 0;
+
+  // Immediately calls VolumeListCallback or ErrorCallback.
+  virtual void GetVolumeList(content::BrowserContext* browser_context,
+                             const VolumeListCallback& success_callback,
+                             const ErrorCallback& error_callback) = 0;
+#endif
+
+  virtual SavedFilesServiceInterface* GetSavedFilesService(
+      content::BrowserContext* browser_context) = 0;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_FILE_SYSTEM_FILE_SYSTEM_DELEGATE_H_
diff --git a/extensions/browser/api/lock_screen_data/data_item.cc b/extensions/browser/api/lock_screen_data/data_item.cc
new file mode 100644
index 0000000..4b0779a6
--- /dev/null
+++ b/extensions/browser/api/lock_screen_data/data_item.cc
@@ -0,0 +1,435 @@
+// 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 "extensions/browser/api/lock_screen_data/data_item.h"
+
+#include <utility>
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/values.h"
+#include "crypto/encryptor.h"
+#include "crypto/symmetric_key.h"
+#include "extensions/browser/api/lock_screen_data/operation_result.h"
+#include "extensions/browser/api/storage/local_value_store_cache.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/value_store/value_store.h"
+
+namespace extensions {
+namespace lock_screen_data {
+
+namespace {
+
+// Key for the dictionary in the value store containing all items registered
+// for the extension.
+const char kStoreKeyRegisteredItems[] = "registered_items";
+
+constexpr int kAesInitializationVectorLength = 16;
+
+// Encrypts |data| with AES key |raw_key|. Returns whether the encryption was
+// successful, in which case |*result| will be set to the encrypted data.
+bool EncryptData(const std::vector<char> data,
+                 const std::string& raw_key,
+                 std::string* result) {
+  std::string initialization_vector(kAesInitializationVectorLength, ' ');
+  std::unique_ptr<crypto::SymmetricKey> key =
+      crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key);
+  if (!key)
+    return false;
+
+  crypto::Encryptor encryptor;
+  if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, initialization_vector))
+    return false;
+
+  return encryptor.Encrypt(std::string(data.data(), data.size()), result);
+}
+
+// Decrypts |data| content using AES key |raw_key|. Returns the operation result
+// code. On success, |*result| will be set to the clear-text data.
+OperationResult DecryptData(const std::string& data,
+                            const std::string& raw_key,
+                            std::vector<char>* result) {
+  std::string initialization_vector(kAesInitializationVectorLength, ' ');
+  std::unique_ptr<crypto::SymmetricKey> key =
+      crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key);
+  if (!key)
+    return OperationResult::kInvalidKey;
+
+  crypto::Encryptor encryptor;
+  if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, initialization_vector))
+    return OperationResult::kInvalidKey;
+
+  std::string decrypted;
+  if (!encryptor.Decrypt(data, &decrypted))
+    return OperationResult::kWrongKey;
+
+  *result =
+      std::vector<char>(decrypted.data(), decrypted.data() + decrypted.size());
+
+  return OperationResult::kSuccess;
+}
+
+// Returns whether the value store |store| contains a registered item with ID
+// |item_id|.
+bool IsItemRegistered(ValueStore* store, const std::string& item_id) {
+  ValueStore::ReadResult read = store->Get(kStoreKeyRegisteredItems);
+
+  const base::DictionaryValue* registered_items = nullptr;
+  return read->status().ok() &&
+         read->settings().GetDictionary(kStoreKeyRegisteredItems,
+                                        &registered_items) &&
+         registered_items->HasKey(item_id);
+}
+
+// Gets a dictionary value that contains set of all registered data items from
+// the values store |store|.
+// |result| - the item fetch operation status code.
+// |value| - on success, set to the dictionary containing registered data items.
+//     Note that the dictionary will not contain data item content.
+void GetRegisteredItems(OperationResult* result,
+                        base::DictionaryValue* values,
+                        ValueStore* store) {
+  ValueStore::ReadResult read = store->Get(kStoreKeyRegisteredItems);
+
+  values->Clear();
+
+  std::unique_ptr<base::Value> registered_items;
+  if (!read->status().ok()) {
+    *result = OperationResult::kFailed;
+    return;
+  }
+
+  // Using remove to pass ownership of registered_item dict to
+  // |registered_items| (and avoid doing a copy |read->settings()|
+  // sub-dictionary).
+  if (!read->settings().Remove(kStoreKeyRegisteredItems, &registered_items)) {
+    // If the registered items dictionary cannot be found, assume no items have
+    // yet been registered, and return empty result.
+    *result = OperationResult::kSuccess;
+    return;
+  }
+
+  std::unique_ptr<base::DictionaryValue> items_dict =
+      base::DictionaryValue::From(std::move(registered_items));
+
+  *result =
+      items_dict.get() ? OperationResult::kSuccess : OperationResult::kFailed;
+  if (items_dict)
+    values->Swap(items_dict.get());
+}
+
+// Registers a data item with ID |item_id| in value store |store|.
+void RegisterItem(OperationResult* result,
+                  const std::string& item_id,
+                  ValueStore* store) {
+  ValueStore::ReadResult read = store->Get(kStoreKeyRegisteredItems);
+
+  std::unique_ptr<base::Value> registered_items;
+  if (!read->status().ok()) {
+    *result = OperationResult::kFailed;
+    return;
+  }
+  if (!read->settings().Remove(kStoreKeyRegisteredItems, &registered_items))
+    registered_items = base::MakeUnique<base::DictionaryValue>();
+
+  std::unique_ptr<base::DictionaryValue> dict =
+      base::DictionaryValue::From(std::move(registered_items));
+  if (!dict) {
+    *result = OperationResult::kFailed;
+    return;
+  }
+
+  if (dict->HasKey(item_id)) {
+    *result = OperationResult::kAlreadyRegistered;
+    return;
+  }
+
+  dict->Set(item_id, base::MakeUnique<base::DictionaryValue>());
+
+  ValueStore::WriteResult write =
+      store->Set(ValueStore::DEFAULTS, kStoreKeyRegisteredItems, *dict);
+  *result = write->status().ok() ? OperationResult::kSuccess
+                                 : OperationResult::kFailed;
+}
+
+// Encrypts |data| with AES key |encryption_key| and saved it as |item_id|
+// content to the value store |store|. The encrypted data is saved base64
+// encoded.
+void WriteImpl(OperationResult* result,
+               const std::string item_id,
+               const std::vector<char>& data,
+               const std::string& encryption_key,
+               ValueStore* store) {
+  if (!IsItemRegistered(store, item_id)) {
+    *result = OperationResult::kNotFound;
+    return;
+  }
+
+  std::string encrypted;
+  if (!EncryptData(data, encryption_key, &encrypted)) {
+    *result = OperationResult::kInvalidKey;
+    return;
+  }
+  base::Base64Encode(encrypted, &encrypted);
+
+  ValueStore::WriteResult write = store->Set(ValueStore::DEFAULTS, item_id,
+                                             base::Value(std::move(encrypted)));
+
+  *result = write->status().ok() ? OperationResult::kSuccess
+                                 : OperationResult::kFailed;
+}
+
+// Gets content of the data item with ID |item_id| from value store |store|,
+// and decrypts it using |decryption_key|. On success, the decrypted data is
+// returned as |*data| contents. Note that this method expects the encrypted
+// data content in the value store is base64 encoded.
+void ReadImpl(OperationResult* result,
+              std::vector<char>* data,
+              const std::string& item_id,
+              const std::string& decryption_key,
+              ValueStore* store) {
+  if (!IsItemRegistered(store, item_id)) {
+    *result = OperationResult::kNotFound;
+    return;
+  }
+
+  ValueStore::ReadResult read = store->Get(item_id);
+  if (!read->status().ok()) {
+    *result = OperationResult::kNotFound;
+    return;
+  }
+
+  const base::Value* item;
+  if (!read->settings().Get(item_id, &item)) {
+    *result = OperationResult::kSuccess;
+    *data = std::vector<char>();
+    return;
+  }
+
+  std::string read_data;
+  if (!item->is_string() ||
+      !base::Base64Decode(item->GetString(), &read_data)) {
+    *result = OperationResult::kFailed;
+    return;
+  }
+
+  *result = DecryptData(read_data, decryption_key, data);
+}
+
+// Unregisters and deletes the item with |item_id| from the |valus_store|.
+void DeleteImpl(OperationResult* result,
+                const std::string& item_id,
+                ValueStore* store) {
+  ValueStore::WriteResult remove =
+      store->Remove(std::vector<std::string>({item_id}));
+  if (!remove->status().ok()) {
+    *result = OperationResult::kFailed;
+    return;
+  }
+
+  ValueStore::ReadResult read = store->Get(kStoreKeyRegisteredItems);
+  if (!read->status().ok()) {
+    *result = OperationResult::kFailed;
+    return;
+  }
+
+  base::DictionaryValue* registered_items = nullptr;
+  if (!read->settings().GetDictionary(kStoreKeyRegisteredItems,
+                                      &registered_items) ||
+      !registered_items->Remove(item_id, nullptr)) {
+    *result = OperationResult::kNotFound;
+    return;
+  }
+
+  ValueStore::WriteResult write = store->Set(
+      ValueStore::DEFAULTS, kStoreKeyRegisteredItems, *registered_items);
+  *result = write->status().ok() ? OperationResult::kSuccess
+                                 : OperationResult::kFailed;
+}
+
+void OnGetRegisteredValues(const DataItem::RegisteredValuesCallback& callback,
+                           std::unique_ptr<OperationResult> result,
+                           std::unique_ptr<base::DictionaryValue> values) {
+  callback.Run(*result, std::move(values));
+}
+
+}  // namespace
+
+// static
+void DataItem::GetRegisteredValuesForExtension(
+    content::BrowserContext* context,
+    ValueStoreCache* value_store_cache,
+    base::SequencedTaskRunner* task_runner,
+    const std::string& extension_id,
+    const RegisteredValuesCallback& callback) {
+  scoped_refptr<const Extension> extension =
+      ExtensionRegistry::Get(context)->GetExtensionById(
+          extension_id, ExtensionRegistry::ENABLED);
+  if (!extension) {
+    callback.Run(OperationResult::kUnknownExtension, nullptr);
+    return;
+  }
+
+  std::unique_ptr<OperationResult> result =
+      base::MakeUnique<OperationResult>(OperationResult::kFailed);
+  OperationResult* result_ptr = result.get();
+  std::unique_ptr<base::DictionaryValue> values =
+      base::MakeUnique<base::DictionaryValue>();
+  base::DictionaryValue* values_ptr = values.get();
+
+  task_runner->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&ValueStoreCache::RunWithValueStoreForExtension,
+                     base::Unretained(value_store_cache),
+                     base::Bind(&GetRegisteredItems, result_ptr, values_ptr),
+                     extension),
+      base::BindOnce(&OnGetRegisteredValues, callback, std::move(result),
+                     std::move(values)));
+}
+
+// static
+void DataItem::DeleteAllItemsForExtension(
+    content::BrowserContext* context,
+    ValueStoreCache* value_store_cache,
+    base::SequencedTaskRunner* task_runner,
+    const std::string& extension_id,
+    const base::Closure& callback) {
+  task_runner->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&ValueStoreCache::DeleteStorageSoon,
+                     base::Unretained(value_store_cache), extension_id),
+      callback);
+}
+
+DataItem::DataItem(const std::string& id,
+                   const std::string& extension_id,
+                   content::BrowserContext* context,
+                   ValueStoreCache* value_store_cache,
+                   base::SequencedTaskRunner* task_runner,
+                   const std::string& crypto_key)
+    : id_(id),
+      extension_id_(extension_id),
+      context_(context),
+      value_store_cache_(value_store_cache),
+      task_runner_(task_runner),
+      crypto_key_(crypto_key),
+      weak_ptr_factory_(this) {}
+
+DataItem::~DataItem() = default;
+
+void DataItem::Register(const WriteCallback& callback) {
+  scoped_refptr<const Extension> extension =
+      ExtensionRegistry::Get(context_)->GetExtensionById(
+          extension_id_, ExtensionRegistry::ENABLED);
+  if (!extension) {
+    callback.Run(OperationResult::kUnknownExtension);
+    return;
+  }
+
+  std::unique_ptr<OperationResult> result =
+      base::MakeUnique<OperationResult>(OperationResult::kFailed);
+  OperationResult* result_ptr = result.get();
+
+  task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&ValueStoreCache::RunWithValueStoreForExtension,
+                     base::Unretained(value_store_cache_),
+                     base::Bind(&RegisterItem, result_ptr, id()), extension),
+      base::BindOnce(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(),
+                     callback, std::move(result)));
+}
+
+void DataItem::Write(const std::vector<char>& data,
+                     const WriteCallback& callback) {
+  scoped_refptr<const Extension> extension =
+      ExtensionRegistry::Get(context_)->GetExtensionById(
+          extension_id_, ExtensionRegistry::ENABLED);
+  if (!extension) {
+    callback.Run(OperationResult::kUnknownExtension);
+    return;
+  }
+
+  std::unique_ptr<OperationResult> result =
+      base::MakeUnique<OperationResult>(OperationResult::kFailed);
+  OperationResult* result_ptr = result.get();
+
+  task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&ValueStoreCache::RunWithValueStoreForExtension,
+                     base::Unretained(value_store_cache_),
+                     base::Bind(&WriteImpl, result_ptr, id_, data, crypto_key_),
+                     extension),
+      base::BindOnce(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(),
+                     callback, std::move(result)));
+}
+
+void DataItem::Read(const ReadCallback& callback) {
+  scoped_refptr<const Extension> extension =
+      ExtensionRegistry::Get(context_)->GetExtensionById(
+          extension_id_, ExtensionRegistry::ENABLED);
+  if (!extension) {
+    callback.Run(OperationResult::kUnknownExtension, nullptr);
+    return;
+  }
+
+  std::unique_ptr<OperationResult> result =
+      base::MakeUnique<OperationResult>(OperationResult::kFailed);
+  OperationResult* result_ptr = result.get();
+
+  std::unique_ptr<std::vector<char>> data =
+      base::MakeUnique<std::vector<char>>();
+  std::vector<char>* data_ptr = data.get();
+
+  task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(
+          &ValueStoreCache::RunWithValueStoreForExtension,
+          base::Unretained(value_store_cache_),
+          base::Bind(&ReadImpl, result_ptr, data_ptr, id_, crypto_key_),
+          extension),
+      base::BindOnce(&DataItem::OnReadDone, weak_ptr_factory_.GetWeakPtr(),
+                     callback, std::move(result), std::move(data)));
+}
+
+void DataItem::Delete(const WriteCallback& callback) {
+  scoped_refptr<const Extension> extension =
+      ExtensionRegistry::Get(context_)->GetExtensionById(
+          extension_id_, ExtensionRegistry::ENABLED);
+  if (!extension) {
+    callback.Run(OperationResult::kUnknownExtension);
+    return;
+  }
+  std::unique_ptr<OperationResult> result =
+      base::MakeUnique<OperationResult>(OperationResult::kFailed);
+  OperationResult* result_ptr = result.get();
+
+  task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&ValueStoreCache::RunWithValueStoreForExtension,
+                     base::Unretained(value_store_cache_),
+                     base::Bind(&DeleteImpl, result_ptr, id_), extension),
+      base::BindOnce(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(),
+                     callback, std::move(result)));
+}
+
+void DataItem::OnWriteDone(const DataItem::WriteCallback& callback,
+                           std::unique_ptr<OperationResult> success) {
+  callback.Run(*success);
+}
+
+void DataItem::OnReadDone(const DataItem::ReadCallback& callback,
+                          std::unique_ptr<OperationResult> success,
+                          std::unique_ptr<std::vector<char>> data) {
+  callback.Run(*success, std::move(data));
+}
+
+}  // namespace lock_screen_data
+}  // namespace extensions
diff --git a/extensions/browser/api/lock_screen_data/data_item.h b/extensions/browser/api/lock_screen_data/data_item.h
new file mode 100644
index 0000000..eec82c9
--- /dev/null
+++ b/extensions/browser/api/lock_screen_data/data_item.h
@@ -0,0 +1,144 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_DATA_ITEM_H_
+#define EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_DATA_ITEM_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace base {
+class DictionaryValue;
+class SequencedTaskRunner;
+}  // namespace base
+
+namespace extensions {
+
+class ValueStoreCache;
+
+namespace lock_screen_data {
+
+enum class OperationResult;
+
+// Wrapper around a per extension value store backed lock screen data item.
+class DataItem {
+ public:
+  using WriteCallback = base::Callback<void(OperationResult result)>;
+  using ReadCallback =
+      base::Callback<void(OperationResult result,
+                          std::unique_ptr<std::vector<char>> data)>;
+  using RegisteredValuesCallback =
+      base::Callback<void(OperationResult result,
+                          std::unique_ptr<base::DictionaryValue> values)>;
+
+  // Gets all registered data items for the extension with the provided
+  // extension ID - the items are returned as a DictionaryValue with keys set
+  // to data item IDs.
+  static void GetRegisteredValuesForExtension(
+      content::BrowserContext* context,
+      ValueStoreCache* value_store_cache,
+      base::SequencedTaskRunner* task_runner,
+      const std::string& extension_id,
+      const RegisteredValuesCallback& callback);
+
+  // Clears data item value store for the extension with the provided extension
+  // ID.
+  static void DeleteAllItemsForExtension(content::BrowserContext* context,
+                                         ValueStoreCache* value_store_cache,
+                                         base::SequencedTaskRunner* task_runner,
+                                         const std::string& extension_id,
+                                         const base::Closure& callback);
+
+  // |id| - Data item ID.
+  // |extension_id| - The extension that owns the item.
+  // |context| - The browser context to which the owning extension is attached.
+  // |value_store_cache| - Used to retrieve value store for the extension with
+  //     |extension_id| ID. Not owned - the caller should ensure the value store
+  //     cache outlives the data item. Note that DataItem post tasks with
+  //     unretained |value_store_cache| to |task_runner|, which means any usage
+  //     of DataItem should happen before value store cache deletion is
+  ///    scheduled to |task_runner|.
+  // |task_runner| - The task runner on which value store should be used. Note
+  //     that the Data item does not retain a reference to the task runner -
+  //     the caller should ensure |task_runner| outlives the data item.
+  // |crypto_key| - Symmetric AES key for encrypting/decrypting data item
+  //     content.
+  DataItem(const std::string& id,
+           const std::string& extension_id,
+           content::BrowserContext* context,
+           ValueStoreCache* value_store_cache,
+           base::SequencedTaskRunner* task_runner,
+           const std::string& crypto_key);
+  virtual ~DataItem();
+
+  // Registers the data item in the persistent data item storage.
+  virtual void Register(const WriteCallback& callback);
+
+  // Sets the data item content, saving it to persistent data storage.
+  // This will fail if the data item is not registered.
+  virtual void Write(const std::vector<char>& data,
+                     const WriteCallback& callback);
+
+  // Gets the data item content from the persistent data storage.
+  // This will fail is the item is not registered.
+  virtual void Read(const ReadCallback& callback);
+
+  // Unregisters the data item, and clears previously persisted data item
+  // content.
+  virtual void Delete(const WriteCallback& callback);
+
+  const std::string& id() const { return id_; }
+
+  const std::string& extension_id() const { return extension_id_; }
+
+ private:
+  // Internal callback for write operations - wraps |callback| to ensure
+  // |callback| is not run after |this| has been destroyed.
+  void OnWriteDone(const WriteCallback& callback,
+                   std::unique_ptr<OperationResult> result);
+
+  // Internal callback for the read operation - wraps |callback| to ensure
+  // |callback| is not run after |this| has been destroyed.
+  void OnReadDone(const ReadCallback& callback,
+                  std::unique_ptr<OperationResult> result,
+                  std::unique_ptr<std::vector<char>> data);
+
+  // The data item ID.
+  std::string id_;
+
+  // The ID of the extension that owns the data item.
+  std::string extension_id_;
+
+  content::BrowserContext* context_;
+
+  // Cache used to retrieve the values store to which the data item should be
+  // saved - the value stores are mapped by the extension ID.
+  ValueStoreCache* value_store_cache_;
+
+  // Task runner on which value store should be accessed.
+  base::SequencedTaskRunner* task_runner_;
+
+  // They symmetric AES key that should be used to encrypt data item content
+  // when the content is written to the storage, and to decrypt item content
+  // when reading it from the storage.
+  const std::string crypto_key_;
+
+  base::WeakPtrFactory<DataItem> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(DataItem);
+};
+
+}  // namespace lock_screen_data
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_DATA_ITEM_H_
diff --git a/extensions/browser/api/lock_screen_data/data_item_unittest.cc b/extensions/browser/api/lock_screen_data/data_item_unittest.cc
new file mode 100644
index 0000000..f9d198c
--- /dev/null
+++ b/extensions/browser/api/lock_screen_data/data_item_unittest.cc
@@ -0,0 +1,733 @@
+// 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 "extensions/browser/api/lock_screen_data/data_item.h"
+
+#include <memory>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "crypto/symmetric_key.h"
+#include "extensions/browser/api/lock_screen_data/operation_result.h"
+#include "extensions/browser/api/storage/backend_task_runner.h"
+#include "extensions/browser/api/storage/local_value_store_cache.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/test_extensions_browser_client.h"
+#include "extensions/browser/value_store/test_value_store_factory.h"
+#include "extensions/browser/value_store/testing_value_store.h"
+#include "extensions/common/extension_builder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+namespace lock_screen_data {
+
+namespace {
+
+const char kPrimaryExtensionId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+const char kSecondaryExtensionId[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+
+void WriteCallbackNotCalled(const std::string& message,
+                            OperationResult result) {
+  ADD_FAILURE() << "Unexpected callback " << message;
+}
+
+void ReadCallbackNotCalled(const std::string& message,
+                           OperationResult result,
+                           std::unique_ptr<std::vector<char>> data) {
+  ADD_FAILURE() << "Unexpected callback " << message;
+}
+
+void WriteCallback(const base::Closure& callback,
+                   OperationResult* result_out,
+                   OperationResult result) {
+  *result_out = result;
+  callback.Run();
+}
+
+void ReadCallback(const base::Closure& callback,
+                  OperationResult* result_out,
+                  std::unique_ptr<std::vector<char>>* content_out,
+                  OperationResult result,
+                  std::unique_ptr<std::vector<char>> content) {
+  *result_out = result;
+  *content_out = std::move(content);
+  callback.Run();
+}
+
+void GetRegisteredItemsCallback(
+    const base::Closure& callback,
+    OperationResult* result_out,
+    std::unique_ptr<base::DictionaryValue>* value_out,
+    OperationResult result,
+    std::unique_ptr<base::DictionaryValue> value) {
+  *result_out = result;
+  *value_out = std::move(value);
+  callback.Run();
+}
+
+}  // namespace
+
+class DataItemTest : public testing::Test {
+ public:
+  DataItemTest() {}
+  ~DataItemTest() override = default;
+
+  void SetUp() override {
+    task_runner_ = GetBackendTaskRunner();
+    ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
+
+    context_ = base::MakeUnique<content::TestBrowserContext>();
+    extensions_browser_client_ =
+        base::MakeUnique<TestExtensionsBrowserClient>(context_.get());
+    BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(
+        context_.get());
+
+    ExtensionsBrowserClient::Set(extensions_browser_client_.get());
+
+    value_store_factory_ = base::MakeRefCounted<TestValueStoreFactory>();
+    value_store_cache_ =
+        base::MakeUnique<LocalValueStoreCache>(value_store_factory_);
+
+    extension_ = CreateTestExtension(kPrimaryExtensionId);
+  }
+
+  void TearDown() override {
+    TearDownValueStoreCache();
+
+    BrowserContextDependencyManager::GetInstance()
+        ->DestroyBrowserContextServices(context_.get());
+    ExtensionsBrowserClient::Set(nullptr);
+    extensions_browser_client_.reset();
+    context_.reset();
+  }
+
+  std::string GenerateKey(const std::string& password) {
+    std::unique_ptr<crypto::SymmetricKey> key =
+        crypto::SymmetricKey::DeriveKeyFromPassword(
+            crypto::SymmetricKey::AES, password, "salt", 1000, 256);
+    if (!key) {
+      ADD_FAILURE() << "Failed to create symmetric key";
+      return std::string();
+    }
+
+    return key->key();
+  }
+
+  std::unique_ptr<DataItem> CreateDataItem(const std::string& item_id,
+                                           const std::string& extension_id,
+                                           const std::string& crypto_key) {
+    return base::MakeUnique<DataItem>(item_id, extension_id, context_.get(),
+                                      value_store_cache_.get(),
+                                      task_runner_.get(), crypto_key);
+  }
+
+  std::unique_ptr<DataItem> CreateAndRegisterDataItem(
+      const std::string& item_id,
+      const std::string& extension_id,
+      const std::string& crypto_key) {
+    std::unique_ptr<DataItem> item =
+        CreateDataItem(item_id, extension_id, crypto_key);
+
+    OperationResult result = OperationResult::kFailed;
+    base::RunLoop run_loop;
+    item->Register(base::Bind(&WriteCallback, run_loop.QuitClosure(), &result));
+    run_loop.Run();
+
+    EXPECT_EQ(OperationResult::kSuccess, result);
+    return item;
+  }
+
+  void DrainTaskRunner() {
+    base::RunLoop run_loop;
+    task_runner()->PostTaskAndReply(FROM_HERE, base::Bind(&base::DoNothing),
+                                    run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  const base::FilePath& test_dir() const { return test_dir_.GetPath(); }
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner() {
+    return task_runner_;
+  }
+
+  scoped_refptr<const Extension> CreateTestExtension(
+      const std::string& extension_id) {
+    DictionaryBuilder app_builder;
+    app_builder.Set("background",
+                    DictionaryBuilder()
+                        .Set("scripts", ListBuilder().Append("script").Build())
+                        .Build());
+    ListBuilder app_handlers_builder;
+    app_handlers_builder.Append(DictionaryBuilder()
+                                    .Set("action", "new_note")
+                                    .SetBoolean("enabled_on_lock_screen", true)
+                                    .Build());
+    scoped_refptr<const Extension> extension =
+        ExtensionBuilder()
+            .SetID(extension_id)
+            .SetManifest(
+                DictionaryBuilder()
+                    .Set("name", "Test app")
+                    .Set("version", "1.0")
+                    .Set("manifest_version", 2)
+                    .Set("app", app_builder.Build())
+                    .Set("action_handlers", app_handlers_builder.Build())
+                    .Set("permissions",
+                         ListBuilder().Append("lockScreen").Build())
+                    .Build())
+            .Build();
+    ExtensionRegistry::Get(context_.get())->AddEnabled(extension);
+    return extension;
+  }
+
+  OperationResult WriteItemAndWaitForResult(DataItem* item,
+                                            const std::vector<char>& data) {
+    OperationResult result = OperationResult::kFailed;
+    base::RunLoop run_loop;
+    item->Write(data,
+                base::Bind(&WriteCallback, run_loop.QuitClosure(), &result));
+    run_loop.Run();
+    return result;
+  }
+
+  OperationResult ReadItemAndWaitForResult(
+      DataItem* item,
+      std::unique_ptr<std::vector<char>>* data) {
+    OperationResult result = OperationResult::kFailed;
+    std::unique_ptr<std::vector<char>> read_content;
+    base::RunLoop run_loop;
+    item->Read(base::Bind(&ReadCallback, run_loop.QuitClosure(), &result,
+                          &read_content));
+    run_loop.Run();
+    if (data)
+      *data = std::move(read_content);
+    return result;
+  }
+
+  OperationResult DeleteItemAndWaitForResult(DataItem* item) {
+    OperationResult result = OperationResult::kFailed;
+    base::RunLoop run_loop;
+    item->Delete(base::Bind(&WriteCallback, run_loop.QuitClosure(), &result));
+    run_loop.Run();
+    return result;
+  }
+
+  OperationResult RegisterItemAndWaitForResult(DataItem* item) {
+    OperationResult result = OperationResult::kFailed;
+    base::RunLoop run_loop;
+    item->Register(base::Bind(&WriteCallback, run_loop.QuitClosure(), &result));
+    run_loop.Run();
+    return result;
+  }
+
+  void SetReturnCodeForValueStoreOperations(const std::string& extension_id,
+                                            ValueStore::StatusCode code) {
+    TestingValueStore* store = static_cast<TestingValueStore*>(
+        value_store_factory_->GetExisting(extension_id));
+    ASSERT_TRUE(store);
+    store->set_status_code(code);
+  }
+
+  OperationResult GetRegisteredItemIds(const std::string& extension_id,
+                                       std::set<std::string>* items) {
+    OperationResult result = OperationResult::kFailed;
+    std::unique_ptr<base::DictionaryValue> items_value;
+
+    base::RunLoop run_loop;
+    DataItem::GetRegisteredValuesForExtension(
+        context_.get(), value_store_cache_.get(), task_runner_.get(),
+        extension_id,
+        base::Bind(&GetRegisteredItemsCallback, run_loop.QuitClosure(), &result,
+                   &items_value));
+    run_loop.Run();
+
+    if (result != OperationResult::kSuccess)
+      return result;
+
+    items->clear();
+    for (base::DictionaryValue::Iterator iter(*items_value); !iter.IsAtEnd();
+         iter.Advance()) {
+      EXPECT_EQ(0u, items->count(iter.key()));
+      items->insert(iter.key());
+    }
+    return OperationResult::kSuccess;
+  }
+
+  void DeleteAllItems(const std::string& extension_id) {
+    base::RunLoop run_loop;
+    DataItem::DeleteAllItemsForExtension(
+        context_.get(), value_store_cache_.get(), task_runner_.get(),
+        extension_id, run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  const Extension* extension() const { return extension_.get(); }
+
+ private:
+  void TearDownValueStoreCache() {
+    base::RunLoop run_loop;
+    task_runner_->PostTaskAndReply(
+        FROM_HERE,
+        base::Bind(&DataItemTest::ReleaseValueStoreCache,
+                   base::Unretained(this)),
+        run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  void ReleaseValueStoreCache() { value_store_cache_.reset(); }
+
+  base::ScopedTempDir test_dir_;
+
+  std::unique_ptr<content::TestBrowserContext> context_;
+
+  content::TestBrowserThreadBundle thread_bundle_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  std::unique_ptr<TestExtensionsBrowserClient> extensions_browser_client_;
+
+  scoped_refptr<TestValueStoreFactory> value_store_factory_;
+  std::unique_ptr<ValueStoreCache> value_store_cache_;
+
+  scoped_refptr<const Extension> extension_;
+
+  DISALLOW_COPY_AND_ASSIGN(DataItemTest);
+};
+
+TEST_F(DataItemTest, OperationsOnUnregisteredItem) {
+  std::unique_ptr<DataItem> item =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kNotFound,
+            WriteItemAndWaitForResult(item.get(), content));
+
+  EXPECT_EQ(OperationResult::kNotFound,
+            ReadItemAndWaitForResult(item.get(), nullptr));
+
+  EXPECT_EQ(OperationResult::kNotFound, DeleteItemAndWaitForResult(item.get()));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            RegisterItemAndWaitForResult(item.get()));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(item.get(), content));
+}
+
+TEST_F(DataItemTest, OperationsWithUnknownExtension) {
+  std::unique_ptr<DataItem> item =
+      CreateDataItem("data_id", "unknown", GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kUnknownExtension,
+            WriteItemAndWaitForResult(item.get(), content));
+
+  EXPECT_EQ(OperationResult::kUnknownExtension,
+            ReadItemAndWaitForResult(item.get(), nullptr));
+
+  EXPECT_EQ(OperationResult::kUnknownExtension,
+            DeleteItemAndWaitForResult(item.get()));
+
+  EXPECT_EQ(OperationResult::kUnknownExtension,
+            RegisterItemAndWaitForResult(item.get()));
+
+  std::set<std::string> item_ids;
+  EXPECT_EQ(OperationResult::kUnknownExtension,
+            GetRegisteredItemIds("unknown", &item_ids));
+}
+
+TEST_F(DataItemTest, ValueStoreErrors) {
+  std::unique_ptr<DataItem> item = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(item.get(), content));
+
+  SetReturnCodeForValueStoreOperations(extension()->id(),
+                                       ValueStore::OTHER_ERROR);
+
+  EXPECT_EQ(OperationResult::kNotFound,
+            ReadItemAndWaitForResult(item.get(), nullptr));
+  EXPECT_EQ(OperationResult::kNotFound,
+            WriteItemAndWaitForResult(item.get(), {'x'}));
+  EXPECT_EQ(OperationResult::kFailed, DeleteItemAndWaitForResult(item.get()));
+
+  std::unique_ptr<DataItem> unregistered =
+      CreateDataItem("data_id_1", extension()->id(), GenerateKey("key_1"));
+  EXPECT_EQ(OperationResult::kFailed,
+            RegisterItemAndWaitForResult(unregistered.get()));
+
+  std::set<std::string> item_ids;
+  EXPECT_EQ(OperationResult::kFailed,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+}
+
+TEST_F(DataItemTest, GetRegisteredItems) {
+  std::set<std::string> item_ids;
+  EXPECT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+  EXPECT_TRUE(item_ids.empty());
+
+  std::unique_ptr<DataItem> item_1 =
+      CreateDataItem("data_id_1", extension()->id(), GenerateKey("key_1"));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+  EXPECT_TRUE(item_ids.empty());
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            RegisterItemAndWaitForResult(item_1.get()));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+  EXPECT_EQ(std::set<std::string>({"data_id_1"}), item_ids);
+
+  std::unique_ptr<DataItem> item_2 = CreateAndRegisterDataItem(
+      "data_id_2", extension()->id(), GenerateKey("key_1"));
+
+  std::unique_ptr<DataItem> unregistered =
+      CreateDataItem("unregistered", extension()->id(), GenerateKey("key_1"));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+  EXPECT_EQ(std::set<std::string>({"data_id_1", "data_id_2"}), item_ids);
+
+  scoped_refptr<const Extension> secondary_extension =
+      CreateTestExtension(kSecondaryExtensionId);
+
+  std::unique_ptr<DataItem> secondary_extension_item =
+      CreateAndRegisterDataItem("data_id_2", secondary_extension->id(),
+                                GenerateKey("key_1"));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+  EXPECT_EQ(std::set<std::string>({"data_id_1", "data_id_2"}), item_ids);
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(secondary_extension->id(), &item_ids));
+  EXPECT_EQ(std::set<std::string>({"data_id_2"}), item_ids);
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            DeleteItemAndWaitForResult(item_2.get()));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+  EXPECT_EQ(std::set<std::string>({"data_id_1"}), item_ids);
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            DeleteItemAndWaitForResult(item_1.get()));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+  EXPECT_TRUE(item_ids.empty());
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(secondary_extension->id(), &item_ids));
+  EXPECT_EQ(std::set<std::string>({"data_id_2"}), item_ids);
+}
+
+TEST_F(DataItemTest, DoubleRegistration) {
+  std::unique_ptr<DataItem> item =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            RegisterItemAndWaitForResult(item.get()));
+
+  std::unique_ptr<DataItem> duplicate =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+
+  EXPECT_EQ(OperationResult::kAlreadyRegistered,
+            RegisterItemAndWaitForResult(duplicate.get()));
+
+  EXPECT_EQ(OperationResult::kSuccess, DeleteItemAndWaitForResult(item.get()));
+
+  EXPECT_EQ(OperationResult::kSuccess,
+            RegisterItemAndWaitForResult(duplicate.get()));
+}
+
+TEST_F(DataItemTest, ReadWrite) {
+  std::unique_ptr<DataItem> item = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(item.get(), content));
+
+  std::unique_ptr<std::vector<char>> read_content;
+  ASSERT_EQ(OperationResult::kSuccess,
+            ReadItemAndWaitForResult(item.get(), &read_content));
+  ASSERT_TRUE(read_content);
+  EXPECT_EQ(content, *read_content);
+
+  read_content.reset();
+  std::unique_ptr<DataItem> item_copy =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+  ASSERT_EQ(OperationResult::kSuccess,
+            ReadItemAndWaitForResult(item_copy.get(), &read_content));
+  ASSERT_TRUE(read_content);
+  EXPECT_EQ(content, *read_content);
+
+  std::unique_ptr<DataItem> different_key =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_2"));
+  EXPECT_EQ(OperationResult::kWrongKey,
+            ReadItemAndWaitForResult(different_key.get(), nullptr));
+}
+
+TEST_F(DataItemTest, ExtensionsWithConflictingDataItemIds) {
+  std::unique_ptr<DataItem> first = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  scoped_refptr<const Extension> second_extension =
+      CreateTestExtension(kSecondaryExtensionId);
+  ASSERT_NE(extension()->id(), second_extension->id());
+  std::unique_ptr<DataItem> second = CreateAndRegisterDataItem(
+      "data_id", second_extension->id(), GenerateKey("key_1"));
+
+  std::vector<char> first_content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(first.get(), first_content));
+
+  std::vector<char> second_content = {'f', 'i', 'l', 'e', '_', '2'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(second.get(), second_content));
+
+  std::unique_ptr<std::vector<char>> first_read;
+  ASSERT_EQ(OperationResult::kSuccess,
+            ReadItemAndWaitForResult(first.get(), &first_read));
+  ASSERT_TRUE(first_read);
+  EXPECT_EQ(first_content, *first_read);
+
+  std::unique_ptr<std::vector<char>> second_read;
+  ASSERT_EQ(OperationResult::kSuccess,
+            ReadItemAndWaitForResult(second.get(), &second_read));
+  ASSERT_TRUE(second_read);
+  EXPECT_EQ(second_content, *second_read);
+
+  EXPECT_EQ(OperationResult::kSuccess, DeleteItemAndWaitForResult(first.get()));
+
+  // The second extension item is still writable after the first extension's one
+  // went away.
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(second.get(), {'x'}));
+}
+
+TEST_F(DataItemTest, ReadNonRegisteredItem) {
+  std::unique_ptr<DataItem> item =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+
+  EXPECT_EQ(OperationResult::kNotFound,
+            ReadItemAndWaitForResult(item.get(), nullptr));
+}
+
+TEST_F(DataItemTest, ReadOldFile) {
+  std::unique_ptr<DataItem> writer = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(writer.get(), content));
+  writer.reset();
+
+  std::unique_ptr<DataItem> reader =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+  std::unique_ptr<std::vector<char>> read_content;
+  ASSERT_EQ(OperationResult::kSuccess,
+            ReadItemAndWaitForResult(reader.get(), &read_content));
+  ASSERT_TRUE(read_content);
+  EXPECT_EQ(content, *read_content);
+}
+
+TEST_F(DataItemTest, RepeatedWrite) {
+  std::unique_ptr<DataItem> writer = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  OperationResult write_result = OperationResult::kFailed;
+  std::vector<char> first_write = {'f', 'i', 'l', 'e', '_', '1'};
+  std::vector<char> second_write = {'f', 'i', 'l', 'e', '_', '2'};
+
+  writer->Write(
+      first_write,
+      base::Bind(&WriteCallback, base::Bind(&base::DoNothing), &write_result));
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(writer.get(), second_write));
+
+  std::unique_ptr<DataItem> reader =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+  std::unique_ptr<std::vector<char>> read_content;
+  ASSERT_EQ(OperationResult::kSuccess,
+            ReadItemAndWaitForResult(reader.get(), &read_content));
+  ASSERT_TRUE(read_content);
+  EXPECT_EQ(second_write, *read_content);
+}
+
+TEST_F(DataItemTest, ReadDeletedAndReregisteredItem) {
+  std::unique_ptr<DataItem> item = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(item.get(), content));
+
+  EXPECT_EQ(OperationResult::kSuccess, DeleteItemAndWaitForResult(item.get()));
+
+  std::unique_ptr<DataItem> duplicate = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::unique_ptr<std::vector<char>> read;
+  ASSERT_EQ(OperationResult::kSuccess,
+            ReadItemAndWaitForResult(duplicate.get(), &read));
+  ASSERT_TRUE(read);
+  EXPECT_TRUE(read->empty());
+}
+
+TEST_F(DataItemTest, ReadEmpty) {
+  std::unique_ptr<DataItem> item = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::unique_ptr<std::vector<char>> read_content;
+  ASSERT_EQ(OperationResult::kSuccess,
+            ReadItemAndWaitForResult(item.get(), &read_content));
+  ASSERT_TRUE(read_content);
+  EXPECT_TRUE(read_content->empty());
+
+  ASSERT_EQ(OperationResult::kSuccess, DeleteItemAndWaitForResult(item.get()));
+
+  EXPECT_EQ(OperationResult::kNotFound,
+            ReadItemAndWaitForResult(item.get(), nullptr));
+}
+
+TEST_F(DataItemTest, ReadDeletedItem) {
+  std::unique_ptr<DataItem> item = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(item.get(), content));
+
+  ASSERT_EQ(OperationResult::kSuccess, DeleteItemAndWaitForResult(item.get()));
+
+  EXPECT_EQ(OperationResult::kNotFound,
+            ReadItemAndWaitForResult(item.get(), nullptr));
+}
+
+TEST_F(DataItemTest, WriteDeletedItem) {
+  std::unique_ptr<DataItem> item = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(item.get(), content));
+
+  ASSERT_EQ(OperationResult::kSuccess, DeleteItemAndWaitForResult(item.get()));
+
+  EXPECT_EQ(OperationResult::kNotFound,
+            WriteItemAndWaitForResult(item.get(), content));
+}
+
+TEST_F(DataItemTest, WriteWithInvalidKey) {
+  std::unique_ptr<DataItem> item =
+      CreateAndRegisterDataItem("data_id", extension()->id(), "invalid");
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kInvalidKey,
+            WriteItemAndWaitForResult(item.get(), content));
+}
+
+TEST_F(DataItemTest, ReadWithInvalidKey) {
+  std::unique_ptr<DataItem> item = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(item.get(), content));
+
+  std::unique_ptr<DataItem> reader =
+      CreateDataItem("data_id", extension()->id(), "invalid");
+  EXPECT_EQ(OperationResult::kInvalidKey,
+            ReadItemAndWaitForResult(reader.get(), nullptr));
+}
+
+TEST_F(DataItemTest, ReadWithWrongKey) {
+  std::unique_ptr<DataItem> item = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  EXPECT_EQ(OperationResult::kSuccess,
+            WriteItemAndWaitForResult(item.get(), content));
+
+  std::unique_ptr<DataItem> reader =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_2"));
+  EXPECT_EQ(OperationResult::kWrongKey,
+            ReadItemAndWaitForResult(reader.get(), nullptr));
+}
+
+TEST_F(DataItemTest, ResetBeforeCallback) {
+  std::unique_ptr<DataItem> writer = CreateAndRegisterDataItem(
+      "data_id", extension()->id(), GenerateKey("key_1"));
+
+  std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
+  writer->Write(content, base::Bind(&WriteCallbackNotCalled, "Reset writer"));
+  writer.reset();
+
+  std::unique_ptr<DataItem> reader =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+  std::unique_ptr<std::vector<char>> read_content;
+  ASSERT_EQ(OperationResult::kSuccess,
+            ReadItemAndWaitForResult(reader.get(), &read_content));
+  ASSERT_TRUE(read_content);
+  EXPECT_EQ(content, *read_content);
+
+  reader->Read(base::Bind(&ReadCallbackNotCalled, "Reset read"));
+  reader.reset();
+
+  std::unique_ptr<DataItem> deleter =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+  deleter->Delete(base::Bind(&WriteCallbackNotCalled, "Reset deleter"));
+  deleter.reset();
+
+  DrainTaskRunner();
+
+  // Verify item write fails now the item's been deleted.
+  std::unique_ptr<DataItem> second_writer =
+      CreateDataItem("data_id", extension()->id(), GenerateKey("key_1"));
+  EXPECT_EQ(OperationResult::kNotFound,
+            WriteItemAndWaitForResult(second_writer.get(), content));
+}
+
+TEST_F(DataItemTest, DeleteAllForExtension) {
+  std::unique_ptr<DataItem> item_1 = CreateAndRegisterDataItem(
+      "data_id_1", extension()->id(), GenerateKey("key_1"));
+  ASSERT_TRUE(item_1);
+
+  std::unique_ptr<DataItem> item_2 = CreateAndRegisterDataItem(
+      "data_id_2", extension()->id(), GenerateKey("key_1"));
+  ASSERT_TRUE(item_2);
+
+  DeleteAllItems(extension()->id());
+
+  std::set<std::string> item_ids;
+  ASSERT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+  EXPECT_TRUE(item_ids.empty());
+
+  std::unique_ptr<DataItem> new_item = CreateAndRegisterDataItem(
+      "data_id_1", extension()->id(), GenerateKey("key_1"));
+  ASSERT_TRUE(item_2);
+
+  ASSERT_EQ(OperationResult::kSuccess,
+            GetRegisteredItemIds(extension()->id(), &item_ids));
+  EXPECT_EQ(std::set<std::string>({"data_id_1"}), item_ids);
+}
+
+}  // namespace lock_screen_data
+}  // namespace extensions
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_data_api.cc b/extensions/browser/api/lock_screen_data/lock_screen_data_api.cc
index 87943df..ad4fd781 100644
--- a/extensions/browser/api/lock_screen_data/lock_screen_data_api.cc
+++ b/extensions/browser/api/lock_screen_data/lock_screen_data_api.cc
@@ -4,21 +4,70 @@
 
 #include "extensions/browser/api/lock_screen_data/lock_screen_data_api.h"
 
-#include <memory>
+#include <string>
+#include <utility>
 #include <vector>
 
+#include "extensions/browser/api/lock_screen_data/data_item.h"
+#include "extensions/browser/api/lock_screen_data/lock_screen_item_storage.h"
+#include "extensions/browser/api/lock_screen_data/operation_result.h"
 #include "extensions/common/api/lock_screen_data.h"
 
 namespace extensions {
 
+namespace {
+
+std::string GetErrorString(lock_screen_data::OperationResult result) {
+  switch (result) {
+    case lock_screen_data::OperationResult::kSuccess:
+      NOTREACHED() << "Expected a failure code.";
+      return "Unknown";
+    case lock_screen_data::OperationResult::kFailed:
+      return "Unknown";
+    case lock_screen_data::OperationResult::kInvalidKey:
+    case lock_screen_data::OperationResult::kWrongKey:
+      return "Internal - encryption";
+    case lock_screen_data::OperationResult::kAlreadyRegistered:
+      return "Duplicate item";
+    case lock_screen_data::OperationResult::kNotFound:
+    case lock_screen_data::OperationResult::kUnknownExtension:
+      return "Not found";
+  }
+  NOTREACHED() << "Unknown operation status";
+  return "Unknown";
+}
+
+}  // namespace
+
 LockScreenDataCreateFunction::LockScreenDataCreateFunction() {}
 
 LockScreenDataCreateFunction::~LockScreenDataCreateFunction() {}
 
 ExtensionFunction::ResponseAction LockScreenDataCreateFunction::Run() {
+  lock_screen_data::LockScreenItemStorage* storage =
+      lock_screen_data::LockScreenItemStorage::GetIfAllowed(browser_context());
+  if (!storage) {
+    LOG(ERROR) << "Attempt to create data item from context which cannot use "
+               << "lock screen data item storage: " << source_context_type();
+    return RespondNow(Error("Not available"));
+  }
+
+  storage->CreateItem(extension_id(),
+                      base::Bind(&LockScreenDataCreateFunction::OnDone, this));
+  return RespondLater();
+}
+
+void LockScreenDataCreateFunction::OnDone(
+    lock_screen_data::OperationResult result,
+    const lock_screen_data::DataItem* item) {
+  if (result != lock_screen_data::OperationResult::kSuccess) {
+    Respond(Error(GetErrorString(result)));
+    return;
+  }
+
   api::lock_screen_data::DataItemInfo item_info;
-  item_info.id = "fake";
-  return RespondNow(
+  item_info.id = item->id();
+  Respond(
       ArgumentList(api::lock_screen_data::Create::Results::Create(item_info)));
 }
 
@@ -27,8 +76,28 @@
 LockScreenDataGetAllFunction::~LockScreenDataGetAllFunction() {}
 
 ExtensionFunction::ResponseAction LockScreenDataGetAllFunction::Run() {
+  lock_screen_data::LockScreenItemStorage* storage =
+      lock_screen_data::LockScreenItemStorage::GetIfAllowed(browser_context());
+  if (!storage)
+    return RespondNow(Error("Not available"));
+
+  storage->GetAllForExtension(
+      extension_id(), base::Bind(&LockScreenDataGetAllFunction::OnDone, this));
+  return RespondLater();
+}
+
+void LockScreenDataGetAllFunction::OnDone(
+    const std::vector<const lock_screen_data::DataItem*>& items) {
   std::vector<api::lock_screen_data::DataItemInfo> items_info;
-  return RespondNow(
+  for (auto* const item : items) {
+    if (!item)
+      continue;
+    api::lock_screen_data::DataItemInfo item_info;
+    item_info.id = item->id();
+    items_info.emplace_back(std::move(item_info));
+  }
+
+  Respond(
       ArgumentList(api::lock_screen_data::GetAll::Results::Create(items_info)));
 }
 
@@ -37,11 +106,30 @@
 LockScreenDataGetContentFunction::~LockScreenDataGetContentFunction() {}
 
 ExtensionFunction::ResponseAction LockScreenDataGetContentFunction::Run() {
+  lock_screen_data::LockScreenItemStorage* storage =
+      lock_screen_data::LockScreenItemStorage::GetIfAllowed(browser_context());
+  if (!storage)
+    return RespondNow(Error("Not available"));
+
   std::unique_ptr<api::lock_screen_data::GetContent::Params> params(
       api::lock_screen_data::GetContent::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  return RespondNow(Error("Not found"));
+  storage->GetItemContent(
+      extension_id(), params->id,
+      base::Bind(&LockScreenDataGetContentFunction::OnDone, this));
+  return RespondLater();
+}
+
+void LockScreenDataGetContentFunction::OnDone(
+    lock_screen_data::OperationResult result,
+    std::unique_ptr<std::vector<char>> data) {
+  if (result == lock_screen_data::OperationResult::kSuccess) {
+    Respond(ArgumentList(
+        api::lock_screen_data::GetContent::Results::Create(*data)));
+    return;
+  }
+  Respond(Error(GetErrorString(result)));
 }
 
 LockScreenDataSetContentFunction::LockScreenDataSetContentFunction() {}
@@ -53,7 +141,24 @@
       api::lock_screen_data::SetContent::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  return RespondNow(Error("Not found"));
+  lock_screen_data::LockScreenItemStorage* storage =
+      lock_screen_data::LockScreenItemStorage::GetIfAllowed(browser_context());
+  if (!storage)
+    return RespondNow(Error("Not available"));
+
+  storage->SetItemContent(
+      extension_id(), params->id, params->data,
+      base::Bind(&LockScreenDataSetContentFunction::OnDone, this));
+  return RespondLater();
+}
+
+void LockScreenDataSetContentFunction::OnDone(
+    lock_screen_data::OperationResult result) {
+  if (result == lock_screen_data::OperationResult::kSuccess) {
+    Respond(NoArguments());
+    return;
+  }
+  Respond(Error(GetErrorString(result)));
 }
 
 LockScreenDataDeleteFunction::LockScreenDataDeleteFunction() {}
@@ -64,7 +169,24 @@
   std::unique_ptr<api::lock_screen_data::Delete::Params> params(
       api::lock_screen_data::Delete::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  return RespondNow(Error("Not found."));
+
+  lock_screen_data::LockScreenItemStorage* storage =
+      lock_screen_data::LockScreenItemStorage::GetIfAllowed(browser_context());
+  if (!storage)
+    return RespondNow(Error("Not available"));
+
+  storage->DeleteItem(extension_id(), params->id,
+                      base::Bind(&LockScreenDataDeleteFunction::OnDone, this));
+  return RespondLater();
+}
+
+void LockScreenDataDeleteFunction::OnDone(
+    lock_screen_data::OperationResult result) {
+  if (result == lock_screen_data::OperationResult::kSuccess) {
+    Respond(NoArguments());
+    return;
+  }
+  Respond(Error(GetErrorString(result)));
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_data_api.h b/extensions/browser/api/lock_screen_data/lock_screen_data_api.h
index 83c75f6..bca0c76 100644
--- a/extensions/browser/api/lock_screen_data/lock_screen_data_api.h
+++ b/extensions/browser/api/lock_screen_data/lock_screen_data_api.h
@@ -5,11 +5,19 @@
 #ifndef EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_LOCK_SCREEN_DATA_API_H_
 #define EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_LOCK_SCREEN_DATA_API_H_
 
+#include <memory>
+#include <vector>
+
 #include "base/macros.h"
 #include "extensions/browser/extension_function.h"
 
 namespace extensions {
 
+namespace lock_screen_data {
+enum class OperationResult;
+class DataItem;
+}  // namespace lock_screen_data
+
 class LockScreenDataCreateFunction : public UIThreadExtensionFunction {
  public:
   LockScreenDataCreateFunction();
@@ -19,6 +27,9 @@
 
   ResponseAction Run() override;
 
+  void OnDone(lock_screen_data::OperationResult result,
+              const lock_screen_data::DataItem* item);
+
   DECLARE_EXTENSION_FUNCTION("lockScreen.data.create", LOCKSCREENDATA_CREATE);
   DISALLOW_COPY_AND_ASSIGN(LockScreenDataCreateFunction);
 };
@@ -32,6 +43,8 @@
 
   ResponseAction Run() override;
 
+  void OnDone(const std::vector<const lock_screen_data::DataItem*>& items);
+
   DECLARE_EXTENSION_FUNCTION("lockScreen.data.getAll", LOCKSCREENDATA_GETALL);
   DISALLOW_COPY_AND_ASSIGN(LockScreenDataGetAllFunction);
 };
@@ -45,6 +58,9 @@
 
   ResponseAction Run() override;
 
+  void OnDone(lock_screen_data::OperationResult result,
+              std::unique_ptr<std::vector<char>> data);
+
   DECLARE_EXTENSION_FUNCTION("lockScreen.data.getContent",
                              LOCKSCREENDATA_GETCONTENT);
   DISALLOW_COPY_AND_ASSIGN(LockScreenDataGetContentFunction);
@@ -59,6 +75,8 @@
 
   ResponseAction Run() override;
 
+  void OnDone(lock_screen_data::OperationResult result);
+
   DECLARE_EXTENSION_FUNCTION("lockScreen.data.setContent",
                              LOCKSCREENDATA_SETCONTENT);
   DISALLOW_COPY_AND_ASSIGN(LockScreenDataSetContentFunction);
@@ -73,6 +91,8 @@
 
   ResponseAction Run() override;
 
+  void OnDone(lock_screen_data::OperationResult result);
+
   DECLARE_EXTENSION_FUNCTION("lockScreen.data.delete", LOCKSCREENDATA_DELETE);
 
   DISALLOW_COPY_AND_ASSIGN(LockScreenDataDeleteFunction);
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_item_storage.cc b/extensions/browser/api/lock_screen_data/lock_screen_item_storage.cc
new file mode 100644
index 0000000..542af03
--- /dev/null
+++ b/extensions/browser/api/lock_screen_data/lock_screen_item_storage.cc
@@ -0,0 +1,486 @@
+// 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 "extensions/browser/api/lock_screen_data/lock_screen_item_storage.h"
+
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "extensions/browser/api/lock_screen_data/data_item.h"
+#include "extensions/browser/api/lock_screen_data/operation_result.h"
+#include "extensions/browser/api/storage/backend_task_runner.h"
+#include "extensions/browser/api/storage/local_value_store_cache.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/value_store/value_store.h"
+#include "extensions/browser/value_store/value_store_factory_impl.h"
+#include "extensions/common/api/lock_screen_data.h"
+
+namespace extensions {
+
+namespace lock_screen_data {
+
+namespace {
+
+const char kLockScreenDataPrefKey[] = "lockScreenDataItems";
+
+LockScreenItemStorage* g_data_item_storage = nullptr;
+
+LockScreenItemStorage::ItemFactoryCallback* g_test_item_factory_callback =
+    nullptr;
+LockScreenItemStorage::RegisteredItemsGetter*
+    g_test_registered_items_getter_callback = nullptr;
+LockScreenItemStorage::ItemStoreDeleter* g_test_delete_all_items_callback =
+    nullptr;
+
+std::unique_ptr<DataItem> CreateDataItem(const std::string& item_id,
+                                         const std::string& extension_id,
+                                         content::BrowserContext* context,
+                                         ValueStoreCache* value_store_cache,
+                                         base::SequencedTaskRunner* task_runner,
+                                         const std::string& crypto_key) {
+  return g_test_item_factory_callback
+             ? g_test_item_factory_callback->Run(item_id, extension_id,
+                                                 crypto_key)
+             : base::MakeUnique<DataItem>(item_id, extension_id, context,
+                                          value_store_cache, task_runner,
+                                          crypto_key);
+}
+
+void GetRegisteredItems(const std::string& extension_id,
+                        content::BrowserContext* context,
+                        ValueStoreCache* value_store_cache,
+                        base::SequencedTaskRunner* task_runner,
+                        const DataItem::RegisteredValuesCallback& callback) {
+  if (g_test_registered_items_getter_callback) {
+    g_test_registered_items_getter_callback->Run(extension_id, callback);
+    return;
+  }
+  DataItem::GetRegisteredValuesForExtension(
+      context, value_store_cache, task_runner, extension_id, callback);
+}
+
+void DeleteAllItems(const std::string& extension_id,
+                    content::BrowserContext* context,
+                    ValueStoreCache* value_store_cache,
+                    base::SequencedTaskRunner* task_runner,
+                    const base::Closure& callback) {
+  if (g_test_delete_all_items_callback) {
+    g_test_delete_all_items_callback->Run(extension_id, callback);
+    return;
+  }
+  DataItem::DeleteAllItemsForExtension(context, value_store_cache, task_runner,
+                                       extension_id, callback);
+}
+
+void ReleaseValueStoreCache(std::unique_ptr<LocalValueStoreCache> cache) {
+  // Nothing to do. Used only to defer |cache| destruction to the FILE thread.
+}
+
+}  // namespace
+
+// static
+LockScreenItemStorage* LockScreenItemStorage::GetIfAllowed(
+    content::BrowserContext* context) {
+  if (g_data_item_storage && !g_data_item_storage->IsContextAllowed(context))
+    return nullptr;
+  return g_data_item_storage;
+}
+
+// static
+void LockScreenItemStorage::RegisterLocalState(PrefRegistrySimple* registry) {
+  registry->RegisterDictionaryPref(kLockScreenDataPrefKey);
+}
+
+LockScreenItemStorage::LockScreenItemStorage(content::BrowserContext* context,
+                                             PrefService* local_state,
+                                             const std::string& crypto_key,
+                                             const base::FilePath& storage_root)
+    : context_(context),
+      user_id_(
+          ExtensionsBrowserClient::Get()->GetUserIdHashFromContext(context)),
+      crypto_key_(crypto_key),
+      local_state_(local_state),
+      storage_root_(storage_root.Append(user_id_)),
+      extension_registry_observer_(this),
+      value_store_cache_(base::MakeUnique<LocalValueStoreCache>(
+          new ValueStoreFactoryImpl(storage_root))),
+      weak_ptr_factory_(this) {
+  CHECK(!user_id_.empty());
+  extension_registry_observer_.Add(ExtensionRegistry::Get(context));
+  task_runner_ = GetBackendTaskRunner();
+
+  DCHECK(!g_data_item_storage);
+  g_data_item_storage = this;
+
+  ClearUninstalledAppData();
+}
+
+LockScreenItemStorage::~LockScreenItemStorage() {
+  data_item_cache_.clear();
+
+  task_runner_->PostTask(
+      FROM_HERE, base::Bind(&ReleaseValueStoreCache,
+                            base::Passed(std::move(value_store_cache_))));
+
+  DCHECK_EQ(g_data_item_storage, this);
+  g_data_item_storage = nullptr;
+}
+
+// static
+void LockScreenItemStorage::SetItemProvidersForTesting(
+    RegisteredItemsGetter* items_getter_callback,
+    ItemFactoryCallback* factory_callback,
+    ItemStoreDeleter* deleter_callback) {
+  g_test_registered_items_getter_callback = items_getter_callback;
+  g_test_item_factory_callback = factory_callback;
+  g_test_delete_all_items_callback = deleter_callback;
+}
+
+void LockScreenItemStorage::SetSessionLocked(bool session_locked) {
+  SessionLockedState new_state = session_locked
+                                     ? SessionLockedState::kLocked
+                                     : SessionLockedState::kNotLocked;
+  if (new_state == session_locked_state_)
+    return;
+
+  bool was_locked = session_locked_state_ == SessionLockedState::kLocked;
+  session_locked_state_ = new_state;
+
+  if (session_locked_state_ != SessionLockedState::kNotLocked)
+    return;
+
+  EventRouter* event_router = EventRouter::Get(context_);
+  std::set<std::string> extensions = GetExtensionsWithDataItems(false);
+  for (const auto& id : extensions) {
+    // If the session state is unlocked, dispatch Item availability events to
+    // apps with available data items.
+    api::lock_screen_data::DataItemsAvailableEvent event_args;
+    event_args.was_locked = was_locked;
+
+    std::unique_ptr<Event> event = base::MakeUnique<Event>(
+        events::LOCK_SCREEN_DATA_ON_DATA_ITEMS_AVAILABLE,
+        api::lock_screen_data::OnDataItemsAvailable::kEventName,
+        api::lock_screen_data::OnDataItemsAvailable::Create(event_args));
+    event_router->DispatchEventToExtension(id, std::move(event));
+  }
+}
+
+void LockScreenItemStorage::CreateItem(const std::string& extension_id,
+                                       const CreateCallback& callback) {
+  EnsureCacheForExtensionLoaded(
+      extension_id,
+      base::Bind(&LockScreenItemStorage::CreateItemImpl,
+                 weak_ptr_factory_.GetWeakPtr(), extension_id, callback));
+}
+
+void LockScreenItemStorage::GetAllForExtension(
+    const std::string& extension_id,
+    const DataItemListCallback& callback) {
+  EnsureCacheForExtensionLoaded(
+      extension_id,
+      base::Bind(&LockScreenItemStorage::GetAllForExtensionImpl,
+                 weak_ptr_factory_.GetWeakPtr(), extension_id, callback));
+}
+
+void LockScreenItemStorage::SetItemContent(
+    const std::string& extension_id,
+    const std::string& item_id,
+    const std::vector<char>& data,
+    const LockScreenItemStorage::WriteCallback& callback) {
+  EnsureCacheForExtensionLoaded(
+      extension_id, base::Bind(&LockScreenItemStorage::SetItemContentImpl,
+                               weak_ptr_factory_.GetWeakPtr(), extension_id,
+                               item_id, data, callback));
+}
+
+void LockScreenItemStorage::GetItemContent(
+    const std::string& extension_id,
+    const std::string& item_id,
+    const LockScreenItemStorage::ReadCallback& callback) {
+  EnsureCacheForExtensionLoaded(
+      extension_id, base::Bind(&LockScreenItemStorage::GetItemContentImpl,
+                               weak_ptr_factory_.GetWeakPtr(), extension_id,
+                               item_id, callback));
+}
+
+void LockScreenItemStorage::DeleteItem(const std::string& extension_id,
+                                       const std::string& item_id,
+                                       const WriteCallback& callback) {
+  EnsureCacheForExtensionLoaded(
+      extension_id, base::Bind(&LockScreenItemStorage::DeleteItemImpl,
+                               weak_ptr_factory_.GetWeakPtr(), extension_id,
+                               item_id, callback));
+}
+
+void LockScreenItemStorage::OnExtensionUninstalled(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    UninstallReason reason) {
+  ClearExtensionData(extension->id());
+}
+
+LockScreenItemStorage::CachedExtensionData::CachedExtensionData() = default;
+
+LockScreenItemStorage::CachedExtensionData::~CachedExtensionData() = default;
+
+bool LockScreenItemStorage::IsContextAllowed(content::BrowserContext* context) {
+  switch (session_locked_state_) {
+    case SessionLockedState::kUnknown:
+      return false;
+    case SessionLockedState::kLocked:
+      return ExtensionsBrowserClient::Get()->IsLockScreenContext(context);
+    case SessionLockedState::kNotLocked:
+      return context_ == context;
+  }
+  NOTREACHED() << "Unknown session locked state";
+  return false;
+}
+
+void LockScreenItemStorage::CreateItemImpl(const std::string& extension_id,
+                                           const CreateCallback& callback) {
+  std::unique_ptr<DataItem> item =
+      CreateDataItem(base::GenerateGUID(), extension_id, context_,
+                     value_store_cache_.get(), task_runner_.get(), crypto_key_);
+  DataItem* item_ptr = item.get();
+  item_ptr->Register(base::Bind(
+      &LockScreenItemStorage::OnItemRegistered, weak_ptr_factory_.GetWeakPtr(),
+      base::Passed(std::move(item)), extension_id, callback));
+}
+
+void LockScreenItemStorage::GetAllForExtensionImpl(
+    const std::string& extension_id,
+    const DataItemListCallback& callback) {
+  std::vector<const DataItem*> items;
+  ExtensionDataMap::iterator extension_data =
+      data_item_cache_.find(extension_id);
+  if (extension_data == data_item_cache_.end()) {
+    callback.Run(items);
+    return;
+  }
+
+  for (const auto& item : extension_data->second.data_items) {
+    if (!item.second)
+      continue;
+    items.push_back(item.second.get());
+  }
+
+  callback.Run(items);
+}
+
+void LockScreenItemStorage::SetItemContentImpl(
+    const std::string& extension_id,
+    const std::string& item_id,
+    const std::vector<char>& data,
+    const LockScreenItemStorage::WriteCallback& callback) {
+  DataItem* item = FindItem(extension_id, item_id);
+  if (!item) {
+    callback.Run(OperationResult::kNotFound);
+    return;
+  }
+
+  item->Write(data, callback);
+}
+
+void LockScreenItemStorage::GetItemContentImpl(const std::string& extension_id,
+                                               const std::string& item_id,
+                                               const ReadCallback& callback) {
+  DataItem* item = FindItem(extension_id, item_id);
+  if (!item) {
+    callback.Run(OperationResult::kNotFound, nullptr);
+    return;
+  }
+
+  item->Read(callback);
+}
+
+void LockScreenItemStorage::DeleteItemImpl(const std::string& extension_id,
+                                           const std::string& item_id,
+                                           const WriteCallback& callback) {
+  DataItem* item = FindItem(extension_id, item_id);
+  if (!item) {
+    callback.Run(OperationResult::kNotFound);
+    return;
+  }
+
+  item->Delete(base::Bind(&LockScreenItemStorage::OnItemDeleted,
+                          base::Unretained(this), extension_id, item_id,
+                          callback));
+}
+
+void LockScreenItemStorage::OnItemRegistered(std::unique_ptr<DataItem> item,
+                                             const std::string& extension_id,
+                                             const CreateCallback& callback,
+                                             OperationResult result) {
+  if (result != OperationResult::kSuccess) {
+    callback.Run(result, nullptr);
+    return;
+  }
+
+  DataItem* item_ptr = item.get();
+  data_item_cache_[extension_id].data_items.emplace(item_ptr->id(),
+                                                    std::move(item));
+
+  {
+    DictionaryPrefUpdate update(local_state_, kLockScreenDataPrefKey);
+    update->SetInteger(user_id_ + "." + extension_id,
+                       data_item_cache_[extension_id].data_items.size());
+  }
+
+  callback.Run(OperationResult::kSuccess, item_ptr);
+}
+
+void LockScreenItemStorage::OnItemDeleted(const std::string& extension_id,
+                                          const std::string& item_id,
+                                          const WriteCallback& callback,
+                                          OperationResult result) {
+  data_item_cache_[extension_id].data_items.erase(item_id);
+  {
+    DictionaryPrefUpdate update(local_state_, kLockScreenDataPrefKey);
+    update->SetInteger(user_id_ + "." + extension_id,
+                       data_item_cache_[extension_id].data_items.size());
+  }
+
+  callback.Run(result);
+}
+
+void LockScreenItemStorage::EnsureCacheForExtensionLoaded(
+    const std::string& extension_id,
+    const base::Closure& callback) {
+  CachedExtensionData* data = &data_item_cache_[extension_id];
+  if (data->state == CachedExtensionData::State::kLoaded) {
+    callback.Run();
+    return;
+  }
+
+  data->load_callbacks.push_back(callback);
+
+  if (data->state == CachedExtensionData::State::kLoading)
+    return;
+
+  data->state = CachedExtensionData::State::kLoading;
+
+  GetRegisteredItems(extension_id, context_, value_store_cache_.get(),
+                     task_runner_.get(),
+                     base::Bind(&LockScreenItemStorage::OnGotExtensionItems,
+                                weak_ptr_factory_.GetWeakPtr(), extension_id));
+}
+
+void LockScreenItemStorage::OnGotExtensionItems(
+    const std::string& extension_id,
+    OperationResult result,
+    std::unique_ptr<base::DictionaryValue> items) {
+  ExtensionDataMap::iterator data = data_item_cache_.find(extension_id);
+  if (data == data_item_cache_.end() ||
+      data->second.state != CachedExtensionData::State::kLoading) {
+    return;
+  }
+
+  if (result == OperationResult::kSuccess) {
+    for (base::DictionaryValue::Iterator item_iter(*items);
+         !item_iter.IsAtEnd(); item_iter.Advance()) {
+      std::unique_ptr<DataItem> item = CreateDataItem(
+          item_iter.key(), extension_id, context_, value_store_cache_.get(),
+          task_runner_.get(), crypto_key_);
+      data->second.data_items.emplace(item_iter.key(), std::move(item));
+    }
+  }
+
+  DictionaryPrefUpdate update(local_state_, kLockScreenDataPrefKey);
+  update->SetInteger(user_id_ + "." + extension_id,
+                     data->second.data_items.size());
+
+  data->second.state = CachedExtensionData::State::kLoaded;
+
+  std::vector<base::Closure> callbacks;
+  callbacks.swap(data->second.load_callbacks);
+  for (auto& callback : callbacks)
+    callback.Run();
+}
+
+DataItem* LockScreenItemStorage::FindItem(const std::string& extension_id,
+                                          const std::string& item_id) {
+  ExtensionDataMap::iterator extension_data =
+      data_item_cache_.find(extension_id);
+  if (extension_data == data_item_cache_.end())
+    return nullptr;
+
+  if (extension_data->second.state != CachedExtensionData::State::kLoaded)
+    return nullptr;
+  DataItemMap::iterator item_it =
+      extension_data->second.data_items.find(item_id);
+  if (item_it == extension_data->second.data_items.end())
+    return nullptr;
+
+  if (!item_it->second)
+    return nullptr;
+  return item_it->second.get();
+}
+
+std::set<std::string> LockScreenItemStorage::GetExtensionsWithDataItems(
+    bool include_empty) {
+  std::set<std::string> result;
+
+  const base::DictionaryValue* user_data = nullptr;
+  const base::DictionaryValue* items =
+      local_state_->GetDictionary(kLockScreenDataPrefKey);
+  if (!items || !items->GetDictionary(user_id_, &user_data) || !user_data)
+    return result;
+
+  for (base::DictionaryValue::Iterator extension_iter(*user_data);
+       !extension_iter.IsAtEnd(); extension_iter.Advance()) {
+    if (extension_iter.value().is_int() &&
+        (include_empty || extension_iter.value().GetInt() > 0)) {
+      result.insert(extension_iter.key());
+    }
+  }
+  return result;
+}
+
+void LockScreenItemStorage::ClearUninstalledAppData() {
+  std::set<std::string> extensions =
+      GetExtensionsWithDataItems(true /* include_empty */);
+  for (const auto& id : extensions) {
+    if (!ExtensionRegistry::Get(context_)->GetInstalledExtension(id))
+      ClearExtensionData(id);
+  }
+}
+
+void LockScreenItemStorage::ClearExtensionData(const std::string& id) {
+  DeleteAllItems(
+      id, context_, value_store_cache_.get(), task_runner_.get(),
+      base::Bind(&LockScreenItemStorage::RemoveExtensionFromLocalState,
+                 weak_ptr_factory_.GetWeakPtr(), id));
+}
+
+void LockScreenItemStorage::RemoveExtensionFromLocalState(
+    const std::string& id) {
+  {
+    DictionaryPrefUpdate update(local_state_, kLockScreenDataPrefKey);
+    update->Remove(user_id_ + "." + id, nullptr);
+  }
+
+  ExtensionDataMap::iterator it = data_item_cache_.find(id);
+  if (it == data_item_cache_.end())
+    return;
+
+  std::vector<base::Closure> callbacks;
+  callbacks.swap(it->second.load_callbacks);
+
+  data_item_cache_.erase(it);
+
+  for (auto& callback : callbacks)
+    callback.Run();
+}
+
+}  // namespace lock_screen_data
+}  // namespace extensions
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_item_storage.h b/extensions/browser/api/lock_screen_data/lock_screen_item_storage.h
new file mode 100644
index 0000000..b7d593b
--- /dev/null
+++ b/extensions/browser/api/lock_screen_data/lock_screen_item_storage.h
@@ -0,0 +1,267 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_LOCK_SCREEN_ITEM_STORAGE_H_
+#define EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_LOCK_SCREEN_ITEM_STORAGE_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
+#include "base/sequenced_task_runner.h"
+#include "extensions/browser/api/lock_screen_data/data_item.h"
+#include "extensions/browser/extension_registry_observer.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+
+class Extension;
+class ExtensionRegistry;
+class LocalValueStoreCache;
+
+namespace lock_screen_data {
+
+class DataItem;
+enum class OperationResult;
+
+// Keeps track of lock screen data items created by extensions.
+// Note that only a single instance is allowed per process - once created, the
+// instance can be retrieved using LockScreenItemStorage::GetIfAllowed().
+class LockScreenItemStorage : public ExtensionRegistryObserver {
+ public:
+  using CreateCallback =
+      base::Callback<void(OperationResult result, const DataItem* item)>;
+  using DataItemListCallback =
+      base::Callback<void(const std::vector<const DataItem*>& items)>;
+  using WriteCallback = DataItem::WriteCallback;
+  using ReadCallback = DataItem::ReadCallback;
+
+  static void RegisterLocalState(PrefRegistrySimple* registry);
+
+  // Gets the global LockScreenItemStorage instance if lock screen item storage
+  // can be used from the browser context.
+  // |context| - Context from which the item storage is needed, if the context
+  // is not allowed to use LockScreenItemStorage, this will return nullptr.
+  // LockScreenItemStorage can be only used from:
+  //  *  lock screen browser context while session state is set to locked
+  //  *  from the browser process passed to the LockScreenItemStorage ctor when
+  //     the session state is set to unlocked.
+  static LockScreenItemStorage* GetIfAllowed(content::BrowserContext* context);
+
+  // Creates a LockScreenItemStorage instance. Note that only one
+  // LockScreenItemStorage can be present at a time - the constructor will set a
+  // global reference to the created object that can be retrieved using
+  // LockScreenItemStorage::GetIfAllowed (the reference will be reset when the
+  // instance goes out of scoped, i.e. in ~LockScreenItemStorage).
+  //
+  // |context| - primary user context, only apps from that context should be
+  //     able to use the storage.
+  // |local_state| - Local state preference.
+  // |crypto_key| - Symmetric key that should be used to encrypt data content
+  //     when it's persisted on the disk.
+  // |storage_root| - Directory on the disk to which data item content should be
+  //     persisted.
+  LockScreenItemStorage(content::BrowserContext* context,
+                        PrefService* local_state,
+                        const std::string& crypto_key,
+                        const base::FilePath& storage_root);
+  ~LockScreenItemStorage() override;
+
+  // Updates the LockScreenItemStorage's view of whether the user session is
+  // locked.
+  void SetSessionLocked(bool session_locked);
+
+  // Creates a new data item for the extension.
+  void CreateItem(const std::string& extension_id,
+                  const CreateCallback& callback);
+
+  // Returns all existing data items associated with the extension.
+  void GetAllForExtension(const std::string& extension_id,
+                          const DataItemListCallback& callback);
+
+  // Updates the content of the item identified by |item_id| that is associated
+  // with the provided extension.
+  void SetItemContent(const std::string& extension_id,
+                      const std::string& item_id,
+                      const std::vector<char>& data,
+                      const WriteCallback& callback);
+
+  // Retrieves the content of the item identified by |item_id| that is
+  // associated with the provided extension.
+  void GetItemContent(const std::string& extension_id,
+                      const std::string& item_id,
+                      const ReadCallback& callback);
+
+  // Deletes the data item associated with the extension.
+  void DeleteItem(const std::string& extension_id,
+                  const std::string& item_id,
+                  const WriteCallback& callback);
+
+  // extensions::ExtensionRegistryObserver:
+  void OnExtensionUninstalled(content::BrowserContext* browser_context,
+                              const Extension* extension,
+                              UninstallReason reason) override;
+
+  // Used in tests to inject fake data items implementations.
+  using ItemFactoryCallback =
+      base::Callback<std::unique_ptr<DataItem>(const std::string& id,
+                                               const std::string& extension_id,
+                                               const std::string& crypto_key)>;
+  using RegisteredItemsGetter =
+      base::Callback<void(const std::string& extension_id,
+                          const DataItem::RegisteredValuesCallback& callback)>;
+  using ItemStoreDeleter = base::Callback<void(const std::string& extension_id,
+                                               const base::Closure& callback)>;
+  static void SetItemProvidersForTesting(
+      RegisteredItemsGetter* item_fetch_callback,
+      ItemFactoryCallback* factory_callback,
+      ItemStoreDeleter* deleter_callback);
+
+ private:
+  // Maps a data item ID to the data item instance.
+  using DataItemMap =
+      std::unordered_map<std::string, std::unique_ptr<DataItem>>;
+
+  // Contains information about cached data item information for an extension -
+  // in particular, the list of existing data items.
+  struct CachedExtensionData {
+    enum class State {
+      // The set of registered data items has not been requested.
+      kInitial,
+      // The initial set of registered data items is being loaded.
+      kLoading,
+      // The set of registered data items has been loaded; the cached list of
+      // items should be up to date.
+      kLoaded,
+    };
+
+    CachedExtensionData();
+    ~CachedExtensionData();
+
+    State state = State::kInitial;
+    // The set of registered data items.
+    DataItemMap data_items;
+    // When the initial data item list is being loaded, contains the callback
+    // waiting for the load to finish. When the initial data item set is loaded,
+    // all of the callbacks in this list will be run.
+    std::vector<base::Closure> load_callbacks;
+  };
+
+  // Maps an extension ID to data items associated with the extension.
+  using ExtensionDataMap = std::unordered_map<std::string, CachedExtensionData>;
+
+  // The session state as seen by the LockScreenItemStorage.
+  enum class SessionLockedState { kUnknown, kLocked, kNotLocked };
+
+  // Whether the context is allowed to use LockScreenItemStorage.
+  // Result depends on the current LockScreenItemStorage state - see
+  // |LockScreenItemStorage::GetIfAllowed|.
+  bool IsContextAllowed(content::BrowserContext* context);
+
+  // Implementations for data item management methods - called when the data
+  // cache for the associated extension was initialized:
+  void CreateItemImpl(const std::string& extension_id,
+                      const CreateCallback& callback);
+  void GetAllForExtensionImpl(const std::string& extension_id,
+                              const DataItemListCallback& callback);
+  void SetItemContentImpl(const std::string& extension_id,
+                          const std::string& item_id,
+                          const std::vector<char>& data,
+                          const WriteCallback& callback);
+  void GetItemContentImpl(const std::string& extension_id,
+                          const std::string& item_id,
+                          const ReadCallback& callback);
+  void DeleteItemImpl(const std::string& extension_id,
+                      const std::string& item_id,
+                      const WriteCallback& callback);
+
+  // Defers |callback| until the cached data item set is loaded for the
+  // extension. If the data is already loaded, |callback| will be run
+  // immediately.
+  void EnsureCacheForExtensionLoaded(const std::string& extension_id,
+                                     const base::Closure& callback);
+
+  // Callback for loading initial set of known data items for an extension.
+  void OnGotExtensionItems(const std::string& extension_id,
+                           OperationResult result,
+                           std::unique_ptr<base::DictionaryValue> items);
+
+  // Callback for registration operation of a newly created data item - it adds
+  // the item to the cached data item state, and invoked the callback.
+  void OnItemRegistered(std::unique_ptr<DataItem> item,
+                        const std::string& extension_id,
+                        const CreateCallback& callback,
+                        OperationResult result);
+
+  // Callback for item deletion operation. It removes the item from the cached
+  // state and invokes the callback with the operation result.
+  void OnItemDeleted(const std::string& extension_id,
+                     const std::string& item_id,
+                     const WriteCallback& callback,
+                     OperationResult result);
+
+  // Finds a data item associated with the extension.
+  DataItem* FindItem(const std::string& extension_id,
+                     const std::string& item_id);
+
+  // Gets the set of extensions that are known to have registered data items -
+  // this information is kept in the local state so it can be used to
+  // synchronously determine the set of extensions that should be sent a
+  // DataItemsAvailable event, and to determine the set of extensions whose data
+  // should be deleted (for example if they are not installed anymore).
+  std::set<std::string> GetExtensionsWithDataItems(bool include_empty);
+
+  // Deletes data item data for all extensions that have existing data items,
+  // but are not currently installed.
+  void ClearUninstalledAppData();
+
+  // Clears all data items associated with the extension.
+  void ClearExtensionData(const std::string& id);
+
+  // Removes local state entry for the extension.
+  void RemoveExtensionFromLocalState(const std::string& id);
+
+  content::BrowserContext* context_;
+
+  // The user associated with the primary profile.
+  const std::string user_id_;
+  const std::string crypto_key_;
+  PrefService* local_state_;
+  const base::FilePath storage_root_;
+
+  SessionLockedState session_locked_state_ = SessionLockedState::kUnknown;
+
+  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
+      extension_registry_observer_;
+
+  // Expected to be used only on FILE thread.
+  std::unique_ptr<LocalValueStoreCache> value_store_cache_;
+
+  // Mapping containing all known data items for extensions.
+  ExtensionDataMap data_item_cache_;
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  base::WeakPtrFactory<LockScreenItemStorage> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(LockScreenItemStorage);
+};
+
+}  // namespace lock_screen_data
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_LOCK_SCREEN_ITEM_STORAGE_H_
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc b/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc
new file mode 100644
index 0000000..e84a970
--- /dev/null
+++ b/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc
@@ -0,0 +1,1046 @@
+// 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 "extensions/browser/api/lock_screen_data/lock_screen_item_storage.h"
+
+#include <map>
+#include <memory>
+#include <queue>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/time/time.h"
+#include "chromeos/login/login_state.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/browser/api/lock_screen_data/data_item.h"
+#include "extensions/browser/api/lock_screen_data/operation_result.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/event_router_factory.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extensions_test.h"
+#include "extensions/browser/test_extensions_browser_client.h"
+#include "extensions/common/api/lock_screen_data.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/value_builder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+namespace lock_screen_data {
+
+namespace {
+
+const char kTestUserIdHash[] = "user_id_hash";
+const char kTestSymmetricKey[] = "fake_symmetric_key";
+
+void RecordCreateResult(OperationResult* result_out,
+                        const DataItem** item_out,
+                        OperationResult result,
+                        const DataItem* item) {
+  *result_out = result;
+  *item_out = item;
+}
+
+void RecordGetAllItemsResult(std::vector<std::string>* items_out,
+                             const std::vector<const DataItem*>& items) {
+  items_out->clear();
+  for (const DataItem* item : items)
+    items_out->push_back(item->id());
+}
+
+void RecordWriteResult(OperationResult* result_out, OperationResult result) {
+  *result_out = result;
+}
+
+void RecordReadResult(OperationResult* result_out,
+                      std::unique_ptr<std::vector<char>>* content_out,
+                      OperationResult result,
+                      std::unique_ptr<std::vector<char>> content) {
+  *result_out = result;
+  *content_out = std::move(content);
+}
+
+class TestEventRouter : public extensions::EventRouter {
+ public:
+  explicit TestEventRouter(content::BrowserContext* context)
+      : extensions::EventRouter(context, nullptr) {}
+  ~TestEventRouter() override = default;
+
+  bool ExtensionHasEventListener(const std::string& extension_id,
+                                 const std::string& event_name) const override {
+    return event_name ==
+           extensions::api::lock_screen_data::OnDataItemsAvailable::kEventName;
+  }
+
+  void BroadcastEvent(std::unique_ptr<extensions::Event> event) override {}
+
+  void DispatchEventToExtension(
+      const std::string& extension_id,
+      std::unique_ptr<extensions::Event> event) override {
+    if (event->event_name !=
+        extensions::api::lock_screen_data::OnDataItemsAvailable::kEventName) {
+      return;
+    }
+    ASSERT_TRUE(event->event_args);
+    const base::Value* arg_value = nullptr;
+    ASSERT_TRUE(event->event_args->Get(0, &arg_value));
+    ASSERT_TRUE(arg_value);
+
+    std::unique_ptr<extensions::api::lock_screen_data::DataItemsAvailableEvent>
+        event_args = extensions::api::lock_screen_data::
+            DataItemsAvailableEvent::FromValue(*arg_value);
+    ASSERT_TRUE(event_args);
+    was_locked_values_.push_back(event_args->was_locked);
+  }
+
+  const std::vector<bool>& was_locked_values() const {
+    return was_locked_values_;
+  }
+
+  void ClearWasLockedValues() { was_locked_values_.clear(); }
+
+ private:
+  std::vector<bool> was_locked_values_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestEventRouter);
+};
+
+std::unique_ptr<KeyedService> TestEventRouterFactoryFunction(
+    content::BrowserContext* context) {
+  return base::MakeUnique<TestEventRouter>(context);
+}
+
+// Keeps track of all fake data items registered during a test.
+class ItemRegistry {
+ public:
+  explicit ItemRegistry(const std::string& extension_id)
+      : extension_id_(extension_id) {}
+  ~ItemRegistry() = default;
+
+  // Adds a new item to set of registered items.
+  bool Add(const std::string& item_id) {
+    EXPECT_FALSE(items_.count(item_id));
+
+    if (!allow_new_)
+      return false;
+    items_.insert(item_id);
+    return true;
+  }
+
+  // Removes an item from the set of registered items.
+  void Remove(const std::string& item_id) {
+    ASSERT_TRUE(items_.count(item_id));
+    items_.erase(item_id);
+  }
+
+  void RemoveAll() { items_.clear(); }
+
+  // Gets the set of registered data items.
+  void HandleGetRequest(const DataItem::RegisteredValuesCallback& callback) {
+    if (!throttle_get_) {
+      RunCallback(callback);
+      return;
+    }
+
+    ASSERT_TRUE(pending_callback_.is_null());
+    pending_callback_ = callback;
+  }
+
+  // Completes a pending |HandleGetRequest| request.
+  void RunPendingCallback() {
+    ASSERT_FALSE(pending_callback_.is_null());
+    DataItem::RegisteredValuesCallback callback = pending_callback_;
+    pending_callback_.Reset();
+    RunCallback(callback);
+  }
+
+  bool HasPendingCallback() const { return !pending_callback_.is_null(); }
+
+  void set_allow_new(bool allow_new) { allow_new_ = allow_new; }
+  void set_fail(bool fail) { fail_ = fail; }
+  void set_throttle_get(bool throttle_get) { throttle_get_ = throttle_get; }
+
+ private:
+  void RunCallback(const DataItem::RegisteredValuesCallback& callback) {
+    callback.Run(fail_ ? OperationResult::kFailed : OperationResult::kSuccess,
+                 ItemsToValue());
+  }
+
+  std::unique_ptr<base::DictionaryValue> ItemsToValue() {
+    if (fail_)
+      return nullptr;
+
+    std::unique_ptr<base::DictionaryValue> result =
+        base::MakeUnique<base::DictionaryValue>();
+
+    for (const std::string& item_id : items_)
+      result->Set(item_id, base::MakeUnique<base::DictionaryValue>());
+
+    return result;
+  }
+
+  const std::string extension_id_;
+  // Whether data item registration should succeed.
+  bool allow_new_ = true;
+  // Whether data item retrievals should fail.
+  bool fail_ = false;
+  // Whether the data item retrivals should be throttled. If set,
+  // |HandleGetRequest| callback will be saved to |pending_callback_| without
+  // returning. Test will have to invoke |RunPendingCallback| in order to
+  // complete the request.
+  bool throttle_get_ = false;
+
+  DataItem::RegisteredValuesCallback pending_callback_;
+  // Set of registered item ids.
+  std::set<std::string> items_;
+
+  DISALLOW_COPY_AND_ASSIGN(ItemRegistry);
+};
+
+// Keeps track of all operations requested from the test data item.
+// The operations will remain in pending state until completed by calling
+// CompleteNextOperation.
+// This is owned by the test class, but data items created during the test have
+// a reference to the object. More than one data item can have a reference to
+// this - data items with the same ID will get the same operation queue.
+class OperationQueue {
+ public:
+  enum class OperationType { kWrite, kRead, kDelete };
+
+  struct PendingOperation {
+    explicit PendingOperation(OperationType type) : type(type) {}
+
+    OperationType type;
+    // Set only for write - data to be written.
+    std::vector<char> data;
+
+    // Callback for write operation.
+    DataItem::WriteCallback write_callback;
+
+    // Callback for read operation.
+    DataItem::ReadCallback read_callback;
+
+    // Callback for delete operation.
+    DataItem::WriteCallback delete_callback;
+  };
+
+  OperationQueue(const std::string& id, ItemRegistry* item_registry)
+      : id_(id), item_registry_(item_registry) {}
+
+  ~OperationQueue() = default;
+
+  void Register(const DataItem::WriteCallback& callback) {
+    bool registered = item_registry_->Add(id_);
+    callback.Run(registered ? OperationResult::kSuccess
+                            : OperationResult::kFailed);
+  }
+
+  void AddWrite(const std::vector<char>& data,
+                const DataItem::WriteCallback& callback) {
+    PendingOperation operation(OperationType::kWrite);
+    operation.data = data;
+    operation.write_callback = callback;
+
+    pending_operations_.emplace(std::move(operation));
+  }
+
+  void AddRead(const DataItem::ReadCallback& callback) {
+    PendingOperation operation(OperationType::kRead);
+    operation.read_callback = callback;
+
+    pending_operations_.emplace(std::move(operation));
+  }
+
+  void AddDelete(const DataItem::WriteCallback& callback) {
+    PendingOperation operation(OperationType::kDelete);
+    operation.delete_callback = callback;
+
+    pending_operations_.emplace(std::move(operation));
+  }
+
+  // Completes the next pendig operation.
+  // |expected_type| - the expected type of the next operation - this will fail
+  //     if the operation does not match.
+  // |result| - the intended operation result.
+  void CompleteNextOperation(OperationType expected_type,
+                             OperationResult result) {
+    ASSERT_FALSE(pending_operations_.empty());
+    ASSERT_FALSE(deleted_);
+
+    const PendingOperation& operation = pending_operations_.front();
+
+    ASSERT_EQ(expected_type, operation.type);
+
+    switch (expected_type) {
+      case OperationType::kWrite: {
+        if (result == OperationResult::kSuccess)
+          content_ = operation.data;
+        DataItem::WriteCallback callback = operation.write_callback;
+        pending_operations_.pop();
+        callback.Run(result);
+        break;
+      }
+      case OperationType::kDelete: {
+        if (result == OperationResult::kSuccess) {
+          deleted_ = true;
+          item_registry_->Remove(id_);
+          content_ = std::vector<char>();
+        }
+
+        DataItem::WriteCallback callback = operation.delete_callback;
+        pending_operations_.pop();
+        callback.Run(result);
+        break;
+      }
+      case OperationType::kRead: {
+        std::unique_ptr<std::vector<char>> result_data;
+        if (result == OperationResult::kSuccess) {
+          result_data = base::MakeUnique<std::vector<char>>(content_.begin(),
+                                                            content_.end());
+        }
+
+        DataItem::ReadCallback callback = operation.read_callback;
+        pending_operations_.pop();
+        callback.Run(result, std::move(result_data));
+        break;
+      }
+      default:
+        ADD_FAILURE() << "Unexpected operation";
+        return;
+    }
+  }
+
+  bool HasPendingOperations() const { return !pending_operations_.empty(); }
+
+  bool deleted() const { return deleted_; }
+
+  const std::vector<char>& content() const { return content_; }
+
+ private:
+  std::string id_;
+  ItemRegistry* item_registry_;
+  std::queue<PendingOperation> pending_operations_;
+  std::vector<char> content_;
+  bool deleted_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(OperationQueue);
+};
+
+// Test data item - routes all requests to the OperationQueue provided through
+// the ctor - the owning test is responsible for completing the started
+// operations.
+class TestDataItem : public DataItem {
+ public:
+  // |operations| - Operation queue used by this data item - not owned by this,
+  // and expected to outlive this object.
+  TestDataItem(const std::string& id,
+               const std::string& extension_id,
+               const std::string& crypto_key,
+               OperationQueue* operations)
+      : DataItem(id, extension_id, nullptr, nullptr, nullptr, crypto_key),
+        operations_(operations) {}
+
+  ~TestDataItem() override = default;
+
+  void Register(const WriteCallback& callback) override {
+    operations_->Register(callback);
+  }
+
+  void Write(const std::vector<char>& data,
+             const WriteCallback& callback) override {
+    operations_->AddWrite(data, callback);
+  }
+
+  void Read(const ReadCallback& callback) override {
+    operations_->AddRead(callback);
+  }
+
+  void Delete(const WriteCallback& callback) override {
+    operations_->AddDelete(callback);
+  }
+
+ private:
+  OperationQueue* operations_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDataItem);
+};
+
+class LockScreenItemStorageTest : public ExtensionsTest {
+ public:
+  LockScreenItemStorageTest()
+      : ExtensionsTest(base::MakeUnique<content::TestBrowserThreadBundle>()) {}
+  ~LockScreenItemStorageTest() override = default;
+
+  void SetUp() override {
+    ExtensionsTest::SetUp();
+
+    ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
+    LockScreenItemStorage::RegisterLocalState(local_state_.registry());
+    user_prefs::UserPrefs::Set(browser_context(), &testing_pref_service_);
+    extensions_browser_client()->set_lock_screen_context(&lock_screen_context_);
+
+    chromeos::LoginState::Initialize();
+    chromeos::LoginState::Get()->SetLoggedInStateAndPrimaryUser(
+        chromeos::LoginState::LOGGED_IN_ACTIVE,
+        chromeos::LoginState::LOGGED_IN_USER_REGULAR, kTestUserIdHash);
+
+    CreateTestExtension();
+    item_registry_ = base::MakeUnique<ItemRegistry>(extension()->id());
+
+    // Inject custom data item factory to be used with LockScreenItemStorage
+    // instances.
+    item_factory_ = base::Bind(&LockScreenItemStorageTest::CreateItem,
+                               base::Unretained(this));
+    registered_items_getter_ = base::Bind(
+        &LockScreenItemStorageTest::GetRegisteredItems, base::Unretained(this));
+    item_store_deleter_ = base::Bind(&LockScreenItemStorageTest::RemoveAllItems,
+                                     base::Unretained(this));
+    LockScreenItemStorage::SetItemProvidersForTesting(
+        &registered_items_getter_, &item_factory_, &item_store_deleter_);
+
+    ResetLockScreenItemStorage();
+  }
+
+  void TearDown() override {
+    lock_screen_item_storage_.reset();
+    operations_.clear();
+    item_registry_.reset();
+    LockScreenItemStorage::SetItemProvidersForTesting(nullptr, nullptr,
+                                                      nullptr);
+    chromeos::LoginState::Shutdown();
+    ExtensionsTest::TearDown();
+  }
+
+  OperationQueue* GetOperations(const std::string& id) {
+    return operations_[id].get();
+  }
+
+  void UnsetLockScreenItemStorage() { lock_screen_item_storage_.reset(); }
+
+  void ResetLockScreenItemStorage() {
+    lock_screen_item_storage_.reset();
+    lock_screen_item_storage_ = base::MakeUnique<LockScreenItemStorage>(
+        browser_context(), &local_state_, kTestSymmetricKey,
+        test_dir_.GetPath());
+  }
+
+  // Utility method for setting test item content.
+  bool SetItemContent(const std::string& id, const std::vector<char>& content) {
+    OperationQueue* item_operations = GetOperations(id);
+    if (!item_operations) {
+      ADD_FAILURE() << "No item operations";
+      return false;
+    }
+    OperationResult write_result = OperationResult::kFailed;
+    lock_screen_item_storage()->SetItemContent(
+        extension()->id(), id, content,
+        base::Bind(&RecordWriteResult, &write_result));
+    if (!item_operations->HasPendingOperations()) {
+      ADD_FAILURE() << "Write not registered";
+      return false;
+    }
+    item_operations->CompleteNextOperation(
+        OperationQueue::OperationType::kWrite, OperationResult::kSuccess);
+    EXPECT_EQ(OperationResult::kSuccess, write_result);
+    return write_result == OperationResult::kSuccess;
+  }
+
+  const DataItem* CreateNewItem() {
+    OperationResult create_result = OperationResult::kFailed;
+    const DataItem* item = nullptr;
+    lock_screen_item_storage()->CreateItem(
+        extension()->id(),
+        base::Bind(&RecordCreateResult, &create_result, &item));
+    EXPECT_EQ(OperationResult::kSuccess, create_result);
+
+    return item;
+  }
+
+  // Utility method for creating a new testing data item, and setting its
+  // content.
+  const DataItem* CreateItemWithContent(const std::vector<char>& content) {
+    const DataItem* item = CreateNewItem();
+    if (!item) {
+      ADD_FAILURE() << "Item creation failed";
+      return nullptr;
+    }
+
+    if (!SetItemContent(item->id(), content))
+      return nullptr;
+
+    return item;
+  }
+
+  void GetAllItems(std::vector<std::string>* all_items) {
+    lock_screen_item_storage()->GetAllForExtension(
+        extension()->id(), base::Bind(&RecordGetAllItemsResult, all_items));
+  }
+
+  // Finds an item with the ID |id| in list of items |items|.
+  const DataItem* FindItem(const std::string& id,
+                           const std::vector<const DataItem*> items) {
+    for (const auto* item : items) {
+      if (item && item->id() == id)
+        return item;
+    }
+    return nullptr;
+  }
+
+  LockScreenItemStorage* lock_screen_item_storage() {
+    return lock_screen_item_storage_.get();
+  }
+
+  content::BrowserContext* lock_screen_context() {
+    return &lock_screen_context_;
+  }
+
+  const Extension* extension() const { return extension_.get(); }
+
+  const base::FilePath& test_dir() const { return test_dir_.GetPath(); }
+
+  PrefService* local_state() { return &local_state_; }
+
+  ItemRegistry* item_registry() { return item_registry_.get(); }
+
+ private:
+  void CreateTestExtension() {
+    DictionaryBuilder app_builder;
+    app_builder.Set("background",
+                    DictionaryBuilder()
+                        .Set("scripts", ListBuilder().Append("script").Build())
+                        .Build());
+    ListBuilder app_handlers_builder;
+    app_handlers_builder.Append(DictionaryBuilder()
+                                    .Set("action", "new_note")
+                                    .SetBoolean("enabled_on_lock_screen", true)
+                                    .Build());
+    extension_ =
+        ExtensionBuilder()
+            .SetManifest(
+                DictionaryBuilder()
+                    .Set("name", "Test app")
+                    .Set("version", "1.0")
+                    .Set("manifest_version", 2)
+                    .Set("app", app_builder.Build())
+                    .Set("action_handlers", app_handlers_builder.Build())
+                    .Set("permissions",
+                         ListBuilder().Append("lockScreen").Build())
+                    .Build())
+            .Build();
+    ExtensionRegistry::Get(browser_context())->AddEnabled(extension_);
+  }
+
+  // Callback for creating test data items - this is the callback passed to
+  // LockScreenItemStorage via SetItemFactoryForTesting.
+  std::unique_ptr<DataItem> CreateItem(const std::string& id,
+                                       const std::string& extension_id,
+                                       const std::string& crypto_key) {
+    EXPECT_EQ(extension()->id(), extension_id);
+    EXPECT_EQ(kTestSymmetricKey, crypto_key);
+
+    // If there is an operation queue for the item id, reuse it in order to
+    // retain state on LockScreenItemStorage restart.
+    OperationQueue* operation_queue = GetOperations(id);
+    if (!operation_queue) {
+      operations_[id] =
+          base::MakeUnique<OperationQueue>(id, item_registry_.get());
+      operation_queue = operations_[id].get();
+    }
+    return base::MakeUnique<TestDataItem>(id, extension_id, crypto_key,
+                                          operation_queue);
+  }
+
+  void GetRegisteredItems(const std::string& extension_id,
+                          const DataItem::RegisteredValuesCallback& callback) {
+    if (extension()->id() != extension_id) {
+      callback.Run(OperationResult::kUnknownExtension, nullptr);
+      return;
+    }
+    item_registry_->HandleGetRequest(callback);
+  }
+
+  void RemoveAllItems(const std::string& extension_id,
+                      const base::Closure& callback) {
+    ASSERT_EQ(extension()->id(), extension_id);
+    item_registry_->RemoveAll();
+    callback.Run();
+  }
+
+  std::unique_ptr<LockScreenItemStorage> lock_screen_item_storage_;
+
+  content::TestBrowserContext lock_screen_context_;
+  TestingPrefServiceSimple local_state_;
+
+  base::ScopedTempDir test_dir_;
+
+  sync_preferences::TestingPrefServiceSyncable testing_pref_service_;
+
+  LockScreenItemStorage::ItemFactoryCallback item_factory_;
+  LockScreenItemStorage::RegisteredItemsGetter registered_items_getter_;
+  LockScreenItemStorage::ItemStoreDeleter item_store_deleter_;
+
+  scoped_refptr<const Extension> extension_;
+
+  std::unique_ptr<ItemRegistry> item_registry_;
+  std::map<std::string, std::unique_ptr<OperationQueue>> operations_;
+
+  DISALLOW_COPY_AND_ASSIGN(LockScreenItemStorageTest);
+};
+
+}  // namespace
+
+TEST_F(LockScreenItemStorageTest, GetDependingOnSessionState) {
+  // Session state not initialized.
+  EXPECT_FALSE(LockScreenItemStorage::GetIfAllowed(browser_context()));
+  EXPECT_FALSE(LockScreenItemStorage::GetIfAllowed(lock_screen_context()));
+
+  // Locked session.
+  lock_screen_item_storage()->SetSessionLocked(true);
+  EXPECT_FALSE(LockScreenItemStorage::GetIfAllowed(browser_context()));
+  EXPECT_EQ(lock_screen_item_storage(),
+            LockScreenItemStorage::GetIfAllowed(lock_screen_context()));
+
+  lock_screen_item_storage()->SetSessionLocked(false);
+
+  EXPECT_EQ(lock_screen_item_storage(),
+            LockScreenItemStorage::GetIfAllowed(browser_context()));
+  EXPECT_FALSE(LockScreenItemStorage::GetIfAllowed(lock_screen_context()));
+}
+
+TEST_F(LockScreenItemStorageTest, SetAndGetContent) {
+  lock_screen_item_storage()->SetSessionLocked(true);
+
+  const DataItem* item = CreateNewItem();
+  ASSERT_TRUE(item);
+
+  std::vector<std::string> all_items;
+  GetAllItems(&all_items);
+  ASSERT_EQ(1u, all_items.size());
+  EXPECT_EQ(item->id(), all_items[0]);
+
+  OperationQueue* item_operations = GetOperations(item->id());
+  ASSERT_TRUE(item_operations);
+  EXPECT_FALSE(item_operations->HasPendingOperations());
+
+  std::vector<char> content = {'f', 'i', 'l', 'e'};
+  OperationResult write_result = OperationResult::kFailed;
+  lock_screen_item_storage()->SetItemContent(
+      extension()->id(), item->id(), content,
+      base::Bind(&RecordWriteResult, &write_result));
+
+  item_operations->CompleteNextOperation(OperationQueue::OperationType::kWrite,
+                                         OperationResult::kSuccess);
+
+  EXPECT_EQ(OperationResult::kSuccess, write_result);
+  EXPECT_EQ(content, item_operations->content());
+
+  OperationResult read_result = OperationResult::kFailed;
+  std::unique_ptr<std::vector<char>> read_content;
+
+  lock_screen_item_storage()->GetItemContent(
+      extension()->id(), item->id(),
+      base::Bind(&RecordReadResult, &read_result, &read_content));
+
+  item_operations->CompleteNextOperation(OperationQueue::OperationType::kRead,
+                                         OperationResult::kSuccess);
+  EXPECT_EQ(OperationResult::kSuccess, read_result);
+  EXPECT_EQ(content, *read_content);
+
+  OperationResult delete_result = OperationResult::kFailed;
+  lock_screen_item_storage()->DeleteItem(
+      extension()->id(), item->id(),
+      base::Bind(&RecordWriteResult, &delete_result));
+
+  item_operations->CompleteNextOperation(OperationQueue::OperationType::kDelete,
+                                         OperationResult::kSuccess);
+  EXPECT_EQ(OperationResult::kSuccess, delete_result);
+  EXPECT_TRUE(item_operations->deleted());
+}
+
+TEST_F(LockScreenItemStorageTest, FailToInitializeData) {
+  lock_screen_item_storage()->SetSessionLocked(true);
+
+  const DataItem* item = CreateNewItem();
+  ASSERT_TRUE(item);
+  const std::string item_id = item->id();
+
+  ResetLockScreenItemStorage();
+  item_registry()->set_fail(true);
+
+  OperationResult write_result = OperationResult::kFailed;
+  lock_screen_item_storage()->SetItemContent(
+      extension()->id(), item_id, {'x'},
+      base::Bind(&RecordWriteResult, &write_result));
+  EXPECT_EQ(OperationResult::kNotFound, write_result);
+
+  OperationResult read_result = OperationResult::kFailed;
+  std::unique_ptr<std::vector<char>> read_content;
+  lock_screen_item_storage()->GetItemContent(
+      extension()->id(), item_id,
+      base::Bind(&RecordReadResult, &read_result, &read_content));
+  EXPECT_EQ(OperationResult::kNotFound, read_result);
+
+  OperationResult delete_result = OperationResult::kFailed;
+  lock_screen_item_storage()->DeleteItem(
+      extension()->id(), "non_existen",
+      base::Bind(&RecordWriteResult, &delete_result));
+  EXPECT_EQ(OperationResult::kNotFound, delete_result);
+
+  OperationQueue* operations = GetOperations(item_id);
+  ASSERT_TRUE(operations);
+  EXPECT_FALSE(operations->HasPendingOperations());
+
+  item_registry()->set_fail(false);
+
+  const DataItem* new_item = CreateNewItem();
+  ASSERT_TRUE(new_item);
+
+  write_result = OperationResult::kFailed;
+  lock_screen_item_storage()->SetItemContent(
+      extension()->id(), new_item->id(), {'y'},
+      base::Bind(&RecordWriteResult, &write_result));
+
+  OperationQueue* new_item_operations = GetOperations(new_item->id());
+  ASSERT_TRUE(new_item_operations);
+  new_item_operations->CompleteNextOperation(
+      OperationQueue::OperationType::kWrite, OperationResult::kSuccess);
+  EXPECT_EQ(OperationResult::kSuccess, write_result);
+
+  std::vector<std::string> items;
+  GetAllItems(&items);
+  ASSERT_EQ(1u, items.size());
+  EXPECT_EQ(new_item->id(), items[0]);
+}
+
+TEST_F(LockScreenItemStorageTest, RequestsDuringInitialLoad) {
+  lock_screen_item_storage()->SetSessionLocked(true);
+
+  const DataItem* item = CreateNewItem();
+  ASSERT_TRUE(item);
+  const std::string item_id = item->id();
+
+  item_registry()->set_throttle_get(true);
+  ResetLockScreenItemStorage();
+
+  EXPECT_FALSE(item_registry()->HasPendingCallback());
+
+  OperationResult write_result = OperationResult::kFailed;
+  lock_screen_item_storage()->SetItemContent(
+      extension()->id(), item_id, {'x'},
+      base::Bind(&RecordWriteResult, &write_result));
+
+  OperationResult read_result = OperationResult::kFailed;
+  std::unique_ptr<std::vector<char>> read_content;
+  lock_screen_item_storage()->GetItemContent(
+      extension()->id(), item_id,
+      base::Bind(&RecordReadResult, &read_result, &read_content));
+
+  std::vector<std::string> items;
+  lock_screen_item_storage()->GetAllForExtension(
+      extension()->id(), base::Bind(&RecordGetAllItemsResult, &items));
+  EXPECT_TRUE(items.empty());
+
+  OperationResult delete_result = OperationResult::kFailed;
+  lock_screen_item_storage()->DeleteItem(
+      extension()->id(), item_id,
+      base::Bind(&RecordWriteResult, &delete_result));
+
+  OperationQueue* operations = GetOperations(item_id);
+  ASSERT_TRUE(operations);
+  EXPECT_FALSE(operations->HasPendingOperations());
+
+  OperationResult create_result = OperationResult::kFailed;
+  const DataItem* new_item = nullptr;
+  lock_screen_item_storage()->CreateItem(
+      extension()->id(),
+      base::Bind(&RecordCreateResult, &create_result, &new_item));
+  EXPECT_FALSE(new_item);
+
+  EXPECT_TRUE(item_registry()->HasPendingCallback());
+  item_registry()->RunPendingCallback();
+
+  EXPECT_TRUE(operations->HasPendingOperations());
+
+  operations->CompleteNextOperation(OperationQueue::OperationType::kWrite,
+                                    OperationResult::kSuccess);
+  operations->CompleteNextOperation(OperationQueue::OperationType::kRead,
+                                    OperationResult::kSuccess);
+  operations->CompleteNextOperation(OperationQueue::OperationType::kDelete,
+                                    OperationResult::kSuccess);
+
+  EXPECT_EQ(OperationResult::kSuccess, write_result);
+  EXPECT_EQ(OperationResult::kSuccess, read_result);
+  ASSERT_TRUE(read_content);
+  EXPECT_EQ(std::vector<char>({'x'}), *read_content);
+  EXPECT_EQ(OperationResult::kSuccess, delete_result);
+  EXPECT_EQ(OperationResult::kSuccess, create_result);
+
+  EXPECT_TRUE(new_item);
+
+  ASSERT_EQ(1u, items.size());
+  EXPECT_EQ(item_id, items[0]);
+
+  GetAllItems(&items);
+  ASSERT_EQ(1u, items.size());
+  EXPECT_EQ(new_item->id(), items[0]);
+}
+
+TEST_F(LockScreenItemStorageTest, HandleNonExistent) {
+  lock_screen_item_storage()->SetSessionLocked(true);
+
+  const DataItem* item = CreateNewItem();
+  ASSERT_TRUE(item);
+
+  std::vector<char> content = {'x'};
+
+  OperationResult write_result = OperationResult::kFailed;
+  lock_screen_item_storage()->SetItemContent(
+      extension()->id(), "non_existent", content,
+      base::Bind(&RecordWriteResult, &write_result));
+  EXPECT_EQ(OperationResult::kNotFound, write_result);
+
+  write_result = OperationResult::kFailed;
+  lock_screen_item_storage()->SetItemContent(
+      "non_existent", item->id(), content,
+      base::Bind(&RecordWriteResult, &write_result));
+  EXPECT_EQ(OperationResult::kNotFound, write_result);
+
+  OperationResult read_result = OperationResult::kFailed;
+  std::unique_ptr<std::vector<char>> read_content;
+  lock_screen_item_storage()->GetItemContent(
+      extension()->id(), "non_existent",
+      base::Bind(&RecordReadResult, &read_result, &read_content));
+  EXPECT_EQ(OperationResult::kNotFound, read_result);
+  read_result = OperationResult::kFailed;
+
+  lock_screen_item_storage()->GetItemContent(
+      "non_existent", item->id(),
+      base::Bind(&RecordReadResult, &read_result, &read_content));
+  EXPECT_EQ(OperationResult::kNotFound, read_result);
+
+  OperationResult delete_result = OperationResult::kFailed;
+  lock_screen_item_storage()->DeleteItem(
+      extension()->id(), "non_existen",
+      base::Bind(&RecordWriteResult, &delete_result));
+  EXPECT_EQ(OperationResult::kNotFound, delete_result);
+
+  delete_result = OperationResult::kFailed;
+  lock_screen_item_storage()->DeleteItem(
+      "non_existent", item->id(),
+      base::Bind(&RecordWriteResult, &delete_result));
+  EXPECT_EQ(OperationResult::kNotFound, delete_result);
+}
+
+TEST_F(LockScreenItemStorageTest, HandleFailure) {
+  lock_screen_item_storage()->SetSessionLocked(true);
+
+  const DataItem* item = CreateItemWithContent({'x'});
+  ASSERT_TRUE(item);
+  OperationQueue* operations = GetOperations(item->id());
+  ASSERT_TRUE(operations);
+
+  OperationResult write_result = OperationResult::kFailed;
+  lock_screen_item_storage()->SetItemContent(
+      extension()->id(), item->id(), {'x'},
+      base::Bind(&RecordWriteResult, &write_result));
+  operations->CompleteNextOperation(OperationQueue::OperationType::kWrite,
+                                    OperationResult::kInvalidKey);
+  EXPECT_EQ(OperationResult::kInvalidKey, write_result);
+
+  OperationResult read_result = OperationResult::kFailed;
+  std::unique_ptr<std::vector<char>> read_content;
+  lock_screen_item_storage()->GetItemContent(
+      extension()->id(), item->id(),
+      base::Bind(&RecordReadResult, &read_result, &read_content));
+  operations->CompleteNextOperation(OperationQueue::OperationType::kRead,
+                                    OperationResult::kWrongKey);
+  EXPECT_EQ(OperationResult::kWrongKey, read_result);
+  EXPECT_FALSE(read_content);
+
+  EXPECT_FALSE(operations->HasPendingOperations());
+}
+
+TEST_F(LockScreenItemStorageTest, DataItemsAvailableEventOnUnlock) {
+  TestEventRouter* event_router = static_cast<TestEventRouter*>(
+      extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
+          browser_context(), &TestEventRouterFactoryFunction));
+  ASSERT_TRUE(event_router);
+
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+
+  lock_screen_item_storage()->SetSessionLocked(true);
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+
+  // No event since no data items associated with the app exist.
+  lock_screen_item_storage()->SetSessionLocked(false);
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+
+  lock_screen_item_storage()->SetSessionLocked(true);
+  const DataItem* item = CreateItemWithContent({'f', 'i', 'l', 'e', '1'});
+  const std::string item_id = item->id();
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+
+  // There's an available data item, so unlock should trigger the event.
+  lock_screen_item_storage()->SetSessionLocked(false);
+  EXPECT_EQ(std::vector<bool>({true}), event_router->was_locked_values());
+  event_router->ClearWasLockedValues();
+
+  // Update the item content while the session is unlocked.
+  EXPECT_TRUE(SetItemContent(item_id, {'f', 'i', 'l', 'e', '2'}));
+
+  lock_screen_item_storage()->SetSessionLocked(true);
+
+  // Data item is still around - notify the app it's available.
+  lock_screen_item_storage()->SetSessionLocked(false);
+  EXPECT_EQ(std::vector<bool>({true}), event_router->was_locked_values());
+  event_router->ClearWasLockedValues();
+
+  lock_screen_item_storage()->SetSessionLocked(true);
+
+  EXPECT_TRUE(SetItemContent(item_id, {'f', 'i', 'l', 'e', '3'}));
+
+  lock_screen_item_storage()->SetSessionLocked(false);
+  EXPECT_EQ(std::vector<bool>({true}), event_router->was_locked_values());
+  event_router->ClearWasLockedValues();
+
+  // When the item is deleted, the data item avilable event should stop firing.
+  OperationResult delete_result;
+  lock_screen_item_storage()->DeleteItem(
+      extension()->id(), item_id,
+      base::Bind(&RecordWriteResult, &delete_result));
+  OperationQueue* operations = GetOperations(item_id);
+  ASSERT_TRUE(operations);
+  operations->CompleteNextOperation(OperationQueue::OperationType::kDelete,
+                                    OperationResult::kSuccess);
+  lock_screen_item_storage()->SetSessionLocked(false);
+  lock_screen_item_storage()->SetSessionLocked(true);
+
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+}
+
+TEST_F(LockScreenItemStorageTest,
+       NoDataItemsAvailableEventAfterFailedCreation) {
+  TestEventRouter* event_router = static_cast<TestEventRouter*>(
+      extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
+          browser_context(), &TestEventRouterFactoryFunction));
+  ASSERT_TRUE(event_router);
+
+  lock_screen_item_storage()->SetSessionLocked(true);
+
+  item_registry()->set_allow_new(false);
+
+  OperationResult create_result = OperationResult::kFailed;
+  const DataItem* item = nullptr;
+  lock_screen_item_storage()->CreateItem(
+      extension()->id(),
+      base::Bind(&RecordCreateResult, &create_result, &item));
+  EXPECT_EQ(OperationResult::kFailed, create_result);
+
+  lock_screen_item_storage()->SetSessionLocked(false);
+  lock_screen_item_storage()->SetSessionLocked(true);
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+}
+
+TEST_F(LockScreenItemStorageTest, DataItemsAvailableEventOnRestart) {
+  TestEventRouter* event_router = static_cast<TestEventRouter*>(
+      extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
+          browser_context(), &TestEventRouterFactoryFunction));
+  ASSERT_TRUE(event_router);
+
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+
+  lock_screen_item_storage()->SetSessionLocked(true);
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+
+  const DataItem* item = CreateItemWithContent({'f', 'i', 'l', 'e', '1'});
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+  const std::string item_id = item->id();
+
+  ResetLockScreenItemStorage();
+
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+  lock_screen_item_storage()->SetSessionLocked(false);
+
+  EXPECT_EQ(std::vector<bool>({false}), event_router->was_locked_values());
+  event_router->ClearWasLockedValues();
+
+  // The event should be dispatched on next unlock event, as long as a valid
+  // item exists.
+  ResetLockScreenItemStorage();
+  lock_screen_item_storage()->SetSessionLocked(false);
+
+  EXPECT_EQ(std::vector<bool>({false}), event_router->was_locked_values());
+  event_router->ClearWasLockedValues();
+
+  ResetLockScreenItemStorage();
+
+  OperationResult delete_result = OperationResult::kFailed;
+  lock_screen_item_storage()->DeleteItem(
+      extension()->id(), item_id,
+      base::Bind(&RecordWriteResult, &delete_result));
+  OperationQueue* operations = GetOperations(item_id);
+  ASSERT_TRUE(operations);
+  operations->CompleteNextOperation(OperationQueue::OperationType::kDelete,
+                                    OperationResult::kSuccess);
+
+  lock_screen_item_storage()->SetSessionLocked(false);
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+}
+
+TEST_F(LockScreenItemStorageTest, ClearDataOnUninstall) {
+  const DataItem* item = CreateItemWithContent({'x'});
+  ASSERT_TRUE(item);
+
+  ExtensionRegistry::Get(browser_context())->RemoveEnabled(extension()->id());
+  ExtensionRegistry::Get(browser_context())
+      ->TriggerOnUninstalled(extension(), UNINSTALL_REASON_FOR_TESTING);
+  ExtensionRegistry::Get(browser_context())->AddEnabled(extension());
+
+  std::vector<std::string> items;
+  GetAllItems(&items);
+  EXPECT_TRUE(items.empty());
+}
+
+TEST_F(LockScreenItemStorageTest,
+       ClearOnUninstallWhileLockScreenItemStorageNotSet) {
+  TestEventRouter* event_router = static_cast<TestEventRouter*>(
+      extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
+          browser_context(), &TestEventRouterFactoryFunction));
+  ASSERT_TRUE(event_router);
+
+  const DataItem* item = CreateItemWithContent({'x'});
+  ASSERT_TRUE(item);
+
+  UnsetLockScreenItemStorage();
+
+  ExtensionRegistry::Get(browser_context())->RemoveEnabled(extension()->id());
+  ExtensionRegistry::Get(browser_context())
+      ->TriggerOnUninstalled(extension(), UNINSTALL_REASON_FOR_TESTING);
+
+  ResetLockScreenItemStorage();
+  ExtensionRegistry::Get(browser_context())->AddEnabled(extension());
+  lock_screen_item_storage()->SetSessionLocked(false);
+
+  std::vector<std::string> items;
+  GetAllItems(&items);
+  EXPECT_TRUE(items.empty());
+
+  EXPECT_TRUE(event_router->was_locked_values().empty());
+}
+
+}  // namespace lock_screen_data
+}  // namespace extensions
diff --git a/extensions/browser/api/lock_screen_data/operation_result.h b/extensions/browser/api/lock_screen_data/operation_result.h
new file mode 100644
index 0000000..ff53663f
--- /dev/null
+++ b/extensions/browser/api/lock_screen_data/operation_result.h
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_OPERATION_RESULT_H_
+#define EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_OPERATION_RESULT_H_
+
+namespace extensions {
+namespace lock_screen_data {
+
+// Enum containing possible results of data item operations exposed by
+// ItemStorage and DataItem.
+enum class OperationResult {
+  kSuccess,
+  kFailed,
+  kNotFound,
+  kUnknownExtension,
+  kAlreadyRegistered,
+  kInvalidKey,
+  kWrongKey,
+};
+
+}  // namespace lock_screen_data
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_LOCK_SCREEN_DATA_OPERATION_RESULT_H_
diff --git a/extensions/browser/api/system_network/system_network_api.cc b/extensions/browser/api/system_network/system_network_api.cc
index c2c1f70..d82a35a 100644
--- a/extensions/browser/api/system_network/system_network_api.cc
+++ b/extensions/browser/api/system_network/system_network_api.cc
@@ -4,8 +4,21 @@
 
 #include "extensions/browser/api/system_network/system_network_api.h"
 
+#include "base/task_scheduler/post_task.h"
+
 namespace {
 const char kNetworkListError[] = "Network lookup failed or unsupported";
+
+std::unique_ptr<net::NetworkInterfaceList> GetListOnBlockingTaskRunner() {
+  auto interface_list = base::MakeUnique<net::NetworkInterfaceList>();
+  if (net::GetNetworkList(interface_list.get(),
+                          net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) {
+    return interface_list;
+  }
+
+  return nullptr;
+}
+
 }  // namespace
 
 namespace extensions {
@@ -21,48 +34,28 @@
 
 ExtensionFunction::ResponseAction
 SystemNetworkGetNetworkInterfacesFunction::Run() {
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE,
-      FROM_HERE,
-      base::Bind(
-          &SystemNetworkGetNetworkInterfacesFunction::GetListOnFileThread,
-          this));
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  constexpr base::TaskTraits kTraits = {
+      base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+      base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
+  using Self = SystemNetworkGetNetworkInterfacesFunction;
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, kTraits, base::BindOnce(&GetListOnBlockingTaskRunner),
+      base::BindOnce(&Self::SendResponseOnUIThread, this));
   return RespondLater();
 }
 
-void SystemNetworkGetNetworkInterfacesFunction::GetListOnFileThread() {
-  net::NetworkInterfaceList interface_list;
-  if (net::GetNetworkList(&interface_list,
-                          net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(
-            &SystemNetworkGetNetworkInterfacesFunction::SendResponseOnUIThread,
-            this,
-            interface_list));
+void SystemNetworkGetNetworkInterfacesFunction::SendResponseOnUIThread(
+    std::unique_ptr<net::NetworkInterfaceList> interface_list) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!interface_list) {
+    Respond(Error(kNetworkListError));
     return;
   }
 
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(&SystemNetworkGetNetworkInterfacesFunction::HandleGetListError,
-                 this));
-}
-
-void SystemNetworkGetNetworkInterfacesFunction::HandleGetListError() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  Respond(Error(kNetworkListError));
-}
-
-void SystemNetworkGetNetworkInterfacesFunction::SendResponseOnUIThread(
-    const net::NetworkInterfaceList& interface_list) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
   std::vector<api::system_network::NetworkInterface> create_arg;
-  create_arg.reserve(interface_list.size());
-  for (const net::NetworkInterface& interface : interface_list) {
+  create_arg.reserve(interface_list->size());
+  for (const net::NetworkInterface& interface : *interface_list) {
     api::system_network::NetworkInterface info;
     info.name = interface.name;
     info.address = interface.address.ToString();
diff --git a/extensions/browser/api/system_network/system_network_api.h b/extensions/browser/api/system_network/system_network_api.h
index 38e9e6c..385fed4 100644
--- a/extensions/browser/api/system_network/system_network_api.h
+++ b/extensions/browser/api/system_network/system_network_api.h
@@ -5,6 +5,8 @@
 #ifndef EXTENSIONS_BROWSER_API_SYSTEM_NETWORK_SYSTEM_NETWORK_API_H_
 #define EXTENSIONS_BROWSER_API_SYSTEM_NETWORK_SYSTEM_NETWORK_API_H_
 
+#include <memory>
+
 #include "extensions/browser/extension_function.h"
 #include "extensions/common/api/system_network.h"
 #include "net/base/network_interfaces.h"
@@ -27,9 +29,8 @@
   ResponseAction Run() override;
 
  private:
-  void GetListOnFileThread();
-  void HandleGetListError();
-  void SendResponseOnUIThread(const net::NetworkInterfaceList& interface_list);
+  void SendResponseOnUIThread(
+      std::unique_ptr<net::NetworkInterfaceList> interface_list);
 };
 
 }  // namespace api
diff --git a/extensions/browser/test_extensions_browser_client.cc b/extensions/browser/test_extensions_browser_client.cc
index 9d6ae67..ceb96de4 100644
--- a/extensions/browser/test_extensions_browser_client.cc
+++ b/extensions/browser/test_extensions_browser_client.cc
@@ -22,9 +22,10 @@
 TestExtensionsBrowserClient::TestExtensionsBrowserClient(
     BrowserContext* main_context)
     : main_context_(main_context),
-      incognito_context_(NULL),
-      process_manager_delegate_(NULL),
-      extension_system_factory_(NULL),
+      incognito_context_(nullptr),
+      lock_screen_context_(nullptr),
+      process_manager_delegate_(nullptr),
+      extension_system_factory_(nullptr),
       extension_cache_(new NullExtensionCache) {
   DCHECK(main_context_);
   DCHECK(!main_context_->IsOffTheRecord());
@@ -67,14 +68,14 @@
 
 bool TestExtensionsBrowserClient::HasOffTheRecordContext(
     BrowserContext* context) {
-  return context == main_context_ && incognito_context_ != NULL;
+  return context == main_context_ && incognito_context_ != nullptr;
 }
 
 BrowserContext* TestExtensionsBrowserClient::GetOffTheRecordContext(
     BrowserContext* context) {
   if (context == main_context_)
     return incognito_context_;
-  return NULL;
+  return nullptr;
 }
 
 BrowserContext* TestExtensionsBrowserClient::GetOriginalContext(
@@ -115,7 +116,7 @@
     const base::FilePath& directory_path,
     const std::string& content_security_policy,
     bool send_cors_header) {
-  return NULL;
+  return nullptr;
 }
 
 bool TestExtensionsBrowserClient::AllowCrossRendererResourceLoad(
@@ -180,7 +181,7 @@
 
 const ComponentExtensionResourceManager*
 TestExtensionsBrowserClient::GetComponentExtensionResourceManager() {
-  return NULL;
+  return nullptr;
 }
 
 void TestExtensionsBrowserClient::BroadcastEventToRenderers(
@@ -189,7 +190,7 @@
     std::unique_ptr<base::ListValue> args) {}
 
 net::NetLog* TestExtensionsBrowserClient::GetNetLog() {
-  return NULL;
+  return nullptr;
 }
 
 ExtensionCache* TestExtensionsBrowserClient::GetExtensionCache() {
@@ -225,7 +226,7 @@
 
 bool TestExtensionsBrowserClient::IsLockScreenContext(
     content::BrowserContext* context) {
-  return false;
+  return lock_screen_context_ && context == lock_screen_context_;
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/test_extensions_browser_client.h b/extensions/browser/test_extensions_browser_client.h
index b052034d..dd522a8 100644
--- a/extensions/browser/test_extensions_browser_client.h
+++ b/extensions/browser/test_extensions_browser_client.h
@@ -5,6 +5,7 @@
 #ifndef EXTENSIONS_BROWSER_TEST_EXTENSIONS_BROWSER_CLIENT_H_
 #define EXTENSIONS_BROWSER_TEST_EXTENSIONS_BROWSER_CLIENT_H_
 
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
@@ -40,6 +41,10 @@
     extension_cache_ = std::move(extension_cache);
   }
 
+  void set_lock_screen_context(content::BrowserContext* context) {
+    lock_screen_context_ = context;
+  }
+
   // Sets a factory to respond to calls of the CreateUpdateClient method.
   void SetUpdateClientFactory(
       const base::Callback<update_client::UpdateClient*(void)>& factory);
@@ -120,13 +125,17 @@
   }
 
  private:
-  content::BrowserContext* main_context_;       // Not owned.
-  content::BrowserContext* incognito_context_;  // Not owned, defaults to NULL.
+  // Not owned.
+  content::BrowserContext* main_context_;
+  // Not owned, defaults to nullptr.
+  content::BrowserContext* incognito_context_;
+  // Not owned, defaults to nullptr.
+  content::BrowserContext* lock_screen_context_;
 
-  // Not owned, defaults to NULL.
+  // Not owned, defaults to nullptr.
   ProcessManagerDelegate* process_manager_delegate_;
 
-  // Not owned, defaults to NULL.
+  // Not owned, defaults to nullptr.
   ExtensionSystemProvider* extension_system_factory_;
 
   std::unique_ptr<ExtensionCache> extension_cache_;
diff --git a/chrome/common/extensions/api/file_system.idl b/extensions/common/api/file_system.idl
similarity index 100%
rename from chrome/common/extensions/api/file_system.idl
rename to extensions/common/api/file_system.idl
diff --git a/extensions/common/api/schema.gni b/extensions/common/api/schema.gni
index d3415c8..0296e5fb 100644
--- a/extensions/common/api/schema.gni
+++ b/extensions/common/api/schema.gni
@@ -23,6 +23,7 @@
   "extension_options_internal.idl",
   "extension_view_internal.json",
   "extension_types.json",
+  "file_system.idl",
   "guest_view_internal.json",
   "management.json",
   "hid.idl",
diff --git a/extensions/renderer/bindings/api_binding_js_util.cc b/extensions/renderer/bindings/api_binding_js_util.cc
index 8f1fb4367..22e5a23 100644
--- a/extensions/renderer/bindings/api_binding_js_util.cc
+++ b/extensions/renderer/bindings/api_binding_js_util.cc
@@ -4,12 +4,14 @@
 
 #include "extensions/renderer/bindings/api_binding_js_util.h"
 
+#include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "extensions/renderer/bindings/api_event_handler.h"
 #include "extensions/renderer/bindings/api_request_handler.h"
 #include "extensions/renderer/bindings/api_signature.h"
 #include "extensions/renderer/bindings/api_type_reference_map.h"
 #include "extensions/renderer/bindings/declarative_event.h"
+#include "extensions/renderer/bindings/exception_handler.h"
 #include "gin/converter.h"
 #include "gin/dictionary.h"
 #include "gin/handle.h"
@@ -22,10 +24,12 @@
 APIBindingJSUtil::APIBindingJSUtil(APITypeReferenceMap* type_refs,
                                    APIRequestHandler* request_handler,
                                    APIEventHandler* event_handler,
+                                   ExceptionHandler* exception_handler,
                                    const binding::RunJSFunction& run_js)
     : type_refs_(type_refs),
       request_handler_(request_handler),
       event_handler_(event_handler),
+      exception_handler_(exception_handler),
       run_js_(run_js) {}
 
 APIBindingJSUtil::~APIBindingJSUtil() {}
@@ -44,7 +48,9 @@
       .SetMethod("clearLastError", &APIBindingJSUtil::ClearLastError)
       .SetMethod("hasLastError", &APIBindingJSUtil::HasLastError)
       .SetMethod("runCallbackWithLastError",
-                 &APIBindingJSUtil::RunCallbackWithLastError);
+                 &APIBindingJSUtil::RunCallbackWithLastError)
+      .SetMethod("handleException", &APIBindingJSUtil::HandleException)
+      .SetMethod("setExceptionHandler", &APIBindingJSUtil::SetExceptionHandler);
 }
 
 void APIBindingJSUtil::SendRequest(
@@ -206,4 +212,35 @@
   request_handler_->last_error()->ClearError(context, report_if_unchecked);
 }
 
+void APIBindingJSUtil::HandleException(gin::Arguments* arguments,
+                                       const std::string& message,
+                                       v8::Local<v8::Value> exception) {
+  v8::Isolate* isolate = arguments->isolate();
+  v8::HandleScope handle_scope(isolate);
+  v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
+
+  std::string full_message;
+  if (!exception->IsUndefined() && !exception->IsNull()) {
+    v8::TryCatch try_catch(isolate);
+    std::string exception_string;
+    v8::Local<v8::String> v8_exception_string;
+    if (exception->ToString(context).ToLocal(&v8_exception_string))
+      exception_string = gin::V8ToString(v8_exception_string);
+    else
+      exception_string = "(failed to get error message)";
+    full_message =
+        base::StringPrintf("%s: %s", message.c_str(), exception_string.c_str());
+  } else {
+    full_message = message;
+  }
+
+  exception_handler_->HandleException(context, full_message, exception);
+}
+
+void APIBindingJSUtil::SetExceptionHandler(gin::Arguments* arguments,
+                                           v8::Local<v8::Function> handler) {
+  exception_handler_->SetHandlerForContext(
+      arguments->GetHolderCreationContext(), handler);
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/bindings/api_binding_js_util.h b/extensions/renderer/bindings/api_binding_js_util.h
index 78675d30..d15a69a 100644
--- a/extensions/renderer/bindings/api_binding_js_util.h
+++ b/extensions/renderer/bindings/api_binding_js_util.h
@@ -20,6 +20,7 @@
 class APIEventHandler;
 class APIRequestHandler;
 class APITypeReferenceMap;
+class ExceptionHandler;
 
 // An object that exposes utility methods to the existing JS bindings, such as
 // sendRequest and registering event argument massagers. If/when we get rid of
@@ -29,6 +30,7 @@
   APIBindingJSUtil(APITypeReferenceMap* type_refs,
                    APIRequestHandler* request_handler,
                    APIEventHandler* event_handler,
+                   ExceptionHandler* exception_handler,
                    const binding::RunJSFunction& run_js);
   ~APIBindingJSUtil() override;
 
@@ -89,14 +91,27 @@
                                 const std::string& error,
                                 v8::Local<v8::Function> callback);
 
+  // Handles an exception with the given |message| and |exception| value.
+  void HandleException(gin::Arguments* arguments,
+                       const std::string& message,
+                       v8::Local<v8::Value> exception);
+
+  // Sets a custom exception handler to be used when an uncaught exception is
+  // found.
+  void SetExceptionHandler(gin::Arguments* arguments,
+                           v8::Local<v8::Function> handler);
+
   // Type references. Guaranteed to outlive this object.
-  APITypeReferenceMap* type_refs_;
+  APITypeReferenceMap* const type_refs_;
 
   // The request handler. Guaranteed to outlive this object.
-  APIRequestHandler* request_handler_;
+  APIRequestHandler* const request_handler_;
 
   // The event handler. Guaranteed to outlive this object.
-  APIEventHandler* event_handler_;
+  APIEventHandler* const event_handler_;
+
+  // The exception handler. Guaranteed to outlive this object.
+  ExceptionHandler* const exception_handler_;
 
   binding::RunJSFunction run_js_;
 
diff --git a/extensions/renderer/bindings/api_binding_js_util_unittest.cc b/extensions/renderer/bindings/api_binding_js_util_unittest.cc
index c9bd3131..df21db2 100644
--- a/extensions/renderer/bindings/api_binding_js_util_unittest.cc
+++ b/extensions/renderer/bindings/api_binding_js_util_unittest.cc
@@ -8,10 +8,24 @@
 #include "extensions/renderer/bindings/api_binding_test_util.h"
 #include "extensions/renderer/bindings/api_bindings_system.h"
 #include "extensions/renderer/bindings/api_bindings_system_unittest.h"
+#include "gin/arguments.h"
 #include "gin/handle.h"
+#include "testing/gmock/include/gmock/gmock.h"
 
 namespace extensions {
 
+namespace {
+
+// Calls handleException on |obj|, which is presumed to be the JS binding util.
+const char kHandleException[] =
+    "try {\n"
+    "  throw new Error('some error');\n"
+    "} catch (e) {\n"
+    "  obj.handleException('handled', e);\n"
+    "}";
+
+}  // namespace
+
 class APIBindingJSUtilUnittest : public APIBindingsSystemTest {
  protected:
   APIBindingJSUtilUnittest() {}
@@ -23,6 +37,7 @@
         new APIBindingJSUtil(bindings_system()->type_reference_map(),
                              bindings_system()->request_handler(),
                              bindings_system()->event_handler(),
+                             bindings_system()->exception_handler(),
                              base::Bind(&RunFunctionOnGlobalAndIgnoreResult)));
   }
 
@@ -32,6 +47,11 @@
     return context->Global();
   }
 
+  void AddConsoleError(v8::Local<v8::Context> context,
+                       const std::string& error) override {
+    console_errors_.push_back(error);
+  }
+
   std::string GetExposedError(v8::Local<v8::Context> context) {
     v8::Local<v8::Value> last_error =
         GetPropertyFromObject(context->Global(), context, "lastError");
@@ -56,7 +76,13 @@
     return bindings_system()->request_handler()->last_error();
   }
 
+  const std::vector<std::string>& console_errors() const {
+    return console_errors_;
+  }
+
  private:
+  std::vector<std::string> console_errors_;
+
   DISALLOW_COPY_AND_ASSIGN(APIBindingJSUtilUnittest);
 };
 
@@ -191,4 +217,75 @@
                                                 "callbackCalled"));
 }
 
+TEST_F(APIBindingJSUtilUnittest, TestCallHandleException) {
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = MainContext();
+
+  gin::Handle<APIBindingJSUtil> util = CreateUtil();
+  v8::Local<v8::Object> v8_util = util.ToV8().As<v8::Object>();
+
+  ASSERT_TRUE(console_errors().empty());
+  CallFunctionOnObject(context, v8_util, kHandleException);
+  EXPECT_THAT(console_errors(),
+              testing::ElementsAre("handled: Error: some error"));
+
+  const char kHandleTrickyException[] =
+      "try {\n"
+      "  throw { toString: function() { throw new Error('hahaha'); } };\n"
+      "} catch (e) {\n"
+      "  obj.handleException('handled again', e);\n"
+      "}\n";
+  CallFunctionOnObject(context, v8_util, kHandleTrickyException);
+  EXPECT_THAT(
+      console_errors(),
+      testing::ElementsAre("handled: Error: some error",
+                           "handled again: (failed to get error message)"));
+}
+
+TEST_F(APIBindingJSUtilUnittest, TestSetExceptionHandler) {
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = MainContext();
+
+  gin::Handle<APIBindingJSUtil> util = CreateUtil();
+  v8::Local<v8::Object> v8_util = util.ToV8().As<v8::Object>();
+
+  struct ErrorInfo {
+    std::string full_message;
+    std::string exception_message;
+  };
+
+  auto custom_handler = [](const v8::FunctionCallbackInfo<v8::Value>& info) {
+    gin::Arguments arguments(info);
+    std::string full_message;
+    ASSERT_TRUE(arguments.GetNext(&full_message));
+    v8::Local<v8::Object> error_object;
+    ASSERT_TRUE(arguments.GetNext(&error_object));
+
+    ASSERT_TRUE(info.Data()->IsExternal());
+    ErrorInfo* error_out =
+        static_cast<ErrorInfo*>(info.Data().As<v8::External>()->Value());
+    error_out->full_message = full_message;
+    error_out->exception_message = GetStringPropertyFromObject(
+        error_object, arguments.GetHolderCreationContext(), "message");
+  };
+
+  ErrorInfo error_info;
+  v8::Local<v8::Function> v8_handler =
+      v8::Function::New(context, custom_handler,
+                        v8::External::New(isolate(), &error_info))
+          .ToLocalChecked();
+  v8::Local<v8::Function> add_handler = FunctionFromString(
+      context,
+      "(function(util, handler) { util.setExceptionHandler(handler); })");
+  v8::Local<v8::Value> args[] = {v8_util, v8_handler};
+  RunFunction(add_handler, context, arraysize(args), args);
+
+  CallFunctionOnObject(context, v8_util, kHandleException);
+  // The error should not have been reported to the console since we have a
+  // cusotm handler.
+  EXPECT_TRUE(console_errors().empty());
+  EXPECT_EQ("handled: Error: some error", error_info.full_message);
+  EXPECT_EQ("\"some error\"", error_info.exception_message);
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/bindings/api_binding_unittest.cc b/extensions/renderer/bindings/api_binding_unittest.cc
index 655146b..97c155d 100644
--- a/extensions/renderer/bindings/api_binding_unittest.cc
+++ b/extensions/renderer/bindings/api_binding_unittest.cc
@@ -179,7 +179,7 @@
     event_handler_ = base::MakeUnique<APIEventHandler>(
         base::Bind(&RunFunctionOnGlobalAndIgnoreResult),
         base::Bind(&RunFunctionOnGlobalAndReturnHandle),
-        base::Bind(&OnEventListenersChanged));
+        base::Bind(&OnEventListenersChanged), nullptr);
     access_checker_ =
         base::MakeUnique<BindingAccessChecker>(availability_callback_);
     binding_ = base::MakeUnique<APIBinding>(
diff --git a/extensions/renderer/bindings/api_bindings_system.cc b/extensions/renderer/bindings/api_bindings_system.cc
index be402e4..b98612a3 100644
--- a/extensions/renderer/bindings/api_bindings_system.cc
+++ b/extensions/renderer/bindings/api_bindings_system.cc
@@ -28,7 +28,10 @@
                        call_js,
                        std::move(last_error),
                        &exception_handler_),
-      event_handler_(call_js, call_js_sync, event_listeners_changed),
+      event_handler_(call_js,
+                     call_js_sync,
+                     event_listeners_changed,
+                     &exception_handler_),
       access_checker_(is_available),
       call_js_(call_js),
       call_js_sync_(call_js_sync),
diff --git a/extensions/renderer/bindings/api_bindings_system_unittest.cc b/extensions/renderer/bindings/api_bindings_system_unittest.cc
index 0b02f93..bd9a477 100644
--- a/extensions/renderer/bindings/api_bindings_system_unittest.cc
+++ b/extensions/renderer/bindings/api_bindings_system_unittest.cc
@@ -115,6 +115,8 @@
     api_schemas_[api.name] = std::move(api_schema);
   }
 
+  binding::AddConsoleError add_console_error(base::Bind(
+      &APIBindingsSystemTest::AddConsoleError, base::Unretained(this)));
   bindings_system_ = base::MakeUnique<APIBindingsSystem>(
       base::Bind(&RunFunctionOnGlobalAndIgnoreResult),
       base::Bind(&RunFunctionOnGlobalAndReturnHandle),
@@ -123,10 +125,10 @@
       base::Bind(&APIBindingsSystemTest::OnAPIRequest, base::Unretained(this)),
       base::Bind(&APIBindingsSystemTest::OnEventListenersChanged,
                  base::Unretained(this)),
-      base::Bind(&DoNothingWithSilentRequest), binding::AddConsoleError(),
+      base::Bind(&DoNothingWithSilentRequest), add_console_error,
       APILastError(base::Bind(&APIBindingsSystemTest::GetLastErrorParent,
                               base::Unretained(this)),
-                   binding::AddConsoleError()));
+                   add_console_error));
 }
 
 void APIBindingsSystemTest::TearDown() {
diff --git a/extensions/renderer/bindings/api_bindings_system_unittest.h b/extensions/renderer/bindings/api_bindings_system_unittest.h
index 2413eef..25d649fd 100644
--- a/extensions/renderer/bindings/api_bindings_system_unittest.h
+++ b/extensions/renderer/bindings/api_bindings_system_unittest.h
@@ -53,6 +53,10 @@
       v8::Local<v8::Context> context,
       v8::Local<v8::Object>* secondary_parent);
 
+  // Simulates logging an error to the console.
+  virtual void AddConsoleError(v8::Local<v8::Context> context,
+                               const std::string& error) {}
+
   // Returns the DictionaryValue representing the schema with the given API
   // name.
   const base::DictionaryValue& GetAPISchema(const std::string& api_name);
diff --git a/extensions/renderer/bindings/api_event_handler.cc b/extensions/renderer/bindings/api_event_handler.cc
index e1c1200e..7935df6 100644
--- a/extensions/renderer/bindings/api_event_handler.cc
+++ b/extensions/renderer/bindings/api_event_handler.cc
@@ -109,10 +109,12 @@
 APIEventHandler::APIEventHandler(
     const binding::RunJSFunction& call_js,
     const binding::RunJSFunctionSync& call_js_sync,
-    const EventListenersChangedMethod& listeners_changed)
+    const EventListenersChangedMethod& listeners_changed,
+    ExceptionHandler* exception_handler)
     : call_js_(call_js),
       call_js_sync_(call_js_sync),
-      listeners_changed_(listeners_changed) {}
+      listeners_changed_(listeners_changed),
+      exception_handler_(exception_handler) {}
 APIEventHandler::~APIEventHandler() {}
 
 v8::Local<v8::Object> APIEventHandler::CreateEventInstance(
@@ -142,10 +144,10 @@
         base::MakeUnique<UnfilteredEventListeners>(updated, max_listeners);
   }
 
-  gin::Handle<EventEmitter> emitter_handle =
-      gin::CreateHandle(context->GetIsolate(),
-                        new EventEmitter(supports_filters, std::move(listeners),
-                                         call_js_, call_js_sync_));
+  gin::Handle<EventEmitter> emitter_handle = gin::CreateHandle(
+      context->GetIsolate(),
+      new EventEmitter(supports_filters, std::move(listeners), call_js_,
+                       call_js_sync_, exception_handler_));
   CHECK(!emitter_handle.IsEmpty());
   v8::Local<v8::Value> emitter_value = emitter_handle.ToV8();
   CHECK(emitter_value->IsObject());
@@ -165,10 +167,10 @@
   std::unique_ptr<APIEventListeners> listeners =
       base::MakeUnique<UnfilteredEventListeners>(
           base::Bind(&DoNothingOnListenersChanged), binding::kNoListenerMax);
-  gin::Handle<EventEmitter> emitter_handle =
-      gin::CreateHandle(context->GetIsolate(),
-                        new EventEmitter(supports_filters, std::move(listeners),
-                                         call_js_, call_js_sync_));
+  gin::Handle<EventEmitter> emitter_handle = gin::CreateHandle(
+      context->GetIsolate(),
+      new EventEmitter(supports_filters, std::move(listeners), call_js_,
+                       call_js_sync_, exception_handler_));
   CHECK(!emitter_handle.IsEmpty());
   v8::Local<v8::Object> emitter_object = emitter_handle.ToV8().As<v8::Object>();
   data->anonymous_emitters.push_back(
diff --git a/extensions/renderer/bindings/api_event_handler.h b/extensions/renderer/bindings/api_event_handler.h
index bca7319..edb744a 100644
--- a/extensions/renderer/bindings/api_event_handler.h
+++ b/extensions/renderer/bindings/api_event_handler.h
@@ -19,6 +19,7 @@
 }
 
 namespace extensions {
+class ExceptionHandler;
 struct EventFilteringInfo;
 
 // The object to handle API events. This includes vending v8::Objects for the
@@ -40,7 +41,8 @@
 
   APIEventHandler(const binding::RunJSFunction& call_js,
                   const binding::RunJSFunctionSync& call_js_sync,
-                  const EventListenersChangedMethod& listeners_changed);
+                  const EventListenersChangedMethod& listeners_changed,
+                  ExceptionHandler* exception_handler);
   ~APIEventHandler();
 
   // Returns a new v8::Object for an event with the given |event_name|. If
@@ -104,6 +106,10 @@
   // The associated EventFilter; shared across all contexts and events.
   EventFilter event_filter_;
 
+  // The exception handler associated with the bindings system; guaranteed to
+  // outlive this object.
+  ExceptionHandler* const exception_handler_;
+
   DISALLOW_COPY_AND_ASSIGN(APIEventHandler);
 };
 
diff --git a/extensions/renderer/bindings/api_event_handler_unittest.cc b/extensions/renderer/bindings/api_event_handler_unittest.cc
index a249aaf..ca349769 100644
--- a/extensions/renderer/bindings/api_event_handler_unittest.cc
+++ b/extensions/renderer/bindings/api_event_handler_unittest.cc
@@ -13,6 +13,7 @@
 #include "extensions/common/event_filtering_info.h"
 #include "extensions/renderer/bindings/api_binding_test.h"
 #include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/exception_handler.h"
 #include "gin/arguments.h"
 #include "gin/converter.h"
 #include "gin/public/context_holder.h"
@@ -41,7 +42,7 @@
     handler_ = base::MakeUnique<APIEventHandler>(
         base::Bind(&RunFunctionOnGlobalAndIgnoreResult),
         base::Bind(&RunFunctionOnGlobalAndReturnHandle),
-        base::Bind(&DoNothingOnEventListenersChanged));
+        base::Bind(&DoNothingOnEventListenersChanged), nullptr);
   }
 
   void TearDown() override {
@@ -551,10 +552,18 @@
       result.Reset(context->GetIsolate(), local);
   };
 
+  auto log_error =
+      [](std::vector<std::string>* errors_out, v8::Local<v8::Context> context,
+         const std::string& error) { errors_out->push_back(error); };
+
+  std::vector<std::string> logged_errors;
+  ExceptionHandler exception_handler(
+      base::Bind(log_error, &logged_errors),
+      base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
   SetHandler(base::MakeUnique<APIEventHandler>(
       base::Bind(run_js_and_expect_error),
       base::Bind(&RunFunctionOnGlobalAndReturnHandle),
-      base::Bind(&DoNothingOnEventListenersChanged)));
+      base::Bind(&DoNothingOnEventListenersChanged), &exception_handler));
 
   v8::HandleScope handle_scope(isolate());
   v8::Local<v8::Context> context = MainContext();
@@ -564,25 +573,6 @@
       kEventName, false, binding::kNoListenerMax, true, context);
   ASSERT_FALSE(event.IsEmpty());
 
-  bool did_throw = false;
-  auto message_listener = [](v8::Local<v8::Message> message,
-                             v8::Local<v8::Value> data) {
-    ASSERT_FALSE(data.IsEmpty());
-    ASSERT_TRUE(data->IsExternal());
-    bool* did_throw = static_cast<bool*>(data.As<v8::External>()->Value());
-    *did_throw = true;
-    EXPECT_EQ("Uncaught Error: Event handler error",
-              gin::V8ToString(message->Get()));
-  };
-
-  isolate()->AddMessageListener(message_listener,
-                                v8::External::New(isolate(), &did_throw));
-  base::ScopedClosureRunner remove_message_listener(base::Bind(
-      [](v8::Isolate* isolate, v8::MessageCallback listener) {
-        isolate->RemoveMessageListeners(listener);
-      },
-      isolate(), message_listener));
-
   // A listener that will throw an exception. We guarantee that we throw the
   // exception first so that we don't rely on event listener ordering.
   const char kListenerFunction[] =
@@ -617,7 +607,9 @@
                                                 "didThrow"));
   EXPECT_EQ("[42]", GetStringPropertyFromObject(context->Global(), context,
                                                 "eventArgs"));
-  EXPECT_TRUE(did_throw);
+  ASSERT_EQ(1u, logged_errors.size());
+  EXPECT_EQ("Error in event handler: Uncaught Error: Event handler error",
+            logged_errors[0]);
 }
 
 // Tests being notified as listeners are added or removed from events.
@@ -625,7 +617,8 @@
   MockEventChangeHandler change_handler;
   SetHandler(base::MakeUnique<APIEventHandler>(
       base::Bind(&RunFunctionOnGlobalAndIgnoreResult),
-      base::Bind(&RunFunctionOnGlobalAndReturnHandle), change_handler.Get()));
+      base::Bind(&RunFunctionOnGlobalAndReturnHandle), change_handler.Get(),
+      nullptr));
 
   v8::HandleScope handle_scope(isolate());
 
@@ -911,7 +904,7 @@
   MockEventChangeHandler change_handler;
   APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult),
                           base::Bind(&RunFunctionOnGlobalAndReturnHandle),
-                          change_handler.Get());
+                          change_handler.Get(), nullptr);
 
   v8::Local<v8::Object> event = handler.CreateAnonymousEventInstance(context);
   ASSERT_FALSE(event.IsEmpty());
@@ -960,7 +953,7 @@
   MockEventChangeHandler change_handler;
   APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult),
                           base::Bind(&RunFunctionOnGlobalAndReturnHandle),
-                          change_handler.Get());
+                          change_handler.Get(), nullptr);
 
   v8::Local<v8::Object> event = handler.CreateAnonymousEventInstance(context);
   ASSERT_FALSE(event.IsEmpty());
@@ -987,7 +980,7 @@
 
   APIEventHandler handler(base::Bind(&RunFunctionOnGlobalAndIgnoreResult),
                           base::Bind(&RunFunctionOnGlobalAndReturnHandle),
-                          base::Bind(fail_on_notified));
+                          base::Bind(fail_on_notified), nullptr);
 
   const char kEventName[] = "alpha";
   v8::Local<v8::Object> event = handler.CreateEventInstance(
diff --git a/extensions/renderer/bindings/event_emitter.cc b/extensions/renderer/bindings/event_emitter.cc
index 4d9a391..0abca94 100644
--- a/extensions/renderer/bindings/event_emitter.cc
+++ b/extensions/renderer/bindings/event_emitter.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "extensions/renderer/bindings/api_event_listeners.h"
+#include "extensions/renderer/bindings/exception_handler.h"
 #include "gin/data_object_builder.h"
 #include "gin/object_template_builder.h"
 #include "gin/per_context_data.h"
@@ -18,11 +19,13 @@
 EventEmitter::EventEmitter(bool supports_filters,
                            std::unique_ptr<APIEventListeners> listeners,
                            const binding::RunJSFunction& run_js,
-                           const binding::RunJSFunctionSync& run_js_sync)
+                           const binding::RunJSFunctionSync& run_js_sync,
+                           ExceptionHandler* exception_handler)
     : supports_filters_(supports_filters),
       listeners_(std::move(listeners)),
       run_js_(run_js),
-      run_js_sync_(run_js_sync) {}
+      run_js_sync_(run_js_sync),
+      exception_handler_(exception_handler) {}
 
 EventEmitter::~EventEmitter() {}
 
@@ -178,10 +181,6 @@
 
   v8::Isolate* isolate = context->GetIsolate();
   v8::TryCatch try_catch(isolate);
-  // SetVerbose() means the error will still get logged, which is what we
-  // want. We don't let it bubble up any further to prevent it from being
-  // surfaced in e.g. JS code that triggered the event.
-  try_catch.SetVerbose(true);
   for (const auto& listener : listeners) {
     if (run_sync) {
       DCHECK(out_values);
@@ -192,6 +191,11 @@
     } else {
       run_js_.Run(listener, context, args->size(), args->data());
     }
+
+    if (try_catch.HasCaught()) {
+      exception_handler_->HandleException(context, "Error in event handler",
+                                          &try_catch);
+    }
   }
 }
 
diff --git a/extensions/renderer/bindings/event_emitter.h b/extensions/renderer/bindings/event_emitter.h
index 9f9cbe5e..1f86961 100644
--- a/extensions/renderer/bindings/event_emitter.h
+++ b/extensions/renderer/bindings/event_emitter.h
@@ -17,6 +17,7 @@
 
 namespace extensions {
 class APIEventListeners;
+class ExceptionHandler;
 struct EventFilteringInfo;
 
 // A gin::Wrappable Event object. One is expected to be created per event, per
@@ -27,7 +28,8 @@
   EventEmitter(bool supports_filters,
                std::unique_ptr<APIEventListeners> listeners,
                const binding::RunJSFunction& run_js,
-               const binding::RunJSFunctionSync& run_js_sync);
+               const binding::RunJSFunctionSync& run_js_sync,
+               ExceptionHandler* exception_handler);
   ~EventEmitter() override;
 
   static gin::WrapperInfo kWrapperInfo;
@@ -77,6 +79,9 @@
   binding::RunJSFunction run_js_;
   binding::RunJSFunctionSync run_js_sync_;
 
+  // The associated exception handler; guaranteed to outlive this object.
+  ExceptionHandler* const exception_handler_;
+
   DISALLOW_COPY_AND_ASSIGN(EventEmitter);
 };
 
diff --git a/extensions/renderer/bindings/event_emitter_unittest.cc b/extensions/renderer/bindings/event_emitter_unittest.cc
index 4f0395d7..1491fdd3 100644
--- a/extensions/renderer/bindings/event_emitter_unittest.cc
+++ b/extensions/renderer/bindings/event_emitter_unittest.cc
@@ -10,6 +10,7 @@
 #include "extensions/renderer/bindings/api_binding_test.h"
 #include "extensions/renderer/bindings/api_binding_test_util.h"
 #include "extensions/renderer/bindings/api_event_listeners.h"
+#include "extensions/renderer/bindings/exception_handler.h"
 #include "gin/handle.h"
 
 namespace extensions {
@@ -50,9 +51,18 @@
     ignore_result(function->Call(context, context->Global(), argc, argv));
   };
 
+  auto log_error = [](std::vector<std::string>* errors,
+                      v8::Local<v8::Context> context,
+                      const std::string& error) { errors->push_back(error); };
+
+  std::vector<std::string> logged_errors;
+  ExceptionHandler exception_handler(base::Bind(log_error, &logged_errors),
+                                     base::Bind(run_js));
+
   gin::Handle<EventEmitter> event = gin::CreateHandle(
-      isolate(), new EventEmitter(false, std::move(listeners),
-                                  base::Bind(run_js), base::Bind(run_js_sync)));
+      isolate(),
+      new EventEmitter(false, std::move(listeners), base::Bind(run_js),
+                       base::Bind(run_js_sync), &exception_handler));
 
   v8::Local<v8::Value> v8_event = event.ToV8();
 
@@ -114,6 +124,9 @@
   }
   EXPECT_EQ("{\"results\":[\"listener1\",{\"listener\":\"listener2\"}]}",
             V8ToString(dispatch_result, context));
+
+  ASSERT_EQ(1u, logged_errors.size());
+  EXPECT_EQ("Error in event handler: Uncaught Error: hahaha", logged_errors[0]);
 }
 
 }  // namespace extensions
diff --git a/extensions/renderer/bindings/exception_handler.cc b/extensions/renderer/bindings/exception_handler.cc
index 2f4f773..433fd706 100644
--- a/extensions/renderer/bindings/exception_handler.cc
+++ b/extensions/renderer/bindings/exception_handler.cc
@@ -63,19 +63,29 @@
           ? base::StringPrintf("%s: %s", message.c_str(),
                                gin::V8ToString(v8_message->Get()).c_str())
           : message;
+  HandleException(context, full_message, try_catch->Exception());
+  try_catch->Reset();  // Reset() to avoid handling the error more than once.
+}
+
+void ExceptionHandler::HandleException(v8::Local<v8::Context> context,
+                                       const std::string& full_message,
+                                       v8::Local<v8::Value> exception_value) {
+  v8::Isolate* isolate = context->GetIsolate();
+  v8::HandleScope handle_scope(isolate);
 
   v8::Local<v8::Function> handler = GetCustomHandler(context);
   if (!handler.IsEmpty()) {
     v8::Local<v8::Value> arguments[] = {
-        gin::StringToV8(isolate, full_message), try_catch->Exception(),
+        gin::StringToV8(isolate, full_message), exception_value,
     };
+    // Hopefully, handling an exception doesn't throw an exception - but it's
+    // possible. Handle this gracefully, and log errors normally.
     v8::TryCatch handler_try_catch(isolate);
+    handler_try_catch.SetVerbose(true);
     run_js_.Run(handler, context, arraysize(arguments), arguments);
   } else {
     add_console_error_.Run(context, full_message);
   }
-
-  try_catch->Reset();  // Reset() to avoid handling the error more than once.
 }
 
 void ExceptionHandler::SetHandlerForContext(v8::Local<v8::Context> context,
diff --git a/extensions/renderer/bindings/exception_handler.h b/extensions/renderer/bindings/exception_handler.h
index aa8e5fbe..943a78d 100644
--- a/extensions/renderer/bindings/exception_handler.h
+++ b/extensions/renderer/bindings/exception_handler.h
@@ -29,6 +29,11 @@
   void HandleException(v8::Local<v8::Context> context,
                        const std::string& message,
                        v8::TryCatch* try_catch);
+  // Same as above, but accepts a v8::Value for the exception rather than
+  // retrieving it from a TryCatch.
+  void HandleException(v8::Local<v8::Context> context,
+                       const std::string& full_message,
+                       v8::Local<v8::Value> exception_value);
 
   // Sets a custom handler for the given context, which will be notified of
   // exceptions thrown. This is only allowed to be called while the context is
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index e43e801e..450ff44 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -707,7 +707,8 @@
       context->GetIsolate(),
       new APIBindingJSUtil(
           api_system_.type_reference_map(), api_system_.request_handler(),
-          api_system_.event_handler(), base::Bind(&CallJsFunction)));
+          api_system_.event_handler(), api_system_.exception_handler(),
+          base::Bind(&CallJsFunction)));
   *binding_util_out = handle.ToV8();
 }
 
diff --git a/extensions/renderer/resources/test_custom_bindings.js b/extensions/renderer/resources/test_custom_bindings.js
index b797d3d..950b339 100644
--- a/extensions/renderer/resources/test_custom_bindings.js
+++ b/extensions/renderer/resources/test_custom_bindings.js
@@ -12,11 +12,26 @@
     requireNative('apiDefinitions').GetExtensionAPIDefinitionsForTest;
 var GetAPIFeatures = requireNative('test_features').GetAPIFeatures;
 var natives = requireNative('test_native_handler');
-var uncaughtExceptionHandler = require('uncaught_exception_handler');
 var userGestures = requireNative('user_gestures');
 
 var GetModuleSystem = requireNative('v8_context').GetModuleSystem;
 
+var jsExceptionHandler =
+    bindingUtil ? undefined : require('uncaught_exception_handler');
+function setExceptionHandler(handler) {
+  if (bindingUtil)
+    bindingUtil.setExceptionHandler(handler);
+  else
+    jsExceptionHandler.setHandler(handler);
+}
+
+function handleException(message, error) {
+  if (bindingUtil)
+    bindingUtil.handleException(message, error);
+  else
+    jsExceptionHandler.handle(message, error);
+}
+
 binding.registerCustomHook(function(api) {
   var chromeTest = api.compiledApi;
   var apiFunctions = api.apiFunctions;
@@ -88,13 +103,13 @@
 
     try {
       chromeTest.log("( RUN      ) " + testName(currentTest));
-      uncaughtExceptionHandler.setHandler(function(message, e) {
+      setExceptionHandler(function(message, e) {
         if (e !== failureException)
           chromeTest.fail('uncaught exception: ' + message);
       });
       currentTest.call();
     } catch (e) {
-      uncaughtExceptionHandler.handle(e.message, e);
+      handleException(e.message, e);
     }
   });
 
@@ -261,7 +276,7 @@
     } catch (e) {
       if (e === failureException)
         throw e;
-      uncaughtExceptionHandler.handle(e.message, e);
+      handleException(e.message, e);
     }
   };
 
@@ -354,7 +369,7 @@
 
   apiFunctions.setHandleRequest('setExceptionHandler', function(callback) {
     chromeTest.assertEq(typeof(callback), 'function');
-    uncaughtExceptionHandler.setHandler(callback);
+    setExceptionHandler(callback);
   });
 
   apiFunctions.setHandleRequest('getWakeEventPage', function() {
diff --git a/extensions/shell/installer/linux/BUILD.gn b/extensions/shell/installer/linux/BUILD.gn
index 08f8bfa..77211396 100644
--- a/extensions/shell/installer/linux/BUILD.gn
+++ b/extensions/shell/installer/linux/BUILD.gn
@@ -129,10 +129,6 @@
     ]
   }
 
-  # TODO(thomasanderson): Move this variable into a .gni file
-  # somewhere.  It is currently copied from
-  # buildtools/third_party/libc++/BUILD.gn.
-  libcpp_is_static = !is_component_build && !using_sanitizer
   if (!libcpp_is_static && use_custom_libcxx) {
     public_deps += [ "//buildtools/third_party/libc++:libc++" ]
   }
@@ -162,10 +158,6 @@
     ]
   }
 
-  # TODO(thomasanderson): Move this variable into a .gni file
-  # somewhere.  It is currently copied from
-  # buildtools/third_party/libc++/BUILD.gn.
-  libcpp_is_static = !is_component_build && !using_sanitizer
   if (!libcpp_is_static && use_custom_libcxx) {
     packaging_files_binaries += [ "$root_out_dir/libc++.so" ]
   }
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index 98d864d5..3411e972 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -245,7 +245,9 @@
   bool HaveContexts();
   void ReportProgress();
 
-  const GpuPreferences& gpu_preferences_;
+  // It's safer to make a copy of the GpuPreferences struct rather
+  // than refer to the one passed in to the constructor.
+  const GpuPreferences gpu_preferences_;
   MailboxManager* mailbox_manager_;
   scoped_refptr<MemoryTracker> memory_tracker_;
   ShaderTranslatorCache* shader_translator_cache_;
diff --git a/gpu/config/software_rendering_list.json b/gpu/config/software_rendering_list.json
index 3d3938b..ed5c6d6 100644
--- a/gpu/config/software_rendering_list.json
+++ b/gpu/config/software_rendering_list.json
@@ -1,6 +1,6 @@
 {
   "name": "software rendering list",
-  "version": "13.9",
+  "version": "13.10",
   "entries": [
     {
       "id": 1,
@@ -1520,6 +1520,18 @@
         "accelerated_2d_canvas",
         "gpu_rasterization"
       ]
+    },
+    {
+      "id": 148,
+      "description": "VideoCore V has corrupt rendering with GPU Rasterization",
+      "cr_bugs": [710273],
+      "os": {
+        "type": "android"
+      },
+      "gl_renderer": ".*VideoCore V.*",
+      "features": [
+        "gpu_rasterization"
+      ]
     }
   ],
   "comment": [
diff --git a/ios/build/bots/chromium.mac/ios-device.json b/ios/build/bots/chromium.mac/ios-device.json
index c03de84..4e3993b9 100644
--- a/ios/build/bots/chromium.mac/ios-device.json
+++ b/ios/build/bots/chromium.mac/ios-device.json
@@ -18,6 +18,7 @@
     "all"
   ],
   "configuration": "Release",
+  "explain": true,
   "sdk": "iphoneos10.0",
   "tests": [
   ]
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 21a0542..3560175 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -145,6 +145,7 @@
     "//components/crash/core/common",
     "//components/favicon/core",
     "//components/favicon_base",
+    "//components/feature_engagement_tracker",
     "//components/handoff",
     "//components/history/core/browser",
     "//components/infobars/core",
@@ -177,6 +178,7 @@
     "//ios/chrome/browser/crash_report",
     "//ios/chrome/browser/crash_report:crash_report_internal",
     "//ios/chrome/browser/favicon",
+    "//ios/chrome/browser/feature_engagement_tracker",
     "//ios/chrome/browser/first_run",
     "//ios/chrome/browser/geolocation",
     "//ios/chrome/browser/geolocation:geolocation_internal",
diff --git a/ios/chrome/app/DEPS b/ios/chrome/app/DEPS
index e9d61b1a..f62aa619 100644
--- a/ios/chrome/app/DEPS
+++ b/ios/chrome/app/DEPS
@@ -9,6 +9,7 @@
   "+components/crash/core/common",
   "+components/favicon/core",
   "+components/favicon_base",
+  "+components/feature_engagement_tracker",
   "+components/handoff",
   "+components/history/core/browser",
   "+components/metrics",
@@ -21,6 +22,7 @@
   "+components/url_formatter",
   "+components/web_resource",
   "+ios/chrome/browser",
+  "+ios/chrome/browser/feature_engagement_tracker",
   "+ios/net",
   "+ios/public/provider/chrome",
   "+ios/web/public",
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn
index 3e4ce4b3..6d42912 100644
--- a/ios/chrome/app/application_delegate/BUILD.gn
+++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -96,6 +96,7 @@
     ":application_delegate",
     "//base",
     "//components/crash/core/common",
+    "//components/feature_engagement_tracker",
     "//components/handoff",
     "//components/metrics",
     "//components/prefs",
@@ -107,6 +108,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/crash_report",
     "//ios/chrome/browser/device_sharing",
+    "//ios/chrome/browser/feature_engagement_tracker",
     "//ios/chrome/browser/geolocation",
     "//ios/chrome/browser/metrics",
     "//ios/chrome/browser/metrics:metrics_internal",
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm
index d1bed69..d36f0ff 100644
--- a/ios/chrome/app/application_delegate/app_state.mm
+++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -10,6 +10,8 @@
 #include "base/critical_closure.h"
 #import "base/mac/bind_objc_block.h"
 #include "base/metrics/histogram_macros.h"
+#include "components/feature_engagement_tracker/public/event_constants.h"
+#include "components/feature_engagement_tracker/public/feature_engagement_tracker.h"
 #include "components/metrics/metrics_service.h"
 #import "ios/chrome/app/application_delegate/app_navigation.h"
 #import "ios/chrome/app/application_delegate/browser_launcher.h"
@@ -31,6 +33,7 @@
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
 #import "ios/chrome/browser/crash_report/crash_report_background_uploader.h"
 #import "ios/chrome/browser/device_sharing/device_sharing_manager.h"
+#include "ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.h"
 #import "ios/chrome/browser/geolocation/omnibox_geolocation_config.h"
 #import "ios/chrome/browser/metrics/previous_session_info.h"
 #import "ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller.h"
@@ -325,6 +328,13 @@
     net::CheckForCookieLoss(cookie_count,
                             net::COOKIES_APPLICATION_FOREGROUNDED);
   }
+
+  if (currentBrowserState) {
+    // Send the "Chrome Opened" event to the FeatureEngagementTracker on a warm
+    // start.
+    FeatureEngagementTrackerFactory::GetForBrowserState(currentBrowserState)
+        ->NotifyEvent(feature_engagement_tracker::events::kChromeOpened);
+  }
 }
 
 - (void)resumeSessionWithTabOpener:(id<TabOpening>)tabOpener
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index ce454bf2..5bdb0be0 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -25,6 +25,8 @@
 #include "base/time/time.h"
 #include "components/component_updater/component_updater_service.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/feature_engagement_tracker/public/event_constants.h"
+#include "components/feature_engagement_tracker/public/feature_engagement_tracker.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_service.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -71,6 +73,7 @@
 #import "ios/chrome/browser/crash_report/crash_report_background_uploader.h"
 #import "ios/chrome/browser/crash_report/crash_restore_helper.h"
 #include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/feature_engagement_tracker/feature_engagement_tracker_factory.h"
 #include "ios/chrome/browser/file_metadata_util.h"
 #import "ios/chrome/browser/first_run/first_run.h"
 #include "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h"
@@ -682,6 +685,11 @@
       [[BrowserViewWrangler alloc] initWithBrowserState:_mainBrowserState
                                        tabModelObserver:self
                              applicationCommandEndpoint:self];
+
+  // Send "Chrome Opened" event to the FeatureEngagementTracker on cold start.
+  FeatureEngagementTrackerFactory::GetForBrowserState(chromeBrowserState)
+      ->NotifyEvent(feature_engagement_tracker::events::kChromeOpened);
+
   // Ensure the main tab model is created.
   ignore_result([_browserViewWrangler mainTabModel]);
 
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 1921db05..cbcbe9b1 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -33,6 +33,7 @@
   "+components/invalidation",
   "+components/keyed_service/core",
   "+components/keyed_service/ios",
+  "+components/language",
   "+components/language_usage_metrics",
   "+components/leveldb_proto",
   "+components/metrics",
diff --git a/ios/chrome/browser/browsing_data/BUILD.gn b/ios/chrome/browser/browsing_data/BUILD.gn
index fce3d9f..8e998f4 100644
--- a/ios/chrome/browser/browsing_data/BUILD.gn
+++ b/ios/chrome/browser/browsing_data/BUILD.gn
@@ -23,6 +23,7 @@
     "//components/browsing_data/core",
     "//components/history/core/browser",
     "//components/keyed_service/core",
+    "//components/language/core/browser",
     "//components/omnibox/browser",
     "//components/password_manager/core/browser",
     "//components/prefs",
@@ -32,6 +33,7 @@
     "//ios/chrome/browser/autofill",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/history",
+    "//ios/chrome/browser/language",
     "//ios/chrome/browser/passwords",
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/sessions",
diff --git a/ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.mm b/ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.mm
index 19ae87a..2af1591a 100644
--- a/ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.mm
+++ b/ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.mm
@@ -19,22 +19,22 @@
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/keyed_service/core/service_access_type.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/omnibox/browser/omnibox_pref_names.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/prefs/pref_service.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/sessions/core/tab_restore_service.h"
-#include "components/translate/core/browser/language_model.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/history/web_history_service_factory.h"
 #include "ios/chrome/browser/ios_chrome_io_thread.h"
+#include "ios/chrome/browser/language/url_language_histogram_factory.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
-#include "ios/chrome/browser/translate/language_model_factory.h"
 #include "ios/chrome/browser/web_data_service_factory.h"
 #include "ios/net/http_cache_helper.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
@@ -247,11 +247,11 @@
         data_manager->Refresh();
     }
 
-    // Remove language model history.
-    translate::LanguageModel* language_model =
-        LanguageModelFactory::GetForBrowserState(browser_state_);
-    if (language_model) {
-      language_model->ClearHistory(delete_begin_, delete_end_);
+    // Remove language histogram history.
+    language::UrlLanguageHistogram* language_histogram =
+        UrlLanguageHistogramFactory::GetForBrowserState(browser_state_);
+    if (language_histogram) {
+      language_histogram->ClearHistory(delete_begin_, delete_end_);
     }
   }
 
diff --git a/ios/chrome/browser/language/BUILD.gn b/ios/chrome/browser/language/BUILD.gn
new file mode 100644
index 0000000..9c11dcb1d
--- /dev/null
+++ b/ios/chrome/browser/language/BUILD.gn
@@ -0,0 +1,41 @@
+# 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.
+
+source_set("language") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "url_language_histogram_factory.cc",
+    "url_language_histogram_factory.h",
+  ]
+  deps = [
+    "//base",
+    "//components/keyed_service/core",
+    "//components/keyed_service/ios",
+    "//components/language/core/browser",
+    "//components/prefs",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+  ]
+}
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "url_language_histogram_factory_unittest.cc",
+  ]
+  deps = [
+    ":language",
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/web:test_support",
+    "//ios/public/provider/chrome/browser:test_support",
+    "//ios/web",
+    "//ios/web/public/test",
+    "//testing/gmock:gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/language/OWNERS b/ios/chrome/browser/language/OWNERS
new file mode 100644
index 0000000..f1e82d5
--- /dev/null
+++ b/ios/chrome/browser/language/OWNERS
@@ -0,0 +1 @@
+file://components/language/OWNERS
diff --git a/ios/chrome/browser/language/url_language_histogram_factory.cc b/ios/chrome/browser/language/url_language_histogram_factory.cc
new file mode 100644
index 0000000..9649507
--- /dev/null
+++ b/ios/chrome/browser/language/url_language_histogram_factory.cc
@@ -0,0 +1,39 @@
+// 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 "ios/chrome/browser/language/url_language_histogram_factory.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/language/core/browser/url_language_histogram.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+
+// static
+UrlLanguageHistogramFactory* UrlLanguageHistogramFactory::GetInstance() {
+  return base::Singleton<UrlLanguageHistogramFactory>::get();
+}
+
+// static
+language::UrlLanguageHistogram* UrlLanguageHistogramFactory::GetForBrowserState(
+    ios::ChromeBrowserState* const state) {
+  return static_cast<language::UrlLanguageHistogram*>(
+      GetInstance()->GetServiceForBrowserState(state, true));
+}
+
+UrlLanguageHistogramFactory::UrlLanguageHistogramFactory()
+    : BrowserStateKeyedServiceFactory(
+          "UrlLanguageHistogram",
+          BrowserStateDependencyManager::GetInstance()) {}
+
+UrlLanguageHistogramFactory::~UrlLanguageHistogramFactory() {}
+
+std::unique_ptr<KeyedService>
+UrlLanguageHistogramFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  ios::ChromeBrowserState* browser_state =
+      ios::ChromeBrowserState::FromBrowserState(context);
+  return base::MakeUnique<language::UrlLanguageHistogram>(
+      browser_state->GetPrefs());
+}
diff --git a/ios/chrome/browser/language/url_language_histogram_factory.h b/ios/chrome/browser/language/url_language_histogram_factory.h
new file mode 100644
index 0000000..37b0683b
--- /dev/null
+++ b/ios/chrome/browser/language/url_language_histogram_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_LANGUAGE_URL_LANGUAGE_HISTOGRAM_FACTORY_H
+#define IOS_CHROME_BROWSER_LANGUAGE_URL_LANGUAGE_HISTOGRAM_FACTORY_H
+
+#include <memory>
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+namespace ios {
+class ChromeBrowserState;
+}
+
+namespace language {
+class UrlLanguageHistogram;
+}
+
+class UrlLanguageHistogramFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  static UrlLanguageHistogramFactory* GetInstance();
+  static language::UrlLanguageHistogram* GetForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+
+ private:
+  friend struct base::DefaultSingletonTraits<UrlLanguageHistogramFactory>;
+
+  UrlLanguageHistogramFactory();
+  ~UrlLanguageHistogramFactory() override;
+
+  // BrowserStateKeyedServiceFactory implementation.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlLanguageHistogramFactory);
+};
+
+#endif  // IOS_CHROME_BROWSER_LANGUAGE_URL_LANGUAGE_HISTOGRAM_FACTORY_H
diff --git a/ios/chrome/browser/language/url_language_histogram_factory_unittest.cc b/ios/chrome/browser/language/url_language_histogram_factory_unittest.cc
new file mode 100644
index 0000000..de91204
--- /dev/null
+++ b/ios/chrome/browser/language/url_language_histogram_factory_unittest.cc
@@ -0,0 +1,43 @@
+// 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 "ios/chrome/browser/language/url_language_histogram_factory.h"
+
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/web/public/test/test_web_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::IsNull;
+using testing::Not;
+
+class UrlLanguageHistogramFactoryTest : public testing::Test {
+ public:
+  UrlLanguageHistogramFactoryTest() {
+    TestChromeBrowserState::Builder browser_state_builder;
+    chrome_browser_state_ = browser_state_builder.Build();
+  }
+
+  ~UrlLanguageHistogramFactoryTest() override { chrome_browser_state_.reset(); }
+
+  ios::ChromeBrowserState* chrome_browser_state() {
+    return chrome_browser_state_.get();
+  }
+
+ private:
+  web::TestWebThreadBundle thread_bundle_;
+  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
+};
+
+TEST_F(UrlLanguageHistogramFactoryTest, NotCreatedInIncognito) {
+  EXPECT_THAT(
+      UrlLanguageHistogramFactory::GetForBrowserState(chrome_browser_state()),
+      Not(IsNull()));
+
+  ios::ChromeBrowserState* otr_browser_state =
+      chrome_browser_state()->GetOffTheRecordChromeBrowserState();
+  language::UrlLanguageHistogram* language_histogram =
+      UrlLanguageHistogramFactory::GetForBrowserState(otr_browser_state);
+  EXPECT_THAT(language_histogram, IsNull());
+}
diff --git a/ios/chrome/browser/payments/payment_request.h b/ios/chrome/browser/payments/payment_request.h
index 6def1bae..f5f8000 100644
--- a/ios/chrome/browser/payments/payment_request.h
+++ b/ios/chrome/browser/payments/payment_request.h
@@ -310,14 +310,18 @@
   std::vector<PaymentInstrument*> payment_methods_;
   PaymentInstrument* selected_payment_method_;
 
-  // A vector of supported basic card networks. This encompasses everything that
-  // the merchant supports and should be used for support checks.
+  // A vector of supported basic card networks.
   std::vector<std::string> supported_card_networks_;
   // A subset of |supported_card_networks_| which is only the networks that have
   // been specified as part of the "basic-card" supported method. Callers should
   // use |supported_card_networks_| for merchant support checks.
   std::set<std::string> basic_card_specified_networks_;
 
+  // A vector of url-based payment method identifers supported by the merchant
+  // which encompasses one of the two types of payment method identifers, the
+  // other being standardized payment method identifiers i.e., basic-card.
+  std::vector<std::string> url_payment_method_identifiers_;
+
   // A mapping of the payment method names to the corresponding JSON-stringified
   // payment method specific data.
   std::map<std::string, std::set<std::string>> stringified_method_data_;
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm
index d8a40a9..592c386 100644
--- a/ios/chrome/browser/payments/payment_request.mm
+++ b/ios/chrome/browser/payments/payment_request.mm
@@ -365,9 +365,9 @@
   }
 
   // TODO(crbug.com/709036): Validate method data.
-  data_util::ParseBasicCardSupportedNetworks(web_payment_request_.method_data,
-                                             &supported_card_networks_,
-                                             &basic_card_specified_networks_);
+  data_util::ParseSupportedMethods(
+      web_payment_request_.method_data, &supported_card_networks_,
+      &basic_card_specified_networks_, &url_payment_method_identifiers_);
 
   data_util::ParseSupportedCardTypes(web_payment_request_.method_data,
                                      &supported_card_types_set_);
diff --git a/ios/chrome/browser/prefs/BUILD.gn b/ios/chrome/browser/prefs/BUILD.gn
index 46b7374..3b10894 100644
--- a/ios/chrome/browser/prefs/BUILD.gn
+++ b/ios/chrome/browser/prefs/BUILD.gn
@@ -37,6 +37,7 @@
     "//components/flags_ui",
     "//components/gcm_driver",
     "//components/handoff",
+    "//components/language/core/browser",
     "//components/metrics",
     "//components/network_time",
     "//components/ntp_snippets",
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 2211f2e..1c46425 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -11,6 +11,7 @@
 #include "components/flags_ui/pref_service_flags_storage.h"
 #include "components/gcm_driver/gcm_channel_status_syncer.h"
 #import "components/handoff/handoff_manager.h"
+#include "components/language/core/browser/url_language_histogram.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/network_time/network_time_tracker.h"
 #include "components/ntp_snippets/category_rankers/click_based_category_ranker.h"
@@ -33,7 +34,6 @@
 #include "components/ssl_config/ssl_config_service_manager.h"
 #include "components/strings/grit/components_locale_settings.h"
 #include "components/sync/base/sync_prefs.h"
-#include "components/translate/core/browser/language_model.h"
 #include "components/translate/core/browser/translate_pref_names.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/update_client/update_client.h"
@@ -103,6 +103,7 @@
   gcm::GCMChannelStatusSyncer::RegisterProfilePrefs(registry);
   HostContentSettingsMap::RegisterProfilePrefs(registry);
   HttpServerPropertiesManagerFactory::RegisterProfilePrefs(registry);
+  language::UrlLanguageHistogram::RegisterProfilePrefs(registry);
   ntp_snippets::ClickBasedCategoryRanker::RegisterProfilePrefs(registry);
   ntp_snippets::ContentSuggestionsService::RegisterProfilePrefs(registry);
   ntp_snippets::RemoteSuggestionsProviderImpl::RegisterProfilePrefs(registry);
@@ -117,7 +118,6 @@
   PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry);
   syncer::SyncPrefs::RegisterProfilePrefs(registry);
   TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
-  translate::LanguageModel::RegisterProfilePrefs(registry);
   translate::TranslatePrefs::RegisterProfilePrefs(registry);
   variations::VariationsService::RegisterProfilePrefs(registry);
   ZeroSuggestProvider::RegisterProfilePrefs(registry);
diff --git a/ios/chrome/browser/prefs/ios_chrome_pref_service_factory.cc b/ios/chrome/browser/prefs/ios_chrome_pref_service_factory.cc
index 6d2cf5b..e60535f3 100644
--- a/ios/chrome/browser/prefs/ios_chrome_pref_service_factory.cc
+++ b/ios/chrome/browser/prefs/ios_chrome_pref_service_factory.cc
@@ -81,6 +81,5 @@
   overlay_pref_names.push_back(proxy_config::prefs::kProxy);
   return base::WrapUnique(pref_service->CreateIncognitoPrefService(
       nullptr,  // incognito_extension_pref_store
-      overlay_pref_names, std::set<PrefValueStore::PrefStoreType>(), nullptr,
-      nullptr));
+      overlay_pref_names, nullptr));
 }
diff --git a/ios/chrome/browser/translate/BUILD.gn b/ios/chrome/browser/translate/BUILD.gn
index 4ca6001..f9c4414 100644
--- a/ios/chrome/browser/translate/BUILD.gn
+++ b/ios/chrome/browser/translate/BUILD.gn
@@ -11,8 +11,6 @@
     "before_translate_infobar_controller.mm",
     "chrome_ios_translate_client.h",
     "chrome_ios_translate_client.mm",
-    "language_model_factory.cc",
-    "language_model_factory.h",
     "never_translate_infobar_controller.h",
     "never_translate_infobar_controller.mm",
     "translate_accept_languages_factory.cc",
@@ -46,6 +44,7 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/language",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/ui/infobars",
     "//ios/web",
@@ -62,7 +61,6 @@
   testonly = true
   sources = [
     "js_language_detection_manager_unittest.mm",
-    "language_model_factory_unittest.cc",
     "translate_service_ios_unittest.cc",
   ]
   deps = [
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.mm b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
index 65bef03..c066aed 100644
--- a/ios/chrome/browser/translate/chrome_ios_translate_client.mm
+++ b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
@@ -29,11 +29,11 @@
 #include "ios/chrome/browser/infobars/infobar.h"
 #include "ios/chrome/browser/infobars/infobar_controller.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
+#include "ios/chrome/browser/language/url_language_histogram_factory.h"
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/sync/ios_user_event_service_factory.h"
 #import "ios/chrome/browser/translate/after_translate_infobar_controller.h"
 #import "ios/chrome/browser/translate/before_translate_infobar_controller.h"
-#include "ios/chrome/browser/translate/language_model_factory.h"
 #import "ios/chrome/browser/translate/never_translate_infobar_controller.h"
 #include "ios/chrome/browser/translate/translate_accept_languages_factory.h"
 #import "ios/chrome/browser/translate/translate_message_infobar_controller.h"
@@ -63,7 +63,7 @@
       translate_driver_(web_state,
                         web_state->GetNavigationManager(),
                         translate_manager_.get(),
-                        LanguageModelFactory::GetForBrowserState(
+                        UrlLanguageHistogramFactory::GetForBrowserState(
                             ios::ChromeBrowserState::FromBrowserState(
                                 web_state->GetBrowserState()))) {}
 
diff --git a/ios/chrome/browser/translate/language_model_factory.cc b/ios/chrome/browser/translate/language_model_factory.cc
deleted file mode 100644
index 45b3ec28..0000000
--- a/ios/chrome/browser/translate/language_model_factory.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/chrome/browser/translate/language_model_factory.h"
-
-#include "base/memory/ptr_util.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/keyed_service/ios/browser_state_dependency_manager.h"
-#include "components/translate/core/browser/language_model.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-
-// static
-LanguageModelFactory* LanguageModelFactory::GetInstance() {
-  return base::Singleton<LanguageModelFactory>::get();
-}
-
-// static
-translate::LanguageModel* LanguageModelFactory::GetForBrowserState(
-    ios::ChromeBrowserState* const state) {
-  return static_cast<translate::LanguageModel*>(
-      GetInstance()->GetServiceForBrowserState(state, true));
-}
-
-LanguageModelFactory::LanguageModelFactory()
-    : BrowserStateKeyedServiceFactory(
-          "LanguageModel",
-          BrowserStateDependencyManager::GetInstance()) {}
-
-LanguageModelFactory::~LanguageModelFactory() {}
-
-std::unique_ptr<KeyedService> LanguageModelFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ios::ChromeBrowserState* browser_state =
-      ios::ChromeBrowserState::FromBrowserState(context);
-  return base::MakeUnique<translate::LanguageModel>(browser_state->GetPrefs());
-}
diff --git a/ios/chrome/browser/translate/language_model_factory.h b/ios/chrome/browser/translate/language_model_factory.h
deleted file mode 100644
index a128a98..0000000
--- a/ios/chrome/browser/translate/language_model_factory.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_TRANSLATE_LANGUAGE_MODEL_FACTORY_H
-#define IOS_CHROME_BROWSER_TRANSLATE_LANGUAGE_MODEL_FACTORY_H
-
-#include <memory>
-
-#include "base/memory/singleton.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
-
-namespace ios {
-class ChromeBrowserState;
-}
-
-namespace translate {
-class LanguageModel;
-}
-
-class LanguageModelFactory : public BrowserStateKeyedServiceFactory {
- public:
-  static LanguageModelFactory* GetInstance();
-  static translate::LanguageModel* GetForBrowserState(
-      ios::ChromeBrowserState* browser_state);
-
- private:
-  friend struct base::DefaultSingletonTraits<LanguageModelFactory>;
-
-  LanguageModelFactory();
-  ~LanguageModelFactory() override;
-
-  // BrowserStateKeyedServiceFactory implementation.
-  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(LanguageModelFactory);
-};
-
-#endif  // IOS_CHROME_BROWSER_TRANSLATE_LANGUAGE_MODEL_FACTORY_H
diff --git a/ios/chrome/browser/translate/language_model_factory_unittest.cc b/ios/chrome/browser/translate/language_model_factory_unittest.cc
deleted file mode 100644
index a5b84cd..0000000
--- a/ios/chrome/browser/translate/language_model_factory_unittest.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/chrome/browser/translate/language_model_factory.h"
-
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/web/public/test/test_web_thread_bundle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::IsNull;
-using testing::Not;
-
-class LanguageModelFactoryTest : public testing::Test {
- public:
-  LanguageModelFactoryTest() {
-    TestChromeBrowserState::Builder browser_state_builder;
-    chrome_browser_state_ = browser_state_builder.Build();
-  }
-
-  ~LanguageModelFactoryTest() override { chrome_browser_state_.reset(); }
-
-  ios::ChromeBrowserState* chrome_browser_state() {
-    return chrome_browser_state_.get();
-  }
-
- private:
-  web::TestWebThreadBundle thread_bundle_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-};
-
-TEST_F(LanguageModelFactoryTest, NotCreatedInIncognito) {
-  EXPECT_THAT(LanguageModelFactory::GetForBrowserState(chrome_browser_state()),
-              Not(IsNull()));
-
-  ios::ChromeBrowserState* otr_browser_state =
-      chrome_browser_state()->GetOffTheRecordChromeBrowserState();
-  translate::LanguageModel* language_model =
-      LanguageModelFactory::GetForBrowserState(otr_browser_state);
-  EXPECT_THAT(language_model, IsNull());
-}
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 08ed9ac..f7938545 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -32,6 +32,7 @@
     "bookmark_home_tablet_ntp_controller.mm",
     "bookmark_home_view_controller.h",
     "bookmark_home_view_controller.mm",
+    "bookmark_home_view_controller_protected.h",
     "bookmark_home_waiting_view.h",
     "bookmark_home_waiting_view.mm",
     "bookmark_interaction_controller.h",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.mm
index aa89c54e1..18f60cb 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.mm
@@ -23,6 +23,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_primary_view.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_waiting_view.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_item.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_view.h"
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.mm
index d205e68..533330c1 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.mm
@@ -26,6 +26,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_primary_view.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_waiting_view.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_item.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_view.h"
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
index dcad8cb..c613ae3 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
@@ -11,28 +11,11 @@
 #include <vector>
 
 @protocol UrlLoader;
-@protocol BookmarkHomePrimaryView;
 
 namespace ios {
 class ChromeBrowserState;
 }  // namespace ios
 
-namespace bookmarks {
-class BookmarkModel;
-class BookmarkNode;
-}  // namespace bookmarks
-
-@class BookmarkCollectionView;
-@class BookmarkEditViewController;
-@class BookmarkFolderEditorViewController;
-@class BookmarkFolderViewController;
-@class BookmarkHomeWaitingView;
-@class BookmarkMenuItem;
-@class BookmarkMenuView;
-@class BookmarkNavigationBar;
-@class BookmarkPanelView;
-@class BookmarkPromoController;
-
 // Class to navigate the bookmark hierarchy, needs subclassing for tablet /
 // handset case.
 @interface BookmarkHomeViewController : UIViewController
@@ -45,91 +28,6 @@
                   browserState:(ios::ChromeBrowserState*)browserState
     NS_DESIGNATED_INITIALIZER;
 
-// The bookmark model used.
-@property(nonatomic, assign, readonly) bookmarks::BookmarkModel* bookmarks;
-
-// The user's browser state model used.
-@property(nonatomic, assign, readonly) ios::ChromeBrowserState* browserState;
-
-// The main view showing all the bookmarks.
-@property(nonatomic, strong, readonly) BookmarkCollectionView* folderView;
-
-// The view controller used to pick a folder in which to move the selected
-// bookmarks.
-@property(nonatomic, strong, readonly)
-    BookmarkFolderViewController* folderSelector;
-
-// Object to load URLs.
-@property(nonatomic, weak, readonly) id<UrlLoader> loader;
-
-// The menu with all the folders.
-@property(nonatomic, strong, readonly) BookmarkMenuView* menuView;
-
-// The navigation bar sits on top of the main content.
-@property(nonatomic, strong, readonly) BookmarkNavigationBar* navigationBar;
-
-// At any point in time, there is exactly one collection view whose view is part
-// of the view hierarchy. This property determines what data is visible in the
-// collection view.
-@property(nonatomic, strong, readonly) BookmarkMenuItem* primaryMenuItem;
-
-// This view holds a content view, and a menu view.
-@property(nonatomic, strong, readonly) BookmarkPanelView* panelView;
-
-// Either the menu or the primaryView can scrollToTop.
-@property(nonatomic, assign) BOOL scrollToTop;
-
-// This view is created and used if the model is not fully loaded yet by the
-// time this controller starts. Property is readwrite, so that subclasses can
-// set it to nil, once finished with it.
-@property(nonatomic, strong) BookmarkHomeWaitingView* waitForModelView;
-
-// The view controller used to view and edit a single bookmark.
-@property(nonatomic, strong, readonly)
-    BookmarkEditViewController* editViewController;
-
-// The view controller to present when editing the current folder.
-@property(nonatomic, strong, readonly)
-    BookmarkFolderEditorViewController* folderEditor;
-
-// This method should be called at most once in the life-cycle of the class.
-// It should be called at the soonest possible time after the view has been
-// loaded, and the bookmark model is loaded.
-- (void)loadBookmarkViews;
-
-// Returns the width of the menu.
-- (CGFloat)menuWidth;
-
-// This method is called if the view needs to be loaded and the model is not
-// ready yet.
-- (void)loadWaitingView;
-
-// Updates the property 'primaryMenuItem'.
-// Updates the UI to reflect the new state of 'primaryMenuItem'.
-- (void)updatePrimaryMenuItem:(BookmarkMenuItem*)menuItem;
-
-// The active collection view that corresponds to primaryMenuItem.
-- (UIView<BookmarkHomePrimaryView>*)primaryView;
-
-// The controller managing the display of the promo cell and the promo view
-// controller.
-@property(nonatomic, strong, readonly)
-    BookmarkPromoController* bookmarkPromoController;
-
-#pragma mark - Navigation bar callbacks.
-
-// Called when the edit button is pressed on the navigation bar.
-- (void)navigationBarWantsEditing:(id)sender;
-
-#pragma mark - Action sheet callbacks
-
-// Opens the folder move editor for the given node.
-- (void)moveNodes:(const std::set<const bookmarks::BookmarkNode*>&)nodes;
-
-// Deletes the current node.
-- (void)deleteNodes:(const std::set<const bookmarks::BookmarkNode*>&)nodes;
-
-- (void)editNode:(const bookmarks::BookmarkNode*)node;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_HOME_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index a94aa82a..2ada57ec 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -13,6 +13,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_primary_view.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_waiting_view.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_item.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_view.h"
@@ -36,19 +37,6 @@
     BookmarkFolderEditorViewControllerDelegate,
     BookmarkFolderViewControllerDelegate,
     BookmarkPromoControllerDelegate>
-// Read / write declaration of read only properties.
-@property(nonatomic, strong) BookmarkPromoController* bookmarkPromoController;
-@property(nonatomic, assign) bookmarks::BookmarkModel* bookmarks;
-@property(nonatomic, assign) ios::ChromeBrowserState* browserState;
-@property(nonatomic, strong) BookmarkEditViewController* editViewController;
-@property(nonatomic, strong) BookmarkFolderEditorViewController* folderEditor;
-@property(nonatomic, strong) BookmarkFolderViewController* folderSelector;
-@property(nonatomic, strong) BookmarkCollectionView* folderView;
-@property(nonatomic, weak) id<UrlLoader> loader;
-@property(nonatomic, strong) BookmarkMenuView* menuView;
-@property(nonatomic, strong) BookmarkNavigationBar* navigationBar;
-@property(nonatomic, strong) BookmarkPanelView* panelView;
-@property(nonatomic, strong) BookmarkMenuItem* primaryMenuItem;
 
 @end
 
@@ -109,7 +97,7 @@
 
   // Create menu view.
   self.menuView = [[BookmarkMenuView alloc]
-      initWithBrowserState:_browserState
+      initWithBrowserState:self.browserState
                      frame:LayoutRectGetRect(menuLayout)];
   self.menuView.autoresizingMask =
       UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h
new file mode 100644
index 0000000..9ddc698
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h
@@ -0,0 +1,114 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_HOME_VIEW_CONTROLLER_PROTECTED_H_
+#define IOS_CHROME_BROWSER_UI_BOOKMARKS_HOME_VIEW_CONTROLLER_PROTECTED_H_
+
+@protocol BookmarkHomePrimaryView;
+
+namespace bookmarks {
+class BookmarkModel;
+class BookmarkNode;
+}  // namespace bookmarks
+
+@class BookmarkCollectionView;
+@class BookmarkEditViewController;
+@class BookmarkFolderEditorViewController;
+@class BookmarkFolderViewController;
+@class BookmarkHomeWaitingView;
+@class BookmarkMenuItem;
+@class BookmarkMenuView;
+@class BookmarkNavigationBar;
+@class BookmarkPanelView;
+@class BookmarkPromoController;
+
+// BookmarkHomeViewController class extention for protected read/write
+// properties and methods for subclasses.
+@interface BookmarkHomeViewController ()
+
+// The bookmark model used.
+@property(nonatomic, assign) bookmarks::BookmarkModel* bookmarks;
+
+// The user's browser state model used.
+@property(nonatomic, assign) ios::ChromeBrowserState* browserState;
+
+// The main view showing all the bookmarks.
+@property(nonatomic, strong) BookmarkCollectionView* folderView;
+
+// The view controller used to pick a folder in which to move the selected
+// bookmarks.
+@property(nonatomic, strong) BookmarkFolderViewController* folderSelector;
+
+// Object to load URLs.
+@property(nonatomic, weak) id<UrlLoader> loader;
+
+// The menu with all the folders.
+@property(nonatomic, strong) BookmarkMenuView* menuView;
+
+// The navigation bar sits on top of the main content.
+@property(nonatomic, strong) BookmarkNavigationBar* navigationBar;
+
+// At any point in time, there is exactly one collection view whose view is part
+// of the view hierarchy. This property determines what data is visible in the
+// collection view.
+@property(nonatomic, strong) BookmarkMenuItem* primaryMenuItem;
+
+// This view holds a content view, and a menu view.
+@property(nonatomic, strong) BookmarkPanelView* panelView;
+
+// Either the menu or the primaryView can scrollToTop.
+@property(nonatomic, assign) BOOL scrollToTop;
+
+// This view is created and used if the model is not fully loaded yet by the
+// time this controller starts.
+@property(nonatomic, strong) BookmarkHomeWaitingView* waitForModelView;
+
+// The view controller used to view and edit a single bookmark.
+@property(nonatomic, strong) BookmarkEditViewController* editViewController;
+
+// The view controller to present when editing the current folder.
+@property(nonatomic, strong) BookmarkFolderEditorViewController* folderEditor;
+
+// The controller managing the display of the promo cell and the promo view
+// controller.
+@property(nonatomic, strong) BookmarkPromoController* bookmarkPromoController;
+
+// This method should be called at most once in the life-cycle of the class.
+// It should be called at the soonest possible time after the view has been
+// loaded, and the bookmark model is loaded.
+- (void)loadBookmarkViews;
+
+// Returns the width of the menu.
+- (CGFloat)menuWidth;
+
+// This method is called if the view needs to be loaded and the model is not
+// ready yet.
+- (void)loadWaitingView;
+
+// Updates the property 'primaryMenuItem'.
+// Updates the UI to reflect the new state of 'primaryMenuItem'.
+- (void)updatePrimaryMenuItem:(BookmarkMenuItem*)menuItem;
+
+// The active collection view that corresponds to primaryMenuItem.
+- (UIView<BookmarkHomePrimaryView>*)primaryView;
+
+#pragma mark - Navigation bar callbacks.
+
+// Called when the edit button is pressed on the navigation bar.
+- (void)navigationBarWantsEditing:(id)sender;
+
+#pragma mark - Action sheet callbacks
+
+// Opens the folder move editor for the given node.
+- (void)moveNodes:(const std::set<const bookmarks::BookmarkNode*>&)nodes;
+
+// Deletes the current node.
+- (void)deleteNodes:(const std::set<const bookmarks::BookmarkNode*>&)nodes;
+
+// Opens the editor on the given node.
+- (void)editNode:(const bookmarks::BookmarkNode*)node;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_HOME_VIEW_CONTROLLER_PROTECTED_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm
index 039f704..002f26a 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h"
 
 #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h"
 #include "ios/chrome/browser/ui/bookmarks/bookmark_ios_unittest.h"
 
 namespace {
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index a50fcfd5..e4d8fa2e 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -472,14 +472,16 @@
   // than |fieldText|, it seems it's OK to skip calling self.attributedText
   // during the condition added below. If we change mobile omnibox to match
   // desktop and also color the omnibox while self.editing, this workaround will
-  // no longer work.
+  // no longer work. The check for |autocompleteLength| reduces the scope of
+  // this workaround, without it having introduced crbug.com/740075.
   BOOL updateText = YES;
   // Before M61 branch point this should also go behind a Japanese flag, e.g.
   // [self.textInputMode.primaryLanguage isEqualToString:@"ja-JP"] to be as
   // restrictive as possible.
   if (experimental_flags::IsThirdPartyKeyboardWorkaroundEnabled()) {
     updateText =
-        (!self.editing || ![self.text isEqualToString:fieldText.string]);
+        (!self.editing || ![self.text isEqualToString:fieldText.string] ||
+         autocompleteLength == 0);
   }
   if (updateText) {
     self.attributedText = fieldText;
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn
index f9b3f80..456e57e 100644
--- a/ios/chrome/browser/ui/toolbar/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -6,6 +6,8 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
     "keyboard_accessory_view_delegate.h",
+    "keyboard_assist/toolbar_assistive_keyboard_views.h",
+    "keyboard_assist/toolbar_assistive_keyboard_views.mm",
     "new_keyboard_accessory_view.h",
     "new_keyboard_accessory_view.mm",
     "new_tab_button.h",
diff --git a/ios/chrome/browser/ui/toolbar/keyboard_assist/OWNERS b/ios/chrome/browser/ui/toolbar/keyboard_assist/OWNERS
new file mode 100644
index 0000000..d2e1add
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/keyboard_assist/OWNERS
@@ -0,0 +1 @@
+jif@chromium.org
diff --git a/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.h b/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.h
new file mode 100644
index 0000000..6a3a2bb
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.h
@@ -0,0 +1,15 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ASSIST_ASSISTIVE_KEYBOARD_VIEWS_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ASSIST_ASSISTIVE_KEYBOARD_VIEWS_H_
+
+#import <UIKit/UIKIt.h>
+
+@protocol KeyboardAccessoryViewDelegate;
+
+NSArray<UIButton*>* ToolbarAssistiveKeyboardLeadingButtons(
+    id<KeyboardAccessoryViewDelegate> delegate);
+
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_KEYBOARD_ASSIST_ASSISTIVE_KEYBOARD_VIEWS_H_
diff --git a/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.mm b/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.mm
new file mode 100644
index 0000000..c19b100
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.mm
@@ -0,0 +1,59 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.h"
+
+#import "ios/chrome/browser/ui/toolbar/keyboard_accessory_view_delegate.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+UIButton* ButtonWitIcon(NSString* iconName) {
+  const CGFloat kButtonShadowOpacity = 0.35;
+  const CGFloat kButtonShadowRadius = 1.0;
+  const CGFloat kButtonShadowVerticalOffset = 1.0;
+
+  UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
+  [button setTranslatesAutoresizingMaskIntoConstraints:NO];
+  UIImage* icon = [UIImage imageNamed:iconName];
+  [button setImage:icon forState:UIControlStateNormal];
+  button.layer.shadowColor = [UIColor blackColor].CGColor;
+  button.layer.shadowOffset = CGSizeMake(0, kButtonShadowVerticalOffset);
+  button.layer.shadowOpacity = kButtonShadowOpacity;
+  button.layer.shadowRadius = kButtonShadowRadius;
+  return button;
+}
+
+}  // namespace
+
+NSArray<UIButton*>* ToolbarAssistiveKeyboardLeadingButtons(
+    id<KeyboardAccessoryViewDelegate> delegate) {
+  UIButton* voiceSearchButton =
+      ButtonWitIcon(@"keyboard_accessory_voice_search");
+  [voiceSearchButton addTarget:delegate
+                        action:@selector(keyboardAccessoryVoiceSearchTouchDown:)
+              forControlEvents:UIControlEventTouchDown];
+  SetA11yLabelAndUiAutomationName(voiceSearchButton,
+                                  IDS_IOS_KEYBOARD_ACCESSORY_VIEW_VOICE_SEARCH,
+                                  @"Voice Search");
+  [voiceSearchButton
+             addTarget:delegate
+                action:@selector(keyboardAccessoryVoiceSearchTouchUpInside:)
+      forControlEvents:UIControlEventTouchUpInside];
+
+  UIButton* cameraButton = ButtonWitIcon(@"keyboard_accessory_qr_scanner");
+  [cameraButton addTarget:delegate
+                   action:@selector(keyboardAccessoryCameraSearchTouchUpInside:)
+         forControlEvents:UIControlEventTouchUpInside];
+  SetA11yLabelAndUiAutomationName(
+      cameraButton, IDS_IOS_KEYBOARD_ACCESSORY_VIEW_QR_CODE_SEARCH,
+      @"QR code Search");
+
+  return @[ voiceSearchButton, cameraButton ];
+}
diff --git a/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.mm b/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.mm
index 8e5a007d..aced4ca 100644
--- a/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.mm
+++ b/ios/chrome/browser/ui/toolbar/new_keyboard_accessory_view.mm
@@ -10,9 +10,9 @@
 #include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
+#import "ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
-#include "ios/chrome/grit/ios_strings.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -27,8 +27,6 @@
 - (void)keyboardButtonPressed:(NSString*)title;
 // Creates a button shortcut for |title|.
 - (UIView*)shortcutButtonWithTitle:(NSString*)title;
-// Creates a button with an icon based on |iconName|.
-- (UIButton*)iconButton:(NSString*)iconName;
 
 @end
 
@@ -77,34 +75,16 @@
   }
   [self addSubview:shortcutStackView];
 
-  // Create buttons for voice search and camera search.
-  UIButton* voiceSearchButton =
-      [self iconButton:@"keyboard_accessory_voice_search"];
-  [voiceSearchButton addTarget:_delegate
-                        action:@selector(keyboardAccessoryVoiceSearchTouchDown:)
-              forControlEvents:UIControlEventTouchDown];
-  SetA11yLabelAndUiAutomationName(voiceSearchButton,
-                                  IDS_IOS_KEYBOARD_ACCESSORY_VIEW_VOICE_SEARCH,
-                                  @"Voice Search");
-  [voiceSearchButton
-             addTarget:_delegate
-                action:@selector(keyboardAccessoryVoiceSearchTouchUpInside:)
-      forControlEvents:UIControlEventTouchUpInside];
-  UIButton* cameraButton = [self iconButton:@"keyboard_accessory_qr_scanner"];
-  [cameraButton addTarget:_delegate
-                   action:@selector(keyboardAccessoryCameraSearchTouchUpInside:)
-         forControlEvents:UIControlEventTouchUpInside];
-  SetA11yLabelAndUiAutomationName(
-      cameraButton, IDS_IOS_KEYBOARD_ACCESSORY_VIEW_QR_CODE_SEARCH,
-      @"QR code Search");
-
-  // Create and add a stackview containing containing the buttons for voice
-  // search and camera search.
+  // Create and add a stackview containing the leading assistive buttons, i.e.
+  // Voice search and camera search.
+  NSArray<UIButton*>* leadingButtons =
+      ToolbarAssistiveKeyboardLeadingButtons(_delegate);
   UIStackView* searchStackView = [[UIStackView alloc] init];
   searchStackView.translatesAutoresizingMaskIntoConstraints = NO;
   searchStackView.spacing = kBetweenSearchButtonSpacing;
-  [searchStackView addArrangedSubview:voiceSearchButton];
-  [searchStackView addArrangedSubview:cameraButton];
+  for (UIButton* button in leadingButtons) {
+    [searchStackView addArrangedSubview:button];
+  }
   [self addSubview:searchStackView];
 
   // Position the stack views.
@@ -151,22 +131,6 @@
   return button;
 }
 
-- (UIButton*)iconButton:(NSString*)iconName {
-  const CGFloat kButtonShadowOpacity = 0.35;
-  const CGFloat kButtonShadowRadius = 1.0;
-  const CGFloat kButtonShadowVerticalOffset = 1.0;
-
-  UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
-  [button setTranslatesAutoresizingMaskIntoConstraints:NO];
-  UIImage* icon = [UIImage imageNamed:iconName];
-  [button setImage:icon forState:UIControlStateNormal];
-  button.layer.shadowColor = [UIColor blackColor].CGColor;
-  button.layer.shadowOffset = CGSizeMake(0, kButtonShadowVerticalOffset);
-  button.layer.shadowOpacity = kButtonShadowOpacity;
-  button.layer.shadowRadius = kButtonShadowRadius;
-  return button;
-}
-
 - (BOOL)enableInputClicksWhenVisible {
   return YES;
 }
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 87b6db2..4d7a12fc 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -140,6 +140,7 @@
     "//ios/chrome/browser/find_in_page:unit_tests",
     "//ios/chrome/browser/geolocation:unit_tests",
     "//ios/chrome/browser/itunes_links:unit_tests",
+    "//ios/chrome/browser/language:unit_tests",
     "//ios/chrome/browser/metrics:unit_tests",
     "//ios/chrome/browser/metrics:unit_tests_internal",
     "//ios/chrome/browser/native_app_launcher:unit_tests",
diff --git a/ios/web_view/internal/translate/web_view_translate_client.mm b/ios/web_view/internal/translate/web_view_translate_client.mm
index 591082a..5da081a7 100644
--- a/ios/web_view/internal/translate/web_view_translate_client.mm
+++ b/ios/web_view/internal/translate/web_view_translate_client.mm
@@ -36,8 +36,8 @@
 namespace ios_web_view {
 
 // TODO(crbug.com/729859): Support logging histogram data on detected language
-// page, by passing a valid language_model, when histogram logging is available
-// on ios/web_view.
+// page, by passing a valid language_histogram, when histogram logging is
+// available on ios/web_view.
 WebViewTranslateClient::WebViewTranslateClient(web::WebState* web_state)
     : web::WebStateObserver(web_state),
       translate_manager_(base::MakeUnique<translate::TranslateManager>(
@@ -49,7 +49,7 @@
       translate_driver_(web_state,
                         web_state->GetNavigationManager(),
                         translate_manager_.get(),
-                        nullptr /* language_model */) {}
+                        nullptr /* language_histogram */) {}
 
 WebViewTranslateClient::~WebViewTranslateClient() = default;
 
diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn
index d0b521a..bc999b5 100644
--- a/media/audio/BUILD.gn
+++ b/media/audio/BUILD.gn
@@ -276,6 +276,13 @@
     }
   }
 
+  if (is_fuchsia) {
+    sources += [
+      "fuchsia/audio_manager_fuchsia.cc",
+      "fuchsia/audio_manager_fuchsia.h",
+    ]
+  }
+
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 }
 
diff --git a/media/audio/fuchsia/audio_manager_fuchsia.cc b/media/audio/fuchsia/audio_manager_fuchsia.cc
new file mode 100644
index 0000000..661e681
--- /dev/null
+++ b/media/audio/fuchsia/audio_manager_fuchsia.cc
@@ -0,0 +1,100 @@
+// 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 "media/audio/fuchsia/audio_manager_fuchsia.h"
+
+#include "base/memory/ptr_util.h"
+
+namespace media {
+
+// TODO(fuchsia): Implement this class.
+
+AudioManagerFuchsia::AudioManagerFuchsia(
+    std::unique_ptr<AudioThread> audio_thread,
+    AudioLogFactory* audio_log_factory)
+    : AudioManagerBase(std::move(audio_thread), audio_log_factory) {}
+AudioManagerFuchsia::~AudioManagerFuchsia() {}
+
+bool AudioManagerFuchsia::HasAudioOutputDevices() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool AudioManagerFuchsia::HasAudioInputDevices() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+void AudioManagerFuchsia::ShowAudioInputSettings() {
+  NOTIMPLEMENTED();
+}
+
+void AudioManagerFuchsia::GetAudioInputDeviceNames(
+    AudioDeviceNames* device_names) {
+  device_names->clear();
+  NOTIMPLEMENTED();
+}
+
+void AudioManagerFuchsia::GetAudioOutputDeviceNames(
+    AudioDeviceNames* device_names) {
+  device_names->clear();
+  NOTIMPLEMENTED();
+}
+
+AudioParameters AudioManagerFuchsia::GetInputStreamParameters(
+    const std::string& device_id) {
+  NOTREACHED();
+  return AudioParameters();
+}
+
+AudioParameters AudioManagerFuchsia::GetPreferredOutputStreamParameters(
+    const std::string& output_device_id,
+    const AudioParameters& input_params) {
+  NOTREACHED();
+  return AudioParameters();
+}
+
+const char* AudioManagerFuchsia::GetName() {
+  return "Fuchsia";
+}
+
+AudioOutputStream* AudioManagerFuchsia::MakeLinearOutputStream(
+    const AudioParameters& params,
+    const LogCallback& log_callback) {
+  NOTREACHED();
+  return nullptr;
+}
+
+AudioOutputStream* AudioManagerFuchsia::MakeLowLatencyOutputStream(
+    const AudioParameters& params,
+    const std::string& device_id,
+    const LogCallback& log_callback) {
+  NOTREACHED();
+  return nullptr;
+}
+
+AudioInputStream* AudioManagerFuchsia::MakeLinearInputStream(
+    const AudioParameters& params,
+    const std::string& device_id,
+    const LogCallback& log_callback) {
+  NOTREACHED();
+  return nullptr;
+}
+
+AudioInputStream* AudioManagerFuchsia::MakeLowLatencyInputStream(
+    const AudioParameters& params,
+    const std::string& device_id,
+    const LogCallback& log_callback) {
+  NOTREACHED();
+  return nullptr;
+}
+
+std::unique_ptr<AudioManager> CreateAudioManager(
+    std::unique_ptr<AudioThread> audio_thread,
+    AudioLogFactory* audio_log_factory) {
+  return base::MakeUnique<AudioManagerFuchsia>(std::move(audio_thread),
+                                               audio_log_factory);
+}
+
+}  // namespace media
diff --git a/media/audio/fuchsia/audio_manager_fuchsia.h b/media/audio/fuchsia/audio_manager_fuchsia.h
new file mode 100644
index 0000000..9ab3a17
--- /dev/null
+++ b/media/audio/fuchsia/audio_manager_fuchsia.h
@@ -0,0 +1,56 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_AUDIO_FUCHSIA_AUDIO_MANAGER_FUCHSIA_H_
+#define MEDIA_AUDIO_FUCHSIA_AUDIO_MANAGER_FUCHSIA_H_
+
+#include "media/audio/audio_manager_base.h"
+
+namespace media {
+
+class AudioManagerFuchsia : public AudioManagerBase {
+ public:
+  AudioManagerFuchsia(std::unique_ptr<AudioThread> audio_thread,
+                      AudioLogFactory* audio_log_factory);
+  ~AudioManagerFuchsia() override;
+
+  // Implementation of AudioManager.
+  bool HasAudioOutputDevices() override;
+  bool HasAudioInputDevices() override;
+  void ShowAudioInputSettings() override;
+  void GetAudioInputDeviceNames(AudioDeviceNames* device_names) override;
+  void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
+  AudioParameters GetInputStreamParameters(
+      const std::string& device_id) override;
+  const char* GetName() override;
+
+  // Implementation of AudioManagerBase.
+  AudioOutputStream* MakeLinearOutputStream(
+      const AudioParameters& params,
+      const LogCallback& log_callback) override;
+  AudioOutputStream* MakeLowLatencyOutputStream(
+      const AudioParameters& params,
+      const std::string& device_id,
+      const LogCallback& log_callback) override;
+  AudioInputStream* MakeLinearInputStream(
+      const AudioParameters& params,
+      const std::string& device_id,
+      const LogCallback& log_callback) override;
+  AudioInputStream* MakeLowLatencyInputStream(
+      const AudioParameters& params,
+      const std::string& device_id,
+      const LogCallback& log_callback) override;
+
+ protected:
+  AudioParameters GetPreferredOutputStreamParameters(
+      const std::string& output_device_id,
+      const AudioParameters& input_params) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AudioManagerFuchsia);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_AUDIO_FUCHSIA_AUDIO_MANAGER_FUCHSIA_H_
diff --git a/net/BUILD.gn b/net/BUILD.gn
index ec967c9..cdfb84b 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -795,8 +795,6 @@
       "http/bidirectional_stream_request_info.h",
       "http/broken_alternative_services.cc",
       "http/broken_alternative_services.h",
-      "http/des.cc",
-      "http/des.h",
       "http/failing_http_transaction_factory.cc",
       "http/failing_http_transaction_factory.h",
       "http/http_auth.cc",
@@ -885,8 +883,6 @@
       "http/http_transaction.h",
       "http/http_transaction_factory.h",
       "http/http_version.h",
-      "http/md4.cc",
-      "http/md4.h",
       "http/partial_data.cc",
       "http/partial_data.h",
       "http/proxy_client_socket.cc",
@@ -1028,6 +1024,17 @@
       "nqe/throughput_analyzer.cc",
       "nqe/throughput_analyzer.h",
       "nqe/weighted_observation.h",
+      "ntlm/des.cc",
+      "ntlm/des.h",
+      "ntlm/md4.cc",
+      "ntlm/md4.h",
+      "ntlm/ntlm.cc",
+      "ntlm/ntlm.h",
+      "ntlm/ntlm_buffer_reader.cc",
+      "ntlm/ntlm_buffer_reader.h",
+      "ntlm/ntlm_buffer_writer.cc",
+      "ntlm/ntlm_buffer_writer.h",
+      "ntlm/ntlm_constants.h",
       "proxy/dhcp_proxy_script_adapter_fetcher_win.cc",
       "proxy/dhcp_proxy_script_adapter_fetcher_win.h",
       "proxy/dhcp_proxy_script_fetcher.cc",
@@ -1769,6 +1776,22 @@
       }
     }
 
+    if (is_win) {
+      sources -= [
+        "ntlm/des.cc",
+        "ntlm/des.h",
+        "ntlm/md4.cc",
+        "ntlm/md4.h",
+        "ntlm/ntlm.cc",
+        "ntlm/ntlm.h",
+        "ntlm/ntlm_buffer_reader.cc",
+        "ntlm/ntlm_buffer_reader.h",
+        "ntlm/ntlm_buffer_writer.cc",
+        "ntlm/ntlm_buffer_writer.h",
+        "ntlm/ntlm_constants.h",
+      ]
+    }
+
     if (!enable_built_in_dns) {
       sources -= [
         "dns/address_sorter_posix.cc",
@@ -4690,7 +4713,6 @@
     "ftp/ftp_util_unittest.cc",
     "http/bidirectional_stream_unittest.cc",
     "http/broken_alternative_services_unittest.cc",
-    "http/des_unittest.cc",
     "http/http_auth_cache_unittest.cc",
     "http/http_auth_challenge_tokenizer_unittest.cc",
     "http/http_auth_controller_unittest.cc",
@@ -4702,6 +4724,7 @@
     "http/http_auth_handler_mock.cc",
     "http/http_auth_handler_mock.h",
     "http/http_auth_handler_negotiate_unittest.cc",
+    "http/http_auth_handler_ntlm_portable_unittest.cc",
     "http/http_auth_handler_unittest.cc",
     "http/http_auth_multi_round_parse_unittest.cc",
     "http/http_auth_preferences_unittest.cc",
@@ -4829,6 +4852,11 @@
     "nqe/observation_buffer_unittest.cc",
     "nqe/socket_watcher_unittest.cc",
     "nqe/throughput_analyzer_unittest.cc",
+    "ntlm/des_unittest.cc",
+    "ntlm/ntlm_buffer_reader_unittest.cc",
+    "ntlm/ntlm_buffer_writer_unittest.cc",
+    "ntlm/ntlm_test_data.h",
+    "ntlm/ntlm_unittest.cc",
     "proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc",
     "proxy/dhcp_proxy_script_fetcher_factory_unittest.cc",
     "proxy/dhcp_proxy_script_fetcher_win_unittest.cc",
@@ -5242,6 +5270,17 @@
     deps += [ "//gin" ]
   }
 
+  if (is_win) {
+    sources -= [
+      "http/http_auth_handler_ntlm_portable_unittest.cc",
+      "ntlm/des_unittest.cc",
+      "ntlm/ntlm_buffer_reader_unittest.cc",
+      "ntlm/ntlm_buffer_writer_unittest.cc",
+      "ntlm/ntlm_test_data.h",
+      "ntlm/ntlm_unittest.cc",
+    ]
+  }
+
   if (!use_nss_certs) {
     sources -= [
       "cert/internal/trust_store_nss_unittest.cc",
diff --git a/net/http/http_auth_handler_ntlm_portable.cc b/net/http/http_auth_handler_ntlm_portable.cc
index 1f590a0e..38c73e5 100644
--- a/net/http/http_auth_handler_ntlm_portable.cc
+++ b/net/http/http_auth_handler_ntlm_portable.cc
@@ -19,8 +19,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "net/base/net_errors.h"
 #include "net/base/network_interfaces.h"
-#include "net/http/des.h"
-#include "net/http/md4.h"
+#include "net/ntlm/des.h"
+#include "net/ntlm/md4.h"
 
 namespace net {
 
@@ -363,11 +363,19 @@
   uint32_t offset = ReadUint32(cursor);  // get offset from in_buf
   msg->target_len = 0;
   msg->target = NULL;
-  // Check the offset / length combo is in range of the input buffer, including
-  // integer overflow checking.
-  if (offset + target_len > offset && offset + target_len <= in_len) {
-    msg->target_len = target_len;
-    msg->target = ((const uint8_t*)in_buf) + offset;
+
+  // Target length 0 is valid and indicates no target information.
+  if (target_len != 0) {
+    // Check the offset / length combo is in range of the input buffer,
+    // including integer overflow checking.
+    if (target_len <= in_len && in_len - offset >= target_len) {
+      msg->target_len = target_len;
+      msg->target = ((const uint8_t*)in_buf) + offset;
+    } else {
+      // Reject a message with a non-zero target length that
+      // would cause an overflow.
+      return ERR_UNEXPECTED;
+    }
   }
 
   // read flags
diff --git a/net/http/http_auth_handler_ntlm_portable_unittest.cc b/net/http/http_auth_handler_ntlm_portable_unittest.cc
new file mode 100644
index 0000000..9d77ec4a
--- /dev/null
+++ b/net/http/http_auth_handler_ntlm_portable_unittest.cc
@@ -0,0 +1,577 @@
+// 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 <string>
+
+#include "base/base64.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "net/base/test_completion_callback.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/http/http_auth_challenge_tokenizer.h"
+#include "net/http/http_auth_handler_ntlm.h"
+#include "net/http/http_request_info.h"
+#include "net/http/mock_allow_http_auth_preferences.h"
+#include "net/log/net_log_with_source.h"
+#include "net/ntlm/ntlm.h"
+#include "net/ntlm/ntlm_buffer_reader.h"
+#include "net/ntlm/ntlm_buffer_writer.h"
+#include "net/ntlm/ntlm_test_data.h"
+#include "net/ssl/ssl_info.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace net {
+
+class HttpAuthHandlerNtlmPortableTest : public PlatformTest {
+ public:
+  // Test input value defined in [MS-NLMP] Section 4.2.1.
+  HttpAuthHandlerNtlmPortableTest() {
+    http_auth_preferences_.reset(new MockAllowHttpAuthPreferences());
+    factory_.reset(new HttpAuthHandlerNTLM::Factory());
+    factory_->set_http_auth_preferences(http_auth_preferences_.get());
+    creds_ = AuthCredentials(
+        ntlm::test::kNtlmDomain + base::ASCIIToUTF16("\\") + ntlm::test::kUser,
+        ntlm::test::kPassword);
+  }
+
+  int CreateHandler() {
+    GURL gurl("https://foo.com");
+    SSLInfo null_ssl_info;
+
+    return factory_->CreateAuthHandlerFromString(
+        "NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, NetLogWithSource(),
+        &auth_handler_);
+  }
+
+  std::string CreateNtlmAuthHeader(base::StringPiece message) {
+    std::string output;
+    base::Base64Encode(message, &output);
+
+    return "NTLM " + output;
+  }
+
+  HttpAuth::AuthorizationResult HandleAnotherChallenge(
+      const std::string& challenge) {
+    HttpAuthChallengeTokenizer tokenizer(challenge.begin(), challenge.end());
+    return GetAuthHandler()->HandleAnotherChallenge(&tokenizer);
+  }
+
+  bool DecodeChallenge(const std::string& challenge, std::string* decoded) {
+    HttpAuthChallengeTokenizer tokenizer(challenge.begin(), challenge.end());
+    return base::Base64Decode(tokenizer.base64_param(), decoded);
+  }
+
+  int GenerateAuthToken(std::string* token) {
+    TestCompletionCallback callback;
+    HttpRequestInfo request_info;
+    return callback.GetResult(GetAuthHandler()->GenerateAuthToken(
+        GetCreds(), &request_info, callback.callback(), token));
+  }
+
+  bool ReadBytesPayload(ntlm::NtlmBufferReader* reader,
+                        uint8_t* buffer,
+                        size_t len) {
+    ntlm::SecurityBuffer sec_buf;
+    return reader->ReadSecurityBuffer(&sec_buf) && (sec_buf.length == len) &&
+           reader->ReadBytesFrom(sec_buf, buffer);
+  }
+
+  // Reads bytes from a payload and assigns them to a string. This makes
+  // no assumptions about the underlying encoding.
+  bool ReadStringPayload(ntlm::NtlmBufferReader* reader, std::string* str) {
+    ntlm::SecurityBuffer sec_buf;
+    if (!reader->ReadSecurityBuffer(&sec_buf))
+      return false;
+
+    std::unique_ptr<uint8_t[]> raw(new uint8_t[sec_buf.length]);
+    if (!reader->ReadBytesFrom(sec_buf, raw.get()))
+      return false;
+
+    str->assign(reinterpret_cast<const char*>(raw.get()), sec_buf.length);
+    return true;
+  }
+
+  // Reads bytes from a payload and assigns them to a string16. This makes
+  // no assumptions about the underlying encoding. This will fail if there
+  // are an odd number of bytes in the payload.
+  void ReadString16Payload(ntlm::NtlmBufferReader* reader,
+                           base::string16* str) {
+    ntlm::SecurityBuffer sec_buf;
+    EXPECT_TRUE(reader->ReadSecurityBuffer(&sec_buf));
+    EXPECT_EQ(0, sec_buf.length % 2);
+
+    std::unique_ptr<uint8_t[]> raw(new uint8_t[sec_buf.length]);
+    EXPECT_TRUE(reader->ReadBytesFrom(sec_buf, raw.get()));
+
+#ifdef IS_BIG_ENDIAN
+    for (size_t i = 0; i < sec_buf.length; i += 2) {
+      std::swap(raw[i], raw[i + 1]);
+    }
+#endif
+
+    str->assign(reinterpret_cast<const base::char16*>(raw.get()),
+                sec_buf.length / 2);
+  }
+
+  int GetGenerateAuthTokenResult() {
+    std::string token;
+    return GenerateAuthToken(&token);
+  }
+
+  AuthCredentials* GetCreds() { return &creds_; }
+
+  HttpAuthHandlerNTLM* GetAuthHandler() {
+    return static_cast<HttpAuthHandlerNTLM*>(auth_handler_.get());
+  }
+
+  static void MockRandom(uint8_t* output, size_t n) {
+    // This is set to 0xaa because the client challenge for testing in
+    // [MS-NLMP] Section 4.2.1 is 8 bytes of 0xaa.
+    memset(output, 0xaa, n);
+  }
+
+  static std::string MockGetHostName() { return ntlm::test::kHostnameAscii; }
+
+ private:
+  AuthCredentials creds_;
+  std::unique_ptr<HttpAuthHandler> auth_handler_;
+  std::unique_ptr<MockAllowHttpAuthPreferences> http_auth_preferences_;
+  std::unique_ptr<HttpAuthHandlerNTLM::Factory> factory_;
+};
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, SimpleConstruction) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_TRUE(GetAuthHandler() != nullptr);
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, DoNotAllowDefaultCreds) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_FALSE(GetAuthHandler()->AllowsDefaultCredentials());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, AllowsExplicitCredentials) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_TRUE(GetAuthHandler()->AllowsExplicitCredentials());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, VerifyType1Message) {
+  ASSERT_EQ(OK, CreateHandler());
+
+  std::string token;
+  ASSERT_EQ(OK, GenerateAuthToken(&token));
+  // The type 1 message generated is always the same. The only variable
+  // part of the message is the flags and this implementation always offers
+  // the same set of flags.
+  ASSERT_EQ("NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=", token);
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, EmptyTokenFails) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // The encoded token for a type 2 message can't be empty.
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
+            HandleAnotherChallenge("NTLM"));
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, InvalidBase64Encoding) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // Token isn't valid base64.
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge("NTLM !!!!!!!!!!!!!"));
+  ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, CantChangeSchemeMidway) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // Can't switch to a different auth scheme in the middle of the process.
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
+            HandleAnotherChallenge("Negotiate SSdtIG5vdCBhIHJlYWwgdG9rZW4h"));
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, MinimalStructurallyValidType2) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(CreateNtlmAuthHeader(base::StringPiece(
+                reinterpret_cast<const char*>(ntlm::test::kMinChallengeMessage),
+                ntlm::kChallengeHeaderLen))));
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageTooShort) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  char raw[31];
+  memcpy(raw, ntlm::test::kMinChallengeMessage, 31);
+
+  // Fail because the minimum size valid message is 32 bytes.
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(
+                CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
+  ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageWrongSignature) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  char raw[32];
+  memcpy(raw, ntlm::test::kMinChallengeMessage, 32);
+  // Modify the default valid message to overwrite the last byte of the
+  // signature.
+  raw[7] = 0xff;
+
+  // Fail because the first 8 bytes don't match "NTLMSSP\0"
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(
+                CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
+  ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, Type2WrongMessageType) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  char raw[32];
+  memcpy(raw, ntlm::test::kMinChallengeMessage, 32);
+  // Modify the message type so it is not 0x00000002
+  raw[8] = 0x03;
+
+  // Fail because the message type should be MessageType::kChallenge
+  // (0x00000002)
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(CreateNtlmAuthHeader(raw)));
+  ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageWithNoTargetName) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // The spec (2.2.1.2) states that the length SHOULD be 0 and the offset
+  // SHOULD be where the payload would be if it was present. This is the
+  // expected response from a compliant server when no target name is sent.
+  // In reality the offset should always be ignored if the length is zero.
+  // Also implementations often just write zeros.
+  char raw[32];
+  memcpy(raw, ntlm::test::kMinChallengeMessage, 32);
+  // Modify the default valid message to overwrite the offset to zero.
+  raw[16] = 0x00;
+
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(
+                CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, Type2MessageWithTargetName) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // One extra byte is provided for target name.
+  char raw[33];
+  memcpy(raw, ntlm::test::kMinChallengeMessage, 32);
+  // Modify the default valid message to indicate 1 byte is present in the
+  // target name payload.
+  raw[12] = 0x01;
+  raw[14] = 0x01;
+  // Put something in the target name.
+  raw[32] = 'Z';
+
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(
+                CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, NoTargetNameOverflowFromOffset) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  char raw[32];
+  memcpy(raw, ntlm::test::kMinChallengeMessage, 32);
+  // Modify the default valid message to claim that the target name field is 1
+  // byte long overrunning the end of the message message.
+  raw[12] = 0x01;
+  raw[14] = 0x01;
+
+  // The above malformed message could cause an implementation to read outside
+  // the message buffer because the offset is past the end of the message.
+  // Verify it gets rejected.
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(
+                CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
+  ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, NoTargetNameOverflowFromLength) {
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // Message has 1 extra byte of space after the header for the target name.
+  // One extra byte is provided for target name.
+  char raw[33];
+  memcpy(raw, ntlm::test::kMinChallengeMessage, 32);
+  // Modify the default valid message to indicate 2 bytes are present in the
+  // target name payload (however there is only space for 1).
+  raw[12] = 0x02;
+  raw[14] = 0x02;
+  // Put something in the target name.
+  raw[32] = 'Z';
+
+  // The above malformed message could cause an implementation to read outside
+  // the message buffer because the length is longer than available space.
+  // Verify it gets rejected.
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(
+                CreateNtlmAuthHeader(base::StringPiece(raw, sizeof(raw)))));
+  ASSERT_EQ(ERR_UNEXPECTED, GetGenerateAuthTokenResult());
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, Type3RespectsUnicode) {
+  HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom,
+                                                    MockGetHostName);
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // Generate the type 2 message from the server.
+  ntlm::NtlmBufferWriter writer(ntlm::kChallengeHeaderLen);
+  ASSERT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::kChallenge));
+  // No target name. It is never used.
+  ASSERT_TRUE(writer.WriteSecurityBuffer(
+      ntlm::SecurityBuffer(ntlm::kChallengeHeaderLen, 0)));
+  // Set the unicode flag.
+  ASSERT_TRUE(writer.WriteFlags(ntlm::NegotiateFlags::kUnicode));
+
+  std::string token;
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(CreateNtlmAuthHeader(writer.GetBuffer())));
+  ASSERT_EQ(OK, GenerateAuthToken(&token));
+
+  // Validate the type 3 message
+  std::string decoded;
+  ASSERT_TRUE(DecodeChallenge(token, &decoded));
+  ntlm::NtlmBufferReader reader(decoded);
+  ASSERT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::kAuthenticate));
+
+  // Skip the LM and NTLM Hash fields. This test isn't testing that.
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+  base::string16 domain;
+  base::string16 username;
+  base::string16 hostname;
+  ReadString16Payload(&reader, &domain);
+  ASSERT_EQ(ntlm::test::kNtlmDomain, domain);
+  ReadString16Payload(&reader, &username);
+  ASSERT_EQ(ntlm::test::kUser, username);
+  ReadString16Payload(&reader, &hostname);
+  ASSERT_EQ(ntlm::test::kHostname, hostname);
+
+  // The session key is not used for the NTLM scheme in HTTP. Since
+  // NTLMSSP_NEGOTIATE_KEY_EXCH was not sent this is empty.
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+
+  // Verify the unicode flag is set.
+  ntlm::NegotiateFlags flags;
+  ASSERT_TRUE(reader.ReadFlags(&flags));
+  ASSERT_EQ(ntlm::NegotiateFlags::kUnicode,
+            flags & ntlm::NegotiateFlags::kUnicode);
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, Type3WithoutUnicode) {
+  HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom,
+                                                    MockGetHostName);
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // Generate the type 2 message from the server.
+  ntlm::NtlmBufferWriter writer(ntlm::kChallengeHeaderLen);
+  ASSERT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::kChallenge));
+  // No target name. It is never used.
+  ASSERT_TRUE(writer.WriteSecurityBuffer(
+      ntlm::SecurityBuffer(ntlm::kChallengeHeaderLen, 0)));
+  // Set the OEM flag.
+  ASSERT_TRUE(writer.WriteFlags(ntlm::NegotiateFlags::kOem));
+
+  std::string token;
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(CreateNtlmAuthHeader(writer.GetBuffer())));
+  ASSERT_EQ(OK, GenerateAuthToken(&token));
+
+  // Validate the type 3 message
+  std::string decoded;
+  ASSERT_TRUE(DecodeChallenge(token, &decoded));
+  ntlm::NtlmBufferReader reader(decoded);
+  ASSERT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::kAuthenticate));
+
+  // Skip the 2 hash fields. This test isn't testing that.
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+  std::string domain;
+  std::string username;
+  std::string hostname;
+  ASSERT_TRUE(ReadStringPayload(&reader, &domain));
+  ASSERT_EQ(ntlm::test::kNtlmDomainAscii, domain);
+  ASSERT_TRUE(ReadStringPayload(&reader, &username));
+  ASSERT_EQ(ntlm::test::kUserAscii, username);
+  ASSERT_TRUE(ReadStringPayload(&reader, &hostname));
+  ASSERT_EQ(ntlm::test::kHostnameAscii, hostname);
+
+  // The session key is not used for the NTLM scheme in HTTP. Since
+  // NTLMSSP_NEGOTIATE_KEY_EXCH was not sent this is empty.
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+
+  // Verify the unicode flag is not set and OEM flag is.
+  ntlm::NegotiateFlags flags;
+  ASSERT_TRUE(reader.ReadFlags(&flags));
+  ASSERT_EQ(ntlm::NegotiateFlags::kNone,
+            flags & ntlm::NegotiateFlags::kUnicode);
+  ASSERT_EQ(ntlm::NegotiateFlags::kOem, flags & ntlm::NegotiateFlags::kOem);
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, Type3UnicodeNoSessionSecurity) {
+  // Verify that the client won't be downgraded if the server clears
+  // the session security flag.
+  HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom,
+                                                    MockGetHostName);
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // Generate the type 2 message from the server.
+  ntlm::NtlmBufferWriter writer(ntlm::kChallengeHeaderLen);
+  ASSERT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::kChallenge));
+  // No target name. It is never used.
+  ASSERT_TRUE(writer.WriteSecurityBuffer(
+      ntlm::SecurityBuffer(ntlm::kChallengeHeaderLen, 0)));
+  // Set the unicode but not the session security flag.
+  ASSERT_TRUE(writer.WriteFlags(ntlm::NegotiateFlags::kUnicode));
+
+  ASSERT_TRUE(
+      writer.WriteBytes(ntlm::test::kServerChallenge, ntlm::kChallengeLen));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+
+  std::string token;
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(CreateNtlmAuthHeader(writer.GetBuffer())));
+  ASSERT_EQ(OK, GenerateAuthToken(&token));
+
+  // Validate the type 3 message
+  std::string decoded;
+  ASSERT_TRUE(DecodeChallenge(token, &decoded));
+  ntlm::NtlmBufferReader reader(decoded);
+  ASSERT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::kAuthenticate));
+
+  // Read the LM and NTLM Response Payloads.
+  uint8_t actual_lm_response[ntlm::kResponseLenV1];
+  uint8_t actual_ntlm_response[ntlm::kResponseLenV1];
+  ASSERT_TRUE(
+      ReadBytesPayload(&reader, actual_lm_response, ntlm::kResponseLenV1));
+  ASSERT_TRUE(
+      ReadBytesPayload(&reader, actual_ntlm_response, ntlm::kResponseLenV1));
+
+  // Verify that the client still generated a response that uses
+  // session security.
+  ASSERT_EQ(0, memcmp(ntlm::test::kExpectedLmResponseWithV1SS,
+                      actual_lm_response, ntlm::kResponseLenV1));
+  ASSERT_EQ(0, memcmp(ntlm::test::kExpectedNtlmResponseWithV1SS,
+                      actual_ntlm_response, ntlm::kResponseLenV1));
+
+  base::string16 domain;
+  base::string16 username;
+  base::string16 hostname;
+  ReadString16Payload(&reader, &domain);
+  ASSERT_EQ(ntlm::test::kNtlmDomain, domain);
+  ReadString16Payload(&reader, &username);
+  ASSERT_EQ(ntlm::test::kUser, username);
+  ReadString16Payload(&reader, &hostname);
+  ASSERT_EQ(ntlm::test::kHostname, hostname);
+
+  // The session key is not used for the NTLM scheme in HTTP. Since
+  // NTLMSSP_NEGOTIATE_KEY_EXCH was not sent this is empty.
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+
+  // Verify the unicode flag is set.
+  ntlm::NegotiateFlags flags;
+  ASSERT_TRUE(reader.ReadFlags(&flags));
+  ASSERT_EQ(ntlm::NegotiateFlags::kUnicode,
+            flags & ntlm::NegotiateFlags::kUnicode);
+}
+
+TEST_F(HttpAuthHandlerNtlmPortableTest, Type3UnicodeWithSessionSecurity) {
+  HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockRandom,
+                                                    MockGetHostName);
+  ASSERT_EQ(OK, CreateHandler());
+  ASSERT_EQ(OK, GetGenerateAuthTokenResult());
+
+  // Generate the type 2 message from the server.
+  ntlm::NtlmBufferWriter writer(ntlm::kChallengeHeaderLen);
+  ASSERT_TRUE(writer.WriteMessageHeader(ntlm::MessageType::kChallenge));
+  // No target name. It is never used.
+  ASSERT_TRUE(writer.WriteSecurityBuffer(
+      ntlm::SecurityBuffer(ntlm::kChallengeHeaderLen, 0)));
+  // Set the unicode and session security flag.
+  ASSERT_TRUE(
+      writer.WriteFlags((ntlm::NegotiateFlags::kUnicode |
+                         ntlm::NegotiateFlags::kExtendedSessionSecurity)));
+
+  ASSERT_TRUE(
+      writer.WriteBytes(ntlm::test::kServerChallenge, ntlm::kChallengeLen));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+
+  std::string token;
+  ASSERT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+            HandleAnotherChallenge(CreateNtlmAuthHeader(writer.GetBuffer())));
+  ASSERT_EQ(OK, GenerateAuthToken(&token));
+
+  // Validate the type 3 message
+  std::string decoded;
+  ASSERT_TRUE(DecodeChallenge(token, &decoded));
+  ntlm::NtlmBufferReader reader(decoded);
+  ASSERT_TRUE(reader.MatchMessageHeader(ntlm::MessageType::kAuthenticate));
+
+  // Read the LM and NTLM Response Payloads.
+  uint8_t actual_lm_response[ntlm::kResponseLenV1];
+  uint8_t actual_ntlm_response[ntlm::kResponseLenV1];
+  ASSERT_TRUE(
+      ReadBytesPayload(&reader, actual_lm_response, ntlm::kResponseLenV1));
+  ASSERT_TRUE(
+      ReadBytesPayload(&reader, actual_ntlm_response, ntlm::kResponseLenV1));
+
+  ASSERT_EQ(0, memcmp(ntlm::test::kExpectedLmResponseWithV1SS,
+                      actual_lm_response, ntlm::kResponseLenV1));
+  ASSERT_EQ(0, memcmp(ntlm::test::kExpectedNtlmResponseWithV1SS,
+                      actual_ntlm_response, ntlm::kResponseLenV1));
+
+  base::string16 domain;
+  base::string16 username;
+  base::string16 hostname;
+  ReadString16Payload(&reader, &domain);
+  ASSERT_EQ(ntlm::test::kNtlmDomain, domain);
+  ReadString16Payload(&reader, &username);
+  ASSERT_EQ(ntlm::test::kUser, username);
+  ReadString16Payload(&reader, &hostname);
+  ASSERT_EQ(ntlm::test::kHostname, hostname);
+
+  // The session key is not used for the NTLM scheme in HTTP. Since
+  // NTLMSSP_NEGOTIATE_KEY_EXCH was not sent this is empty.
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+
+  // Verify the unicode flag is set.
+  ntlm::NegotiateFlags flags;
+  ASSERT_TRUE(reader.ReadFlags(&flags));
+  ASSERT_EQ(ntlm::NegotiateFlags::kUnicode,
+            flags & ntlm::NegotiateFlags::kUnicode);
+}
+
+}  // namespace net
diff --git a/net/ntlm/OWNERS b/net/ntlm/OWNERS
new file mode 100644
index 0000000..156ce37
--- /dev/null
+++ b/net/ntlm/OWNERS
@@ -0,0 +1,6 @@
+asanka@chromium.org
+rsleevi@chromium.org
+zentaro@chromium.org
+
+# COMPONENT: Internals>Network>Auth
+# TEAM: net-dev@chromium.org
diff --git a/net/http/des.cc b/net/ntlm/des.cc
similarity index 98%
rename from net/http/des.cc
rename to net/ntlm/des.cc
index 57f67d7c..1967f66 100644
--- a/net/http/des.cc
+++ b/net/ntlm/des.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "net/http/des.h"
+#include "net/ntlm/des.h"
 
 #include "base/logging.h"
 #include "crypto/openssl_util.h"
@@ -11,6 +11,7 @@
 // The iOS version of DESEncrypt is our own code.
 // DESSetKeyParity and DESMakeKey are based on
 // mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp, CVS rev. 1.14.
+/* clang-format off */
 
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
diff --git a/net/http/des.h b/net/ntlm/des.h
similarity index 100%
rename from net/http/des.h
rename to net/ntlm/des.h
diff --git a/net/http/des_unittest.cc b/net/ntlm/des_unittest.cc
similarity index 98%
rename from net/http/des_unittest.cc
rename to net/ntlm/des_unittest.cc
index 63172bb7..d1f9ae5 100644
--- a/net/http/des_unittest.cc
+++ b/net/ntlm/des_unittest.cc
@@ -4,7 +4,7 @@
 
 #include <string.h>
 
-#include "net/http/des.h"
+#include "net/ntlm/des.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
diff --git a/net/http/md4.cc b/net/ntlm/md4.cc
similarity index 98%
rename from net/http/md4.cc
rename to net/ntlm/md4.cc
index 890b98b..cd18e9f 100644
--- a/net/http/md4.cc
+++ b/net/ntlm/md4.cc
@@ -4,6 +4,7 @@
 // WARNING: MD4 is cryptographically weak.  Do not use MD4 except in NTLM
 // authentication.
 
+/* clang-format off */
 /* vim:set ts=2 sw=2 et cindent: */
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
@@ -45,7 +46,7 @@
  * "clean room" MD4 implementation (see RFC 1320)
  */
 
-#include "net/http/md4.h"
+#include "net/ntlm/md4.h"
 
 #include <string.h>
 
diff --git a/net/http/md4.h b/net/ntlm/md4.h
similarity index 100%
rename from net/http/md4.h
rename to net/ntlm/md4.h
diff --git a/net/ntlm/ntlm.cc b/net/ntlm/ntlm.cc
new file mode 100644
index 0000000..14cc4bcd
--- /dev/null
+++ b/net/ntlm/ntlm.cc
@@ -0,0 +1,125 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/ntlm/ntlm.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "net/ntlm/des.h"
+#include "net/ntlm/md4.h"
+#include "net/ntlm/ntlm_buffer_writer.h"
+
+namespace net {
+namespace ntlm {
+
+void GenerateNtlmHashV1(const base::string16& password, uint8_t* hash) {
+  size_t length = password.length() * 2;
+  NtlmBufferWriter writer(length);
+
+  // The writer will handle the big endian case if necessary.
+  bool result = writer.WriteUtf16String(password);
+  DCHECK(result);
+
+  weak_crypto::MD4Sum(
+      reinterpret_cast<const uint8_t*>(writer.GetBuffer().data()), length,
+      hash);
+}
+
+void GenerateResponseDesl(const uint8_t* hash,
+                          const uint8_t* challenge,
+                          uint8_t* response) {
+  // See DESL(K, D) function in [MS-NLMP] Section 6
+  uint8_t key1[8];
+  uint8_t key2[8];
+  uint8_t key3[8];
+
+  // The last 2 bytes of the hash are zero padded (5 zeros) as the
+  // input to generate key3.
+  uint8_t padded_hash[7];
+  padded_hash[0] = hash[14];
+  padded_hash[1] = hash[15];
+  memset(padded_hash + 2, 0, 5);
+
+  DESMakeKey(hash, key1);
+  DESMakeKey(hash + 7, key2);
+  DESMakeKey(padded_hash, key3);
+
+  DESEncrypt(key1, challenge, response);
+  DESEncrypt(key2, challenge, response + 8);
+  DESEncrypt(key3, challenge, response + 16);
+}
+
+void GenerateNtlmResponseV1(const base::string16& password,
+                            const uint8_t* challenge,
+                            uint8_t* ntlm_response) {
+  uint8_t ntlm_hash[kNtlmHashLen];
+  GenerateNtlmHashV1(password, ntlm_hash);
+  GenerateResponseDesl(ntlm_hash, challenge, ntlm_response);
+}
+
+void GenerateResponsesV1(const base::string16& password,
+                         const uint8_t* server_challenge,
+                         uint8_t* lm_response,
+                         uint8_t* ntlm_response) {
+  GenerateNtlmResponseV1(password, server_challenge, ntlm_response);
+
+  // In NTLM v1 (with LMv1 disabled), the lm_response and ntlm_response are the
+  // same. So just copy the ntlm_response into the lm_response.
+  memcpy(lm_response, ntlm_response, kResponseLenV1);
+}
+
+void GenerateLMResponseV1WithSessionSecurity(const uint8_t* client_challenge,
+                                             uint8_t* lm_response) {
+  // In NTLM v1 with Session Security (aka NTLM2) the lm_response is 8 bytes of
+  // client challenge and 16 bytes of zeros. (See 3.3.1)
+  memcpy(lm_response, client_challenge, kChallengeLen);
+  memset(lm_response + kChallengeLen, 0, kResponseLenV1 - kChallengeLen);
+}
+
+void GenerateSessionHashV1WithSessionSecurity(const uint8_t* server_challenge,
+                                              const uint8_t* client_challenge,
+                                              base::MD5Digest* session_hash) {
+  base::MD5Context ctx;
+  base::MD5Init(&ctx);
+  base::MD5Update(
+      &ctx, base::StringPiece(reinterpret_cast<const char*>(server_challenge),
+                              kChallengeLen));
+  base::MD5Update(
+      &ctx, base::StringPiece(reinterpret_cast<const char*>(client_challenge),
+                              kChallengeLen));
+
+  base::MD5Final(session_hash, &ctx);
+}
+
+void GenerateNtlmResponseV1WithSessionSecurity(const base::string16& password,
+                                               const uint8_t* server_challenge,
+                                               const uint8_t* client_challenge,
+                                               uint8_t* ntlm_response) {
+  // Generate the NTLMv1 Hash.
+  uint8_t ntlm_hash[kNtlmHashLen];
+  GenerateNtlmHashV1(password, ntlm_hash);
+
+  // Generate the NTLMv1 Session Hash.
+  base::MD5Digest session_hash;
+  GenerateSessionHashV1WithSessionSecurity(server_challenge, client_challenge,
+                                           &session_hash);
+
+  // Only the first 8 bytes of |session_hash.a| are actually used.
+  GenerateResponseDesl(ntlm_hash, session_hash.a, ntlm_response);
+}
+
+void GenerateResponsesV1WithSessionSecurity(const base::string16& password,
+                                            const uint8_t* server_challenge,
+                                            const uint8_t* client_challenge,
+                                            uint8_t* lm_response,
+                                            uint8_t* ntlm_response) {
+  GenerateLMResponseV1WithSessionSecurity(client_challenge, lm_response);
+  GenerateNtlmResponseV1WithSessionSecurity(password, server_challenge,
+                                            client_challenge, ntlm_response);
+}
+
+}  // namespace ntlm
+}  // namespace net
diff --git a/net/ntlm/ntlm.h b/net/ntlm/ntlm.h
new file mode 100644
index 0000000..1d98611
--- /dev/null
+++ b/net/ntlm/ntlm.h
@@ -0,0 +1,131 @@
+// 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.
+
+// Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
+// Specification version 28.0 [1]. Additional NTLM reference [2].
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+// [2] http://davenport.sourceforge.net/ntlm.html
+
+#ifndef NET_BASE_NTLM_H_
+#define NET_BASE_NTLM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/ntlm/ntlm_constants.h"
+
+namespace base {
+struct MD5Digest;
+}
+
+namespace net {
+namespace ntlm {
+
+// Generates the NTLMv1 Hash and writes the |kNtlmHashLen| byte result to
+// |hash|. Defined by NTOWFv1() in [MS-NLMP] Section 3.3.1.
+NET_EXPORT_PRIVATE void GenerateNtlmHashV1(const base::string16& password,
+                                           uint8_t* hash);
+
+// Generates the |kResponseLenV1| byte NTLMv1 response field according to the
+// DESL(K, V) function in [MS-NLMP] Section 6.
+//
+// |hash| must contain |kNtlmHashLen| bytes.
+// |challenge| must contain |kChallengeLen| bytes.
+// |response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateResponseDesl(const uint8_t* hash,
+                                             const uint8_t* challenge,
+                                             uint8_t* response);
+
+// Generates the NTLM Response field for NTLMv1 without extended session
+// security. Defined by ComputeResponse() in [MS-NLMP] Section 3.3.1 for the
+// case where NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is not set.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |ntlm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateNtlmResponseV1(const base::string16& password,
+                                               const uint8_t* server_challenge,
+                                               uint8_t* ntlm_response);
+
+// Generates both the LM Response and NTLM Response fields for NTLMv1 based
+// on the users password and the servers challenge. Both the LM and NTLM
+// Response are the result of |GenerateNtlmResponseV1|.
+//
+// NOTE: This should not be used. The default flags always include session
+// security. Session security can however be disabled in NTLMv1 by omitting
+// NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY from the flag set used to
+// initialize |NtlmClient|.
+//
+// The default flags include this flag and the client will not be
+// downgraded by the server.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |lm_response| must contain |kResponseLenV1| bytes.
+// |ntlm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateResponsesV1(const base::string16& password,
+                                            const uint8_t* server_challenge,
+                                            uint8_t* lm_response,
+                                            uint8_t* ntlm_response);
+
+// The LM Response in V1 with extended session security is 8 bytes of the
+// |client_challenge| then 16 bytes of zero. This is the value
+// LmChallengeResponse in ComputeResponse() when
+// NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is set. See [MS-NLMP] Section
+// 3.3.1.
+//
+// |lm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateLMResponseV1WithSessionSecurity(
+    const uint8_t* client_challenge,
+    uint8_t* lm_response);
+
+// The |session_hash| is MD5(CONCAT(server_challenge, client_challenge)).
+// It is used instead of just |server_challenge| in NTLMv1 when
+// NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is set. See [MS-NLMP] Section
+// 3.3.1.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |client_challenge| must contain |kChallengeLen| bytes.
+NET_EXPORT_PRIVATE void GenerateSessionHashV1WithSessionSecurity(
+    const uint8_t* server_challenge,
+    const uint8_t* client_challenge,
+    base::MD5Digest* session_hash);
+
+// Generates the NTLM Response for NTLMv1 with session security.
+// Defined by ComputeResponse() in [MS-NLMP] Section 3.3.1 for the
+// case where NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is set.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |client_challenge| must contain |kChallengeLen| bytes.
+// |ntlm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateNtlmResponseV1WithSessionSecurity(
+    const base::string16& password,
+    const uint8_t* server_challenge,
+    const uint8_t* client_challenge,
+    uint8_t* ntlm_response);
+
+// Generates the responses for V1 with extended session security.
+// This is also known as NTLM2 (which is not the same as NTLMv2).
+// |lm_response| is the result of |GenerateLMResponseV1WithSessionSecurity| and
+// |ntlm_response| is the result of |GenerateNtlmResponseV1WithSessionSecurity|.
+// See [MS-NLMP] Section 3.3.1.
+//
+// |server_challenge| must contain |kChallengeLen| bytes.
+// |client_challenge| must contain |kChallengeLen| bytes.
+// |ntlm_response| must contain |kResponseLenV1| bytes.
+NET_EXPORT_PRIVATE void GenerateResponsesV1WithSessionSecurity(
+    const base::string16& password,
+    const uint8_t* server_challenge,
+    const uint8_t* client_challenge,
+    uint8_t* lm_response,
+    uint8_t* ntlm_response);
+
+}  // namespace ntlm
+}  // namespace net
+
+#endif  // NET_BASE_NTLM_H_
diff --git a/net/ntlm/ntlm_buffer_reader.cc b/net/ntlm/ntlm_buffer_reader.cc
new file mode 100644
index 0000000..95ae2e6
--- /dev/null
+++ b/net/ntlm/ntlm_buffer_reader.cc
@@ -0,0 +1,179 @@
+// 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 "net/ntlm/ntlm_buffer_reader.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+
+namespace net {
+namespace ntlm {
+
+NtlmBufferReader::NtlmBufferReader(base::StringPiece buffer)
+    : buffer_(buffer), cursor_(0) {
+  DCHECK(buffer.data());
+}
+
+NtlmBufferReader::NtlmBufferReader(const uint8_t* ptr, size_t len)
+    : NtlmBufferReader(
+          base::StringPiece(reinterpret_cast<const char*>(ptr), len)) {}
+
+NtlmBufferReader::~NtlmBufferReader() {}
+
+bool NtlmBufferReader::CanRead(size_t len) const {
+  return CanReadFrom(GetCursor(), len);
+}
+
+bool NtlmBufferReader::CanReadFrom(size_t offset, size_t len) const {
+  if (len == 0)
+    return true;
+
+  return (len <= GetLength() && offset <= GetLength() - len);
+}
+
+bool NtlmBufferReader::ReadUInt16(uint16_t* value) {
+  return ReadUInt<uint16_t>(value);
+}
+
+bool NtlmBufferReader::ReadUInt32(uint32_t* value) {
+  return ReadUInt<uint32_t>(value);
+}
+
+bool NtlmBufferReader::ReadUInt64(uint64_t* value) {
+  return ReadUInt<uint64_t>(value);
+}
+
+bool NtlmBufferReader::ReadFlags(NegotiateFlags* flags) {
+  uint32_t raw;
+  if (!ReadUInt32(&raw))
+    return false;
+
+  *flags = static_cast<NegotiateFlags>(raw);
+  return true;
+}
+
+bool NtlmBufferReader::ReadBytes(uint8_t* buffer, size_t len) {
+  if (!CanRead(len))
+    return false;
+
+  memcpy(reinterpret_cast<void*>(buffer),
+         reinterpret_cast<const void*>(GetBufferAtCursor()), len);
+
+  AdvanceCursor(len);
+  return true;
+}
+
+bool NtlmBufferReader::ReadBytesFrom(const SecurityBuffer& sec_buf,
+                                     uint8_t* buffer) {
+  if (!CanReadFrom(sec_buf))
+    return false;
+
+  memcpy(reinterpret_cast<void*>(buffer),
+         reinterpret_cast<const void*>(GetBufferPtr() + sec_buf.offset),
+         sec_buf.length);
+
+  return true;
+}
+
+bool NtlmBufferReader::ReadSecurityBuffer(SecurityBuffer* sec_buf) {
+  return ReadUInt16(&sec_buf->length) && SkipBytes(sizeof(uint16_t)) &&
+         ReadUInt32(&sec_buf->offset);
+}
+
+bool NtlmBufferReader::ReadMessageType(MessageType* message_type) {
+  uint32_t raw_message_type;
+  if (!ReadUInt32(&raw_message_type))
+    return false;
+
+  *message_type = static_cast<MessageType>(raw_message_type);
+
+  if (*message_type != MessageType::kNegotiate &&
+      *message_type != MessageType::kChallenge &&
+      *message_type != MessageType::kAuthenticate)
+    return false;
+
+  return true;
+}
+
+bool NtlmBufferReader::SkipSecurityBuffer() {
+  return SkipBytes(kSecurityBufferLen);
+}
+
+bool NtlmBufferReader::SkipSecurityBufferWithValidation() {
+  SecurityBuffer sec_buf;
+  return ReadSecurityBuffer(&sec_buf) && CanReadFrom(sec_buf);
+}
+
+bool NtlmBufferReader::SkipBytes(size_t count) {
+  if (!CanRead(count))
+    return false;
+
+  AdvanceCursor(count);
+  return true;
+}
+
+bool NtlmBufferReader::MatchSignature() {
+  if (!CanRead(kSignatureLen))
+    return false;
+
+  if (memcmp(kSignature, GetBufferAtCursor(), kSignatureLen) != 0)
+    return false;
+
+  AdvanceCursor(kSignatureLen);
+  return true;
+}
+
+bool NtlmBufferReader::MatchMessageType(MessageType message_type) {
+  MessageType actual_message_type;
+  return ReadMessageType(&actual_message_type) &&
+         (actual_message_type == message_type);
+}
+
+bool NtlmBufferReader::MatchMessageHeader(MessageType message_type) {
+  return MatchSignature() && MatchMessageType(message_type);
+}
+
+bool NtlmBufferReader::MatchZeros(size_t count) {
+  if (!CanRead(count))
+    return false;
+
+  for (size_t i = 0; i < count; i++) {
+    if (GetBufferAtCursor()[i] != 0)
+      return false;
+  }
+
+  AdvanceCursor(count);
+  return true;
+}
+
+bool NtlmBufferReader::MatchEmptySecurityBuffer() {
+  SecurityBuffer sec_buf;
+  return ReadSecurityBuffer(&sec_buf) && (sec_buf.offset <= GetLength()) &&
+         (sec_buf.length == 0);
+}
+
+template <typename T>
+bool NtlmBufferReader::ReadUInt(T* value) {
+  size_t int_size = sizeof(T);
+  if (!CanRead(int_size))
+    return false;
+
+  *value = 0;
+  for (size_t i = 0; i < int_size; i++) {
+    *value += static_cast<T>(GetByteAtCursor()) << (i * 8);
+    AdvanceCursor(1);
+  }
+
+  return true;
+}
+
+void NtlmBufferReader::SetCursor(size_t cursor) {
+  DCHECK_LE(cursor, GetLength());
+
+  cursor_ = cursor;
+}
+
+}  // namespace ntlm
+}  // namespace net
diff --git a/net/ntlm/ntlm_buffer_reader.h b/net/ntlm/ntlm_buffer_reader.h
new file mode 100644
index 0000000..d31429f
--- /dev/null
+++ b/net/ntlm/ntlm_buffer_reader.h
@@ -0,0 +1,191 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NTLM_BUFFER_READER_H_
+#define NET_BASE_NTLM_BUFFER_READER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/ntlm/ntlm_constants.h"
+
+namespace net {
+namespace ntlm {
+
+// Supports various bounds-checked low level buffer operations required by an
+// NTLM implementation.
+//
+// The class supports the sequential read of a provided buffer. All reads
+// perform bounds checking to ensure enough space is remaining in the buffer.
+//
+// Read* methods read from the buffer at the current cursor position and
+// perform any necessary type conversion and provide the data in out params.
+// After a successful read the cursor position is advanced past the read
+// field.
+//
+// Failed Read*s or Match*s leave the cursor in an undefined position and the
+// buffer MUST be discarded with no further operations performed.
+//
+// Read*Payload methods first reads a security buffer (see
+// |ReadSecurityBuffer|), then reads the requested payload from the offset
+// and length stated in the security buffer.
+//
+// If the length and offset in the security buffer would cause a read outside
+// the message buffer the payload will not be read and the function will
+// return false.
+//
+// Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
+// Specification version 28.0 [1]. Additional NTLM reference [2].
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+// [2] http://davenport.sourceforge.net/ntlm.html
+class NET_EXPORT_PRIVATE NtlmBufferReader {
+ public:
+  explicit NtlmBufferReader(base::StringPiece buffer);
+
+  // This class does not take ownership of |ptr|, so the caller must ensure
+  // that the buffer outlives the |NtlmBufferReader|.
+  NtlmBufferReader(const uint8_t* ptr, size_t len);
+  ~NtlmBufferReader();
+
+  size_t GetLength() const { return buffer_.length(); }
+  size_t GetCursor() const { return cursor_; }
+  bool IsEndOfBuffer() const { return cursor_ >= GetLength(); }
+
+  // Returns true if there are |len| more bytes between the current cursor
+  // position and the end of the buffer.
+  bool CanRead(size_t len) const;
+
+  // Returns true if there are |len| more bytes between |offset| and the end
+  // of the buffer. The cursor position is not used or modified.
+  bool CanReadFrom(size_t offset, size_t len) const;
+
+  // Returns true if it would be possible to read the payload described by the
+  // security buffer.
+  bool CanReadFrom(SecurityBuffer sec_buf) const {
+    return CanReadFrom(sec_buf.offset, sec_buf.length);
+  }
+
+  // Reads a 16 bit value (little endian) as a uint16_t. If there are not 16
+  // more bits available, it returns false.
+  bool ReadUInt16(uint16_t* value) WARN_UNUSED_RESULT;
+
+  // Reads a 32 bit value (little endian) as a uint32_t. If there are not 32
+  // more bits available, it returns false.
+  bool ReadUInt32(uint32_t* value) WARN_UNUSED_RESULT;
+
+  // Reads a 64 bit value (little endian) as a uint64_t. If there are not 64
+  // more bits available, it returns false.
+  bool ReadUInt64(uint64_t* value) WARN_UNUSED_RESULT;
+
+  // Calls |ReadUInt32| and returns it cast as |NegotiateFlags|. No
+  // validation of the value takes place.
+  bool ReadFlags(NegotiateFlags* flags) WARN_UNUSED_RESULT;
+
+  // Reads |len| bytes and copies them into |buffer|.
+  bool ReadBytes(uint8_t* buffer, size_t len) WARN_UNUSED_RESULT;
+
+  // Reads |sec_buf.length| bytes from offset |sec_buf.offset| and copies them
+  // into |buffer|. If the security buffer specifies a payload outside the
+  // buffer, then the call fails. Unlike the other Read* methods, this does
+  // not move the cursor.
+  bool ReadBytesFrom(const SecurityBuffer& sec_buf,
+                     uint8_t* buffer) WARN_UNUSED_RESULT;
+
+  // A security buffer is an 8 byte structure that defines the offset and
+  // length of a payload (string, struct or byte array) that appears after the
+  // fixed part of the message.
+  //
+  // The structure is (little endian fields):
+  //     uint16 - |length| Length of payload
+  //     uint16 - Allocation (this is always ignored and not returned)
+  //     uint32 - |offset| Offset from start of message
+  bool ReadSecurityBuffer(SecurityBuffer* sec_buf) WARN_UNUSED_RESULT;
+
+  // There are 3 message types Negotiate (sent by client), Challenge (sent by
+  // server), and Authenticate (sent by client).
+  //
+  // This reads the message type from the header and will return false if the
+  // value is invalid.
+  bool ReadMessageType(MessageType* message_type) WARN_UNUSED_RESULT;
+
+  // Skips over a security buffer field without reading the fields. This is
+  // the equivalent of advancing the cursor 8 bytes. Returns false if there
+  // are less than 8 bytes left in the buffer.
+  bool SkipSecurityBuffer() WARN_UNUSED_RESULT;
+
+  // Skips over the security buffer without returning the values, but fails if
+  // the values would cause a read outside the buffer if the payload was
+  // actually read.
+  bool SkipSecurityBufferWithValidation() WARN_UNUSED_RESULT;
+
+  // Skips over |count| bytes in the buffer. Returns false if there are not
+  // |count| bytes left in the buffer.
+  bool SkipBytes(size_t count) WARN_UNUSED_RESULT;
+
+  // Reads and returns true if the next 8 bytes matches the signature in an
+  // NTLM message "NTLMSSP\0". The cursor advances if the the signature
+  // is matched.
+  bool MatchSignature() WARN_UNUSED_RESULT;
+
+  // Performs |ReadMessageType| and returns true if the value is
+  // |message_type|. If the read fails or the message type does not match,
+  // the buffer is invalid and MUST be discarded.
+  bool MatchMessageType(MessageType message_type) WARN_UNUSED_RESULT;
+
+  // Performs |MatchSignature| then |MatchMessageType|.
+  bool MatchMessageHeader(MessageType message_type) WARN_UNUSED_RESULT;
+
+  // Performs |ReadBytes(count)| and returns true if the contents is all
+  // zero.
+  bool MatchZeros(size_t count) WARN_UNUSED_RESULT;
+
+  // Reads the security buffer and returns true if the length is 0 and
+  // the offset is within the message. On failure, the buffer is invalid
+  // and MUST be discarded.
+  bool MatchEmptySecurityBuffer() WARN_UNUSED_RESULT;
+
+ private:
+  // Reads |sizeof(T)| bytes of an integer type from a little-endian buffer.
+  template <typename T>
+  bool ReadUInt(T* value);
+
+  // Sets the cursor position. The caller should use |GetLength|, |CanRead|,
+  // or |CanReadFrom| to verify the bounds before calling this method.
+  void SetCursor(size_t cursor);
+
+  // Advances the cursor by |count| bytes. The caller should use |GetLength|,
+  // |CanRead|, or |CanReadFrom| to verify the bounds before calling this
+  // method.
+  void AdvanceCursor(size_t count) { SetCursor(GetCursor() + count); }
+
+  // Returns a constant pointer to the start of the buffer.
+  const uint8_t* GetBufferPtr() const {
+    return reinterpret_cast<const uint8_t*>(buffer_.data());
+  }
+
+  // Returns a pointer to the underlying buffer at the current cursor
+  // position.
+  const uint8_t* GetBufferAtCursor() const { return GetBufferPtr() + cursor_; }
+
+  // Returns the byte at the current cursor position.
+  uint8_t GetByteAtCursor() const {
+    DCHECK(!IsEndOfBuffer());
+    return *(GetBufferAtCursor());
+  }
+
+  const base::StringPiece buffer_;
+  size_t cursor_;
+
+  DISALLOW_COPY_AND_ASSIGN(NtlmBufferReader);
+};
+
+}  // namespace ntlm
+}  // namespace net
+
+#endif  // NET_BASE_NTLM_BUFFER_READER_H_
diff --git a/net/ntlm/ntlm_buffer_reader_unittest.cc b/net/ntlm/ntlm_buffer_reader_unittest.cc
new file mode 100644
index 0000000..592c5d3
--- /dev/null
+++ b/net/ntlm/ntlm_buffer_reader_unittest.cc
@@ -0,0 +1,367 @@
+// 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 "net/ntlm/ntlm_buffer_reader.h"
+
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace ntlm {
+
+TEST(NtlmBufferReaderTest, Initialization) {
+  const uint8_t buf[1] = {0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_EQ(arraysize(buf), reader.GetLength());
+  ASSERT_EQ(0u, reader.GetCursor());
+  ASSERT_FALSE(reader.IsEndOfBuffer());
+  ASSERT_TRUE(reader.CanRead(1));
+  ASSERT_FALSE(reader.CanRead(2));
+  ASSERT_TRUE(reader.CanReadFrom(0, 1));
+  ASSERT_TRUE(reader.CanReadFrom(SecurityBuffer(0, 1)));
+  ASSERT_FALSE(reader.CanReadFrom(1, 1));
+  ASSERT_FALSE(reader.CanReadFrom(SecurityBuffer(1, 1)));
+  ASSERT_FALSE(reader.CanReadFrom(0, 2));
+  ASSERT_FALSE(reader.CanReadFrom(SecurityBuffer(0, 2)));
+
+  // With length=0 the offset can be out of bounds.
+  ASSERT_TRUE(reader.CanReadFrom(99, 0));
+  ASSERT_TRUE(reader.CanReadFrom(SecurityBuffer(99, 0)));
+}
+
+TEST(NtlmBufferReaderTest, Read16) {
+  const uint8_t buf[2] = {0x22, 0x11};
+  const uint16_t expected = 0x1122;
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  uint16_t actual;
+  ASSERT_TRUE(reader.ReadUInt16(&actual));
+  ASSERT_EQ(expected, actual);
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.ReadUInt16(&actual));
+}
+
+TEST(NtlmBufferReaderTest, Read32) {
+  const uint8_t buf[4] = {0x44, 0x33, 0x22, 0x11};
+  const uint32_t expected = 0x11223344;
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  uint32_t actual;
+  ASSERT_TRUE(reader.ReadUInt32(&actual));
+  ASSERT_EQ(expected, actual);
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.ReadUInt32(&actual));
+}
+
+TEST(NtlmBufferReaderTest, Read64) {
+  const uint8_t buf[8] = {0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+  const uint64_t expected = 0x1122334455667788;
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  uint64_t actual;
+  ASSERT_TRUE(reader.ReadUInt64(&actual));
+  ASSERT_EQ(expected, actual);
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.ReadUInt64(&actual));
+}
+
+TEST(NtlmBufferReaderTest, ReadBytes) {
+  const uint8_t expected[8] = {0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+  uint8_t actual[8];
+
+  NtlmBufferReader reader(expected, arraysize(expected));
+
+  ASSERT_TRUE(reader.ReadBytes(actual, arraysize(actual)));
+  ASSERT_EQ(0, memcmp(actual, expected, arraysize(actual)));
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.ReadBytes(actual, 1));
+}
+
+TEST(NtlmBufferReaderTest, ReadSecurityBuffer) {
+  const uint8_t buf[8] = {0x22, 0x11, 0xFF, 0xEE, 0x88, 0x77, 0x66, 0x55};
+  const uint16_t length = 0x1122;
+  const uint32_t offset = 0x55667788;
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  SecurityBuffer sec_buf;
+  ASSERT_TRUE(reader.ReadSecurityBuffer(&sec_buf));
+  ASSERT_EQ(length, sec_buf.length);
+  ASSERT_EQ(offset, sec_buf.offset);
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.ReadSecurityBuffer(&sec_buf));
+}
+
+TEST(NtlmBufferReaderTest, ReadSecurityBufferPastEob) {
+  const uint8_t buf[7] = {0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  SecurityBuffer sec_buf;
+  ASSERT_FALSE(reader.ReadSecurityBuffer(&sec_buf));
+}
+
+TEST(NtlmBufferReaderTest, SkipSecurityBuffer) {
+  const uint8_t buf[kSecurityBufferLen] = {0};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+  ASSERT_TRUE(reader.SkipSecurityBuffer());
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.SkipSecurityBuffer());
+}
+
+TEST(NtlmBufferReaderTest, SkipSecurityBufferPastEob) {
+  // The buffer is one byte shorter than security buffer.
+  const uint8_t buf[kSecurityBufferLen - 1] = {0};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+  ASSERT_FALSE(reader.SkipSecurityBuffer());
+}
+
+TEST(NtlmBufferReaderTest, SkipSecurityBufferWithValidationEmpty) {
+  const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.SkipSecurityBufferWithValidation());
+}
+
+TEST(NtlmBufferReaderTest, SkipSecurityBufferWithValidationValid) {
+  // A valid security buffer that points to the 1 payload byte.
+  const uint8_t buf[kSecurityBufferLen + 1] = {
+      0x01, 0, 0x01, 0, kSecurityBufferLen, 0, 0, 0, 0xFF};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+  ASSERT_EQ(kSecurityBufferLen, reader.GetCursor());
+  ASSERT_FALSE(reader.SkipSecurityBufferWithValidation());
+}
+
+TEST(NtlmBufferReaderTest,
+     SkipSecurityBufferWithValidationPayloadLengthPastEob) {
+  // Security buffer with length that points past the end of buffer.
+  const uint8_t buf[kSecurityBufferLen + 1] = {
+      0x02, 0, 0x02, 0, kSecurityBufferLen, 0, 0, 0, 0xFF};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+  ASSERT_FALSE(reader.SkipSecurityBufferWithValidation());
+}
+
+TEST(NtlmBufferReaderTest,
+     SkipSecurityBufferWithValidationPayloadOffsetPastEob) {
+  // Security buffer with offset that points past the end of buffer.
+  const uint8_t buf[kSecurityBufferLen + 1] = {
+      0x02, 0, 0x02, 0, kSecurityBufferLen + 1, 0, 0, 0, 0xFF};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+  ASSERT_FALSE(reader.SkipSecurityBufferWithValidation());
+}
+
+TEST(NtlmBufferReaderTest,
+     SkipSecurityBufferWithValidationZeroLengthPayloadOffsetPastEob) {
+  // Security buffer with offset that points past the end of buffer but
+  // length is 0.
+  const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, kSecurityBufferLen + 1,
+                                           0, 0, 0};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+  ASSERT_TRUE(reader.SkipSecurityBufferWithValidation());
+  ASSERT_EQ(kSecurityBufferLen, reader.GetCursor());
+}
+
+TEST(NtlmBufferReaderTest, SkipBytes) {
+  const uint8_t buf[8] = {0};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_TRUE(reader.SkipBytes(arraysize(buf)));
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.SkipBytes(arraysize(buf)));
+}
+
+TEST(NtlmBufferReaderTest, SkipBytesPastEob) {
+  const uint8_t buf[8] = {0};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_FALSE(reader.SkipBytes(arraysize(buf) + 1));
+}
+
+TEST(NtlmBufferReaderTest, MatchSignatureTooShort) {
+  const uint8_t buf[7] = {0};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_TRUE(reader.CanRead(7));
+  ASSERT_FALSE(reader.MatchSignature());
+}
+
+TEST(NtlmBufferReaderTest, MatchSignatureNoMatch) {
+  // The last byte should be a 0.
+  const uint8_t buf[8] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0xff};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_TRUE(reader.CanRead(8));
+  ASSERT_FALSE(reader.MatchSignature());
+}
+
+TEST(NtlmBufferReaderTest, MatchSignatureOk) {
+  const uint8_t buf[8] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_TRUE(reader.MatchSignature());
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, ReadInvalidMessageType) {
+  // Only 0x01, 0x02, and 0x03 are valid message types.
+  const uint8_t buf[4] = {0x04, 0, 0, 0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  MessageType message_type;
+  ASSERT_FALSE(reader.ReadMessageType(&message_type));
+}
+
+TEST(NtlmBufferReaderTest, ReadMessageTypeNegotiate) {
+  const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kNegotiate), 0, 0,
+                          0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  MessageType message_type;
+  ASSERT_TRUE(reader.ReadMessageType(&message_type));
+  ASSERT_EQ(MessageType::kNegotiate, message_type);
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, ReadMessageTypeChallenge) {
+  const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kChallenge), 0, 0,
+                          0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  MessageType message_type;
+  ASSERT_TRUE(reader.ReadMessageType(&message_type));
+  ASSERT_EQ(MessageType::kChallenge, message_type);
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, ReadMessageTypeAuthenticate) {
+  const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kAuthenticate), 0,
+                          0, 0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  MessageType message_type;
+  ASSERT_TRUE(reader.ReadMessageType(&message_type));
+  ASSERT_EQ(MessageType::kAuthenticate, message_type);
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchMessageTypeAuthenticate) {
+  const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kAuthenticate), 0,
+                          0, 0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_TRUE(reader.MatchMessageType(MessageType::kAuthenticate));
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchMessageTypeInvalid) {
+  // Only 0x01, 0x02, and 0x03 are valid message types.
+  const uint8_t buf[4] = {0x04, 0, 0, 0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_FALSE(reader.MatchMessageType(MessageType::kAuthenticate));
+}
+
+TEST(NtlmBufferReaderTest, MatchMessageTypeMismatch) {
+  const uint8_t buf[4] = {static_cast<uint8_t>(MessageType::kChallenge), 0, 0,
+                          0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_FALSE(reader.MatchMessageType(MessageType::kAuthenticate));
+}
+
+TEST(NtlmBufferReaderTest, MatchAuthenticateHeader) {
+  const uint8_t buf[12] = {
+      'N', 'T', 'L',
+      'M', 'S', 'S',
+      'P', 0,   static_cast<uint8_t>(MessageType::kAuthenticate),
+      0,   0,   0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_TRUE(reader.MatchMessageHeader(MessageType::kAuthenticate));
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchAuthenticateHeaderMisMatch) {
+  const uint8_t buf[12] = {
+      'N', 'T', 'L',
+      'M', 'S', 'S',
+      'P', 0,   static_cast<uint8_t>(MessageType::kChallenge),
+      0,   0,   0};
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_FALSE(reader.MatchMessageType(MessageType::kAuthenticate));
+}
+
+TEST(NtlmBufferReaderTest, MatchZeros) {
+  const uint8_t buf[6] = {0, 0, 0, 0, 0, 0};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_TRUE(reader.MatchZeros(arraysize(buf)));
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.MatchZeros(1));
+}
+
+TEST(NtlmBufferReaderTest, MatchZerosFail) {
+  const uint8_t buf[6] = {0, 0, 0, 0, 0, 0xFF};
+
+  NtlmBufferReader reader(buf, arraysize(buf));
+
+  ASSERT_FALSE(reader.MatchZeros(arraysize(buf)));
+}
+
+TEST(NtlmBufferReaderTest, MatchEmptySecurityBuffer) {
+  const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+  NtlmBufferReader reader(buf, kSecurityBufferLen);
+
+  ASSERT_TRUE(reader.MatchEmptySecurityBuffer());
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+  ASSERT_FALSE(reader.MatchEmptySecurityBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchEmptySecurityBufferLengthZeroOffsetEnd) {
+  const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, 0x08, 0, 0, 0};
+
+  NtlmBufferReader reader(buf, kSecurityBufferLen);
+
+  ASSERT_TRUE(reader.MatchEmptySecurityBuffer());
+  ASSERT_TRUE(reader.IsEndOfBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchEmptySecurityBufferLengthZeroPastEob) {
+  const uint8_t buf[kSecurityBufferLen] = {0, 0, 0, 0, 0x09, 0, 0, 0};
+
+  NtlmBufferReader reader(buf, kSecurityBufferLen);
+
+  ASSERT_FALSE(reader.MatchEmptySecurityBuffer());
+}
+
+TEST(NtlmBufferReaderTest, MatchEmptySecurityBufferLengthNonZeroLength) {
+  const uint8_t buf[kSecurityBufferLen + 1] = {0x01, 0, 0, 0,   0x08,
+                                               0,    0, 0, 0xff};
+
+  NtlmBufferReader reader(buf, kSecurityBufferLen);
+
+  ASSERT_FALSE(reader.MatchEmptySecurityBuffer());
+}
+
+}  // namespace ntlm
+}  // namespace net
diff --git a/net/ntlm/ntlm_buffer_writer.cc b/net/ntlm/ntlm_buffer_writer.cc
new file mode 100644
index 0000000..0b5e3aa
--- /dev/null
+++ b/net/ntlm/ntlm_buffer_writer.cc
@@ -0,0 +1,152 @@
+// 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 "net/ntlm/ntlm_buffer_writer.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+
+namespace net {
+namespace ntlm {
+
+NtlmBufferWriter::NtlmBufferWriter(size_t buffer_len)
+    : buffer_len_(buffer_len), cursor_(0) {
+  buffer_.reset(new uint8_t[buffer_len]());
+}
+
+NtlmBufferWriter::~NtlmBufferWriter() {}
+
+bool NtlmBufferWriter::CanWrite(size_t len) const {
+  if (!GetBufferPtr())
+    return false;
+
+  DCHECK_LE(GetCursor(), GetLength());
+
+  if (len == 0)
+    return true;
+
+  return (len <= GetLength()) && (GetCursor() <= GetLength() - len);
+}
+
+bool NtlmBufferWriter::WriteUInt16(uint16_t value) {
+  return WriteUInt<uint16_t>(value);
+}
+
+bool NtlmBufferWriter::WriteUInt32(uint32_t value) {
+  return WriteUInt<uint32_t>(value);
+}
+
+bool NtlmBufferWriter::WriteUInt64(uint64_t value) {
+  return WriteUInt<uint64_t>(value);
+}
+
+bool NtlmBufferWriter::WriteFlags(NegotiateFlags flags) {
+  return WriteUInt32(static_cast<uint32_t>(flags));
+}
+
+bool NtlmBufferWriter::WriteBytes(const uint8_t* buffer, size_t len) {
+  if (!CanWrite(len))
+    return false;
+
+  memcpy(reinterpret_cast<void*>(GetBufferPtrAtCursor()),
+         reinterpret_cast<const void*>(buffer), len);
+
+  AdvanceCursor(len);
+  return true;
+}
+
+bool NtlmBufferWriter::WriteBytes(base::StringPiece bytes) {
+  return WriteBytes(reinterpret_cast<const uint8_t*>(bytes.data()),
+                    bytes.length());
+}
+
+bool NtlmBufferWriter::WriteZeros(size_t count) {
+  if (!CanWrite(count))
+    return false;
+
+  memset(GetBufferPtrAtCursor(), 0, count);
+  AdvanceCursor(count);
+  return true;
+}
+
+bool NtlmBufferWriter::WriteSecurityBuffer(SecurityBuffer sec_buf) {
+  return WriteUInt16(sec_buf.length) && WriteUInt16(sec_buf.length) &&
+         WriteUInt32(sec_buf.offset);
+}
+
+bool NtlmBufferWriter::WriteUtf8String(const std::string& str) {
+  return WriteBytes(reinterpret_cast<const uint8_t*>(str.c_str()),
+                    str.length());
+}
+
+bool NtlmBufferWriter::WriteUtf16AsUtf8String(const base::string16& str) {
+  std::string utf8 = base::UTF16ToUTF8(str);
+  return WriteUtf8String(utf8);
+}
+
+bool NtlmBufferWriter::WriteUtf8AsUtf16String(const std::string& str) {
+  base::string16 unicode = base::UTF8ToUTF16(str);
+  return WriteUtf16String(unicode);
+}
+
+bool NtlmBufferWriter::WriteUtf16String(const base::string16& str) {
+  size_t num_bytes = str.length() * 2;
+  if (!CanWrite(num_bytes))
+    return false;
+
+#if defined(ARCH_CPU_BIG_ENDIAN)
+  uint8_t* ptr = reinterpret_cast<uint8_t*>(GetBufferPtrAtCursor());
+
+  for (int i = 0; i < num_bytes; i += 2) {
+    ptr[i] = str[i / 2] & 0xff;
+    ptr[i + 1] = str[i / 2] >> 8;
+  }
+#else
+  memcpy(reinterpret_cast<void*>(GetBufferPtrAtCursor()), str.c_str(),
+         num_bytes);
+
+#endif
+
+  AdvanceCursor(num_bytes);
+  return true;
+}
+
+bool NtlmBufferWriter::WriteSignature() {
+  return WriteBytes(kSignature, kSignatureLen);
+}
+
+bool NtlmBufferWriter::WriteMessageType(MessageType message_type) {
+  return WriteUInt32(static_cast<uint32_t>(message_type));
+}
+
+bool NtlmBufferWriter::WriteMessageHeader(MessageType message_type) {
+  return WriteSignature() && WriteMessageType(message_type);
+}
+
+template <typename T>
+bool NtlmBufferWriter::WriteUInt(T value) {
+  size_t int_size = sizeof(T);
+  if (!CanWrite(int_size))
+    return false;
+
+  for (size_t i = 0; i < int_size; i++) {
+    GetBufferPtrAtCursor()[i] = static_cast<uint8_t>(value & 0xff);
+    value >>= 8;
+  }
+
+  AdvanceCursor(int_size);
+  return true;
+}
+
+void NtlmBufferWriter::SetCursor(size_t cursor) {
+  DCHECK(GetBufferPtr() && cursor <= GetLength());
+
+  cursor_ = cursor;
+}
+
+}  // namespace ntlm
+}  // namespace net
diff --git a/net/ntlm/ntlm_buffer_writer.h b/net/ntlm/ntlm_buffer_writer.h
new file mode 100644
index 0000000..067885d
--- /dev/null
+++ b/net/ntlm/ntlm_buffer_writer.h
@@ -0,0 +1,177 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NTLM_BUFFER_WRITER_H_
+#define NET_BASE_NTLM_BUFFER_WRITER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/ntlm/ntlm_constants.h"
+
+namespace net {
+namespace ntlm {
+
+// Supports various bounds checked low level buffer operations required by an
+// NTLM implementation.
+//
+// The class supports sequential write to an internally managed buffer. All
+// writes perform bounds checking to ensure enough space is remaining in the
+// buffer.
+//
+// The internal buffer is allocated in the constructor with size |buffer_len|
+// and owned by the class.
+//
+// Write* methods write the buffer at the current cursor position and perform
+// any necessary type conversion and provide the data in out params. After a
+// successful write the cursor position is advanced past the written field.
+//
+// Failed writes leave the internal cursor at the same position as before the
+// call.
+//
+// Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
+// Specification version 28.0 [1]. Additional NTLM reference [2].
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+// [2] http://davenport.sourceforge.net/ntlm.html
+class NET_EXPORT_PRIVATE NtlmBufferWriter {
+ public:
+  explicit NtlmBufferWriter(size_t buffer_len);
+  ~NtlmBufferWriter();
+
+  size_t GetLength() const { return buffer_len_; }
+  size_t GetCursor() const { return cursor_; }
+  bool IsEndOfBuffer() const { return cursor_ >= GetLength(); }
+
+  // Gets a base::StringPiece view over the entire buffer.
+  base::StringPiece GetBuffer() const {
+    return base::StringPiece(reinterpret_cast<const char*>(buffer_.get()),
+                             buffer_len_);
+  }
+
+  // Returns true if there are |len| more bytes between the current cursor
+  // position and the end of the buffer.
+  bool CanWrite(size_t len) const;
+
+  // Writes a 16 bit unsigned value (little endian). If there are not 16
+  // more bits available in the buffer, it returns false.
+  bool WriteUInt16(uint16_t value) WARN_UNUSED_RESULT;
+
+  // Writes a 32 bit unsigned value (little endian). If there are not 32
+  // more bits available in the buffer, it returns false.
+  bool WriteUInt32(uint32_t value) WARN_UNUSED_RESULT;
+
+  // Writes a 64 bit unsigned value (little endian). If there are not 64
+  // more bits available in the buffer, it returns false.
+  bool WriteUInt64(uint64_t value) WARN_UNUSED_RESULT;
+
+  // Writes flags as a 32 bit unsigned value (little endian).
+  bool WriteFlags(NegotiateFlags flags) WARN_UNUSED_RESULT;
+
+  // Writes |len| bytes from |buffer|. If there are not |len| more bytes in
+  // the buffer, it returns false.
+  bool WriteBytes(const uint8_t* buffer, size_t len) WARN_UNUSED_RESULT;
+
+  // Writes the bytes from the |base::StringPiece|. If there are not enough
+  // bytes in the buffer, it returns false.
+  bool WriteBytes(base::StringPiece bytes) WARN_UNUSED_RESULT;
+
+  // Writes |count| bytes of zeros to the buffer. If there are not |count|
+  // more bytes in available in the buffer, it returns false.
+  bool WriteZeros(size_t count) WARN_UNUSED_RESULT;
+
+  // A security buffer is an 8 byte structure that defines the offset and
+  // length of a payload (string, struct, or byte array) that appears after
+  // the fixed part of the message.
+  //
+  // The structure in the NTLM message is (little endian fields):
+  //     uint16 - |length| Length of payload
+  //     uint16 - Allocation (ignored and always set to |length|)
+  //     uint32 - |offset| Offset from start of message
+  bool WriteSecurityBuffer(SecurityBuffer sec_buf) WARN_UNUSED_RESULT;
+
+  // Writes a string of 8 bit characters to the buffer.
+  //
+  // When Unicode was not negotiated only the hostname string will go through
+  // this code path. The 8 bit bytes of the hostname are written to the buffer.
+  // The encoding is not relevant.
+  bool WriteUtf8String(const std::string& str) WARN_UNUSED_RESULT;
+
+  // Converts the 16 bit characters to UTF8 and writes the resulting 8 bit
+  // characters.
+  //
+  // If Unicode was not negotiated, the username and domain get converted to
+  // UTF8 in the message. Since they are just treated as additional bytes
+  // input to hash the encoding doesn't matter. In practice, only a very old or
+  // non-Windows server might trigger this code path since we always attempt
+  // to negotiate Unicode and servers are supposed to honor that request.
+  bool WriteUtf16AsUtf8String(const base::string16& str) WARN_UNUSED_RESULT;
+
+  // Treats |str| as UTF8, converts to UTF-16 and writes it with little-endian
+  // byte order to the buffer.
+  //
+  // Two specific strings go through this code path.
+  //
+  // One case is the hostname. When the the Unicode flag has been set during
+  // negotiation, the hostname needs to appear in the message with 16-bit
+  // characters.
+  //
+  // The other case is the Service Principal Name (SPN). With Extended
+  // Protection for Authentication (EPA) enabled, it appears in the target info
+  // inside an AV Pair, where strings always have 16-bit characters.
+  bool WriteUtf8AsUtf16String(const std::string& str) WARN_UNUSED_RESULT;
+
+  // Writes UTF-16 LE characters to the buffer. For these strings, such as
+  // username and the domain the actual encoding isn't important; they are just
+  // treated as additional bytes of input to the hash.
+  bool WriteUtf16String(const base::string16& str) WARN_UNUSED_RESULT;
+
+  // Writes the 8 byte NTLM signature "NTLMSSP\0" into the buffer.
+  bool WriteSignature() WARN_UNUSED_RESULT;
+
+  // There are 3 message types Negotiate (sent by client), Challenge (sent by
+  // server), and Authenticate (sent by client).
+  //
+  // This writes |message_type| as a uint32_t into the buffer.
+  bool WriteMessageType(MessageType message_type) WARN_UNUSED_RESULT;
+
+  // Performs |WriteSignature| then |WriteMessageType|.
+  bool WriteMessageHeader(MessageType message_type) WARN_UNUSED_RESULT;
+
+ private:
+  // Writes |sizeof(T)| bytes little-endian of an integer type to the buffer.
+  template <typename T>
+  bool WriteUInt(T value);
+
+  // Sets the cursor position. The caller should use |GetLength| or
+  // |CanWrite| to verify the bounds before calling this method.
+  void SetCursor(size_t cursor);
+
+  // Advances the cursor by |count|. The caller should use |GetLength| or
+  // |CanWrite| to verify the bounds before calling this method.
+  void AdvanceCursor(size_t count) { SetCursor(GetCursor() + count); }
+
+  // Returns a pointer to the start of the buffer.
+  uint8_t* GetBufferPtr() const { return buffer_.get(); }
+
+  // Returns pointer into the buffer at the current cursor location.
+  uint8_t* GetBufferPtrAtCursor() const { return buffer_.get() + GetCursor(); }
+
+  std::unique_ptr<uint8_t[]> buffer_;
+  size_t buffer_len_;
+  size_t cursor_;
+
+  DISALLOW_COPY_AND_ASSIGN(NtlmBufferWriter);
+};
+
+}  // namespace ntlm
+}  // namespace net
+
+#endif  // NET_BASE_NTLM_BUFFER_WRITER_H_
diff --git a/net/ntlm/ntlm_buffer_writer_unittest.cc b/net/ntlm/ntlm_buffer_writer_unittest.cc
new file mode 100644
index 0000000..3616b9f
--- /dev/null
+++ b/net/ntlm/ntlm_buffer_writer_unittest.cc
@@ -0,0 +1,235 @@
+// 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 "net/ntlm/ntlm_buffer_writer.h"
+
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace ntlm {
+
+namespace {
+
+// Helper method to hide all the ugly casting.
+const uint8_t* GetBufferPtr(const NtlmBufferWriter& writer) {
+  return reinterpret_cast<const uint8_t*>(writer.GetBuffer().data());
+}
+
+// Helper method to get a byte at a specific index in the buffer.
+uint8_t GetByteFromBuffer(const NtlmBufferWriter& writer, size_t index) {
+  base::StringPiece piece(writer.GetBuffer());
+  EXPECT_TRUE(index < piece.length());
+  return static_cast<uint8_t>(piece.data()[index]);
+}
+
+}  // namespace
+
+TEST(NtlmBufferWriterTest, Initialization) {
+  NtlmBufferWriter writer(1);
+
+  ASSERT_EQ(1u, writer.GetLength());
+  ASSERT_EQ(1u, writer.GetBuffer().length());
+  ASSERT_EQ(0u, writer.GetCursor());
+  ASSERT_FALSE(writer.IsEndOfBuffer());
+  ASSERT_TRUE(writer.CanWrite(1));
+  ASSERT_FALSE(writer.CanWrite(2));
+}
+
+TEST(NtlmBufferWriterTest, Write16) {
+  uint8_t expected[2] = {0x22, 0x11};
+  const uint16_t value = 0x1122;
+
+  NtlmBufferWriter writer(sizeof(uint16_t));
+
+  ASSERT_TRUE(writer.WriteUInt16(value));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+  ASSERT_EQ(arraysize(expected), writer.GetLength());
+  ASSERT_FALSE(writer.WriteUInt16(value));
+
+  ASSERT_EQ(0,
+            memcmp(expected, writer.GetBuffer().data(), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, Write16PastEob) {
+  NtlmBufferWriter writer(sizeof(uint16_t) - 1);
+
+  ASSERT_FALSE(writer.WriteUInt16(0));
+  ASSERT_EQ(0u, writer.GetCursor());
+}
+
+TEST(NtlmBufferWriterTest, Write32) {
+  uint8_t expected[4] = {0x44, 0x33, 0x22, 0x11};
+  const uint32_t value = 0x11223344;
+
+  NtlmBufferWriter writer(sizeof(uint32_t));
+
+  ASSERT_TRUE(writer.WriteUInt32(value));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+  ASSERT_FALSE(writer.WriteUInt32(value));
+
+  ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, Write32PastEob) {
+  NtlmBufferWriter writer(sizeof(uint32_t) - 1);
+
+  ASSERT_FALSE(writer.WriteUInt32(0));
+  ASSERT_EQ(0u, writer.GetCursor());
+}
+
+TEST(NtlmBufferWriterTest, Write64) {
+  uint8_t expected[8] = {0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+  const uint64_t value = 0x1122334455667788;
+
+  NtlmBufferWriter writer(sizeof(uint64_t));
+
+  ASSERT_TRUE(writer.WriteUInt64(value));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+  ASSERT_FALSE(writer.WriteUInt64(value));
+
+  ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, Write64PastEob) {
+  NtlmBufferWriter writer(sizeof(uint64_t) - 1);
+
+  ASSERT_FALSE(writer.WriteUInt64(0));
+  ASSERT_EQ(0u, writer.GetCursor());
+}
+
+TEST(NtlmBufferWriterTest, WriteBytes) {
+  uint8_t expected[8] = {0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+
+  NtlmBufferWriter writer(arraysize(expected));
+
+  ASSERT_TRUE(writer.WriteBytes(expected, arraysize(expected)));
+  ASSERT_EQ(0, memcmp(GetBufferPtr(writer), expected, arraysize(expected)));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+  ASSERT_FALSE(writer.WriteBytes(expected, 1));
+
+  ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteBytesPastEob) {
+  uint8_t buffer[8];
+
+  NtlmBufferWriter writer(arraysize(buffer) - 1);
+
+  ASSERT_FALSE(writer.WriteBytes(buffer, arraysize(buffer)));
+}
+
+TEST(NtlmBufferWriterTest, WriteSecurityBuffer) {
+  uint8_t expected[8] = {0x22, 0x11, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55};
+  uint16_t length = 0x1122;
+  uint32_t offset = 0x55667788;
+
+  NtlmBufferWriter writer(kSecurityBufferLen);
+
+  ASSERT_TRUE(writer.WriteSecurityBuffer(SecurityBuffer(offset, length)));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+  ASSERT_FALSE(writer.WriteSecurityBuffer(SecurityBuffer(offset, length)));
+
+  ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteSecurityBufferPastEob) {
+  SecurityBuffer sec_buf;
+  NtlmBufferWriter writer(kSecurityBufferLen - 1);
+
+  ASSERT_FALSE(writer.WriteSecurityBuffer(sec_buf));
+}
+
+TEST(NtlmBufferWriterTest, WriteNarrowString) {
+  uint8_t expected[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
+  std::string value("12345678");
+
+  NtlmBufferWriter writer(value.size());
+
+  ASSERT_TRUE(writer.WriteUtf8String(value));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+  ASSERT_FALSE(writer.WriteUtf8String(value));
+
+  ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteAsciiStringPastEob) {
+  std::string str("12345678");
+  NtlmBufferWriter writer(str.length() - 1);
+
+  ASSERT_FALSE(writer.WriteUtf8String(str));
+}
+
+TEST(NtlmBufferWriterTest, WriteUtf16String) {
+  uint8_t expected[16] = {'1', 0, '2', 0, '3', 0, '4', 0,
+                          '5', 0, '6', 0, '7', 0, '8', 0};
+  base::string16 value = base::ASCIIToUTF16("12345678");
+
+  NtlmBufferWriter writer(value.size() * 2);
+
+  ASSERT_TRUE(writer.WriteUtf16String(value));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+  ASSERT_FALSE(writer.WriteUtf16String(value));
+
+  ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteUtf16StringPastEob) {
+  base::string16 str = base::ASCIIToUTF16("12345678");
+  NtlmBufferWriter writer((str.length() * 2) - 1);
+
+  ASSERT_FALSE(writer.WriteUtf16String(str));
+}
+
+TEST(NtlmBufferWriterTest, WriteUtf8AsUtf16String) {
+  uint8_t expected[16] = {'1', 0, '2', 0, '3', 0, '4', 0,
+                          '5', 0, '6', 0, '7', 0, '8', 0};
+  std::string input = "12345678";
+
+  NtlmBufferWriter writer(input.size() * 2);
+
+  ASSERT_TRUE(writer.WriteUtf8AsUtf16String(input));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+  ASSERT_FALSE(writer.WriteUtf8AsUtf16String(input));
+
+  ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteSignature) {
+  uint8_t expected[8] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
+  NtlmBufferWriter writer(kSignatureLen);
+
+  ASSERT_TRUE(writer.WriteSignature());
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+
+  ASSERT_EQ(0, memcmp(expected, GetBufferPtr(writer), arraysize(expected)));
+}
+
+TEST(NtlmBufferWriterTest, WriteSignaturePastEob) {
+  NtlmBufferWriter writer(1);
+
+  ASSERT_FALSE(writer.WriteSignature());
+}
+
+TEST(NtlmBufferWriterTest, WriteMessageType) {
+  NtlmBufferWriter writer(4);
+
+  ASSERT_TRUE(writer.WriteMessageType(MessageType::kNegotiate));
+  ASSERT_TRUE(writer.IsEndOfBuffer());
+  ASSERT_EQ(static_cast<uint32_t>(MessageType::kNegotiate),
+            GetByteFromBuffer(writer, 0));
+  ASSERT_EQ(0, GetByteFromBuffer(writer, 1));
+  ASSERT_EQ(0, GetByteFromBuffer(writer, 2));
+  ASSERT_EQ(0, GetByteFromBuffer(writer, 3));
+}
+
+TEST(NtlmBufferWriterTest, WriteMessageTypePastEob) {
+  NtlmBufferWriter writer(sizeof(uint32_t) - 1);
+
+  ASSERT_FALSE(writer.WriteMessageType(MessageType::kNegotiate));
+}
+
+}  // namespace ntlm
+}  // namespace net
diff --git a/net/ntlm/ntlm_constants.h b/net/ntlm/ntlm_constants.h
new file mode 100644
index 0000000..8dc6bb3c
--- /dev/null
+++ b/net/ntlm/ntlm_constants.h
@@ -0,0 +1,91 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NTLM_CONSTANTS_H_
+#define NET_BASE_NTLM_CONSTANTS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <type_traits>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+
+namespace net {
+namespace ntlm {
+
+// A security buffer is a structure within an NTLM message that indicates
+// the offset from the beginning of the message and the length of a payload
+// that occurs later in the message. Within the raw message there is also
+// an additional field, however the field is always written with the same
+// value as length, and readers must always ignore it.
+struct SecurityBuffer {
+  SecurityBuffer(uint32_t offset, uint16_t length)
+      : offset(offset), length(length) {}
+  SecurityBuffer() : SecurityBuffer(0, 0) {}
+
+  uint32_t offset;
+  uint16_t length;
+};
+
+enum class NtlmVersion {
+  kNtlmV1 = 0x01,
+  kNtlmV2 = 0x02,
+};
+
+// There are 3 types of messages in NTLM. The message type is a field in
+// every NTLM message header.
+enum class MessageType : uint32_t {
+  kNegotiate = 0x01,
+  kChallenge = 0x02,
+  kAuthenticate = 0x03,
+};
+
+// Defined in [MS-NLMP] Section 2.2.2.5
+// Only the used subset is defined.
+enum class NegotiateFlags : uint32_t {
+  kNone = 0,
+  kUnicode = 0x01,
+  kOem = 0x02,
+  kRequestTarget = 0x04,
+  kNtlm = 0x200,
+  kAlwaysSign = 0x8000,
+  kExtendedSessionSecurity = 0x80000,
+};
+
+constexpr inline NegotiateFlags operator|(NegotiateFlags lhs,
+                                          NegotiateFlags rhs) {
+  using TFlagsInt = std::underlying_type<NegotiateFlags>::type;
+
+  return static_cast<NegotiateFlags>(static_cast<TFlagsInt>(lhs) |
+                                     static_cast<TFlagsInt>(rhs));
+}
+
+constexpr inline NegotiateFlags operator&(NegotiateFlags lhs,
+                                          NegotiateFlags rhs) {
+  using TFlagsInt = std::underlying_type<NegotiateFlags>::type;
+
+  return static_cast<NegotiateFlags>(static_cast<TFlagsInt>(lhs) &
+                                     static_cast<TFlagsInt>(rhs));
+}
+
+static constexpr uint8_t kSignature[] = "NTLMSSP";
+static constexpr size_t kSignatureLen = arraysize(kSignature);
+static constexpr size_t kSecurityBufferLen =
+    (2 * sizeof(uint16_t)) + sizeof(uint32_t);
+static constexpr size_t kNegotiateMessageLen = 32;
+static constexpr size_t kChallengeHeaderLen = 32;
+static constexpr size_t kResponseLenV1 = 24;
+static constexpr size_t kChallengeLen = 8;
+static constexpr size_t kNtlmHashLen = 16;
+
+static constexpr NegotiateFlags kNegotiateMessageFlags =
+    NegotiateFlags::kUnicode | NegotiateFlags::kOem |
+    NegotiateFlags::kRequestTarget | NegotiateFlags::kNtlm |
+    NegotiateFlags::kAlwaysSign | NegotiateFlags::kExtendedSessionSecurity;
+
+}  // namespace ntlm
+}  // namespace net
+
+#endif  // NET_BASE_NTLM_CONSTANTS_H_
\ No newline at end of file
diff --git a/net/ntlm/ntlm_test_data.h b/net/ntlm/ntlm_test_data.h
new file mode 100644
index 0000000..2a9913b7
--- /dev/null
+++ b/net/ntlm/ntlm_test_data.h
@@ -0,0 +1,81 @@
+// 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.
+
+// This file contains common input and result values use to verify the NTLM
+// implementation. They are defined in [MS-NLMP] Section 4.2 [1].
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+
+#ifndef NET_BASE_NTLM_TEST_DATA_H_
+#define NET_BASE_NTLM_TEST_DATA_H_
+
+#include "net/ntlm/ntlm_constants.h"
+
+namespace net {
+namespace ntlm {
+namespace test {
+
+// Common input values defined in [MS-NLMP] Section 4.2.1.
+constexpr base::char16 kPassword[] = {'P', 'a', 's', 's', 'w',
+                                      'o', 'r', 'd', '\0'};
+constexpr base::char16 kNtlmDomain[] = {'D', 'o', 'm', 'a', 'i', 'n', '\0'};
+constexpr base::char16 kUser[] = {'U', 's', 'e', 'r', '\0'};
+constexpr base::char16 kHostname[] = {'C', 'O', 'M', 'P', 'U',
+                                      'T', 'E', 'R', '\0'};
+
+// ASCII Versions of the above strings.
+constexpr char kNtlmDomainAscii[] = "Domain";
+constexpr char kUserAscii[] = "User";
+constexpr char kHostnameAscii[] = "COMPUTER";
+
+// Challenge vectors defined in [MS-NLMP] Section 4.2.1.
+constexpr uint8_t kServerChallenge[kChallengeLen] = {0x01, 0x23, 0x45, 0x67,
+                                                     0x89, 0xab, 0xcd, 0xef};
+constexpr uint8_t kClientChallenge[kChallengeLen] = {0xaa, 0xaa, 0xaa, 0xaa,
+                                                     0xaa, 0xaa, 0xaa, 0xaa};
+
+// A minimal challenge message for tests. For NTLMv1 this implementation only
+// reads the smallest required version of the message (32 bytes). Some
+// servers may still send messages this small. The only relevant flags
+// that affect behavior are that both NTLMSSP_NEGOTIATE_UNICODE and
+// NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are set.
+//
+// [0-7]    - "NTLMSSP\0"                       (Signature)
+// [9-11]   - |MessageType::kChallenge|          (Message Type = 0x00000002)
+// [12-19]  - |SecBuf(kNegotiateMessageLen, 0)|(Target Name - Not Used)
+// [20-23]  - |NEGOTIATE_MESSAGE_FLAGS|         (Flags = 0x00088207)
+// [24-31]  - |SERVER_CHALLENGE|                (Server Challenge)
+//
+// See [MS-NLMP] Section 2.2.2.2 for more information about the Challenge
+// message.
+constexpr uint8_t kMinChallengeMessage[kChallengeHeaderLen] = {
+    'N',  'T',  'L',  'M',  'S',  'S',  'P',  '\0', 0x02, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x82,
+    0x08, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+
+// Test result value for NTOWFv1() defined in [MS-NLMP] Section 4.2.2.1.2.
+constexpr uint8_t kExpectedNtlmHashV1[kNtlmHashLen] = {
+    0xa4, 0xf4, 0x9c, 0x40, 0x65, 0x10, 0xbd, 0xca,
+    0xb6, 0x82, 0x4e, 0xe7, 0xc3, 0x0f, 0xd8, 0x52};
+
+// Test result value defined in [MS-NLMP] Section 4.2.2.1.
+constexpr uint8_t kExpectedNtlmResponseV1[kResponseLenV1] = {
+    0x67, 0xc4, 0x30, 0x11, 0xf3, 0x02, 0x98, 0xa2, 0xad, 0x35, 0xec, 0xe6,
+    0x4f, 0x16, 0x33, 0x1c, 0x44, 0xbd, 0xbe, 0xd9, 0x27, 0x84, 0x1f, 0x94};
+
+// Test result value defined in [MS-NLMP] Section 4.2.3.2.2.
+constexpr uint8_t kExpectedNtlmResponseWithV1SS[kResponseLenV1] = {
+    0x75, 0x37, 0xf8, 0x03, 0xae, 0x36, 0x71, 0x28, 0xca, 0x45, 0x82, 0x04,
+    0xbd, 0xe7, 0xca, 0xf8, 0x1e, 0x97, 0xed, 0x26, 0x83, 0x26, 0x72, 0x32};
+
+// Test result value defined in [MS-NLMP] Section 4.2.3.2.1.
+constexpr uint8_t kExpectedLmResponseWithV1SS[kResponseLenV1] = {
+    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+}  // namespace test
+}  // namespace ntlm
+}  // namespace net
+
+#endif  // NET_BASE_NTLM_TEST_DATA_H_
\ No newline at end of file
diff --git a/net/ntlm/ntlm_unittest.cc b/net/ntlm/ntlm_unittest.cc
new file mode 100644
index 0000000..6c40d16a
--- /dev/null
+++ b/net/ntlm/ntlm_unittest.cc
@@ -0,0 +1,120 @@
+// 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.
+
+// Tests on exact results from cryptographic operations are based on test data
+// provided in [MS-NLMP] Version 28.0 [1] Section 4.2.
+//
+// Additional sanity checks on the low level hashing operations test for
+// properties of the outputs, such as whether the hashes change, whether they
+// should be zeroed out, or whether they should be the same or different.
+//
+// [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
+
+#include "net/ntlm/ntlm.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "net/ntlm/ntlm_test_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace ntlm {
+
+TEST(NtlmTest, GenerateNtlmHashV1PasswordSpecTests) {
+  uint8_t hash[kNtlmHashLen];
+  GenerateNtlmHashV1(test::kPassword, hash);
+  ASSERT_EQ(0, memcmp(hash, test::kExpectedNtlmHashV1, kNtlmHashLen));
+}
+
+TEST(NtlmTest, GenerateNtlmHashV1PasswordChangesHash) {
+  base::string16 password1 = base::UTF8ToUTF16("pwd01");
+  base::string16 password2 = base::UTF8ToUTF16("pwd02");
+  uint8_t hash1[kNtlmHashLen];
+  uint8_t hash2[kNtlmHashLen];
+
+  GenerateNtlmHashV1(password1, hash1);
+  GenerateNtlmHashV1(password2, hash2);
+
+  // Verify that the hash is different with a different password.
+  ASSERT_NE(0, memcmp(hash1, hash2, kNtlmHashLen));
+}
+
+TEST(NtlmTest, GenerateResponsesV1SpecTests) {
+  uint8_t lm_response[kResponseLenV1];
+  uint8_t ntlm_response[kResponseLenV1];
+  GenerateResponsesV1(test::kPassword, test::kServerChallenge, lm_response,
+                      ntlm_response);
+
+  ASSERT_EQ(
+      0, memcmp(test::kExpectedNtlmResponseV1, ntlm_response, kResponseLenV1));
+
+  // This implementation never sends an LMv1 response (spec equivalent of the
+  // client variable NoLMResponseNTLMv1 being false) so the LM response is
+  // equal to the NTLM response when
+  // NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY is not negotiated. See
+  // [MS-NLMP] Section 3.3.1.
+  ASSERT_EQ(0,
+            memcmp(test::kExpectedNtlmResponseV1, lm_response, kResponseLenV1));
+}
+
+TEST(NtlmTest, GenerateResponsesV1WithSessionSecuritySpecTests) {
+  uint8_t lm_response[kResponseLenV1];
+  uint8_t ntlm_response[kResponseLenV1];
+  GenerateResponsesV1WithSessionSecurity(
+      test::kPassword, test::kServerChallenge, test::kClientChallenge,
+      lm_response, ntlm_response);
+
+  ASSERT_EQ(0, memcmp(test::kExpectedLmResponseWithV1SS, lm_response,
+                      kResponseLenV1));
+  ASSERT_EQ(0, memcmp(test::kExpectedNtlmResponseWithV1SS, ntlm_response,
+                      kResponseLenV1));
+}
+
+TEST(NtlmTest, GenerateResponsesV1WithSessionSecurityClientChallengeUsed) {
+  uint8_t lm_response1[kResponseLenV1];
+  uint8_t lm_response2[kResponseLenV1];
+  uint8_t ntlm_response1[kResponseLenV1];
+  uint8_t ntlm_response2[kResponseLenV1];
+  uint8_t client_challenge1[kChallengeLen];
+  uint8_t client_challenge2[kChallengeLen];
+
+  memset(client_challenge1, 0x01, kChallengeLen);
+  memset(client_challenge2, 0x02, kChallengeLen);
+
+  GenerateResponsesV1WithSessionSecurity(
+      test::kPassword, test::kServerChallenge, client_challenge1, lm_response1,
+      ntlm_response1);
+  GenerateResponsesV1WithSessionSecurity(
+      test::kPassword, test::kServerChallenge, client_challenge2, lm_response2,
+      ntlm_response2);
+
+  // The point of session security is that the client can introduce some
+  // randomness, so verify different client_challenge gives a different result.
+  ASSERT_NE(0, memcmp(lm_response1, lm_response2, kResponseLenV1));
+  ASSERT_NE(0, memcmp(ntlm_response1, ntlm_response2, kResponseLenV1));
+
+  // With session security the lm and ntlm hash should be different.
+  ASSERT_NE(0, memcmp(lm_response1, ntlm_response1, kResponseLenV1));
+  ASSERT_NE(0, memcmp(lm_response2, ntlm_response2, kResponseLenV1));
+}
+
+TEST(NtlmTest, GenerateResponsesV1WithSessionSecurityVerifySSUsed) {
+  uint8_t lm_response1[kResponseLenV1];
+  uint8_t lm_response2[kResponseLenV1];
+  uint8_t ntlm_response1[kResponseLenV1];
+  uint8_t ntlm_response2[kResponseLenV1];
+
+  GenerateResponsesV1WithSessionSecurity(
+      test::kPassword, test::kServerChallenge, test::kClientChallenge,
+      lm_response1, ntlm_response1);
+  GenerateResponsesV1(test::kPassword, test::kServerChallenge, lm_response2,
+                      ntlm_response2);
+
+  // Verify that the responses with session security are not the
+  // same as without it.
+  ASSERT_NE(0, memcmp(lm_response1, lm_response2, kResponseLenV1));
+  ASSERT_NE(0, memcmp(ntlm_response1, ntlm_response2, kResponseLenV1));
+}
+
+}  // namespace ntlm
+}  // namespace net
\ No newline at end of file
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc
index 4f6c889..99a1280 100644
--- a/net/quic/core/quic_connection.cc
+++ b/net/quic/core/quic_connection.cc
@@ -2441,23 +2441,9 @@
   sent_packet_manager_.SetStreamNotifier(stream_notifier);
 }
 
-void QuicConnection::SetDelegateSavesData(bool delegate_saves_data) {
-  packet_generator_.SetDelegateSavesData(delegate_saves_data);
-}
-
-void QuicConnection::SaveStreamData(QuicStreamId id,
-                                    QuicIOVector iov,
-                                    size_t iov_offset,
-                                    QuicStreamOffset offset,
-                                    QuicByteCount data_length) {
-  visitor_->SaveStreamData(id, iov, iov_offset, offset, data_length);
-}
-
-bool QuicConnection::WriteStreamData(QuicStreamId id,
-                                     QuicStreamOffset offset,
-                                     QuicByteCount data_length,
-                                     QuicDataWriter* writer) {
-  return visitor_->WriteStreamData(id, offset, data_length, writer);
+void QuicConnection::SetDataProducer(
+    QuicStreamFrameDataProducer* data_producer) {
+  framer_.set_data_producer(data_producer);
 }
 
 }  // namespace net
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h
index 4d081cc..6ed6622 100644
--- a/net/quic/core/quic_connection.h
+++ b/net/quic/core/quic_connection.h
@@ -160,19 +160,6 @@
   // Called to ask if any streams are open in this visitor, excluding the
   // reserved crypto and headers stream.
   virtual bool HasOpenDynamicStreams() const = 0;
-
-  // Save |data_length| data starts at |iov_offset| in |iov|.
-  virtual void SaveStreamData(QuicStreamId id,
-                              QuicIOVector iov,
-                              size_t iov_offset,
-                              QuicStreamOffset offset,
-                              QuicByteCount data_length) = 0;
-
-  // Write |data_length| data with |offset| of stream |id| to |writer|.
-  virtual bool WriteStreamData(QuicStreamId id,
-                               QuicStreamOffset offset,
-                               QuicByteCount data_length,
-                               QuicDataWriter* writer) = 0;
 };
 
 // Interface which gets callbacks from the QuicConnection at interesting
@@ -477,17 +464,6 @@
   // QuicPacketCreator::DelegateInterface
   void OnSerializedPacket(SerializedPacket* packet) override;
 
-  // QuicStreamFrameDataProducer methods:
-  void SaveStreamData(QuicStreamId id,
-                      QuicIOVector iov,
-                      size_t iov_offset,
-                      QuicStreamOffset offset,
-                      QuicByteCount data_length) override;
-  bool WriteStreamData(QuicStreamId id,
-                       QuicStreamOffset offset,
-                       QuicByteCount data_length,
-                       QuicDataWriter* writer) override;
-
   // QuicSentPacketManager::NetworkChangeVisitor
   void OnCongestionChange() override;
   void OnPathDegrading() override;
@@ -686,10 +662,8 @@
   // Sets the stream notifer on the SentPacketManager.
   void SetStreamNotifier(StreamNotifierInterface* stream_notifier);
 
-  // Enable/disable delegate saves data in PacketCreator.
-  // TODO(fayang): Remove this method when deprecating
-  // quic_reloadable_flag_quic_stream_owns_data.
-  void SetDelegateSavesData(bool delegate_saves_data);
+  // Set data producer in framer.
+  void SetDataProducer(QuicStreamFrameDataProducer* data_producer);
 
   // Return the name of the cipher of the primary decrypter of the framer.
   const char* cipher_name() const { return framer_.decrypter()->cipher_name(); }
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc
index 009e8a2..ec9ebb4 100644
--- a/net/quic/core/quic_connection_test.cc
+++ b/net/quic/core/quic_connection_test.cc
@@ -825,9 +825,8 @@
     QuicPacketHeader header;
     QuicPacketCreatorPeer::FillPacketHeader(&peer_creator_, &header);
     char encrypted_buffer[kMaxPacketSize];
-    // TODO(fayang): Use data producer to produce data.
     size_t length = peer_framer_.BuildDataPacket(
-        header, frames, encrypted_buffer, kMaxPacketSize, nullptr);
+        header, frames, encrypted_buffer, kMaxPacketSize);
     DCHECK_GT(length, 0u);
 
     const size_t encrypted_length = peer_framer_.EncryptInPlace(
diff --git a/net/quic/core/quic_framer.cc b/net/quic/core/quic_framer.cc
index 590f1aec..b2f2912 100644
--- a/net/quic/core/quic_framer.cc
+++ b/net/quic/core/quic_framer.cc
@@ -140,7 +140,8 @@
       perspective_(perspective),
       validate_flags_(true),
       creation_time_(creation_time),
-      last_timestamp_(QuicTime::Delta::Zero()) {
+      last_timestamp_(QuicTime::Delta::Zero()),
+      data_producer_(nullptr) {
   DCHECK(!supported_versions.empty());
   quic_version_ = supported_versions_[0];
   decrypter_ = QuicMakeUnique<NullDecrypter>(perspective);
@@ -313,8 +314,7 @@
 size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header,
                                    const QuicFrames& frames,
                                    char* buffer,
-                                   size_t packet_length,
-                                   QuicStreamFrameDataProducer* data_producer) {
+                                   size_t packet_length) {
   QuicDataWriter writer(packet_length, buffer, perspective_, endianness());
   if (!AppendPacketHeader(header, &writer)) {
     QUIC_BUG << "AppendPacketHeader failed";
@@ -340,7 +340,7 @@
         break;
       case STREAM_FRAME:
         if (!AppendStreamFrame(*frame.stream_frame, no_stream_frame_length,
-                               &writer, data_producer)) {
+                               &writer)) {
           QUIC_BUG << "AppendStreamFrame failed";
           return 0;
         }
@@ -1793,8 +1793,7 @@
 
 bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame,
                                    bool no_stream_frame_length,
-                                   QuicDataWriter* writer,
-                                   QuicStreamFrameDataProducer* data_producer) {
+                                   QuicDataWriter* writer) {
   if (!AppendStreamId(GetStreamIdSize(frame.stream_id), frame.stream_id,
                       writer)) {
     QUIC_BUG << "Writing stream id size failed.";
@@ -1813,13 +1812,13 @@
     }
   }
 
-  if (data_producer != nullptr) {
+  if (data_producer_ != nullptr) {
     DCHECK_EQ(nullptr, frame.data_buffer);
     if (frame.data_length == 0) {
       return true;
     }
-    if (!data_producer->WriteStreamData(frame.stream_id, frame.offset,
-                                        frame.data_length, writer)) {
+    if (!data_producer_->WriteStreamData(frame.stream_id, frame.offset,
+                                         frame.data_length, writer)) {
       QUIC_BUG << "Writing frame data failed.";
       return false;
     }
@@ -2175,4 +2174,15 @@
   return quic_version_ > QUIC_VERSION_38 ? NETWORK_BYTE_ORDER : HOST_BYTE_ORDER;
 }
 
+void QuicFramer::SaveStreamData(QuicStreamId id,
+                                QuicIOVector iov,
+                                size_t iov_offset,
+                                QuicStreamOffset offset,
+                                QuicByteCount data_length) {
+  DCHECK_NE(nullptr, data_producer_);
+  if (data_producer_ != nullptr) {
+    data_producer_->SaveStreamData(id, iov, iov_offset, offset, data_length);
+  }
+}
+
 }  // namespace net
diff --git a/net/quic/core/quic_framer.h b/net/quic/core/quic_framer.h
index 5131bab..652f412 100644
--- a/net/quic/core/quic_framer.h
+++ b/net/quic/core/quic_framer.h
@@ -11,6 +11,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "net/quic/core/quic_iovector.h"
 #include "net/quic/core/quic_packets.h"
 #include "net/quic/platform/api/quic_endian.h"
 #include "net/quic/platform/api/quic_export.h"
@@ -242,8 +243,7 @@
   size_t BuildDataPacket(const QuicPacketHeader& header,
                          const QuicFrames& frames,
                          char* buffer,
-                         size_t packet_length,
-                         QuicStreamFrameDataProducer* data_producer);
+                         size_t packet_length);
 
   // Returns a new public reset packet.
   static std::unique_ptr<QuicEncryptedPacket> BuildPublicResetPacket(
@@ -264,8 +264,7 @@
                       QuicDataWriter* writer);
   bool AppendStreamFrame(const QuicStreamFrame& frame,
                          bool last_frame_in_packet,
-                         QuicDataWriter* writer,
-                         QuicStreamFrameDataProducer* data_producer);
+                         QuicDataWriter* writer);
 
   // SetDecrypter sets the primary decrypter, replacing any that already exists,
   // and takes ownership. If an alternative decrypter is in place then the
@@ -313,6 +312,14 @@
   // to ciphertext no larger than |ciphertext_size|.
   size_t GetMaxPlaintextSize(size_t ciphertext_size);
 
+  // Let data_producer_ save |data_length| data starts at |iov_offset| in |iov|.
+  // TODO(fayang): Remove this method when data is saved before it is consumed.
+  void SaveStreamData(QuicStreamId id,
+                      QuicIOVector iov,
+                      size_t iov_offset,
+                      QuicStreamOffset offset,
+                      QuicByteCount data_length);
+
   const std::string& detailed_error() { return detailed_error_; }
 
   // The minimum packet number length required to represent |packet_number|.
@@ -324,6 +331,9 @@
     quic_version_ = versions[0];
   }
 
+  // Returns true if data_producer_ is not null.
+  bool HasDataProducer() const { return data_producer_ != nullptr; }
+
   // Returns byte order to read/write integers and floating numbers.
   Endianness endianness() const;
 
@@ -333,6 +343,10 @@
 
   QuicTag last_version_tag() { return last_version_tag_; }
 
+  void set_data_producer(QuicStreamFrameDataProducer* data_producer) {
+    data_producer_ = data_producer;
+  }
+
  private:
   friend class test::QuicFramerPeer;
 
@@ -532,6 +546,10 @@
   // The diversification nonce from the last received packet.
   DiversificationNonce last_nonce_;
 
+  // If not null, framer asks data_producer_ to save and write stream frame
+  // data. Not owned.
+  QuicStreamFrameDataProducer* data_producer_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicFramer);
 };
 
diff --git a/net/quic/core/quic_packet_creator.cc b/net/quic/core/quic_packet_creator.cc
index 84413a9..b21e85ea 100644
--- a/net/quic/core/quic_packet_creator.cc
+++ b/net/quic/core/quic_packet_creator.cc
@@ -48,8 +48,7 @@
       latched_flag_no_stop_waiting_frames_(
           FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames),
       pending_padding_bytes_(0),
-      needs_full_padding_(false),
-      delegate_saves_data_(false) {
+      needs_full_padding_(false) {
   SetMaxPacketLength(kDefaultMaxPacketSize);
 }
 
@@ -208,11 +207,11 @@
       std::min<size_t>(BytesFree() - min_frame_size, data_size);
 
   bool set_fin = fin && bytes_consumed == data_size;  // Last frame.
-  if (delegate_saves_data_) {
+  if (framer_->HasDataProducer()) {
     *frame =
         QuicFrame(new QuicStreamFrame(id, set_fin, offset, bytes_consumed));
     if (bytes_consumed > 0) {
-      delegate_->SaveStreamData(id, iov, iov_offset, offset, bytes_consumed);
+      framer_->SaveStreamData(id, iov, iov_offset, offset, bytes_consumed);
     }
     return;
   }
@@ -338,12 +337,12 @@
 
   const bool set_fin = fin && (bytes_consumed == remaining_data_size);
   std::unique_ptr<QuicStreamFrame> frame;
-  if (delegate_saves_data_) {
+  if (framer_->HasDataProducer()) {
     frame = QuicMakeUnique<QuicStreamFrame>(id, set_fin, stream_offset,
                                             bytes_consumed);
     if (bytes_consumed > 0) {
-      delegate_->SaveStreamData(id, iov, iov_offset, stream_offset,
-                                bytes_consumed);
+      framer_->SaveStreamData(id, iov, iov_offset, stream_offset,
+                              bytes_consumed);
     }
   } else {
     UniqueStreamBuffer stream_buffer =
@@ -363,8 +362,7 @@
     return;
   }
   if (!framer_->AppendStreamFrame(*frame, /* no stream frame length */ true,
-                                  &writer,
-                                  delegate_saves_data_ ? delegate_ : nullptr)) {
+                                  &writer)) {
     QUIC_BUG << "AppendStreamFrame failed";
     return;
   }
@@ -455,9 +453,8 @@
   DCHECK_GE(max_plaintext_size_, packet_size_);
   // Use the packet_size_ instead of the buffer size to ensure smaller
   // packet sizes are properly used.
-  size_t length = framer_->BuildDataPacket(
-      header, queued_frames_, encrypted_buffer, packet_size_,
-      delegate_saves_data_ ? delegate_ : nullptr);
+  size_t length = framer_->BuildDataPacket(header, queued_frames_,
+                                           encrypted_buffer, packet_size_);
   if (length == 0) {
     QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames.";
     return;
@@ -631,7 +628,7 @@
     QuicIOVector iov,
     size_t iov_offset,
     const QuicStreamFrame& frame) const {
-  if (!delegate_saves_data_) {
+  if (!framer_->HasDataProducer()) {
     return frame.stream_id == kCryptoStreamId &&
            frame.data_length >= sizeof(kCHLO) &&
            strncmp(frame.data_buffer, reinterpret_cast<const char*>(&kCHLO),
diff --git a/net/quic/core/quic_packet_creator.h b/net/quic/core/quic_packet_creator.h
index b0500669..3911bea 100644
--- a/net/quic/core/quic_packet_creator.h
+++ b/net/quic/core/quic_packet_creator.h
@@ -32,8 +32,7 @@
  public:
   // A delegate interface for further processing serialized packet.
   class QUIC_EXPORT_PRIVATE DelegateInterface
-      : public QuicConnectionCloseDelegateInterface,
-        public QuicStreamFrameDataProducer {
+      : public QuicConnectionCloseDelegateInterface {
    public:
     ~DelegateInterface() override {}
     // Called when a packet is serialized. Delegate does not take the ownership
@@ -217,10 +216,6 @@
 
   QuicByteCount pending_padding_bytes() const { return pending_padding_bytes_; }
 
-  void set_delegate_saves_data(bool delegate_saves_data) {
-    delegate_saves_data_ = delegate_saves_data;
-  }
-
  private:
   friend class test::QuicPacketCreatorPeer;
 
@@ -320,10 +315,6 @@
   // bytes.
   bool needs_full_padding_;
 
-  // Indicates whether frame data is saved by delegate_. TODO(fayang): Remove
-  // this boolean when deprecating quic_reloadable_flag_quic_stream_owns_data.
-  bool delegate_saves_data_;
-
   DISALLOW_COPY_AND_ASSIGN(QuicPacketCreator);
 };
 
diff --git a/net/quic/core/quic_packet_creator_test.cc b/net/quic/core/quic_packet_creator_test.cc
index 0499ba71..a71e3ef 100644
--- a/net/quic/core/quic_packet_creator_test.cc
+++ b/net/quic/core/quic_packet_creator_test.cc
@@ -43,24 +43,24 @@
   TestParams(QuicVersion version,
              bool version_serialization,
              QuicConnectionIdLength length,
-             bool delegate_saves_data)
+             bool framer_has_data_producer)
       : version(version),
         connection_id_length(length),
         version_serialization(version_serialization),
-        delegate_saves_data(delegate_saves_data) {}
+        framer_has_data_producer(framer_has_data_producer) {}
 
   friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
     os << "{ client_version: " << QuicVersionToString(p.version)
        << " connection id length: " << p.connection_id_length
        << " include version: " << p.version_serialization
-       << " delegate_saves_data: " << p.delegate_saves_data << " }";
+       << " framer_has_data_producer: " << p.framer_has_data_producer << " }";
     return os;
   }
 
   QuicVersion version;
   QuicConnectionIdLength connection_id_length;
   bool version_serialization;
-  bool delegate_saves_data;
+  bool framer_has_data_producer;
 };
 
 // Constructs various test permutations.
@@ -68,18 +68,18 @@
   std::vector<TestParams> params;
   constexpr QuicConnectionIdLength kMax = PACKET_8BYTE_CONNECTION_ID;
   QuicVersionVector all_supported_versions = AllSupportedVersions();
-  for (bool delegate_saves_data : {true, false}) {
+  for (bool framer_has_data_producer : {true, false}) {
     for (size_t i = 0; i < all_supported_versions.size(); ++i) {
       params.push_back(TestParams(all_supported_versions[i], true, kMax,
-                                  delegate_saves_data));
+                                  framer_has_data_producer));
       params.push_back(TestParams(all_supported_versions[i], false, kMax,
-                                  delegate_saves_data));
+                                  framer_has_data_producer));
     }
     params.push_back(TestParams(all_supported_versions[0], true,
                                 PACKET_0BYTE_CONNECTION_ID,
-                                delegate_saves_data));
-    params.push_back(
-        TestParams(all_supported_versions[0], true, kMax, delegate_saves_data));
+                                framer_has_data_producer));
+    params.push_back(TestParams(all_supported_versions[0], true, kMax,
+                                framer_has_data_producer));
   }
   return params;
 }
@@ -132,8 +132,8 @@
                           new NullEncrypter(Perspective::IS_CLIENT));
     client_framer_.set_visitor(&framer_visitor_);
     server_framer_.set_visitor(&framer_visitor_);
-    if (GetParam().delegate_saves_data) {
-      creator_.set_delegate_saves_data(true);
+    if (GetParam().framer_has_data_producer) {
+      client_framer_.set_data_producer(&producer_);
     }
   }
 
@@ -164,12 +164,12 @@
     EXPECT_EQ(STREAM_FRAME, frame.type);
     ASSERT_TRUE(frame.stream_frame);
     EXPECT_EQ(stream_id, frame.stream_frame->stream_id);
-    if (GetParam().delegate_saves_data) {
+    if (client_framer_.HasDataProducer()) {
       char buf[kMaxPacketSize];
       QuicDataWriter writer(kMaxPacketSize, buf, Perspective::IS_CLIENT,
                             HOST_BYTE_ORDER);
       if (frame.stream_frame->data_length > 0) {
-        delegate_.WriteStreamData(stream_id, frame.stream_frame->offset,
+        producer_.WriteStreamData(stream_id, frame.stream_frame->offset,
                                   frame.stream_frame->data_length, &writer);
       }
       EXPECT_EQ(data, QuicStringPiece(buf, frame.stream_frame->data_length));
@@ -233,6 +233,7 @@
   SimpleBufferAllocator buffer_allocator_;
   QuicPacketCreator creator_;
   SerializedPacket serialized_packet_;
+  SimpleDataProducer producer_;
 };
 
 // Run all packet creator tests with all supported versions of QUIC, and with
diff --git a/net/quic/core/quic_packet_generator.cc b/net/quic/core/quic_packet_generator.cc
index be882ce..7487cde 100644
--- a/net/quic/core/quic_packet_generator.cc
+++ b/net/quic/core/quic_packet_generator.cc
@@ -353,8 +353,4 @@
          packet_creator_.HasPendingRetransmittableFrames();
 }
 
-void QuicPacketGenerator::SetDelegateSavesData(bool delegate_saves_data) {
-  packet_creator_.set_delegate_saves_data(delegate_saves_data);
-}
-
 }  // namespace net
diff --git a/net/quic/core/quic_packet_generator.h b/net/quic/core/quic_packet_generator.h
index 1b04881..43bffc1 100644
--- a/net/quic/core/quic_packet_generator.h
+++ b/net/quic/core/quic_packet_generator.h
@@ -180,9 +180,6 @@
   // when there are frames queued in the creator.
   void SetMaxPacketLength(QuicByteCount length);
 
-  // Let delegate save stream data in creator.
-  void SetDelegateSavesData(bool delegate_saves_data);
-
   void set_debug_delegate(QuicPacketCreator::DebugDelegate* debug_delegate) {
     packet_creator_.set_debug_delegate(debug_delegate);
   }
diff --git a/net/quic/core/quic_packet_generator_test.cc b/net/quic/core/quic_packet_generator_test.cc
index 254098c..74a9801a 100644
--- a/net/quic/core/quic_packet_generator_test.cc
+++ b/net/quic/core/quic_packet_generator_test.cc
@@ -70,23 +70,7 @@
         .WillRepeatedly(Return(true));
   }
 
-  void SaveStreamData(QuicStreamId id,
-                      QuicIOVector iov,
-                      size_t iov_offset,
-                      QuicStreamOffset offset,
-                      QuicByteCount data_length) override {
-    producer_.SaveStreamData(id, iov, iov_offset, offset, data_length);
-  }
-  bool WriteStreamData(QuicStreamId id,
-                       QuicStreamOffset offset,
-                       QuicByteCount data_length,
-                       QuicDataWriter* writer) override {
-    return producer_.WriteStreamData(id, offset, data_length, writer);
-  }
-
  private:
-  SimpleDataProducer producer_;
-
   DISALLOW_COPY_AND_ASSIGN(MockDelegate);
 };
 
@@ -133,8 +117,9 @@
     creator_->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
                            new NullEncrypter(Perspective::IS_CLIENT));
     creator_->set_encryption_level(ENCRYPTION_FORWARD_SECURE);
-    generator_.SetDelegateSavesData(
-        FLAGS_quic_reloadable_flag_quic_stream_owns_data);
+    if (FLAGS_quic_reloadable_flag_quic_stream_owns_data) {
+      framer_.set_data_producer(&producer_);
+    }
   }
 
   ~QuicPacketGeneratorTest() override {
diff --git a/net/quic/core/quic_session.cc b/net/quic/core/quic_session.cc
index aaae090..4f7a0ab 100644
--- a/net/quic/core/quic_session.cc
+++ b/net/quic/core/quic_session.cc
@@ -57,7 +57,7 @@
     connection_->SetStreamNotifier(this);
   }
   if (streams_own_data_) {
-    connection_->SetDelegateSavesData(true);
+    connection_->SetDataProducer(this);
   }
   connection_->SetFromConfig(config_);
 
diff --git a/net/quic/core/quic_session.h b/net/quic/core/quic_session.h
index 141610f6..e52b2127 100644
--- a/net/quic/core/quic_session.h
+++ b/net/quic/core/quic_session.h
@@ -20,6 +20,7 @@
 #include "net/quic/core/quic_packet_creator.h"
 #include "net/quic/core/quic_packets.h"
 #include "net/quic/core/quic_stream.h"
+#include "net/quic/core/quic_stream_frame_data_producer.h"
 #include "net/quic/core/quic_write_blocked_list.h"
 #include "net/quic/core/stream_notifier_interface.h"
 #include "net/quic/platform/api/quic_containers.h"
@@ -37,7 +38,8 @@
 }  // namespace test
 
 class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
-                                        public StreamNotifierInterface {
+                                        public StreamNotifierInterface,
+                                        public QuicStreamFrameDataProducer {
  public:
   // An interface from the session to the entity owning the session.
   // This lets the session notify its owner (the Dispatcher) when the connection
@@ -107,6 +109,8 @@
   bool HasPendingHandshake() const override;
   bool HasOpenDynamicStreams() const override;
   void OnPathDegrading() override;
+
+  // QuicStreamFrameDataProducer methods:
   void SaveStreamData(QuicStreamId id,
                       QuicIOVector iov,
                       size_t iov_offset,
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 8edd8c7..09ff585 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -72,8 +72,7 @@
                                    const QuicFrames& frames,
                                    size_t packet_size) {
   char* buffer = new char[packet_size];
-  size_t length =
-      framer->BuildDataPacket(header, frames, buffer, packet_size, nullptr);
+  size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size);
   DCHECK_NE(0u, length);
   // Re-construct the data packet with data ownership.
   return new QuicPacket(buffer, length, /* owns_buffer */ true,
@@ -212,20 +211,6 @@
 
 MockQuicConnectionVisitor::~MockQuicConnectionVisitor() {}
 
-void MockQuicConnectionVisitor::SaveStreamData(QuicStreamId id,
-                                               QuicIOVector iov,
-                                               size_t iov_offset,
-                                               QuicStreamOffset offset,
-                                               QuicByteCount data_length) {
-  producer_.SaveStreamData(id, iov, iov_offset, offset, data_length);
-}
-bool MockQuicConnectionVisitor::WriteStreamData(QuicStreamId id,
-                                                QuicStreamOffset offset,
-                                                QuicByteCount data_length,
-                                                QuicDataWriter* writer) {
-  return producer_.WriteStreamData(id, offset, data_length, writer);
-}
-
 MockQuicConnectionHelper::MockQuicConnectionHelper() {}
 
 MockQuicConnectionHelper::~MockQuicConnectionHelper() {}
@@ -859,21 +844,6 @@
 MockPacketCreatorDelegate::MockPacketCreatorDelegate() {}
 MockPacketCreatorDelegate::~MockPacketCreatorDelegate() {}
 
-void MockPacketCreatorDelegate::SaveStreamData(QuicStreamId id,
-                                               QuicIOVector iov,
-                                               size_t iov_offset,
-                                               QuicStreamOffset offset,
-                                               QuicByteCount data_length) {
-  producer_.SaveStreamData(id, iov, iov_offset, offset, data_length);
-}
-
-bool MockPacketCreatorDelegate::WriteStreamData(QuicStreamId id,
-                                                QuicStreamOffset offset,
-                                                QuicByteCount data_length,
-                                                QuicDataWriter* writer) {
-  return producer_.WriteStreamData(id, offset, data_length, writer);
-}
-
 void CreateClientSessionForTest(QuicServerId server_id,
                                 bool supports_stateless_rejects,
                                 QuicTime::Delta connection_start_time,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index d74a8dc..414a9c01 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -296,19 +296,8 @@
   MOCK_METHOD0(OnConfigNegotiated, void());
   MOCK_METHOD0(PostProcessAfterData, void());
   MOCK_METHOD0(OnAckNeedsRetransmittableFrame, void());
-  void SaveStreamData(QuicStreamId id,
-                      QuicIOVector iov,
-                      size_t iov_offset,
-                      QuicStreamOffset offset,
-                      QuicByteCount data_length) override;
-  bool WriteStreamData(QuicStreamId id,
-                       QuicStreamOffset offset,
-                       QuicByteCount data_length,
-                       QuicDataWriter* writer) override;
 
  private:
-  SimpleDataProducer producer_;
-
   DISALLOW_COPY_AND_ASSIGN(MockQuicConnectionVisitor);
 };
 
@@ -958,19 +947,7 @@
                     const std::string&,
                     ConnectionCloseSource source));
 
-  void SaveStreamData(QuicStreamId id,
-                      QuicIOVector iov,
-                      size_t iov_offset,
-                      QuicStreamOffset offset,
-                      QuicByteCount data_length) override;
-  bool WriteStreamData(QuicStreamId id,
-                       QuicStreamOffset offset,
-                       QuicByteCount data_length,
-                       QuicDataWriter* writer) override;
-
  private:
-  SimpleDataProducer producer_;
-
   DISALLOW_COPY_AND_ASSIGN(MockPacketCreatorDelegate);
 };
 
diff --git a/net/quic/test_tools/simulator/quic_endpoint.cc b/net/quic/test_tools/simulator/quic_endpoint.cc
index f936be8..6e810d43 100644
--- a/net/quic/test_tools/simulator/quic_endpoint.cc
+++ b/net/quic/test_tools/simulator/quic_endpoint.cc
@@ -244,21 +244,6 @@
   }
 }
 
-void QuicEndpoint::SaveStreamData(QuicStreamId id,
-                                  QuicIOVector iov,
-                                  size_t iov_offset,
-                                  QuicStreamOffset offset,
-                                  QuicByteCount data_length) {
-  producer_.SaveStreamData(id, iov, iov_offset, offset, data_length);
-}
-
-bool QuicEndpoint::WriteStreamData(QuicStreamId id,
-                                   QuicStreamOffset offset,
-                                   QuicByteCount data_length,
-                                   QuicDataWriter* writer) {
-  return producer_.WriteStreamData(id, offset, data_length, writer);
-}
-
 QuicEndpointMultiplexer::QuicEndpointMultiplexer(
     string name,
     std::initializer_list<QuicEndpoint*> endpoints)
diff --git a/net/quic/test_tools/simulator/quic_endpoint.h b/net/quic/test_tools/simulator/quic_endpoint.h
index c96d79a..2c8a19e0 100644
--- a/net/quic/test_tools/simulator/quic_endpoint.h
+++ b/net/quic/test_tools/simulator/quic_endpoint.h
@@ -92,15 +92,6 @@
   void OnPathDegrading() override {}
   void PostProcessAfterData() override {}
   void OnAckNeedsRetransmittableFrame() override {}
-  void SaveStreamData(QuicStreamId id,
-                      QuicIOVector iov,
-                      size_t iov_offset,
-                      QuicStreamOffset offset,
-                      QuicByteCount data_length) override;
-  bool WriteStreamData(QuicStreamId id,
-                       QuicStreamOffset offset,
-                       QuicByteCount data_length,
-                       QuicDataWriter* writer) override;
   // End QuicConnectionVisitorInterface implementation.
 
  private:
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index ca33573..e37c7b0 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -921,6 +921,15 @@
     return ERR_UNEXPECTED;
   }
 
+  switch (ssl_config_.tls13_variant) {
+    case kTLS13VariantDraft:
+      SSL_set_tls13_variant(ssl_.get(), tls13_default);
+      break;
+    case kTLS13VariantExperiment:
+      SSL_set_tls13_variant(ssl_.get(), tls13_experiment);
+      break;
+  }
+
   // OpenSSL defaults some options to on, others to off. To avoid ambiguity,
   // set everything we care about to an absolute value.
   SslSetClearMask options;
diff --git a/net/ssl/ssl_config.cc b/net/ssl/ssl_config.cc
index 54d375e..89f8133 100644
--- a/net/ssl/ssl_config.cc
+++ b/net/ssl/ssl_config.cc
@@ -12,6 +12,8 @@
 
 const uint16_t kDefaultSSLVersionMax = SSL_PROTOCOL_VERSION_TLS1_2;
 
+const TLS13Variant kDefaultTLS13Variant = kTLS13VariantDraft;
+
 SSLConfig::CertAndStatus::CertAndStatus() = default;
 SSLConfig::CertAndStatus::CertAndStatus(scoped_refptr<X509Certificate> cert_arg,
                                         CertStatus status)
@@ -27,6 +29,7 @@
       common_name_fallback_local_anchors_enabled(true),
       version_min(kDefaultSSLVersionMin),
       version_max(kDefaultSSLVersionMax),
+      tls13_variant(kDefaultTLS13Variant),
       version_interference_probe(false),
       channel_id_enabled(true),
       false_start_enabled(true),
diff --git a/net/ssl/ssl_config.h b/net/ssl/ssl_config.h
index cb3a233..4a2a13b 100644
--- a/net/ssl/ssl_config.h
+++ b/net/ssl/ssl_config.h
@@ -35,12 +35,20 @@
   TB_PARAM_ECDSAP256 = 2,
 };
 
+enum TLS13Variant {
+  kTLS13VariantDraft = 0,
+  kTLS13VariantExperiment = 1,
+};
+
 // Default minimum protocol version.
 NET_EXPORT extern const uint16_t kDefaultSSLVersionMin;
 
 // Default maximum protocol version.
 NET_EXPORT extern const uint16_t kDefaultSSLVersionMax;
 
+// Default TLS 1.3 variant.
+NET_EXPORT extern const TLS13Variant kDefaultTLS13Variant;
+
 // A collection of SSL-related configuration settings.
 struct NET_EXPORT SSLConfig {
   // Default to revocation checking.
@@ -91,6 +99,10 @@
   uint16_t version_min;
   uint16_t version_max;
 
+  // The TLS 1.3 variant that is enabled. This only takes affect if TLS 1.3 is
+  // also enabled via version_min and version_max.
+  TLS13Variant tls13_variant;
+
   // Presorted list of cipher suites which should be explicitly prevented from
   // being used in addition to those disabled by the net built-in policy.
   //
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index cc17c80..aa6ef57 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -50,12 +50,14 @@
 
 // Collects packets serialized by a QuicPacketCreator in order
 // to be handed off to the time wait list manager.
-class PacketCollector : public QuicPacketCreator::DelegateInterface {
+class PacketCollector : public QuicPacketCreator::DelegateInterface,
+                        public QuicStreamFrameDataProducer {
  public:
   explicit PacketCollector(QuicBufferAllocator* allocator)
       : send_buffer_(allocator) {}
   ~PacketCollector() override {}
 
+  // QuicPacketCreator::DelegateInterface methods:
   void OnSerializedPacket(SerializedPacket* serialized_packet) override {
     // Make a copy of the serialized packet to send later.
     packets_.push_back(std::unique_ptr<QuicEncryptedPacket>(
@@ -70,6 +72,7 @@
                             const string& error_details,
                             ConnectionCloseSource source) override {}
 
+  // QuicStreamFrameDataProducer methods:
   void SaveStreamData(QuicStreamId id,
                       QuicIOVector iov,
                       size_t iov_offset,
@@ -114,7 +117,18 @@
                  framer,
                  helper->GetBufferAllocator(),
                  &collector_),
-        time_wait_list_manager_(time_wait_list_manager) {}
+        time_wait_list_manager_(time_wait_list_manager) {
+    if (FLAGS_quic_reloadable_flag_quic_stream_owns_data) {
+      framer_->set_data_producer(&collector_);
+    }
+  }
+
+  ~StatelessConnectionTerminator() {
+    if (framer_->HasDataProducer()) {
+      // Clear framer's producer.
+      framer_->set_data_producer(nullptr);
+    }
+  }
 
   // Generates a packet containing a CONNECTION_CLOSE frame specifying
   // |error_code| and |error_details| and add the connection to time wait.
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 32dd01f..a02001ba 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -15,11 +15,13 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/rand_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
@@ -1509,6 +1511,10 @@
   UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTime", total_time);
 
   if (reason == FINISHED) {
+    UmaHistogramTimes(
+        base::StringPrintf("Net.HttpJob.TotalTimeSuccess.Priority%d",
+                           request()->priority()),
+        total_time);
     UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeSuccess", total_time);
   } else {
     UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeCancel", total_time);
diff --git a/net/url_request/url_request_http_job_unittest.cc b/net/url_request/url_request_http_job_unittest.cc
index e3a17d7..0fd984c3 100644
--- a/net/url_request/url_request_http_job_unittest.cc
+++ b/net/url_request/url_request_http_job_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/test/histogram_tester.h"
 #include "net/base/auth.h"
@@ -813,6 +814,40 @@
   histograms.ExpectTotalCount("Net.HttpTimeToFirstByte", 0);
 }
 
+TEST_F(URLRequestHttpJobWithMockSocketsTest,
+       TestHttpJobSuccessPriorityKeyedTotalTime) {
+  base::HistogramTester histograms;
+
+  for (int priority = 0; priority < net::NUM_PRIORITIES; ++priority) {
+    for (int request_index = 0; request_index <= priority; ++request_index) {
+      MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
+      MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n"
+                                   "Content-Length: 12\r\n\r\n"),
+                          MockRead("Test Content")};
+
+      StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
+                                           arraysize(writes));
+      socket_factory_.AddSocketDataProvider(&socket_data);
+
+      TestDelegate delegate;
+      std::unique_ptr<URLRequest> request =
+          context_->CreateRequest(GURL("http://www.example.com/"),
+                                  static_cast<net::RequestPriority>(priority),
+                                  &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
+
+      request->Start();
+      base::RunLoop().Run();
+      EXPECT_THAT(delegate.request_status(), IsOk());
+    }
+  }
+
+  for (int priority = 0; priority < net::NUM_PRIORITIES; ++priority) {
+    histograms.ExpectTotalCount(
+        "Net.HttpJob.TotalTimeSuccess.Priority" + base::IntToString(priority),
+        priority + 1);
+  }
+}
+
 TEST_F(URLRequestHttpJobTest, TestCancelWhileReadingCookies) {
   DelayedCookieMonster cookie_monster;
   TestURLRequestContext context(true);
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 09b9c28..083cd24 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -1166,7 +1166,7 @@
   }
 }
 
-#if defined(OS_POSIX)  // Bacause of symbolic links.
+#if defined(OS_POSIX) && !defined(OS_FUCHSIA)  // Because of symbolic links.
 
 TEST_F(URLRequestTest, SymlinksToFiles) {
   base::ScopedTempDir temp_dir;
@@ -1290,7 +1290,7 @@
   }
 }
 
-#endif  // defined(OS_POSIX)
+#endif  // defined(OS_POSIX) && !defined(OS_FUCHSIA)
 
 TEST_F(URLRequestTest, FileDirCancelTest) {
   // Put in mock resource provider.
diff --git a/services/catalog/public/cpp/manifest_parsing_util.cc b/services/catalog/public/cpp/manifest_parsing_util.cc
index 75a2e35..4a19ec6 100644
--- a/services/catalog/public/cpp/manifest_parsing_util.cc
+++ b/services/catalog/public/cpp/manifest_parsing_util.cc
@@ -5,6 +5,7 @@
 #include "services/catalog/public/cpp/manifest_parsing_util.h"
 
 #include "base/values.h"
+#include "build/build_config.h"
 #include "services/catalog/store.h"
 
 namespace catalog {
@@ -15,7 +16,8 @@
   return name == Store::kRequiredFilesKey_PlatformValue_Windows ||
          name == Store::kRequiredFilesKey_PlatformValue_Linux ||
          name == Store::kRequiredFilesKey_PlatformValue_MacOSX ||
-         name == Store::kRequiredFilesKey_PlatformValue_Android;
+         name == Store::kRequiredFilesKey_PlatformValue_Android ||
+         name == Store::kRequiredFilesKey_PlatformValue_Fuchsia;
 }
 
 bool IsCurrentPlatform(const std::string& name) {
@@ -27,6 +29,8 @@
   return name == Store::kRequiredFilesKey_PlatformValue_MacOSX;
 #elif defined(OS_ANDROID)
   return name == Store::kRequiredFilesKey_PlatformValue_Android;
+#elif defined(OS_FUCHSIA)
+  return name == Store::kRequiredFilesKey_PlatformValue_Fuchsia;
 #else
 #error This architecture is not supported.
 #endif
diff --git a/services/catalog/store.cc b/services/catalog/store.cc
index 7095312..70d73ac1 100644
--- a/services/catalog/store.cc
+++ b/services/catalog/store.cc
@@ -32,4 +32,7 @@
 const char Store::kRequiredFilesKey_PlatformValue_MacOSX[] = "macosx";
 // static
 const char Store::kRequiredFilesKey_PlatformValue_Android[] = "android";
+// static
+const char Store::kRequiredFilesKey_PlatformValue_Fuchsia[] = "fuchsia";
+
 }  // namespace catalog
diff --git a/services/catalog/store.h b/services/catalog/store.h
index 752c38d..6bef188 100644
--- a/services/catalog/store.h
+++ b/services/catalog/store.h
@@ -33,6 +33,7 @@
   static const char kRequiredFilesKey_PlatformValue_Linux[];
   static const char kRequiredFilesKey_PlatformValue_MacOSX[];
   static const char kRequiredFilesKey_PlatformValue_Android[];
+  static const char kRequiredFilesKey_PlatformValue_Fuchsia[];
 };
 
 }  // namespace catalog
diff --git a/services/device/generic_sensor/README.md b/services/device/generic_sensor/README.md
index 0e59c0a..2a62756 100644
--- a/services/device/generic_sensor/README.md
+++ b/services/device/generic_sensor/README.md
@@ -14,17 +14,19 @@
 table. An empty cell indicates that the sensor type is not supported on that
 platform.
 
-| SensorType                      | Android                   | Linux          | macOS              | Windows                                   |
-| ------------------------------- | ------------------------- | -------------- | ------------------ | ----------------------------------------- |
-| AMBIENT_LIGHT                   | TYPE_LIGHT                | in_illuminance | AppleLMUController | SENSOR_TYPE_AMBIENT_LIGHT                 |
-| PROXIMITY                       |                           |                |                    |                                           |
-| ACCELEROMETER                   | TYPE_ACCELEROMETER        | in_accel       | SMCMotionSensor    | SENSOR_TYPE_ACCELEROMETER_3D              |
-| LINEAR_ACCELEROMETER            | TYPE_LINEAR_ACCELEROMETER |                |                    |                                           |
-| GYROSCOPE                       | TYPE_GYROSCOPE            | in_anglvel     |                    | SENSOR_TYPE_GYROMETER_3D                  |
-| MAGNETOMETER                    | TYPE_MAGNETIC_FIELD       | in_magn        |                    | SENSOR_TYPE_COMPASS_3D                    |
-| PRESSURE                        |                           |                |                    |                                           |
-| ABSOLUTE_ORIENTATION_QUATERNION | TYPE_ROTATION_VECTOR      |                |                    | SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION |
-| RELATIVE_ORIENTATION_QUATERNION | TYPE_GAME_ROTATION_VECTOR |                |                    |                                           |
+| SensorType                        | Android                   | Linux          | macOS              | Windows                                   |
+| --------------------------------- | ------------------------- | -------------- | ------------------ | ----------------------------------------- |
+| AMBIENT_LIGHT                     | TYPE_LIGHT                | in_illuminance | AppleLMUController | SENSOR_TYPE_AMBIENT_LIGHT                 |
+| PROXIMITY                         |                           |                |                    |                                           |
+| ACCELEROMETER                     | TYPE_ACCELEROMETER        | in_accel       | SMCMotionSensor    | SENSOR_TYPE_ACCELEROMETER_3D              |
+| LINEAR_ACCELEROMETER              | TYPE_LINEAR_ACCELEROMETER |                |                    |                                           |
+| GYROSCOPE                         | TYPE_GYROSCOPE            | in_anglvel     |                    | SENSOR_TYPE_GYROMETER_3D                  |
+| MAGNETOMETER                      | TYPE_MAGNETIC_FIELD       | in_magn        |                    | SENSOR_TYPE_COMPASS_3D                    |
+| PRESSURE                          |                           |                |                    |                                           |
+| ABSOLUTE_ORIENTATION_EULER_ANGLES |                           |                |                    | SENSOR_TYPE_INCLINOMETER_3D               |
+| ABSOLUTE_ORIENTATION_QUATERNION   | TYPE_ROTATION_VECTOR      |                |                    | SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION |
+| RELATIVE_ORIENTATION_EULER_ANGLES |                           |                |                    |                                           |
+| RELATIVE_ORIENTATION_QUATERNION   | TYPE_GAME_ROTATION_VECTOR |                |                    |                                           |
 
 ### Android
 
diff --git a/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc b/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
index c78040b4..12a5d388 100644
--- a/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
+++ b/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
@@ -673,9 +673,53 @@
   EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
 }
 
-// Tests that AbsoluteOrientation sensor readings are correctly converted.
+// Tests that AbsoluteOrientationEulerAngles sensor readings are correctly
+// provided.
 TEST_F(PlatformSensorAndProviderTestWin,
-       CheckDeviceOrientationReadingConversion) {
+       CheckDeviceOrientationEulerAnglesReadingConversion) {
+  mojo::ScopedSharedBufferHandle handle =
+      PlatformSensorProviderWin::GetInstance()->CloneSharedBufferHandle();
+  mojo::ScopedSharedBufferMapping mapping =
+      handle->MapAtOffset(sizeof(SensorReadingSharedBuffer),
+                          SensorReadingSharedBuffer::GetOffset(
+                              SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
+
+  SetSupportedSensor(SENSOR_TYPE_INCLINOMETER_3D);
+  auto sensor = CreateSensor(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES);
+  EXPECT_TRUE(sensor);
+
+  auto client = base::MakeUnique<NiceMock<MockPlatformSensorClient>>(sensor);
+  PlatformSensorConfiguration configuration(10);
+  EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
+  EXPECT_CALL(*client, OnSensorReadingChanged()).Times(1);
+
+  double x = 10;
+  double y = 20;
+  double z = 30;
+
+  base::win::ScopedPropVariant pvX, pvY, pvZ;
+  InitPropVariantFromDouble(x, pvX.Receive());
+  InitPropVariantFromDouble(y, pvY.Receive());
+  InitPropVariantFromDouble(z, pvZ.Receive());
+
+  GenerateDataUpdatedEvent({{SENSOR_DATA_TYPE_TILT_X_DEGREES, pvX.ptr()},
+                            {SENSOR_DATA_TYPE_TILT_Y_DEGREES, pvY.ptr()},
+                            {SENSOR_DATA_TYPE_TILT_Z_DEGREES, pvZ.ptr()}});
+
+  base::RunLoop().RunUntilIdle();
+  SensorReadingSharedBuffer* buffer =
+      static_cast<SensorReadingSharedBuffer*>(mapping.get());
+
+  EXPECT_THAT(buffer->reading.values[0], x);
+  EXPECT_THAT(buffer->reading.values[1], y);
+  EXPECT_THAT(buffer->reading.values[2], z);
+  EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
+}
+
+// Tests that AbsoluteOrientationQuaternion sensor readings are correctly
+// provided.
+TEST_F(PlatformSensorAndProviderTestWin,
+       CheckDeviceOrientationQuaternionReadingConversion) {
   mojo::ScopedSharedBufferHandle handle =
       PlatformSensorProviderWin::GetInstance()->CloneSharedBufferHandle();
   mojo::ScopedSharedBufferMapping mapping =
diff --git a/services/device/generic_sensor/platform_sensor_reader_win.cc b/services/device/generic_sensor/platform_sensor_reader_win.cc
index d98fcf1..d5d88c6b 100644
--- a/services/device/generic_sensor/platform_sensor_reader_win.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_win.cc
@@ -166,8 +166,36 @@
   return params;
 }
 
-// AbsoluteOrientation sensor reader initialization parameters.
-std::unique_ptr<ReaderInitParams> CreateAbsoluteOrientationReaderInitParams() {
+// AbsoluteOrientationEulerAngles sensor reader initialization parameters.
+std::unique_ptr<ReaderInitParams>
+CreateAbsoluteOrientationEulerAnglesReaderInitParams() {
+  auto params = base::MakeUnique<ReaderInitParams>();
+  params->sensor_type_id = SENSOR_TYPE_INCLINOMETER_3D;
+  params->reader_func =
+      base::Bind([](ISensorDataReport* report, SensorReading* reading) {
+        double x = 0.0;
+        double y = 0.0;
+        double z = 0.0;
+        if (!GetReadingValueForProperty(SENSOR_DATA_TYPE_TILT_X_DEGREES, report,
+                                        &x) ||
+            !GetReadingValueForProperty(SENSOR_DATA_TYPE_TILT_Y_DEGREES, report,
+                                        &y) ||
+            !GetReadingValueForProperty(SENSOR_DATA_TYPE_TILT_Z_DEGREES, report,
+                                        &z)) {
+          return E_FAIL;
+        }
+
+        reading->values[0] = x;
+        reading->values[1] = y;
+        reading->values[2] = z;
+        return S_OK;
+      });
+  return params;
+}
+
+// AbsoluteOrientationQuaternion sensor reader initialization parameters.
+std::unique_ptr<ReaderInitParams>
+CreateAbsoluteOrientationQuaternionReaderInitParams() {
   auto params = base::MakeUnique<ReaderInitParams>();
   params->sensor_type_id = SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION;
   params->reader_func =
@@ -211,8 +239,10 @@
       return CreateGyroscopeReaderInitParams();
     case mojom::SensorType::MAGNETOMETER:
       return CreateMagnetometerReaderInitParams();
+    case mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES:
+      return CreateAbsoluteOrientationEulerAnglesReaderInitParams();
     case mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION:
-      return CreateAbsoluteOrientationReaderInitParams();
+      return CreateAbsoluteOrientationQuaternionReaderInitParams();
     default:
       NOTIMPLEMENTED();
       return nullptr;
diff --git a/services/device/public/cpp/generic_sensor/sensor_reading.h b/services/device/public/cpp/generic_sensor/sensor_reading.h
index da46949..573226a9 100644
--- a/services/device/public/cpp/generic_sensor/sensor_reading.h
+++ b/services/device/public/cpp/generic_sensor/sensor_reading.h
@@ -74,6 +74,14 @@
   // PRESSURE:
   // values[0]: atmospheric pressure in hPa (millibar).
   //
+  // ABSOLUTE_ORIENTATION_EULER_ANGLES:
+  // values[0]: x-axis angle in degrees representing the orientation of the
+  // device in 3D space.
+  // values[1]: y-axis angle in degrees representing the orientation of the
+  // device in 3D space.
+  // values[2]: z-axis angle in degrees representing the orientation of the
+  // device in 3D space.
+  //
   // ABSOLUTE_ORIENTATION_QUATERNION:
   // values[0]: x value of a quaternion representing the orientation of the
   // device in 3D space.
@@ -84,9 +92,19 @@
   // values[3]: w value of a quaternion representing the orientation of the
   // device in 3D space.
   //
+  // RELATIVE_ORIENTATION_EULER_ANGLES:
+  // (Identical to ABSOLUTE_ORIENTATION_EULER_ANGLES except that it doesn't use
+  // the geomagnetic field.)
+  // values[0]: x-axis angle in degrees representing the orientation of the
+  // device in 3D space.
+  // values[1]: y-axis angle in degrees representing the orientation of the
+  // device in 3D space.
+  // values[2]: z-axis angle in degrees representing the orientation of the
+  // device in 3D space.
+  //
   // RELATIVE_ORIENTATION_QUATERNION:
-  // (Identical to ABSOLUTE_ORIENTATION except that it doesn't use the
-  // geomagnetic field.)
+  // (Identical to ABSOLUTE_ORIENTATION_QUATERNION except that it doesn't use
+  // the geomagnetic field.)
   // values[0]: x value of a quaternion representing the orientation of the
   // device in 3D space.
   // values[1]: y value of a quaternion representing the orientation of the
diff --git a/services/device/public/interfaces/sensor.mojom b/services/device/public/interfaces/sensor.mojom
index f3c8045..03380a4 100644
--- a/services/device/public/interfaces/sensor.mojom
+++ b/services/device/public/interfaces/sensor.mojom
@@ -16,7 +16,13 @@
   GYROSCOPE,
   MAGNETOMETER,
   PRESSURE,
+  // Legacy sensor to support the W3C DeviceOrientation Event Specification.
+  ABSOLUTE_ORIENTATION_EULER_ANGLES,
+  // Recommended for new code.
   ABSOLUTE_ORIENTATION_QUATERNION,
+  // Legacy sensor to support the W3C DeviceOrientation Event Specification.
+  RELATIVE_ORIENTATION_EULER_ANGLES,
+  // Recommended for new code.
   RELATIVE_ORIENTATION_QUATERNION,
   LAST = RELATIVE_ORIENTATION_QUATERNION // Note: LAST is also equal to the types count.
 };
diff --git a/services/metrics/public/cpp/ukm_recorder.h b/services/metrics/public/cpp/ukm_recorder.h
index ef1802f..5fefaae 100644
--- a/services/metrics/public/cpp/ukm_recorder.h
+++ b/services/metrics/public/cpp/ukm_recorder.h
@@ -19,8 +19,12 @@
 #include "url/gurl.h"
 
 class ContextualSearchRankerLoggerImpl;
+class DocumentWritePageLoadMetricsObserver;
+class FromGWSPageLoadMetricsLogger;
 class PluginInfoMessageFilter;
 class ProcessMemoryMetricsEmitter;
+class ServiceWorkerPageLoadMetricsObserver;
+class SubresourceFilterMetricsObserver;
 class UkmPageLoadMetricsObserver;
 class LocalNetworkRequestsPageLoadMetricsObserver;
 
@@ -94,6 +98,10 @@
   friend PluginInfoMessageFilter;
   friend UkmPageLoadMetricsObserver;
   friend LocalNetworkRequestsPageLoadMetricsObserver;
+  friend DocumentWritePageLoadMetricsObserver;
+  friend FromGWSPageLoadMetricsLogger;
+  friend ServiceWorkerPageLoadMetricsObserver;
+  friend SubresourceFilterMetricsObserver;
   friend translate::TranslateRankerImpl;
   friend TestRecordingHelper;
   friend UkmInterface;
diff --git a/services/preferences/BUILD.gn b/services/preferences/BUILD.gn
index bbdbb28..841cc6b 100644
--- a/services/preferences/BUILD.gn
+++ b/services/preferences/BUILD.gn
@@ -25,10 +25,10 @@
     "//services/service_manager/public/cpp",
   ]
   sources = [
-    "persistent_pref_store_factory.cc",
-    "persistent_pref_store_factory.h",
     "persistent_pref_store_impl.cc",
     "persistent_pref_store_impl.h",
+    "pref_store_impl.cc",
+    "pref_store_impl.h",
     "pref_store_manager_impl.cc",
     "pref_store_manager_impl.h",
     "scoped_pref_connection_builder.cc",
@@ -58,6 +58,7 @@
   sources = [
     "persistent_pref_store_impl_unittest.cc",
     "pref_store_consistency_unittest.cc",
+    "pref_store_impl_unittest.cc",
   ]
   if (!is_ios) {
     sources += [ "pref_service_factory_unittest.cc" ]
diff --git a/services/preferences/manifest.json b/services/preferences/manifest.json
index 4047346..047409d 100644
--- a/services/preferences/manifest.json
+++ b/services/preferences/manifest.json
@@ -5,11 +5,7 @@
     "service_manager:connector": {
       "provides": {
         "pref_client": [
-          "prefs::mojom::PrefStoreConnector",
-          "prefs::mojom::PrefStoreRegistry"
-        ],
-        "pref_control": [
-          "prefs::mojom::PrefServiceControl"
+          "prefs::mojom::PrefStoreConnector"
         ]
       },
       "requires": {
diff --git a/services/preferences/persistent_pref_store_factory.cc b/services/preferences/persistent_pref_store_factory.cc
deleted file mode 100644
index c9145fdc..0000000
--- a/services/preferences/persistent_pref_store_factory.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/preferences/persistent_pref_store_factory.h"
-
-#include <memory>
-#include <utility>
-
-#include "components/prefs/in_memory_pref_store.h"
-#include "components/prefs/json_pref_store.h"
-#include "components/prefs/pref_filter.h"
-#include "services/preferences/persistent_pref_store_impl.h"
-#include "services/preferences/tracked/tracked_persistent_pref_store_factory.h"
-
-namespace prefs {
-namespace {
-
-std::unique_ptr<PersistentPrefStoreImpl> CreateSimplePersistentPrefStore(
-    mojom::SimplePersistentPrefStoreConfigurationPtr config,
-    base::SequencedWorkerPool* worker_pool,
-    base::Closure on_initialized) {
-  return base::MakeUnique<PersistentPrefStoreImpl>(
-      new JsonPrefStore(config->pref_filename,
-                        JsonPrefStore::GetTaskRunnerForFile(
-                            config->pref_filename.DirName(), worker_pool),
-                        nullptr),
-      std::move(on_initialized));
-}
-
-}  // namespace
-
-std::unique_ptr<PersistentPrefStoreImpl> CreatePersistentPrefStore(
-    mojom::PersistentPrefStoreConfigurationPtr configuration,
-    base::SequencedWorkerPool* worker_pool,
-    base::Closure on_initialized) {
-  if (configuration->is_simple_configuration()) {
-    return CreateSimplePersistentPrefStore(
-        std::move(configuration->get_simple_configuration()), worker_pool,
-        std::move(on_initialized));
-  }
-  if (configuration->is_tracked_configuration()) {
-    return base::MakeUnique<PersistentPrefStoreImpl>(
-        CreateTrackedPersistentPrefStore(
-            std::move(configuration->get_tracked_configuration()), worker_pool),
-        std::move(on_initialized));
-  }
-  if (configuration->is_incognito_configuration()) {
-    return base::MakeUnique<PersistentPrefStoreImpl>(
-        base::MakeRefCounted<InMemoryPrefStore>(), std::move(on_initialized));
-  }
-  NOTREACHED();
-  return nullptr;
-}
-
-}  // namespace prefs
diff --git a/services/preferences/persistent_pref_store_factory.h b/services/preferences/persistent_pref_store_factory.h
deleted file mode 100644
index 06cf8f7..0000000
--- a/services/preferences/persistent_pref_store_factory.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_FACTORY_H_
-#define SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_FACTORY_H_
-
-#include <memory>
-
-#include "services/preferences/public/interfaces/preferences.mojom.h"
-
-namespace base {
-class SequencedWorkerPool;
-}
-
-namespace prefs {
-class PersistentPrefStoreImpl;
-
-// Create a new mojom::PersistentPrefStore impl that runs on |worker_pool|
-// configured by |configuration|.
-std::unique_ptr<PersistentPrefStoreImpl> CreatePersistentPrefStore(
-    mojom::PersistentPrefStoreConfigurationPtr configuration,
-    base::SequencedWorkerPool* worker_pool,
-    base::Closure on_initialized);
-
-}  // namespace prefs
-
-#endif  // SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_FACTORY_H_
diff --git a/services/preferences/persistent_pref_store_impl.cc b/services/preferences/persistent_pref_store_impl.cc
index 42cbdce..09357e3 100644
--- a/services/preferences/persistent_pref_store_impl.cc
+++ b/services/preferences/persistent_pref_store_impl.cc
@@ -157,15 +157,16 @@
     scoped_refptr<PersistentPrefStore> backing_pref_store,
     base::OnceClosure on_initialized)
     : backing_pref_store_(backing_pref_store) {
+  backing_pref_store_->AddObserver(this);
   if (!backing_pref_store_->IsInitializationComplete()) {
-    backing_pref_store_->AddObserver(this);
     on_initialized_ = std::move(on_initialized);
     initializing_ = true;
-    backing_pref_store_->ReadPrefsAsync(nullptr);
   }
 }
 
-PersistentPrefStoreImpl::~PersistentPrefStoreImpl() = default;
+PersistentPrefStoreImpl::~PersistentPrefStoreImpl() {
+  backing_pref_store_->RemoveObserver(this);
+}
 
 mojom::PersistentPrefStoreConnectionPtr
 PersistentPrefStoreImpl::CreateConnection(ObservedPrefs observed_prefs) {
@@ -193,17 +194,33 @@
       backing_pref_store_->ReadOnly());
 }
 
-void PersistentPrefStoreImpl::OnPrefValueChanged(const std::string& key) {}
+void PersistentPrefStoreImpl::OnPrefValueChanged(const std::string& key) {
+  if (write_in_progress_)
+    return;
+
+  const base::Value* value = nullptr;
+  for (auto& entry : connections_) {
+    auto update_value = mojom::PrefUpdateValue::New();
+    if (GetValue(key, &value)) {
+      update_value->set_atomic_update(value->CreateDeepCopy());
+    } else {
+      update_value->set_atomic_update(nullptr);
+    }
+    std::vector<mojom::PrefUpdatePtr> updates;
+    updates.emplace_back(base::in_place, key, std::move(update_value), 0);
+    entry.first->OnPrefValuesChanged(updates);
+  }
+}
 
 void PersistentPrefStoreImpl::OnInitializationCompleted(bool succeeded) {
   DCHECK(initializing_);
-  backing_pref_store_->RemoveObserver(this);
   initializing_ = false;
   std::move(on_initialized_).Run();
 }
 
 void PersistentPrefStoreImpl::SetValues(
     std::vector<mojom::PrefUpdatePtr> updates) {
+  base::AutoReset<bool> scoped_call_in_progress(&write_in_progress_, true);
   for (auto& entry : connections_)
     entry.first->OnPrefValuesChanged(updates);
 
diff --git a/services/preferences/persistent_pref_store_impl.h b/services/preferences/persistent_pref_store_impl.h
index b0313415..9d888936b 100644
--- a/services/preferences/persistent_pref_store_impl.h
+++ b/services/preferences/persistent_pref_store_impl.h
@@ -59,6 +59,10 @@
 
   base::OnceClosure on_initialized_;
 
+  // If true then a write is in progress and any update notifications should be
+  // ignored, as those updates would originate from ourselves.
+  bool write_in_progress_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreImpl);
 };
 
diff --git a/services/preferences/persistent_pref_store_impl_unittest.cc b/services/preferences/persistent_pref_store_impl_unittest.cc
index e25c92d..ad364ef 100644
--- a/services/preferences/persistent_pref_store_impl_unittest.cc
+++ b/services/preferences/persistent_pref_store_impl_unittest.cc
@@ -55,56 +55,6 @@
   pref_store->RemoveObserver(&observer);
 }
 
-class InitializationMockPersistentPrefStore : public InMemoryPrefStore {
- public:
-  InitializationMockPersistentPrefStore(
-      bool success,
-      PersistentPrefStore::PrefReadError error,
-      bool read_only)
-      : success_(success), read_error_(error), read_only_(read_only) {}
-
-  bool IsInitializationComplete() const override {
-    return initialized_ && success_;
-  }
-
-  void AddObserver(PrefStore::Observer* observer) override {
-    observers_.AddObserver(observer);
-  }
-
-  void RemoveObserver(PrefStore::Observer* observer) override {
-    observers_.RemoveObserver(observer);
-  }
-
-  void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override {
-    DCHECK(!error_delegate);
-    DCHECK(!initialized_);
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(&InitializationMockPersistentPrefStore::CompleteRead, this));
-  }
-
-  void CompleteRead() {
-    initialized_ = true;
-    for (auto& observer : observers_) {
-      observer.OnInitializationCompleted(success_);
-    }
-  }
-
-  PersistentPrefStore::PrefReadError GetReadError() const override {
-    return read_error_;
-  }
-  bool ReadOnly() const override { return read_only_; }
-
- private:
-  ~InitializationMockPersistentPrefStore() override = default;
-
-  bool initialized_ = false;
-  bool success_;
-  PersistentPrefStore::PrefReadError read_error_;
-  bool read_only_;
-  base::ObserverList<PrefStore::Observer, true> observers_;
-};
-
 constexpr char kKey[] = "path.to.key";
 constexpr char kOtherKey[] = "path.to.other_key";
 
@@ -151,28 +101,6 @@
   DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreImplTest);
 };
 
-TEST_F(PersistentPrefStoreImplTest, InitializationSuccess) {
-  auto backing_pref_store =
-      make_scoped_refptr(new InitializationMockPersistentPrefStore(
-          true, PersistentPrefStore::PREF_READ_ERROR_NONE, false));
-  CreateImpl(backing_pref_store);
-  EXPECT_TRUE(pref_store()->IsInitializationComplete());
-  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
-            pref_store()->GetReadError());
-  EXPECT_FALSE(pref_store()->ReadOnly());
-}
-
-TEST_F(PersistentPrefStoreImplTest, InitializationFailure) {
-  auto backing_pref_store =
-      make_scoped_refptr(new InitializationMockPersistentPrefStore(
-          false, PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, true));
-  CreateImpl(backing_pref_store);
-  EXPECT_FALSE(pref_store()->IsInitializationComplete());
-  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
-            pref_store()->GetReadError());
-  EXPECT_TRUE(pref_store()->ReadOnly());
-}
-
 TEST_F(PersistentPrefStoreImplTest, InitialValue) {
   constexpr char kUnregisteredKey[] = "path.to.unregistered_key";
   constexpr char kUnregisteredTopLevelKey[] = "unregistered_key";
diff --git a/services/preferences/pref_service_factory_unittest.cc b/services/preferences/pref_service_factory_unittest.cc
index 26c3a2b..b38cf3d 100644
--- a/services/preferences/pref_service_factory_unittest.cc
+++ b/services/preferences/pref_service_factory_unittest.cc
@@ -9,15 +9,17 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/sequenced_worker_pool_owner.h"
+#include "components/prefs/in_memory_pref_store.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "components/prefs/pref_service_factory.h"
 #include "components/prefs/value_map_pref_store.h"
 #include "components/prefs/writeable_pref_store.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/preferences/pref_store_impl.h"
 #include "services/preferences/public/cpp/dictionary_value_update.h"
 #include "services/preferences/public/cpp/pref_service_main.h"
-#include "services/preferences/public/cpp/pref_store_impl.h"
 #include "services/preferences/public/cpp/scoped_pref_update.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
@@ -33,10 +35,16 @@
  public:
   ServiceTestClient(
       service_manager::test::ServiceTest* test,
-      scoped_refptr<base::SequencedWorkerPool> worker_pool,
+      scoped_refptr<WriteablePrefStore> above_user_prefs_pref_store,
+      scoped_refptr<WriteablePrefStore> below_user_prefs_pref_store,
+      scoped_refptr<PersistentPrefStore> user_prefs,
+      scoped_refptr<PrefRegistry> pref_registry,
       base::OnceCallback<void(service_manager::Connector*)> connector_callback)
       : service_manager::test::ServiceTestClient(test),
-        worker_pool_(std::move(worker_pool)),
+        above_user_prefs_pref_store_(std::move(above_user_prefs_pref_store)),
+        below_user_prefs_pref_store_(std::move(below_user_prefs_pref_store)),
+        user_prefs_(std::move(user_prefs)),
+        pref_registry_(std::move(pref_registry)),
         connector_callback_(std::move(connector_callback)) {
     registry_.AddInterface<service_manager::mojom::ServiceFactory>(
         base::Bind(&ServiceTestClient::Create, base::Unretained(this)));
@@ -55,10 +63,10 @@
     if (name == prefs::mojom::kServiceName) {
       pref_service_context_.reset(new service_manager::ServiceContext(
           CreatePrefService(
-              {PrefValueStore::COMMAND_LINE_STORE,
-               PrefValueStore::RECOMMENDED_STORE, PrefValueStore::USER_STORE,
-               PrefValueStore::DEFAULT_STORE},
-              worker_pool_),
+              nullptr, nullptr, nullptr, above_user_prefs_pref_store_.get(),
+              user_prefs_.get(), nullptr, below_user_prefs_pref_store_.get(),
+              pref_registry_.get())
+              .first,
           std::move(request)));
     } else if (name == "prefs_unittest_helper") {
       test_helper_service_context_ =
@@ -75,10 +83,13 @@
   }
 
  private:
-  scoped_refptr<base::SequencedWorkerPool> worker_pool_;
   service_manager::BinderRegistry registry_;
   mojo::BindingSet<service_manager::mojom::ServiceFactory>
       service_factory_bindings_;
+  scoped_refptr<WriteablePrefStore> above_user_prefs_pref_store_;
+  scoped_refptr<WriteablePrefStore> below_user_prefs_pref_store_;
+  scoped_refptr<PersistentPrefStore> user_prefs_;
+  scoped_refptr<PrefRegistry> pref_registry_;
   std::unique_ptr<service_manager::ServiceContext> pref_service_context_;
   std::unique_ptr<service_manager::ServiceContext> test_helper_service_context_;
   base::OnceCallback<void(service_manager::Connector*)> connector_callback_;
@@ -89,15 +100,24 @@
 constexpr char kKey[] = "some_key";
 constexpr char kOtherKey[] = "some_other_key";
 constexpr char kDictionaryKey[] = "a.dictionary.pref";
+constexpr char kInitialKey[] = "initial_key";
+constexpr char kOtherInitialKey[] = "other_initial_key";
 
 class PrefServiceFactoryTest : public service_manager::test::ServiceTest {
  public:
-  PrefServiceFactoryTest()
-      : ServiceTest("prefs_unittests", false),
-        worker_pool_owner_(2, "PrefServiceFactoryTest") {}
+  PrefServiceFactoryTest() : ServiceTest("prefs_unittests", false) {}
 
  protected:
   void SetUp() override {
+    above_user_prefs_pref_store_ = new ValueMapPrefStore();
+    below_user_prefs_pref_store_ = new ValueMapPrefStore();
+    user_prefs_ = new InMemoryPrefStore();
+    PrefServiceFactory factory;
+    factory.set_user_prefs(user_prefs_);
+    factory.set_recommended_prefs(below_user_prefs_pref_store_);
+    factory.set_command_line_prefs(above_user_prefs_pref_store_);
+    pref_service_ = factory.Create(GetInitialPrefRegistry().get());
+
     base::RunLoop run_loop;
     connector_callback_ =
         base::BindOnce(&PrefServiceFactoryTest::SetOtherClientConnector,
@@ -106,85 +126,61 @@
     ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
     connector()->StartService("prefs_unittest_helper");
     run_loop.Run();
-
-    // Init the pref service (in production Chrome startup would do this.)
-    mojom::PrefServiceControlPtr control;
-    connector()->BindInterface(mojom::kServiceName, &control);
-    auto config = mojom::PersistentPrefStoreConfiguration::New();
-    config->set_simple_configuration(
-        mojom::SimplePersistentPrefStoreConfiguration::New(
-            profile_dir_.GetPath().AppendASCII("Preferences")));
-    control->Init(std::move(config));
-    above_user_prefs_pref_store_ = new ValueMapPrefStore();
-    below_user_prefs_pref_store_ = new ValueMapPrefStore();
-    connector()->BindInterface(mojom::kServiceName, &pref_store_registry_);
-    CreateLayeredPrefStores();
   }
 
   service_manager::Connector* other_client_connector() {
     return other_client_connector_;
   }
 
-  virtual void CreateLayeredPrefStores() {
-    above_user_prefs_impl_ = PrefStoreImpl::Create(
-        pref_store_registry(), above_user_prefs_pref_store_,
-        PrefValueStore::COMMAND_LINE_STORE);
-    below_user_prefs_impl_ = PrefStoreImpl::Create(
-        pref_store_registry(), below_user_prefs_pref_store_,
-        PrefValueStore::RECOMMENDED_STORE);
-  }
-
   // service_manager::test::ServiceTest:
   std::unique_ptr<service_manager::Service> CreateService() override {
-    return base::MakeUnique<ServiceTestClient>(this, worker_pool_owner_.pool(),
-                                               std::move(connector_callback_));
+    return base::MakeUnique<ServiceTestClient>(
+        this, above_user_prefs_pref_store_, below_user_prefs_pref_store_,
+        user_prefs_, GetInitialPrefRegistry().get(),
+        std::move(connector_callback_));
   }
 
   // Create a fully initialized PrefService synchronously.
   std::unique_ptr<PrefService> Create() {
-    return CreateImpl(CreateDefaultPrefRegistry(), {}, connector());
+    return CreateImpl(CreateDefaultPrefRegistry(), connector());
   }
 
   std::unique_ptr<PrefService> CreateForeign() {
-    return CreateImpl(CreateDefaultForeignPrefRegistry(), {},
+    return CreateImpl(CreateDefaultForeignPrefRegistry(),
                       other_client_connector());
   }
 
-  std::unique_ptr<PrefService> CreateWithLocalLayeredPrefStores() {
-    return CreateImpl(
-        CreateDefaultPrefRegistry(),
-        {{
-             {PrefValueStore::COMMAND_LINE_STORE, above_user_prefs_pref_store_},
-             {PrefValueStore::RECOMMENDED_STORE, below_user_prefs_pref_store_},
-         },
-         base::KEEP_LAST_OF_DUPES},
-        connector());
-  }
-
   std::unique_ptr<PrefService> CreateImpl(
       scoped_refptr<PrefRegistry> pref_registry,
-      base::flat_map<PrefValueStore::PrefStoreType, scoped_refptr<PrefStore>>
-          local_pref_stores,
       service_manager::Connector* connector) {
     std::unique_ptr<PrefService> pref_service;
     base::RunLoop run_loop;
-    CreateAsync(std::move(pref_registry), std::move(local_pref_stores),
-                connector, run_loop.QuitClosure(), &pref_service);
+    CreateAsync(std::move(pref_registry), connector, run_loop.QuitClosure(),
+                &pref_service);
     run_loop.Run();
     return pref_service;
   }
 
   void CreateAsync(scoped_refptr<PrefRegistry> pref_registry,
-                   base::flat_map<PrefValueStore::PrefStoreType,
-                                  scoped_refptr<PrefStore>> local_pref_stores,
                    service_manager::Connector* connector,
                    base::Closure callback,
                    std::unique_ptr<PrefService>* out) {
     ConnectToPrefService(
-        connector, std::move(pref_registry), std::move(local_pref_stores),
+        connector, std::move(pref_registry),
         base::Bind(&PrefServiceFactoryTest::OnCreate, callback, out));
   }
 
+  scoped_refptr<PrefRegistrySimple> GetInitialPrefRegistry() {
+    if (!pref_registry_) {
+      pref_registry_ = base::MakeRefCounted<PrefRegistrySimple>();
+      pref_registry_->RegisterIntegerPref(kInitialKey, kInitialValue,
+                                          PrefRegistry::PUBLIC);
+      pref_registry_->RegisterIntegerPref(kOtherInitialKey, kInitialValue,
+                                          PrefRegistry::PUBLIC);
+    }
+    return pref_registry_;
+  }
+
   scoped_refptr<PrefRegistrySimple> CreateDefaultPrefRegistry() {
     auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
     pref_registry->RegisterIntegerPref(kKey, kInitialValue,
@@ -192,6 +188,8 @@
     pref_registry->RegisterIntegerPref(kOtherKey, kInitialValue,
                                        PrefRegistry::PUBLIC);
     pref_registry->RegisterDictionaryPref(kDictionaryKey, PrefRegistry::PUBLIC);
+    pref_registry->RegisterForeignPref(kInitialKey);
+    pref_registry->RegisterForeignPref(kOtherInitialKey);
     return pref_registry;
   }
 
@@ -218,9 +216,7 @@
   WriteablePrefStore* below_user_prefs_pref_store() {
     return below_user_prefs_pref_store_.get();
   }
-  mojom::PrefStoreRegistry* pref_store_registry() {
-    return pref_store_registry_.get();
-  }
+  PrefService* pref_service() { return pref_service_.get(); }
 
  private:
   void SetOtherClientConnector(base::OnceClosure done,
@@ -246,12 +242,11 @@
   }
 
   base::ScopedTempDir profile_dir_;
-  base::SequencedWorkerPoolOwner worker_pool_owner_;
   scoped_refptr<WriteablePrefStore> above_user_prefs_pref_store_;
-  std::unique_ptr<PrefStoreImpl> above_user_prefs_impl_;
   scoped_refptr<WriteablePrefStore> below_user_prefs_pref_store_;
-  std::unique_ptr<PrefStoreImpl> below_user_prefs_impl_;
-  mojom::PrefStoreRegistryPtr pref_store_registry_;
+  scoped_refptr<PersistentPrefStore> user_prefs_;
+  scoped_refptr<PrefRegistrySimple> pref_registry_;
+  std::unique_ptr<PrefService> pref_service_;
   service_manager::Connector* other_client_connector_ = nullptr;
   base::OnceCallback<void(service_manager::Connector*)> connector_callback_;
 
@@ -279,6 +274,23 @@
   EXPECT_EQ(kUpdatedValue, pref_service2->GetInteger(kKey));
 }
 
+// Check that updates in one client eventually propagates to the other.
+TEST_F(PrefServiceFactoryTest, InternalAndExternalClients) {
+  auto pref_service2 = Create();
+
+  EXPECT_EQ(kInitialValue, pref_service()->GetInteger(kInitialKey));
+  EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kInitialKey));
+  EXPECT_EQ(kInitialValue, pref_service()->GetInteger(kOtherInitialKey));
+  EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kOtherInitialKey));
+  pref_service()->SetInteger(kInitialKey, kUpdatedValue);
+  WaitForPrefChange(pref_service2.get(), kInitialKey);
+  EXPECT_EQ(kUpdatedValue, pref_service2->GetInteger(kInitialKey));
+
+  pref_service2->SetInteger(kOtherInitialKey, kUpdatedValue);
+  WaitForPrefChange(pref_service(), kOtherInitialKey);
+  EXPECT_EQ(kUpdatedValue, pref_service()->GetInteger(kOtherInitialKey));
+}
+
 TEST_F(PrefServiceFactoryTest, MultipleConnectionsFromSingleClient) {
   Create();
   CreateForeign();
@@ -302,9 +314,9 @@
     pref_registry2->RegisterForeignPref(kKey);
     pref_registry2->RegisterIntegerPref(kOtherKey, kInitialValue,
                                         PrefRegistry::PUBLIC);
-    CreateAsync(std::move(pref_registry), {}, connector(), done_closure,
+    CreateAsync(std::move(pref_registry), connector(), done_closure,
                 &pref_service);
-    CreateAsync(std::move(pref_registry2), {}, other_client_connector(),
+    CreateAsync(std::move(pref_registry2), other_client_connector(),
                 done_closure, &pref_service2);
     run_loop.Run();
   }
@@ -333,22 +345,6 @@
   EXPECT_EQ(4, pref_service->GetInteger(kKey));
 }
 
-// Check that local read-only pref store changes are observed.
-TEST_F(PrefServiceFactoryTest, ReadOnlyPrefStore_Local) {
-  auto pref_service = CreateWithLocalLayeredPrefStores();
-
-  EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
-
-  below_user_prefs_pref_store()->SetValue(
-      kKey, base::MakeUnique<base::Value>(kUpdatedValue), 0);
-  EXPECT_EQ(kUpdatedValue, pref_service->GetInteger(kKey));
-  pref_service->SetInteger(kKey, 3);
-  EXPECT_EQ(3, pref_service->GetInteger(kKey));
-  above_user_prefs_pref_store()->SetValue(kKey,
-                                          base::MakeUnique<base::Value>(4), 0);
-  EXPECT_EQ(4, pref_service->GetInteger(kKey));
-}
-
 // Check that updates to read-only pref stores are correctly layered.
 TEST_F(PrefServiceFactoryTest, ReadOnlyPrefStore_Layering) {
   auto pref_service = Create();
@@ -610,83 +606,5 @@
   WaitForPrefChange(pref_service2.get(), kKey);
 }
 
-class PrefServiceFactoryManualPrefStoreRegistrationTest
-    : public PrefServiceFactoryTest {
- protected:
-  void CreateLayeredPrefStores() override {}
-};
-
-class ConnectionReportingPrefStoreImpl : public mojom::PrefStore {
- public:
-  ConnectionReportingPrefStoreImpl(base::OnceClosure on_add_observer,
-                                   mojom::PrefStoreRequest request)
-      : on_add_observer_(std::move(on_add_observer)),
-        binding_(this, std::move(request)) {}
-
-  void AddObserver(const std::vector<std::string>& prefs_to_observe,
-                   AddObserverCallback callback) override {
-    observer_added_ = true;
-    if (on_add_observer_)
-      std::move(on_add_observer_).Run();
-
-    mojom::PrefStoreObserverPtr observer;
-    auto values = base::MakeUnique<base::DictionaryValue>();
-    values->Set(kKey, base::MakeUnique<base::Value>(kUpdatedValue));
-    std::move(callback).Run(mojom::PrefStoreConnection::New(
-        mojo::MakeRequest(&observer), std::move(values), true));
-  }
-
-  bool observer_added() { return observer_added_; }
-
- private:
-  bool observer_added_ = false;
-  base::OnceClosure on_add_observer_;
-  mojo::Binding<mojom::PrefStore> binding_;
-};
-
-// Check that connect calls received before all read-only prefs stores have
-// been registered are correctly handled.
-TEST_F(PrefServiceFactoryManualPrefStoreRegistrationTest,
-       RegistrationBeforeAndAfterConnect) {
-  base::RunLoop add_observer_run_loop;
-
-  mojom::PrefStorePtr below_ptr;
-  ConnectionReportingPrefStoreImpl below_user_prefs(
-      add_observer_run_loop.QuitClosure(), mojo::MakeRequest(&below_ptr));
-  pref_store_registry()->Register(PrefValueStore::RECOMMENDED_STORE,
-                                  std::move(below_ptr));
-
-  std::unique_ptr<PrefService> pref_service;
-
-  base::RunLoop run_loop;
-  auto barrier = base::BarrierClosure(2, run_loop.QuitClosure());
-  CreateAsync(CreateDefaultPrefRegistry(), {}, connector(), barrier,
-              &pref_service);
-
-  add_observer_run_loop.Run();
-  ASSERT_TRUE(below_user_prefs.observer_added());
-
-  EXPECT_FALSE(pref_service);
-
-  mojom::PrefStorePtr above_ptr;
-  ConnectionReportingPrefStoreImpl above_user_prefs(
-      barrier, mojo::MakeRequest(&above_ptr));
-  pref_store_registry()->Register(PrefValueStore::COMMAND_LINE_STORE,
-                                  std::move(above_ptr));
-
-  run_loop.Run();
-  EXPECT_TRUE(above_user_prefs.observer_added());
-  EXPECT_EQ(kUpdatedValue, pref_service->GetInteger(kKey));
-  pref_service->SetInteger(kKey, kInitialValue);
-  EXPECT_EQ(kUpdatedValue, pref_service->GetInteger(kKey));
-}
-
-// Check that connect calls claiming to have all read-only pref stores locally
-// do not wait for those stores to be registered with the pref service.
-TEST_F(PrefServiceFactoryManualPrefStoreRegistrationTest,
-       LocalButNotRegisteredReadOnlyStores) {
-  EXPECT_TRUE(CreateWithLocalLayeredPrefStores());
-}
-
 }  // namespace
 }  // namespace prefs
diff --git a/services/preferences/public/cpp/pref_store_impl.cc b/services/preferences/pref_store_impl.cc
similarity index 77%
rename from services/preferences/public/cpp/pref_store_impl.cc
rename to services/preferences/pref_store_impl.cc
index e311718..de0575db 100644
--- a/services/preferences/public/cpp/pref_store_impl.cc
+++ b/services/preferences/pref_store_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "services/preferences/public/cpp/pref_store_impl.h"
+#include "services/preferences/pref_store_impl.h"
 
 #include <memory>
 #include <set>
@@ -51,11 +51,9 @@
   DISALLOW_COPY_AND_ASSIGN(Observer);
 };
 
-PrefStoreImpl::PrefStoreImpl(scoped_refptr<::PrefStore> pref_store,
-                             mojom::PrefStoreRequest request)
+PrefStoreImpl::PrefStoreImpl(scoped_refptr<::PrefStore> pref_store)
     : backing_pref_store_(std::move(pref_store)),
-      backing_pref_store_initialized_(false),
-      binding_(this, std::move(request)) {
+      backing_pref_store_initialized_(false) {
   DCHECK(backing_pref_store_);
   if (backing_pref_store_->IsInitializationComplete())
     OnInitializationCompleted(true);
@@ -66,18 +64,6 @@
   backing_pref_store_->RemoveObserver(this);
 }
 
-// static
-std::unique_ptr<PrefStoreImpl> PrefStoreImpl::Create(
-    mojom::PrefStoreRegistry* registry_ptr,
-    scoped_refptr<::PrefStore> pref_store,
-    PrefValueStore::PrefStoreType type) {
-  mojom::PrefStorePtr ptr;
-  auto impl = base::MakeUnique<PrefStoreImpl>(std::move(pref_store),
-                                              mojo::MakeRequest(&ptr));
-  registry_ptr->Register(type, std::move(ptr));
-  return impl;
-}
-
 void PrefStoreImpl::OnPrefValueChanged(const std::string& key) {
   auto dictionary = base::MakeUnique<base::DictionaryValue>();
   const base::Value* value = nullptr;
@@ -100,19 +86,19 @@
     observer->OnInitializationCompleted(succeeded);
 }
 
-void PrefStoreImpl::AddObserver(
-    const std::vector<std::string>& prefs_to_observe,
-    AddObserverCallback callback) {
+mojom::PrefStoreConnectionPtr PrefStoreImpl::AddObserver(
+    const std::vector<std::string>& prefs_to_observe) {
   mojom::PrefStoreObserverPtr observer_ptr;
   auto request = mojo::MakeRequest(&observer_ptr);
   std::set<std::string> observed_prefs(prefs_to_observe.begin(),
                                        prefs_to_observe.end());
-  std::move(callback).Run(mojom::PrefStoreConnection::New(
+  auto result = mojom::PrefStoreConnection::New(
       std::move(request),
       FilterPrefs(backing_pref_store_->GetValues(), observed_prefs),
-      backing_pref_store_->IsInitializationComplete()));
+      backing_pref_store_->IsInitializationComplete());
   observers_.push_back(base::MakeUnique<Observer>(std::move(observer_ptr),
                                                   std::move(observed_prefs)));
+  return result;
 }
 
 }  // namespace prefs
diff --git a/services/preferences/public/cpp/pref_store_impl.h b/services/preferences/pref_store_impl.h
similarity index 60%
rename from services/preferences/public/cpp/pref_store_impl.h
rename to services/preferences/pref_store_impl.h
index 6846611c6..8cb9702 100644
--- a/services/preferences/public/cpp/pref_store_impl.h
+++ b/services/preferences/pref_store_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_IMPL_H_
-#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_IMPL_H_
+#ifndef SERVICES_PREFERENCES_PREF_STORE_IMPL_H_
+#define SERVICES_PREFERENCES_PREF_STORE_IMPL_H_
 
 #include <string>
 #include <vector>
@@ -19,18 +19,13 @@
 
 // Wraps an actual PrefStore implementation and exposes it as a
 // mojom::PrefStore interface.
-class PrefStoreImpl : public ::PrefStore::Observer, public mojom::PrefStore {
+class PrefStoreImpl : public ::PrefStore::Observer {
  public:
-  PrefStoreImpl(scoped_refptr<::PrefStore> pref_store,
-                mojom::PrefStoreRequest request);
+  explicit PrefStoreImpl(scoped_refptr<::PrefStore> pref_store);
   ~PrefStoreImpl() override;
 
-  // The created instance is registered in and owned by the
-  // |mojom::PrefStoreRegistry|.
-  static std::unique_ptr<PrefStoreImpl> Create(
-      mojom::PrefStoreRegistry* registry_ptr,
-      scoped_refptr<::PrefStore> pref_store,
-      PrefValueStore::PrefStoreType type);
+  mojom::PrefStoreConnectionPtr AddObserver(
+      const std::vector<std::string>& prefs_to_observe);
 
  private:
   class Observer;
@@ -39,10 +34,6 @@
   void OnPrefValueChanged(const std::string& key) override;
   void OnInitializationCompleted(bool succeeded) override;
 
-  // prefs::mojom::PrefStore:
-  void AddObserver(const std::vector<std::string>& prefs_to_observe,
-                   AddObserverCallback callback) override;
-
   // The backing store we observer for changes.
   scoped_refptr<::PrefStore> backing_pref_store_;
 
@@ -54,11 +45,9 @@
   // OnInitializationCompleted was called.
   bool backing_pref_store_initialized_;
 
-  mojo::Binding<mojom::PrefStore> binding_;
-
   DISALLOW_COPY_AND_ASSIGN(PrefStoreImpl);
 };
 
 }  // namespace prefs
 
-#endif  // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_IMPL_H_
+#endif  // SERVICES_PREFERENCES_PREF_STORE_IMPL_H_
diff --git a/services/preferences/public/cpp/tests/pref_store_impl_unittest.cc b/services/preferences/pref_store_impl_unittest.cc
similarity index 91%
rename from services/preferences/public/cpp/tests/pref_store_impl_unittest.cc
rename to services/preferences/pref_store_impl_unittest.cc
index e35a9d86..6480d48 100644
--- a/services/preferences/public/cpp/tests/pref_store_impl_unittest.cc
+++ b/services/preferences/pref_store_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "services/preferences/public/cpp/pref_store_impl.h"
+#include "services/preferences/pref_store_impl.h"
 
 #include <utility>
 
@@ -104,8 +104,6 @@
   void TearDown() override {
     pref_store_ = nullptr;
     base::RunLoop().RunUntilIdle();
-    pref_store_ptr_.reset();
-    base::RunLoop().RunUntilIdle();
     impl_.reset();
     base::RunLoop().RunUntilIdle();
   }
@@ -113,29 +111,12 @@
   void CreateImpl(
       scoped_refptr<PrefStore> backing_pref_store,
       std::vector<std::string> observed_prefs = std::vector<std::string>()) {
-    impl_ = base::MakeUnique<PrefStoreImpl>(
-        std::move(backing_pref_store), mojo::MakeRequest(&pref_store_ptr_));
+    impl_ = base::MakeUnique<PrefStoreImpl>(std::move(backing_pref_store));
 
     if (observed_prefs.empty())
       observed_prefs.insert(observed_prefs.end(), {kKey, kOtherKey});
-    pref_store_ = CreateConnection(std::move(observed_prefs));
-  }
-
-  scoped_refptr<PrefStore> CreateConnection(
-      std::vector<std::string> observed_prefs) {
-    base::RunLoop run_loop;
-    mojom::PrefStoreConnectionPtr connection;
-    pref_store_ptr_->AddObserver(
-        observed_prefs,
-        base::Bind(
-            [](mojom::PrefStoreConnectionPtr* output, base::OnceClosure quit,
-               mojom::PrefStoreConnectionPtr connection) {
-              std::move(quit).Run();
-              *output = std::move(connection);
-            },
-            &connection, run_loop.QuitClosure()));
-    run_loop.Run();
-    return make_scoped_refptr(new PrefStoreClient(std::move(connection)));
+    pref_store_ = make_scoped_refptr(
+        new PrefStoreClient(impl_->AddObserver(observed_prefs)));
   }
 
   PrefStore* pref_store() { return pref_store_.get(); }
@@ -144,7 +125,6 @@
   base::MessageLoop message_loop_;
 
   std::unique_ptr<PrefStoreImpl> impl_;
-  mojom::PrefStorePtr pref_store_ptr_;
 
   scoped_refptr<PrefStore> pref_store_;
 
diff --git a/services/preferences/pref_store_manager_impl.cc b/services/preferences/pref_store_manager_impl.cc
index dc92971..f9d6784 100644
--- a/services/preferences/pref_store_manager_impl.cc
+++ b/services/preferences/pref_store_manager_impl.cc
@@ -10,13 +10,15 @@
 #include "base/memory/ref_counted.h"
 #include "base/stl_util.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "components/prefs/pref_registry.h"
 #include "components/prefs/pref_value_store.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/preferences/persistent_pref_store_factory.h"
 #include "services/preferences/persistent_pref_store_impl.h"
+#include "services/preferences/pref_store_impl.h"
 #include "services/preferences/scoped_pref_connection_builder.h"
 #include "services/preferences/shared_pref_registry.h"
 #include "services/service_manager/public/cpp/bind_source_info.h"
+#include "services/service_manager/public/cpp/service_context.h"
 
 namespace prefs {
 
@@ -27,22 +29,11 @@
                       const service_manager::BindSourceInfo& source_info)
       : owner_(owner), source_info_(source_info) {}
 
-  // mojom::PrefStoreConnector: |already_connected_types| must not include
-  // PrefValueStore::DEFAULT_STORE and PrefValueStore::USER_STORE as these must
-  // always be accessed through the service.
   void Connect(
       mojom::PrefRegistryPtr pref_registry,
-      const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
       ConnectCallback callback) override {
-    std::set<PrefValueStore::PrefStoreType> required_remote_types;
-    for (auto type : owner_->expected_pref_stores_) {
-      if (!base::ContainsValue(already_connected_types, type)) {
-        required_remote_types.insert(type);
-      }
-    }
     auto connection = owner_->shared_pref_registry_->CreateConnectionBuilder(
-        std::move(pref_registry), std::move(required_remote_types),
-        source_info_.identity, std::move(callback));
+        std::move(pref_registry), source_info_.identity, std::move(callback));
     if (owner_->persistent_pref_store_ &&
         owner_->persistent_pref_store_->initialized()) {
       connection->ProvidePersistentPrefStore(
@@ -50,25 +41,15 @@
     } else {
       owner_->pending_persistent_connections_.push_back(connection);
     }
-    auto remaining_remote_types =
-        connection->ProvidePrefStoreConnections(owner_->pref_store_ptrs_);
-    for (auto type : remaining_remote_types) {
-      owner_->pending_connections_[type].push_back(connection);
+    if (owner_->incognito_persistent_pref_store_underlay_) {
+      if (owner_->incognito_persistent_pref_store_underlay_->initialized()) {
+        connection->ProvideIncognitoPersistentPrefStoreUnderlay(
+            owner_->incognito_persistent_pref_store_underlay_.get());
+      } else {
+        owner_->pending_persistent_incognito_connections_.push_back(connection);
+      }
     }
-    if (!owner_->Initialized()) {
-      owner_->pending_incognito_connections_.push_back(connection);
-    } else if (owner_->incognito_connector_) {
-      connection->ProvideIncognitoConnector(owner_->incognito_connector_);
-    }
-  }
-
-  void ConnectToUserPrefStore(
-      const std::vector<std::string>& observed_prefs,
-      mojom::PrefStoreConnector::ConnectToUserPrefStoreCallback callback)
-      override {
-    std::move(callback).Run(owner_->persistent_pref_store_->CreateConnection(
-        PersistentPrefStoreImpl::ObservedPrefs(observed_prefs.begin(),
-                                               observed_prefs.end())));
+    connection->ProvidePrefStoreConnections(owner_->read_only_pref_stores_);
   }
 
  private:
@@ -77,61 +58,46 @@
 };
 
 PrefStoreManagerImpl::PrefStoreManagerImpl(
-    std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
-    scoped_refptr<base::SequencedWorkerPool> worker_pool)
-    : expected_pref_stores_(std::move(expected_pref_stores)),
-      init_binding_(this),
-      shared_pref_registry_(base::MakeUnique<SharedPrefRegistry>()),
-      worker_pool_(std::move(worker_pool)) {
-  DCHECK(
-      base::ContainsKey(expected_pref_stores_, PrefValueStore::USER_STORE) &&
-      base::ContainsKey(expected_pref_stores_, PrefValueStore::DEFAULT_STORE))
-      << "expected_pref_stores must always include PrefValueStore::USER_STORE "
-         "and PrefValueStore::DEFAULT_STORE.";
-  // The user store is not actually registered or connected to in the
-  // implementation, but accessed directly.
-  expected_pref_stores_.erase(PrefValueStore::USER_STORE);
-  DVLOG(1) << "Expecting " << expected_pref_stores_.size()
-           << " pref store(s) to register";
+    PrefStore* managed_prefs,
+    PrefStore* supervised_user_prefs,
+    PrefStore* extension_prefs,
+    PrefStore* command_line_prefs,
+    PersistentPrefStore* user_prefs,
+    PersistentPrefStore* incognito_user_prefs_underlay,
+    PrefStore* recommended_prefs,
+    PrefRegistry* pref_registry)
+    : shared_pref_registry_(base::MakeUnique<SharedPrefRegistry>(
+          make_scoped_refptr(pref_registry))),
+      weak_factory_(this) {
   // This store is done in-process so it's already "registered":
-  DVLOG(1) << "Registering pref store: " << PrefValueStore::DEFAULT_STORE;
   registry_.AddInterface<prefs::mojom::PrefStoreConnector>(
       base::Bind(&PrefStoreManagerImpl::BindPrefStoreConnectorRequest,
                  base::Unretained(this)));
-  registry_.AddInterface<prefs::mojom::PrefStoreRegistry>(
-      base::Bind(&PrefStoreManagerImpl::BindPrefStoreRegistryRequest,
-                 base::Unretained(this)));
-  registry_.AddInterface<prefs::mojom::PrefServiceControl>(
-      base::Bind(&PrefStoreManagerImpl::BindPrefServiceControlRequest,
-                 base::Unretained(this)));
+  persistent_pref_store_ = base::MakeUnique<PersistentPrefStoreImpl>(
+      make_scoped_refptr(user_prefs),
+      base::BindOnce(&PrefStoreManagerImpl::OnPersistentPrefStoreReady,
+                     base::Unretained(this)));
+  if (incognito_user_prefs_underlay) {
+    incognito_persistent_pref_store_underlay_ =
+        base::MakeUnique<PersistentPrefStoreImpl>(
+            make_scoped_refptr(user_prefs),
+            base::BindOnce(
+                &PrefStoreManagerImpl::OnIncognitoPersistentPrefStoreReady,
+                base::Unretained(this)));
+  }
+  RegisterPrefStore(PrefValueStore::MANAGED_STORE, managed_prefs);
+  RegisterPrefStore(PrefValueStore::SUPERVISED_USER_STORE,
+                    supervised_user_prefs);
+  RegisterPrefStore(PrefValueStore::EXTENSION_STORE, extension_prefs);
+  RegisterPrefStore(PrefValueStore::COMMAND_LINE_STORE, command_line_prefs);
+  RegisterPrefStore(PrefValueStore::RECOMMENDED_STORE, recommended_prefs);
 }
 
-PrefStoreManagerImpl::~PrefStoreManagerImpl() {
-  // For logging consistency:
-  DVLOG(1) << "Deregistering pref store: " << PrefValueStore::DEFAULT_STORE;
-}
+PrefStoreManagerImpl::~PrefStoreManagerImpl() = default;
 
-void PrefStoreManagerImpl::Register(PrefValueStore::PrefStoreType type,
-                                    mojom::PrefStorePtr pref_store_ptr) {
-  if (expected_pref_stores_.count(type) == 0) {
-    LOG(WARNING) << "Not registering unexpected pref store: " << type;
-    return;
-  }
-  DVLOG(1) << "Registering pref store: " << type;
-  pref_store_ptr.set_connection_error_handler(
-      base::Bind(&PrefStoreManagerImpl::OnPrefStoreDisconnect,
-                 base::Unretained(this), type));
-  auto it = pending_connections_.find(type);
-  if (it != pending_connections_.end()) {
-    for (const auto& connection : it->second)
-      connection->ProvidePrefStoreConnection(type, pref_store_ptr.get());
-    pending_connections_.erase(it);
-  }
-
-  const bool success =
-      pref_store_ptrs_.insert(std::make_pair(type, std::move(pref_store_ptr)))
-          .second;
-  DCHECK(success) << "The same pref store registered twice: " << type;
+base::OnceClosure PrefStoreManagerImpl::ShutDownClosure() {
+  return base::BindOnce(&PrefStoreManagerImpl::ShutDown,
+                        weak_factory_.GetWeakPtr());
 }
 
 void PrefStoreManagerImpl::BindPrefStoreConnectorRequest(
@@ -142,47 +108,6 @@
       std::move(request));
 }
 
-void PrefStoreManagerImpl::BindPrefStoreRegistryRequest(
-    const service_manager::BindSourceInfo& source_info,
-    prefs::mojom::PrefStoreRegistryRequest request) {
-  registry_bindings_.AddBinding(this, std::move(request));
-}
-
-void PrefStoreManagerImpl::BindPrefServiceControlRequest(
-    const service_manager::BindSourceInfo& source_info,
-    prefs::mojom::PrefServiceControlRequest request) {
-  if (init_binding_.is_bound()) {
-    LOG(ERROR)
-        << "Pref service received unexpected control interface connection from "
-        << source_info.identity.name();
-    return;
-  }
-
-  init_binding_.Bind(std::move(request));
-}
-
-void PrefStoreManagerImpl::Init(
-    mojom::PersistentPrefStoreConfigurationPtr configuration) {
-  DCHECK(!persistent_pref_store_);
-
-  if (configuration->is_incognito_configuration()) {
-    incognito_connector_ =
-        std::move(configuration->get_incognito_configuration()->connector);
-    for (auto connection : pending_incognito_connections_) {
-      connection->ProvideIncognitoConnector(incognito_connector_);
-    }
-  }
-  pending_incognito_connections_.clear();
-  persistent_pref_store_ = CreatePersistentPrefStore(
-      std::move(configuration), worker_pool_.get(),
-      base::Bind(&PrefStoreManagerImpl::OnPersistentPrefStoreReady,
-                 base::Unretained(this)));
-  DCHECK(persistent_pref_store_);
-  if (persistent_pref_store_->initialized()) {
-    OnPersistentPrefStoreReady();
-  }
-}
-
 void PrefStoreManagerImpl::OnStart() {}
 
 void PrefStoreManagerImpl::OnBindInterface(
@@ -193,12 +118,6 @@
                           std::move(interface_pipe));
 }
 
-void PrefStoreManagerImpl::OnPrefStoreDisconnect(
-    PrefValueStore::PrefStoreType type) {
-  DVLOG(1) << "Deregistering pref store: " << type;
-  pref_store_ptrs_.erase(type);
-}
-
 void PrefStoreManagerImpl::OnPersistentPrefStoreReady() {
   DVLOG(1) << "PersistentPrefStore ready";
   for (const auto& connection : pending_persistent_connections_)
@@ -206,8 +125,27 @@
   pending_persistent_connections_.clear();
 }
 
-bool PrefStoreManagerImpl::Initialized() const {
-  return bool(persistent_pref_store_);
+void PrefStoreManagerImpl::OnIncognitoPersistentPrefStoreReady() {
+  DVLOG(1) << "Incognito PersistentPrefStore ready";
+  for (const auto& connection : pending_persistent_connections_)
+    connection->ProvideIncognitoPersistentPrefStoreUnderlay(
+        incognito_persistent_pref_store_underlay_.get());
+  pending_persistent_incognito_connections_.clear();
+}
+
+void PrefStoreManagerImpl::RegisterPrefStore(PrefValueStore::PrefStoreType type,
+                                             PrefStore* pref_store) {
+  if (!pref_store)
+    return;
+
+  read_only_pref_stores_.emplace(
+      type, base::MakeUnique<PrefStoreImpl>(make_scoped_refptr(pref_store)));
+}
+
+void PrefStoreManagerImpl::ShutDown() {
+  read_only_pref_stores_.clear();
+  persistent_pref_store_.reset();
+  context()->QuitNow();
 }
 
 }  // namespace prefs
diff --git a/services/preferences/pref_store_manager_impl.h b/services/preferences/pref_store_manager_impl.h
index 04c5f82..0e27764 100644
--- a/services/preferences/pref_store_manager_impl.h
+++ b/services/preferences/pref_store_manager_impl.h
@@ -20,52 +20,38 @@
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 
-namespace base {
-class SequencedWorkerPool;
-}
+class PrefRegistry;
 
 namespace prefs {
 class SharedPrefRegistry;
 class PersistentPrefStoreImpl;
+class PrefStoreImpl;
 class ScopedPrefConnectionBuilder;
 
 // This class mediates the connection of clients who wants to read preferences
 // and the pref stores that store those preferences. Pref stores use the
 // |PrefStoreRegistry| interface to register themselves with the manager and
 // clients use the |PrefStoreConnector| interface to connect to these stores.
-class PrefStoreManagerImpl : public mojom::PrefStoreRegistry,
-                             public mojom::PrefServiceControl,
-                             public service_manager::Service {
+class PrefStoreManagerImpl : public service_manager::Service {
  public:
-  // Only replies to Connect calls when all |expected_pref_stores| have
-  // registered. |expected_pref_stores| must contain
-  // PrefValueStore::DEFAULT_STORE and PrefValueStore::USER_STORE for
-  // consistency, as the service always registers these
-  // internally. |worker_pool| is used for any I/O performed by the service.
-  PrefStoreManagerImpl(
-      std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
-      scoped_refptr<base::SequencedWorkerPool> worker_pool);
+  PrefStoreManagerImpl(PrefStore* managed_prefs,
+                       PrefStore* supervised_user_prefs,
+                       PrefStore* extension_prefs,
+                       PrefStore* command_line_prefs,
+                       PersistentPrefStore* user_prefs,
+                       PersistentPrefStore* incognito_user_prefs_underlay,
+                       PrefStore* recommended_prefs,
+                       PrefRegistry* pref_registry);
   ~PrefStoreManagerImpl() override;
 
+  base::OnceClosure ShutDownClosure();
+
  private:
   class ConnectorConnection;
 
-  // mojom::PrefStoreRegistry:
-  void Register(PrefValueStore::PrefStoreType type,
-                mojom::PrefStorePtr pref_store_ptr) override;
-
   void BindPrefStoreConnectorRequest(
       const service_manager::BindSourceInfo& source_info,
       prefs::mojom::PrefStoreConnectorRequest request);
-  void BindPrefStoreRegistryRequest(
-      const service_manager::BindSourceInfo& source_info,
-      prefs::mojom::PrefStoreRegistryRequest request);
-  void BindPrefServiceControlRequest(
-      const service_manager::BindSourceInfo& source_info,
-      prefs::mojom::PrefServiceControlRequest request);
-
-  // PrefServiceControl:
-  void Init(mojom::PersistentPrefStoreConfigurationPtr configuration) override;
 
   // service_manager::Service:
   void OnStart() override;
@@ -73,46 +59,34 @@
                        const std::string& interface_name,
                        mojo::ScopedMessagePipeHandle interface_pipe) override;
 
-  // Called when a PrefStore previously registered using |Register| disconnects.
-  void OnPrefStoreDisconnect(PrefValueStore::PrefStoreType type);
-
   void OnPersistentPrefStoreReady();
+  void OnIncognitoPersistentPrefStoreReady();
 
-  // Has |Init| been called?
-  bool Initialized() const;
+  void RegisterPrefStore(PrefValueStore::PrefStoreType type,
+                         PrefStore* pref_store);
 
-  // PrefStores that need to register before replying to any Connect calls. This
-  // does not include the PersistentPrefStore, which is handled separately.
-  std::set<PrefValueStore::PrefStoreType> expected_pref_stores_;
+  void ShutDown();
 
-  // Registered pref stores.
-  std::unordered_map<PrefValueStore::PrefStoreType, mojom::PrefStorePtr>
-      pref_store_ptrs_;
+  std::unordered_map<PrefValueStore::PrefStoreType,
+                     std::unique_ptr<PrefStoreImpl>>
+      read_only_pref_stores_;
 
   mojo::StrongBindingSet<mojom::PrefStoreConnector> connector_bindings_;
-  mojo::BindingSet<mojom::PrefStoreRegistry> registry_bindings_;
   std::unique_ptr<PersistentPrefStoreImpl> persistent_pref_store_;
-  mojo::Binding<mojom::PrefServiceControl> init_binding_;
-
-  mojom::PrefStoreConnectorPtr incognito_connector_;
+  std::unique_ptr<PersistentPrefStoreImpl>
+      incognito_persistent_pref_store_underlay_;
 
   const std::unique_ptr<SharedPrefRegistry> shared_pref_registry_;
 
-  // The same |ScopedPrefConnectionBuilder| instance may appear multiple times
-  // in |pending_connections_|, once per type of pref store it's waiting for,
-  // and at most once in |pending_persistent_connections_|.
-  std::unordered_map<PrefValueStore::PrefStoreType,
-                     std::vector<scoped_refptr<ScopedPrefConnectionBuilder>>>
-      pending_connections_;
   std::vector<scoped_refptr<ScopedPrefConnectionBuilder>>
       pending_persistent_connections_;
   std::vector<scoped_refptr<ScopedPrefConnectionBuilder>>
-      pending_incognito_connections_;
-
-  const scoped_refptr<base::SequencedWorkerPool> worker_pool_;
+      pending_persistent_incognito_connections_;
 
   service_manager::BinderRegistry registry_;
 
+  base::WeakPtrFactory<PrefStoreManagerImpl> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PrefStoreManagerImpl);
 };
 
diff --git a/services/preferences/public/cpp/BUILD.gn b/services/preferences/public/cpp/BUILD.gn
index 824f4599..fb4d1ce6 100644
--- a/services/preferences/public/cpp/BUILD.gn
+++ b/services/preferences/public/cpp/BUILD.gn
@@ -16,10 +16,6 @@
     "pref_store_client.h",
     "pref_store_client_mixin.cc",
     "pref_store_client_mixin.h",
-    "pref_store_impl.cc",
-    "pref_store_impl.h",
-    "registering_delegate.cc",
-    "registering_delegate.h",
     "scoped_pref_update.cc",
     "scoped_pref_update.h",
   ]
@@ -40,11 +36,14 @@
 source_set("service_main") {
   deps = [
     "//base",
+    "//components/keyed_service/core",
     "//components/prefs",
     "//services/preferences",
     "//services/service_manager/public/cpp",
   ]
   sources = [
+    "in_process_service_factory.cc",
+    "in_process_service_factory.h",
     "pref_service_main.cc",
     "pref_service_main.h",
   ]
diff --git a/services/preferences/public/cpp/DEPS b/services/preferences/public/cpp/DEPS
index 45e227d..afbd4250 100644
--- a/services/preferences/public/cpp/DEPS
+++ b/services/preferences/public/cpp/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/keyed_service/core",
   "+components/prefs",
   "-services/preferences",
   "+services/preferences/public",
diff --git a/services/preferences/public/cpp/in_process_service_factory.cc b/services/preferences/public/cpp/in_process_service_factory.cc
new file mode 100644
index 0000000..4127d29d
--- /dev/null
+++ b/services/preferences/public/cpp/in_process_service_factory.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/preferences/public/cpp/in_process_service_factory.h"
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "components/prefs/persistent_pref_store.h"
+#include "components/prefs/pref_registry.h"
+#include "services/preferences/public/cpp/pref_service_main.h"
+
+namespace prefs {
+namespace {
+
+static std::unique_ptr<service_manager::Service> WeakCreatePrefService(
+    base::WeakPtr<InProcessPrefServiceFactory> weak_factory) {
+  if (!weak_factory)
+    return base::MakeUnique<service_manager::Service>();
+
+  return weak_factory->CreatePrefService();
+}
+
+}  // namespace
+
+// Registers all provided |PrefStore|s with the pref service. The pref stores
+// remaining registered for the life time of |this|.
+class InProcessPrefServiceFactory::RegisteringDelegate
+    : public PrefValueStore::Delegate {
+ public:
+  RegisteringDelegate(base::WeakPtr<InProcessPrefServiceFactory> factory)
+      : factory_(std::move(factory)) {}
+
+  // PrefValueStore::Delegate:
+  void Init(PrefStore* managed_prefs,
+            PrefStore* supervised_user_prefs,
+            PrefStore* extension_prefs,
+            PrefStore* command_line_prefs,
+            PrefStore* user_prefs,
+            PrefStore* recommended_prefs,
+            PrefStore* default_prefs,
+            PrefNotifier* pref_notifier) override {
+    if (!factory_)
+      return;
+
+    factory_->managed_prefs_ = make_scoped_refptr(managed_prefs);
+    factory_->supervised_user_prefs_ =
+        make_scoped_refptr(supervised_user_prefs);
+    factory_->extension_prefs_ = make_scoped_refptr(extension_prefs);
+    factory_->command_line_prefs_ = make_scoped_refptr(command_line_prefs);
+    factory_->user_prefs_ =
+        make_scoped_refptr(static_cast<PersistentPrefStore*>(user_prefs));
+    factory_->recommended_prefs_ = make_scoped_refptr(recommended_prefs);
+  }
+
+  void InitIncognitoUnderlay(
+      PersistentPrefStore* incognito_user_prefs_underlay) override {
+    factory_->incognito_user_prefs_underlay_ =
+        make_scoped_refptr(incognito_user_prefs_underlay);
+  }
+
+  void InitPrefRegistry(PrefRegistry* pref_registry) override {
+    factory_->pref_registry_ = make_scoped_refptr(pref_registry);
+  }
+
+  void UpdateCommandLinePrefStore(PrefStore* command_line_prefs) override {
+    // TODO(tibell): Once we have a way to deregister stores, do so here. At the
+    // moment only local state uses this and local state doesn't use the pref
+    // service yet.
+  }
+
+ private:
+  base::WeakPtr<InProcessPrefServiceFactory> factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegisteringDelegate);
+};
+
+InProcessPrefServiceFactory::InProcessPrefServiceFactory()
+    : weak_factory_(this) {}
+
+InProcessPrefServiceFactory::~InProcessPrefServiceFactory() {
+  if (quit_closure_)
+    std::move(quit_closure_).Run();
+}
+
+std::unique_ptr<PrefValueStore::Delegate>
+InProcessPrefServiceFactory::CreateDelegate() {
+  return base::MakeUnique<RegisteringDelegate>(weak_factory_.GetWeakPtr());
+}
+
+base::Callback<std::unique_ptr<service_manager::Service>()>
+InProcessPrefServiceFactory::CreatePrefServiceFactory() {
+  return base::Bind(&WeakCreatePrefService, weak_factory_.GetWeakPtr());
+}
+
+std::unique_ptr<service_manager::Service>
+InProcessPrefServiceFactory::CreatePrefService() {
+  auto result = prefs::CreatePrefService(
+      managed_prefs_.get(), supervised_user_prefs_.get(),
+      extension_prefs_.get(), command_line_prefs_.get(), user_prefs_.get(),
+      incognito_user_prefs_underlay_.get(), recommended_prefs_.get(),
+      pref_registry_.get());
+  quit_closure_ = std::move(result.second);
+  return std::move(result.first);
+}
+
+}  // namespace prefs
diff --git a/services/preferences/public/cpp/in_process_service_factory.h b/services/preferences/public/cpp/in_process_service_factory.h
new file mode 100644
index 0000000..10bea7d
--- /dev/null
+++ b/services/preferences/public/cpp/in_process_service_factory.h
@@ -0,0 +1,56 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_IN_PROCESS_SERVICE_FACTORY_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_IN_PROCESS_SERVICE_FACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/prefs/pref_value_store.h"
+#include "services/service_manager/public/cpp/service.h"
+
+class PersistentPrefStore;
+class PrefRegistry;
+class PrefStore;
+
+namespace prefs {
+
+class InProcessPrefServiceFactory : public KeyedService {
+ public:
+  InProcessPrefServiceFactory();
+  ~InProcessPrefServiceFactory() override;
+
+  std::unique_ptr<PrefValueStore::Delegate> CreateDelegate();
+
+  base::Callback<std::unique_ptr<service_manager::Service>()>
+  CreatePrefServiceFactory();
+
+  std::unique_ptr<service_manager::Service> CreatePrefService();
+
+ private:
+  class RegisteringDelegate;
+
+  scoped_refptr<PrefStore> managed_prefs_;
+  scoped_refptr<PrefStore> supervised_user_prefs_;
+  scoped_refptr<PrefStore> extension_prefs_;
+  scoped_refptr<PrefStore> command_line_prefs_;
+  scoped_refptr<PersistentPrefStore> user_prefs_;
+  scoped_refptr<PersistentPrefStore> incognito_user_prefs_underlay_;
+  scoped_refptr<PrefStore> recommended_prefs_;
+  scoped_refptr<PrefRegistry> pref_registry_;
+
+  base::OnceClosure quit_closure_;
+
+  base::WeakPtrFactory<InProcessPrefServiceFactory> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(InProcessPrefServiceFactory);
+};
+
+}  // namespace prefs
+
+#endif  // SERVICES_PREFERENCES_PUBLIC_CPP_IN_PROCESS_SERVICE_FACTORY_H_
diff --git a/services/preferences/public/cpp/persistent_pref_store_client.cc b/services/preferences/public/cpp/persistent_pref_store_client.cc
index e13d1c9..3131d4a 100644
--- a/services/preferences/public/cpp/persistent_pref_store_client.cc
+++ b/services/preferences/public/cpp/persistent_pref_store_client.cc
@@ -146,23 +146,20 @@
 };
 
 PersistentPrefStoreClient::PersistentPrefStoreClient(
-    mojom::PrefStoreConnectorPtr connector,
-    scoped_refptr<PrefRegistry> pref_registry,
-    std::vector<PrefValueStore::PrefStoreType> already_connected_types)
-    : connector_(std::move(connector)),
-      pref_registry_(std::move(pref_registry)),
-      already_connected_types_(std::move(already_connected_types)),
-      weak_factory_(this) {
-  DCHECK(connector_);
-}
-
-PersistentPrefStoreClient::PersistentPrefStoreClient(
     mojom::PersistentPrefStoreConnectionPtr connection)
     : weak_factory_(this) {
-  OnConnect(std::move(connection), nullptr,
-            std::vector<mojom::PrefRegistrationPtr>(),
-            std::unordered_map<PrefValueStore::PrefStoreType,
-                               prefs::mojom::PrefStoreConnectionPtr>());
+  read_error_ = connection->read_error;
+  read_only_ = connection->read_only;
+  pref_store_ = std::move(connection->pref_store);
+  if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
+    error_delegate_->OnError(read_error_);
+  error_delegate_.reset();
+  if (connection->pref_store_connection) {
+    Init(std::move(connection->pref_store_connection->initial_prefs), true,
+         std::move(connection->pref_store_connection->observer));
+  } else {
+    Init(nullptr, false, nullptr);
+  }
 }
 
 void PersistentPrefStoreClient::SetValue(const std::string& key,
@@ -222,32 +219,11 @@
 }
 
 PersistentPrefStore::PrefReadError PersistentPrefStoreClient::ReadPrefs() {
-  mojom::PersistentPrefStoreConnectionPtr connection;
-  mojom::PersistentPrefStoreConnectionPtr incognito_connection;
-  std::vector<mojom::PrefRegistrationPtr> defaults;
-  std::unordered_map<PrefValueStore::PrefStoreType,
-                     prefs::mojom::PrefStoreConnectionPtr>
-      other_pref_stores;
-  mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_calls;
-  bool success = connector_->Connect(
-      SerializePrefRegistry(*pref_registry_), already_connected_types_,
-      &connection, &incognito_connection, &defaults, &other_pref_stores);
-  DCHECK(success);
-  pref_registry_ = nullptr;
-  OnConnect(std::move(connection), std::move(incognito_connection),
-            std::move(defaults), std::move(other_pref_stores));
-  return read_error_;
+  return GetReadError();
 }
 
 void PersistentPrefStoreClient::ReadPrefsAsync(
-    ReadErrorDelegate* error_delegate) {
-  error_delegate_.reset(error_delegate);
-  connector_->Connect(SerializePrefRegistry(*pref_registry_),
-                      already_connected_types_,
-                      base::Bind(&PersistentPrefStoreClient::OnConnect,
-                                 base::Unretained(this)));
-  pref_registry_ = nullptr;
-}
+    ReadErrorDelegate* error_delegate) {}
 
 void PersistentPrefStoreClient::CommitPendingWrite(
     base::OnceClosure done_callback) {
@@ -274,29 +250,6 @@
   CommitPendingWrite(base::OnceClosure());
 }
 
-void PersistentPrefStoreClient::OnConnect(
-    mojom::PersistentPrefStoreConnectionPtr connection,
-    mojom::PersistentPrefStoreConnectionPtr incognito_connection,
-    std::vector<mojom::PrefRegistrationPtr> defaults,
-    std::unordered_map<PrefValueStore::PrefStoreType,
-                       prefs::mojom::PrefStoreConnectionPtr>
-        other_pref_stores) {
-  connector_.reset();
-  read_error_ = connection->read_error;
-  read_only_ = connection->read_only;
-  pref_store_ = std::move(connection->pref_store);
-  if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
-    error_delegate_->OnError(read_error_);
-  error_delegate_.reset();
-
-  if (connection->pref_store_connection) {
-    Init(std::move(connection->pref_store_connection->initial_prefs), true,
-         std::move(connection->pref_store_connection->observer));
-  } else {
-    Init(nullptr, false, nullptr);
-  }
-}
-
 void PersistentPrefStoreClient::QueueWrite(
     const std::string& key,
     std::set<std::vector<std::string>> path_components,
diff --git a/services/preferences/public/cpp/persistent_pref_store_client.h b/services/preferences/public/cpp/persistent_pref_store_client.h
index 9cee6fd..e00db15 100644
--- a/services/preferences/public/cpp/persistent_pref_store_client.h
+++ b/services/preferences/public/cpp/persistent_pref_store_client.h
@@ -23,8 +23,6 @@
 class Value;
 }
 
-class PrefRegistry;
-
 namespace prefs {
 
 // An implementation of PersistentPrefStore backed by a
@@ -32,11 +30,6 @@
 class PersistentPrefStoreClient
     : public PrefStoreClientMixin<PersistentPrefStore> {
  public:
-  PersistentPrefStoreClient(
-      mojom::PrefStoreConnectorPtr connector,
-      scoped_refptr<PrefRegistry> pref_registry,
-      std::vector<PrefValueStore::PrefStoreType> already_connected_types);
-
   explicit PersistentPrefStoreClient(
       mojom::PersistentPrefStoreConnectionPtr connection);
 
@@ -72,13 +65,6 @@
   class InFlightWriteTrie;
   struct InFlightWrite;
 
-  void OnConnect(mojom::PersistentPrefStoreConnectionPtr connection,
-                 mojom::PersistentPrefStoreConnectionPtr incognito_connection,
-                 std::vector<mojom::PrefRegistrationPtr> defaults,
-                 std::unordered_map<PrefValueStore::PrefStoreType,
-                                    prefs::mojom::PrefStoreConnectionPtr>
-                     other_pref_stores);
-
   void QueueWrite(const std::string& key,
                   std::set<std::vector<std::string>> path_components,
                   uint32_t flags);
@@ -91,8 +77,6 @@
                        const std::vector<std::string>& path,
                        const base::Value* new_value) override;
 
-  mojom::PrefStoreConnectorPtr connector_;
-  scoped_refptr<PrefRegistry> pref_registry_;
   bool read_only_ = false;
   PrefReadError read_error_ = PersistentPrefStore::PREF_READ_ERROR_NONE;
   mojom::PersistentPrefStorePtr pref_store_;
@@ -100,7 +84,6 @@
       pending_writes_;
 
   std::unique_ptr<ReadErrorDelegate> error_delegate_;
-  std::vector<PrefValueStore::PrefStoreType> already_connected_types_;
 
   std::queue<std::vector<InFlightWrite>> in_flight_writes_queue_;
   std::map<std::string, InFlightWriteTrie> in_flight_writes_tries_;
diff --git a/services/preferences/public/cpp/pref_service_factory.cc b/services/preferences/public/cpp/pref_service_factory.cc
index 3edf054..d7868021 100644
--- a/services/preferences/public/cpp/pref_service_factory.cc
+++ b/services/preferences/public/cpp/pref_service_factory.cc
@@ -42,13 +42,7 @@
 scoped_refptr<PrefStore> CreatePrefStoreClient(
     PrefValueStore::PrefStoreType store_type,
     std::unordered_map<PrefValueStore::PrefStoreType,
-                       mojom::PrefStoreConnectionPtr>* connections,
-    base::flat_map<PrefValueStore::PrefStoreType, scoped_refptr<PrefStore>>*
-        local_layered_pref_stores) {
-  auto local_pref_store_it = local_layered_pref_stores->find(store_type);
-  if (local_pref_store_it != local_layered_pref_stores->end()) {
-    return std::move(local_pref_store_it->second);
-  }
+                       mojom::PrefStoreConnectionPtr>* connections) {
   auto pref_store_it = connections->find(store_type);
   if (pref_store_it != connections->end()) {
     return base::MakeRefCounted<PrefStoreClient>(
@@ -80,28 +74,22 @@
     scoped_refptr<RefCountedInterfacePtr<mojom::PrefStoreConnector>>
         connector_ptr,
     scoped_refptr<PrefRegistry> pref_registry,
-    base::flat_map<PrefValueStore::PrefStoreType, scoped_refptr<PrefStore>>
-        local_layered_pref_stores,
     ConnectCallback callback,
     mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection,
     mojom::PersistentPrefStoreConnectionPtr incognito_connection,
     std::vector<mojom::PrefRegistrationPtr> defaults,
     std::unordered_map<PrefValueStore::PrefStoreType,
                        mojom::PrefStoreConnectionPtr> connections) {
-  scoped_refptr<PrefStore> managed_prefs = CreatePrefStoreClient(
-      PrefValueStore::MANAGED_STORE, &connections, &local_layered_pref_stores);
-  scoped_refptr<PrefStore> supervised_user_prefs =
-      CreatePrefStoreClient(PrefValueStore::SUPERVISED_USER_STORE, &connections,
-                            &local_layered_pref_stores);
+  scoped_refptr<PrefStore> managed_prefs =
+      CreatePrefStoreClient(PrefValueStore::MANAGED_STORE, &connections);
+  scoped_refptr<PrefStore> supervised_user_prefs = CreatePrefStoreClient(
+      PrefValueStore::SUPERVISED_USER_STORE, &connections);
   scoped_refptr<PrefStore> extension_prefs =
-      CreatePrefStoreClient(PrefValueStore::EXTENSION_STORE, &connections,
-                            &local_layered_pref_stores);
+      CreatePrefStoreClient(PrefValueStore::EXTENSION_STORE, &connections);
   scoped_refptr<PrefStore> command_line_prefs =
-      CreatePrefStoreClient(PrefValueStore::COMMAND_LINE_STORE, &connections,
-                            &local_layered_pref_stores);
+      CreatePrefStoreClient(PrefValueStore::COMMAND_LINE_STORE, &connections);
   scoped_refptr<PrefStore> recommended_prefs =
-      CreatePrefStoreClient(PrefValueStore::RECOMMENDED_STORE, &connections,
-                            &local_layered_pref_stores);
+      CreatePrefStoreClient(PrefValueStore::RECOMMENDED_STORE, &connections);
   RegisterRemoteDefaults(pref_registry.get(), std::move(defaults));
   scoped_refptr<PersistentPrefStore> persistent_pref_store(
       new PersistentPrefStoreClient(
@@ -153,16 +141,8 @@
 void ConnectToPrefService(
     service_manager::Connector* connector,
     scoped_refptr<PrefRegistry> pref_registry,
-    base::flat_map<PrefValueStore::PrefStoreType, scoped_refptr<PrefStore>>
-        local_layered_pref_stores,
     ConnectCallback callback,
     base::StringPiece service_name) {
-  std::vector<PrefValueStore::PrefStoreType> already_connected_types;
-  already_connected_types.reserve(local_layered_pref_stores.size());
-  for (const auto& store : local_layered_pref_stores) {
-    already_connected_types.push_back(store.first);
-  }
-  already_connected_types.push_back(PrefValueStore::DEFAULT_STORE);
   auto connector_ptr = make_scoped_refptr(
       new RefCountedInterfacePtr<mojom::PrefStoreConnector>());
   connector->BindInterface(service_name.as_string(), &connector_ptr->get());
@@ -170,9 +150,8 @@
       &OnConnectError, connector_ptr, base::Passed(ConnectCallback{callback})));
   auto serialized_pref_registry = SerializePrefRegistry(*pref_registry);
   connector_ptr->get()->Connect(
-      std::move(serialized_pref_registry), std::move(already_connected_types),
+      std::move(serialized_pref_registry),
       base::BindOnce(&OnConnect, connector_ptr, std::move(pref_registry),
-                     std::move(local_layered_pref_stores),
                      std::move(callback)));
 }
 
diff --git a/services/preferences/public/cpp/pref_service_factory.h b/services/preferences/public/cpp/pref_service_factory.h
index 4a52c790..9bae432 100644
--- a/services/preferences/public/cpp/pref_service_factory.h
+++ b/services/preferences/public/cpp/pref_service_factory.h
@@ -39,8 +39,6 @@
 void ConnectToPrefService(
     service_manager::Connector* connector,
     scoped_refptr<PrefRegistry> pref_registry,
-    base::flat_map<PrefValueStore::PrefStoreType, scoped_refptr<PrefStore>>
-        local_layered_pref_stores,
     ConnectCallback callback,
     base::StringPiece service_name = mojom::kServiceName);
 
diff --git a/services/preferences/public/cpp/pref_service_main.cc b/services/preferences/public/cpp/pref_service_main.cc
index b4c92c5..c481b61 100644
--- a/services/preferences/public/cpp/pref_service_main.cc
+++ b/services/preferences/public/cpp/pref_service_main.cc
@@ -10,11 +10,21 @@
 
 namespace prefs {
 
-std::unique_ptr<service_manager::Service> CreatePrefService(
-    std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
-    scoped_refptr<base::SequencedWorkerPool> worker_pool) {
-  return base::MakeUnique<PrefStoreManagerImpl>(expected_pref_stores,
-                                                std::move(worker_pool));
+std::pair<std::unique_ptr<service_manager::Service>, base::OnceClosure>
+CreatePrefService(PrefStore* managed_prefs,
+                  PrefStore* supervised_user_prefs,
+                  PrefStore* extension_prefs,
+                  PrefStore* command_line_prefs,
+                  PersistentPrefStore* user_prefs,
+                  PersistentPrefStore* incognito_user_prefs_underlay,
+                  PrefStore* recommended_prefs,
+                  PrefRegistry* pref_registry) {
+  auto service = base::MakeUnique<PrefStoreManagerImpl>(
+      managed_prefs, supervised_user_prefs, extension_prefs, command_line_prefs,
+      user_prefs, incognito_user_prefs_underlay, recommended_prefs,
+      pref_registry);
+  auto quit_closure = service->ShutDownClosure();
+  return std::make_pair(std::move(service), std::move(quit_closure));
 }
 
 }  // namespace prefs
diff --git a/services/preferences/public/cpp/pref_service_main.h b/services/preferences/public/cpp/pref_service_main.h
index 6b51efa..e0e50bf 100644
--- a/services/preferences/public/cpp/pref_service_main.h
+++ b/services/preferences/public/cpp/pref_service_main.h
@@ -11,9 +11,8 @@
 #include "base/memory/ref_counted.h"
 #include "components/prefs/pref_value_store.h"
 
-namespace base {
-class SequencedWorkerPool;
-}
+class PersistentPrefStore;
+class PrefRegistry;
 
 namespace service_manager {
 class Service;
@@ -21,9 +20,16 @@
 
 namespace prefs {
 
-std::unique_ptr<service_manager::Service> CreatePrefService(
-    std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
-    scoped_refptr<base::SequencedWorkerPool> worker_pool);
+// Creates a PrefService and a closure that can be used to shut it down.
+std::pair<std::unique_ptr<service_manager::Service>, base::OnceClosure>
+CreatePrefService(PrefStore* managed_prefs,
+                  PrefStore* supervised_user_prefs,
+                  PrefStore* extension_prefs,
+                  PrefStore* command_line_prefs,
+                  PersistentPrefStore* user_prefs,
+                  PersistentPrefStore* incognito_user_prefs_underlay,
+                  PrefStore* recommended_prefs,
+                  PrefRegistry* pref_registry);
 
 }  // namespace prefs
 
diff --git a/services/preferences/public/cpp/registering_delegate.cc b/services/preferences/public/cpp/registering_delegate.cc
deleted file mode 100644
index e90b494..0000000
--- a/services/preferences/public/cpp/registering_delegate.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/preferences/public/cpp/registering_delegate.h"
-
-#include "services/preferences/public/cpp/pref_store_impl.h"
-
-namespace sync_preferences {
-
-RegisteringDelegate::RegisteringDelegate(
-    prefs::mojom::PrefStoreRegistryPtr registry)
-    : registry_(std::move(registry)) {}
-
-RegisteringDelegate::~RegisteringDelegate() = default;
-
-void RegisteringDelegate::Init(PrefStore* managed_prefs,
-                               PrefStore* supervised_user_prefs,
-                               PrefStore* extension_prefs,
-                               PrefStore* command_line_prefs,
-                               PrefStore* user_prefs,
-                               PrefStore* recommended_prefs,
-                               PrefStore* default_prefs,
-                               PrefNotifier* pref_notifier) {
-  RegisterPrefStore(managed_prefs, PrefValueStore::MANAGED_STORE);
-  RegisterPrefStore(supervised_user_prefs,
-                    PrefValueStore::SUPERVISED_USER_STORE);
-  RegisterPrefStore(extension_prefs, PrefValueStore::EXTENSION_STORE);
-  RegisterPrefStore(command_line_prefs, PrefValueStore::COMMAND_LINE_STORE);
-  RegisterPrefStore(recommended_prefs, PrefValueStore::RECOMMENDED_STORE);
-}
-
-void RegisteringDelegate::UpdateCommandLinePrefStore(
-    PrefStore* command_line_prefs) {
-  // TODO(tibell): Once we have a way to deregister stores, do so here. At the
-  // moment only local state uses this and local state doesn't use the pref
-  // service yet.
-}
-
-void RegisteringDelegate::RegisterPrefStore(
-    scoped_refptr<PrefStore> backing_pref_store,
-    PrefValueStore::PrefStoreType type) {
-  if (!backing_pref_store)
-    return;
-
-  impls_.push_back(
-      prefs::PrefStoreImpl::Create(registry_.get(), backing_pref_store, type));
-}
-
-}  // namespace sync_preferences
diff --git a/services/preferences/public/cpp/registering_delegate.h b/services/preferences/public/cpp/registering_delegate.h
deleted file mode 100644
index c77665b8..0000000
--- a/services/preferences/public/cpp/registering_delegate.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "components/prefs/pref_value_store.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
-
-class PrefStore;
-class PrefNotifier;
-
-namespace prefs {
-class PrefStoreImpl;
-}
-
-namespace sync_preferences {
-
-// Registers all provided |PrefStore|s with the pref service. The pref stores
-// remaining registered for the life time of |this|.
-class RegisteringDelegate : public PrefValueStore::Delegate {
- public:
-  RegisteringDelegate(prefs::mojom::PrefStoreRegistryPtr registry);
-  ~RegisteringDelegate() override;
-
-  // PrefValueStore::Delegate:
-  void Init(PrefStore* managed_prefs,
-            PrefStore* supervised_user_prefs,
-            PrefStore* extension_prefs,
-            PrefStore* command_line_prefs,
-            PrefStore* user_prefs,
-            PrefStore* recommended_prefs,
-            PrefStore* default_prefs,
-            PrefNotifier* pref_notifier) override;
-  void UpdateCommandLinePrefStore(PrefStore* command_line_prefs) override;
-
- private:
-  // Expose the |backing_pref_store| through the prefs service.
-  void RegisterPrefStore(scoped_refptr<PrefStore> backing_pref_store,
-                         PrefValueStore::PrefStoreType type);
-
-  prefs::mojom::PrefStoreRegistryPtr registry_;
-  std::vector<std::unique_ptr<prefs::PrefStoreImpl>> impls_;
-};
-
-}  // namespace sync_preferences
diff --git a/services/preferences/public/cpp/tests/BUILD.gn b/services/preferences/public/cpp/tests/BUILD.gn
index 3f0a9c2..6e9cbc6 100644
--- a/services/preferences/public/cpp/tests/BUILD.gn
+++ b/services/preferences/public/cpp/tests/BUILD.gn
@@ -7,7 +7,6 @@
   sources = [
     "persistent_pref_store_client_unittest.cc",
     "pref_store_client_unittest.cc",
-    "pref_store_impl_unittest.cc",
   ]
   deps = [
     "//base",
diff --git a/services/preferences/public/interfaces/preferences.mojom b/services/preferences/public/interfaces/preferences.mojom
index 2e60d86c..09f6bd11 100644
--- a/services/preferences/public/interfaces/preferences.mojom
+++ b/services/preferences/public/interfaces/preferences.mojom
@@ -77,49 +77,22 @@
   bool read_only;
 };
 
-// Manages actual read of preference data. Accepts observers who subscribe to
-// preferences, notifying them of changes.
-interface PrefStore {
-  // Add an observer of changes to prefs contained in |prefs_to_observe|. This
-  // current values of all prefs will not be communicated through a call to
-  // |observer| but instead be returned in |initial_prefs|.
-  AddObserver(array<string> prefs_to_observe) => (
-      PrefStoreConnection connection);
-};
-
-// Manages a registry of all pref stores. Registered pref stores can be
-// connected to through the |PrefStoreConnector| interface.
-interface PrefStoreRegistry {
-  // Register a pref store.
-  Register(PrefStoreType type, PrefStore pref_store);
-};
-
 // Allows connections to pref stores registered with |PrefStoreRegistry|.
 interface PrefStoreConnector {
   // Connect to all registered pref stores, retrieving the current values of all
   // prefs in each store and an |observer| interfaces through which updates can
-  // be received. The client asserts that it is already connected to the
-  // |already_connected_types| pref stores through some other means, so the
-  // Connect call will not connect to those.
+  // be received.
   //
   // The returned |connection| is the connection to the main writable user pref
-  // store. If a |underlay| is returned any writes or reads not serviced by
-  // |connection| should be serviced by |underlay| instead (e.g. by using an
-  // |OverlayUserPrefStore|).
+  // store.
   //
   // Calls to |Connect| before |Init| are allowed and will cause the calls to
   // queue and connect once |Init| has been called.
-  [Sync]
-  Connect(PrefRegistry pref_registry,
-          array<PrefStoreType> already_connected_types) =>
+  Connect(PrefRegistry pref_registry) =>
       (PersistentPrefStoreConnection connection,
        PersistentPrefStoreConnection? underlay,
        array<PrefRegistration> remote_defaults,
        map<PrefStoreType, PrefStoreConnection> connections);
-
-  // Connect to the user pref store. Used for incognito.
-  ConnectToUserPrefStore(array<string> prefs_to_observe) =>
-      (PersistentPrefStoreConnection connection);
 };
 
 // An update to a subcomponent of a pref.
@@ -191,25 +164,9 @@
   uint32 flags;
 };
 
-interface PrefServiceControl {
-  // Initializes the pref service. This must be called before the service can
-  // be used.
-  Init(PersistentPrefStoreConfiguration configuration);
-};
-
 // ---------------------------------------------------------------------
 // Service Configuration
 
-union PersistentPrefStoreConfiguration {
-  SimplePersistentPrefStoreConfiguration simple_configuration;
-  TrackedPersistentPrefStoreConfiguration tracked_configuration;
-  IncognitoPersistentPrefStoreConfiguration incognito_configuration;
-};
-
-struct SimplePersistentPrefStoreConfiguration {
-  mojo.common.mojom.FilePath pref_filename;
-};
-
 // These parameters are passed to prefs::CreateTrackedPersistentPrefStore() in
 // services/preferences/persistent_pref_store_factory.cc.
 struct TrackedPersistentPrefStoreConfiguration {
@@ -253,8 +210,3 @@
 interface ResetOnLoadObserver {
   OnResetOnLoad();
 };
-
-struct IncognitoPersistentPrefStoreConfiguration {
-  // A connector for the underlying profile's prefs.
-  PrefStoreConnector connector;
-};
diff --git a/services/preferences/scoped_pref_connection_builder.cc b/services/preferences/scoped_pref_connection_builder.cc
index 416fe14f0..5ad903c5 100644
--- a/services/preferences/scoped_pref_connection_builder.cc
+++ b/services/preferences/scoped_pref_connection_builder.cc
@@ -5,37 +5,31 @@
 #include "services/preferences/scoped_pref_connection_builder.h"
 
 #include "services/preferences/persistent_pref_store_impl.h"
+#include "services/preferences/pref_store_impl.h"
 
 namespace prefs {
 
 ScopedPrefConnectionBuilder::ScopedPrefConnectionBuilder(
     std::vector<std::string> observed_prefs,
-    std::set<PrefValueStore::PrefStoreType> required_types,
     mojom::PrefStoreConnector::ConnectCallback callback)
     : callback_(std::move(callback)),
-      observed_prefs_(std::move(observed_prefs)),
-      required_types_(std::move(required_types)) {}
+      observed_prefs_(std::move(observed_prefs)) {}
 
-std::set<PrefValueStore::PrefStoreType>
-ScopedPrefConnectionBuilder::ProvidePrefStoreConnections(
+void ScopedPrefConnectionBuilder::ProvidePrefStoreConnections(
     const std::unordered_map<PrefValueStore::PrefStoreType,
-                             mojom::PrefStorePtr>& pref_stores) {
+                             std::unique_ptr<PrefStoreImpl>>& pref_stores) {
   for (const auto& pref_store : pref_stores) {
-    auto it = required_types_.find(pref_store.first);
-    if (it != required_types_.end()) {
-      ProvidePrefStoreConnection(pref_store.first, pref_store.second.get());
-      required_types_.erase(it);
-    }
+    ProvidePrefStoreConnection(pref_store.first, pref_store.second.get());
   }
-  return std::move(required_types_);
 }
 
 void ScopedPrefConnectionBuilder::ProvidePrefStoreConnection(
     PrefValueStore::PrefStoreType type,
-    mojom::PrefStore* pref_store) {
-  pref_store->AddObserver(
-      observed_prefs_,
-      base::Bind(&ScopedPrefConnectionBuilder::OnConnect, this, type));
+    PrefStoreImpl* pref_store) {
+  bool inserted =
+      connections_.emplace(type, pref_store->AddObserver(observed_prefs_))
+          .second;
+  DCHECK(inserted);
 }
 
 void ScopedPrefConnectionBuilder::ProvidePersistentPrefStore(
@@ -46,11 +40,11 @@
                                              observed_prefs_.end()));
 }
 
-void ScopedPrefConnectionBuilder::ProvideIncognitoConnector(
-    const mojom::PrefStoreConnectorPtr& incognito_connector) {
-  incognito_connector->ConnectToUserPrefStore(
-      observed_prefs_,
-      base::Bind(&ScopedPrefConnectionBuilder::OnIncognitoConnect, this));
+void ScopedPrefConnectionBuilder::ProvideIncognitoPersistentPrefStoreUnderlay(
+    PersistentPrefStoreImpl* persistent_pref_store) {
+  incognito_connection_ = persistent_pref_store->CreateConnection(
+      PersistentPrefStoreImpl::ObservedPrefs(observed_prefs_.begin(),
+                                             observed_prefs_.end()));
 }
 
 void ScopedPrefConnectionBuilder::ProvideDefaults(
@@ -64,17 +58,4 @@
                            std::move(defaults_), std::move(connections_));
 }
 
-void ScopedPrefConnectionBuilder::OnConnect(
-    PrefValueStore::PrefStoreType type,
-    mojom::PrefStoreConnectionPtr connection_ptr) {
-  bool inserted = connections_.emplace(type, std::move(connection_ptr)).second;
-  DCHECK(inserted);
-}
-
-void ScopedPrefConnectionBuilder::OnIncognitoConnect(
-    mojom::PersistentPrefStoreConnectionPtr connection_ptr) {
-  DCHECK(!incognito_connection_);
-  incognito_connection_ = std::move(connection_ptr);
-}
-
 }  // namespace prefs
diff --git a/services/preferences/scoped_pref_connection_builder.h b/services/preferences/scoped_pref_connection_builder.h
index 4f638b99..270b31bba 100644
--- a/services/preferences/scoped_pref_connection_builder.h
+++ b/services/preferences/scoped_pref_connection_builder.h
@@ -16,32 +16,29 @@
 
 namespace prefs {
 class PersistentPrefStoreImpl;
+class PrefStoreImpl;
 
 // A builder for connections to pref stores. When all references are released,
 // the connection is created.
 class ScopedPrefConnectionBuilder
     : public base::RefCounted<ScopedPrefConnectionBuilder> {
  public:
-  // |required_types| lists all the |Provide*| calls the client of this object
-  // is expected to make. Once all these |Provide*| calls have been made, the
-  // |callback| will be invoked.
   ScopedPrefConnectionBuilder(
       std::vector<std::string> observed_prefs,
-      std::set<PrefValueStore::PrefStoreType> required_types,
       mojom::PrefStoreConnector::ConnectCallback callback);
 
-  std::set<PrefValueStore::PrefStoreType> ProvidePrefStoreConnections(
+  void ProvidePrefStoreConnections(
       const std::unordered_map<PrefValueStore::PrefStoreType,
-                               mojom::PrefStorePtr>& pref_stores);
+                               std::unique_ptr<PrefStoreImpl>>& pref_stores);
 
   void ProvidePrefStoreConnection(PrefValueStore::PrefStoreType type,
-                                  mojom::PrefStore* ptr);
+                                  PrefStoreImpl* ptr);
 
   void ProvidePersistentPrefStore(
       PersistentPrefStoreImpl* persistent_pref_store);
 
-  void ProvideIncognitoConnector(
-      const mojom::PrefStoreConnectorPtr& incognito_connector);
+  void ProvideIncognitoPersistentPrefStoreUnderlay(
+      PersistentPrefStoreImpl* persistent_pref_store);
 
   void ProvideDefaults(std::vector<mojom::PrefRegistrationPtr> defaults);
 
@@ -49,17 +46,9 @@
   friend class base::RefCounted<ScopedPrefConnectionBuilder>;
   ~ScopedPrefConnectionBuilder();
 
-  void OnConnect(PrefValueStore::PrefStoreType type,
-                 mojom::PrefStoreConnectionPtr connection_ptr);
-
-  void OnIncognitoConnect(
-      mojom::PersistentPrefStoreConnectionPtr connection_ptr);
-
   mojom::PrefStoreConnector::ConnectCallback callback_;
   std::vector<std::string> observed_prefs_;
 
-  std::set<PrefValueStore::PrefStoreType> required_types_;
-
   std::unordered_map<PrefValueStore::PrefStoreType,
                      mojom::PrefStoreConnectionPtr>
       connections_;
diff --git a/services/preferences/shared_pref_registry.cc b/services/preferences/shared_pref_registry.cc
index 1bd46ec4..4889f58 100644
--- a/services/preferences/shared_pref_registry.cc
+++ b/services/preferences/shared_pref_registry.cc
@@ -4,7 +4,8 @@
 
 #include "services/preferences/shared_pref_registry.h"
 
-#include "components/prefs/default_pref_store.h"
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_store.h"
 #include "services/preferences/scoped_pref_connection_builder.h"
 #include "services/service_manager/public/cpp/identity.h"
 
@@ -44,15 +45,22 @@
   DISALLOW_COPY_AND_ASSIGN(PendingConnection);
 };
 
-SharedPrefRegistry::SharedPrefRegistry()
-    : defaults_(base::MakeRefCounted<DefaultPrefStore>()) {}
+SharedPrefRegistry::SharedPrefRegistry(scoped_refptr<PrefRegistry> registry)
+    : registry_(std::move(registry)) {
+  for (const auto& pref : *registry_) {
+#if DCHECK_IS_ON()
+    all_registered_pref_keys_.insert(pref.first);
+#endif
+    if (registry_->GetRegistrationFlags(pref.first) & PrefRegistry::PUBLIC)
+      public_pref_keys_.insert(std::move(pref.first));
+  }
+}
 
 SharedPrefRegistry::~SharedPrefRegistry() = default;
 
 scoped_refptr<ScopedPrefConnectionBuilder>
 SharedPrefRegistry::CreateConnectionBuilder(
     mojom::PrefRegistryPtr pref_registry,
-    std::set<PrefValueStore::PrefStoreType> required_types,
     const service_manager::Identity& identity,
     mojom::PrefStoreConnector::ConnectCallback callback) {
   bool is_initial_connection = connected_services_.insert(identity).second;
@@ -90,8 +98,7 @@
 #endif
 
   auto connection_builder = base::MakeRefCounted<ScopedPrefConnectionBuilder>(
-      std::move(observed_prefs), std::move(required_types),
-      std::move(callback));
+      std::move(observed_prefs), std::move(callback));
   if (remaining_foreign_registrations.empty()) {
     ProvideDefaultPrefs(connection_builder.get(),
                         pref_registry->foreign_registrations);
@@ -138,9 +145,9 @@
       DCHECK(inserted) << "Multiple services claimed ownership of pref \""
                        << key << "\"";
 #endif
-      defaults_->SetDefaultValue(key, std::move(default_value));
-      if (registration->flags)
-        pref_flags_.emplace(key, registration->flags);
+      registry_->RegisterForeignPref(key);
+      registry_->SetDefaultForeignPrefValue(key, std::move(default_value),
+                                            registration->flags);
 
       observed_prefs->push_back(key);
       new_public_prefs.push_back(key);
@@ -158,7 +165,8 @@
       observed_prefs->push_back(registration->key);
 #if DCHECK_IS_ON()
       const base::Value* existing_default_value = nullptr;
-      DCHECK(defaults_->GetValue(registration->key, &existing_default_value));
+      DCHECK(registry_->defaults()->GetValue(registration->key,
+                                             &existing_default_value));
       DCHECK_EQ(*existing_default_value, *registration->default_value);
 #endif
     }
@@ -171,11 +179,9 @@
   std::vector<mojom::PrefRegistrationPtr> defaults;
   for (const auto& key : foreign_prefs) {
     const base::Value* value = nullptr;
-    defaults_->GetValue(key, &value);
-    auto it = pref_flags_.find(key);
-
+    registry_->defaults()->GetValue(key, &value);
     defaults.emplace_back(base::in_place, key, value->CreateDeepCopy(),
-                          it != pref_flags_.end() ? it->second : 0);
+                          registry_->GetRegistrationFlags(key));
   }
 
   connection->ProvideDefaults(std::move(defaults));
diff --git a/services/preferences/shared_pref_registry.h b/services/preferences/shared_pref_registry.h
index e0764b5..397fa6d4 100644
--- a/services/preferences/shared_pref_registry.h
+++ b/services/preferences/shared_pref_registry.h
@@ -14,7 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
 
-class DefaultPrefStore;
+class PrefRegistry;
 
 namespace service_manager {
 class Identity;
@@ -28,12 +28,11 @@
 // connections that require them.
 class SharedPrefRegistry {
  public:
-  SharedPrefRegistry();
+  explicit SharedPrefRegistry(scoped_refptr<PrefRegistry> registry);
   ~SharedPrefRegistry();
 
   scoped_refptr<ScopedPrefConnectionBuilder> CreateConnectionBuilder(
       mojom::PrefRegistryPtr pref_registry,
-      std::set<PrefValueStore::PrefStoreType> required_types,
       const service_manager::Identity& identity,
       mojom::PrefStoreConnector::ConnectCallback callback);
 
@@ -52,8 +51,7 @@
   void ProvideDefaultPrefs(ScopedPrefConnectionBuilder* connection,
                            std::vector<std::string> foreign_prefs);
 
-  scoped_refptr<DefaultPrefStore> defaults_;
-  std::map<std::string, int> pref_flags_;
+  scoped_refptr<PrefRegistry> registry_;
 
   std::set<std::string> public_pref_keys_;
 
diff --git a/services/preferences/tracked/tracked_persistent_pref_store_factory.cc b/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
index be4ce2d..2c32319 100644
--- a/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
+++ b/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
@@ -65,10 +65,7 @@
 
 PersistentPrefStore* CreateTrackedPersistentPrefStore(
     prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr config,
-    base::SequencedWorkerPool* worker_pool) {
-  auto io_task_runner = JsonPrefStore::GetTaskRunnerForFile(
-      config->unprotected_pref_filename.DirName(), worker_pool);
-
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner) {
   std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
       unprotected_configuration;
   std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
diff --git a/services/preferences/tracked/tracked_persistent_pref_store_factory.h b/services/preferences/tracked/tracked_persistent_pref_store_factory.h
index e50d1278..ca08959 100644
--- a/services/preferences/tracked/tracked_persistent_pref_store_factory.h
+++ b/services/preferences/tracked/tracked_persistent_pref_store_factory.h
@@ -10,14 +10,13 @@
 
 namespace base {
 class DictionaryValue;
-class SequencedWorkerPool;
 }
 
 class PersistentPrefStore;
 
 PersistentPrefStore* CreateTrackedPersistentPrefStore(
     prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr config,
-    base::SequencedWorkerPool* worker_pool);
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner);
 
 // TODO(sammc): This should move somewhere more appropriate in the longer term.
 void InitializeMasterPrefsTracking(
diff --git a/services/preferences/unittest_manifest.json b/services/preferences/unittest_manifest.json
index 94e375d..5354cb8 100644
--- a/services/preferences/unittest_manifest.json
+++ b/services/preferences/unittest_manifest.json
@@ -9,7 +9,7 @@
         ]
       },
       "requires": {
-        "preferences": [ "pref_client", "pref_control" ],
+        "preferences": [ "pref_client" ],
         "prefs_unittest_helper": [ "test" ]
       }
     }
diff --git a/services/ui/public/cpp/BUILD.gn b/services/ui/public/cpp/BUILD.gn
index dde36c30c..e59ed0c 100644
--- a/services/ui/public/cpp/BUILD.gn
+++ b/services/ui/public/cpp/BUILD.gn
@@ -16,7 +16,7 @@
     "//base",
     "//cc",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
+    "//components/viz/common",
     "//mojo/public/cpp/bindings",
     "//services/service_manager/public/interfaces",
     "//services/ui/common:mus_common",
@@ -61,7 +61,7 @@
     "//base",
     "//cc",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
+    "//components/viz/common",
     "//mojo/public/cpp/bindings",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/interfaces",
diff --git a/services/ui/ws/BUILD.gn b/services/ui/ws/BUILD.gn
index 351167c..ab7176fc 100644
--- a/services/ui/ws/BUILD.gn
+++ b/services/ui/ws/BUILD.gn
@@ -138,7 +138,7 @@
     "//cc",
     "//cc/ipc:interfaces",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
+    "//components/viz/common",
     "//mojo/common:common_base",
     "//mojo/public/cpp/bindings",
     "//services/service_manager/public/cpp",
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 54df758..3bb4bf0 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -224,10 +224,6 @@
 #define SK_SUPPORT_LEGACY_MASK_BLUR
 #endif
 
-#ifndef SK_SUPPORT_LEGACY_RECT
-#define SK_SUPPORT_LEGACY_RECT
-#endif
-
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
diff --git a/sql/connection.cc b/sql/connection.cc
index c80758f..d7477f57 100644
--- a/sql/connection.cc
+++ b/sql/connection.cc
@@ -31,6 +31,7 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
+#include "build/build_config.h"
 #include "sql/connection_memory_dump_provider.h"
 #include "sql/meta_table.h"
 #include "sql/statement.h"
@@ -1726,7 +1727,7 @@
   }
 
   // TODO(shess): OS_WIN support?
-#if defined(OS_POSIX)
+#if defined(OS_POSIX) && !defined(OS_FUCHSIA)
   if (restrict_to_user_) {
     DCHECK_NE(file_name, std::string(":memory"));
     base::FilePath file_path(file_name);
@@ -1747,7 +1748,7 @@
       base::SetPosixFilePermissions(wal_path, mode);
     }
   }
-#endif  // defined(OS_POSIX)
+#endif  // defined(OS_POSIX) && !defined(OS_FUCHSIA)
 
   // SQLite uses a lookaside buffer to improve performance of small mallocs.
   // Chromium already depends on small mallocs being efficient, so we disable
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 7958a7a..f108173 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -259,6 +259,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "keyboard_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "latency_unittests"
       },
       {
@@ -702,6 +708,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "keyboard_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "latency_unittests"
       },
       {
@@ -1066,6 +1078,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "keyboard_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "latency_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index a8a1f59..e6c0e68 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -11141,8 +11141,14 @@
   "Fuchsia": {
     "additional_compile_targets": [
       "d8",
+      "gl_unittests",
+      "mojo_common_unittests",
+      "mojo_public_bindings_unittests",
+      "mojo_public_system_unittests",
+      "mojo_system_unittests",
       "net_unittests",
-      "skia_unittests"
+      "skia_unittests",
+      "ui_base_unittests"
     ],
     "gtest_tests": [
       {
@@ -11168,8 +11174,14 @@
   "Fuchsia (dbg)": {
     "additional_compile_targets": [
       "d8",
+      "gl_unittests",
+      "mojo_common_unittests",
+      "mojo_public_bindings_unittests",
+      "mojo_public_system_unittests",
+      "mojo_system_unittests",
       "net_unittests",
-      "skia_unittests"
+      "skia_unittests",
+      "ui_base_unittests"
     ],
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 8fc1420..506864e 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -289,6 +289,400 @@
       }
     ]
   },
+  "Linux CFI": {
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "accessibility_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "app_shell_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "aura_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "blink_heap_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "blink_platform_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cacheinvalidation_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "capture_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cast_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cc_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "chromedriver_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "components_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "components_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "compositor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "crypto_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "dbus_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "device_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "display_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "events_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "extensions_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "extensions_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gcm_unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gfx_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gin_unittests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--no-xvfb"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Ubuntu"
+            }
+          ]
+        },
+        "test": "gl_unittests",
+        "use_xvfb": false
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gn_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "google_apis_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gpu_ipc_service_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ipc_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "jingle_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "latency_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_blink_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_common_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_public_bindings_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_public_system_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_system_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "nacl_loader_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "native_theme_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "net_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "pdf_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ppapi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "printing_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "remoting_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sandbox_linux_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "skia_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sql_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "storage_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ui_base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ui_touch_selection_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "url_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "webkit_unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "wm_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "wtf_unittests"
+      }
+    ]
+  },
   "Linux Chromium OS ASan LSan Tests (1)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/filters/OWNERS b/testing/buildbot/filters/OWNERS
index fb790df..83f9ffc 100644
--- a/testing/buildbot/filters/OWNERS
+++ b/testing/buildbot/filters/OWNERS
@@ -10,11 +10,7 @@
 per-file browser-side-navigation*=scottmg@chromium.org
 per-file browser-side-navigation*=yzshen@chromium.org
 
-per-file fuchsia*=jamesr@chromium.org
-per-file fuchsia*=kmarshall@chromium.org
-per-file fuchsia*=scottmg@chromium.org
-per-file fuchsia*=sergeyu@chromium.org
-per-file fuchsia*=wez@chromium.org
+per-file fuchsia*=file://build/fuchsia/OWNERS
 
 # TEAM: infra-dev@chromium.org
 # COMPONENT: Infra>Client>Chrome
diff --git a/testing/buildbot/filters/fuchsia.base_unittests.filter b/testing/buildbot/filters/fuchsia.base_unittests.filter
index f97655e..992b6850 100644
--- a/testing/buildbot/filters/fuchsia.base_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.base_unittests.filter
@@ -3,10 +3,6 @@
 -ActivityTrackerTest.CreateWithFileTest
 -ActivityTrackerTest.ProcessDeathTest
 -ActivityTrackerTest.ThreadDeathTest
--FileLockingTest.LockAndUnlock
--FileLockingTest.UnlockOnClose
--FileLockingTest.UnlockOnExit
--FileLockingTest.UnlockOnTerminate
 -FilePathWatcherTest.DeleteAndRecreate
 -FilePathWatcherTest.DeleteDuringNotify
 -FilePathWatcherTest.DeletedFile
@@ -27,17 +23,7 @@
 -FilePersistentMemoryAllocatorTest.ExtendTest
 -FileProxyTest.SetTimes
 -FileUtilProxyTest.Touch
--FileUtilTest.ChangeDirectoryPermissionsAndEnumerate
--FileUtilTest.ChangeFilePermissionsAndRead
--FileUtilTest.ChangeFilePermissionsAndWrite
--FileUtilTest.CopyDirectoryACL
--FileUtilTest.CopyFileACL
--FileUtilTest.CreateAndReadSymlinks
--FileUtilTest.DeleteSymlinkToExistentFile
--FileUtilTest.DeleteSymlinkToNonExistentFile
--FileUtilTest.ExecutableExistsInPath
 -FileUtilTest.FileToFILE
--FileUtilTest.NormalizeFilePathSymlinks
 -LoggingTest.CheckCausesDistinctBreakpoints
 -MemoryMappedFileTest.ExtendableFile
 -MemoryMappedFileTest.MapLargePartialRegionInTheMiddle
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6f9940d..2a157a0d 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1085,6 +1085,26 @@
             ]
         }
     ],
+    "ExpectCTDynamic": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "DynamicExpectCTEnabled",
+                    "enable_features": [
+                        "DynamicExpectCT"
+                    ]
+                }
+            ]
+        }
+    ],
     "ExpectCTReporting": [
         {
             "platforms": [
@@ -3135,7 +3155,7 @@
             ]
         }
     ],
-    "TLS13Negotiation": [
+    "TLS13Variant": [
         {
             "platforms": [
                 "android",
@@ -3147,10 +3167,10 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "NegotiateTLS13"
-                    ]
+                    "name": "DraftEnabled",
+                    "params": {
+                        "variant": "draft"
+                    }
                 }
             ]
         }
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 24cfcd2d..75935932 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -22128,6 +22128,7 @@
 crbug.com/591099 vr/requestAnimationFrame_submitFrame_combinations.html [ Crash Pass Timeout ]
 crbug.com/591099 vr/requestPresent_reject_badleftbounds.html [ Crash Pass ]
 crbug.com/591099 vr/requestPresent_reject_badrightbounds.html [ Crash Pass ]
+crbug.com/591099 vr/requestPresent_reject_NaN_bounds.html [ Crash Pass ]
 crbug.com/591099 vr/requestPresent_reject_nogesture.html [ Crash Pass ]
 crbug.com/591099 vr/requestPresent_reject_nolayers.html [ Crash Pass ]
 crbug.com/591099 vr/requestPresent_reject_nosource.html [ Crash Pass ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index ff583da5..c73d3c1 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -2025,6 +2025,7 @@
 Bug(none) vr/requestAnimationFrame_submitFrame_combinations.html [ Timeout ]
 Bug(none) vr/requestAnimationFrame_unregister.html [ Timeout ]
 Bug(none) vr/requestPresent_reject_badleftbounds.html [ Timeout ]
+Bug(none) vr/requestPresent_reject_NaN_bounds.html [ Timeout ]
 Bug(none) vr/requestPresent_reject_badrightbounds.html [ Timeout ]
 Bug(none) vr/requestPresent_reject_nogesture.html [ Timeout ]
 Bug(none) vr/requestPresent_reject_nolayers.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index da5f1af5..091587f3 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -860,6 +860,7 @@
 crbug.com/490511 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/color.html [ Failure ]
 crbug.com/490511 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/width.html [ Failure ]
 crbug.com/490511 external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html [ Failure ]
+crbug.com/742672 external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/moving-documents.html [ Failure Pass ]
 # [Slow] didn't help.
 crbug.com/742104 external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html [ Timeout ]
 crbug.com/692560 external/wpt/html/semantics/document-metadata/styling/LinkStyle.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/inspector/components/parsed-url-expected.txt b/third_party/WebKit/LayoutTests/inspector/components/parsed-url-expected.txt
index 076f2cc..2e2a6fb 100644
--- a/third_party/WebKit/LayoutTests/inspector/components/parsed-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/components/parsed-url-expected.txt
@@ -3,6 +3,7 @@
 Parsing url: http://example.com/?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: /
@@ -10,19 +11,21 @@
   fragment: fragmentWith/Many//Slashes
   folderPathComponents: 
   lastPathComponent: 
-Parsing url: http://example.com/foo.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes
+Parsing url: http://example.com/foo.html?queryParam1=value1@&queryParam2=value2#fragmentWith/Many//Slashes
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: /foo.html
-  queryParams: queryParam1=value1&queryParam2=value2
+  queryParams: queryParam1=value1@&queryParam2=value2
   fragment: fragmentWith/Many//Slashes
   folderPathComponents: 
   lastPathComponent: foo.html
-Parsing url: http://example.com/foo/bar.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes
+Parsing url: http://user42:Alina-!$&@example.com/foo/bar.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes
   isValid: true
   scheme: http
+  user: user42:Alina-!$&
   host: example.com
   port: undefined
   path: /foo/bar.html
@@ -30,9 +33,10 @@
   fragment: fragmentWith/Many//Slashes
   folderPathComponents: /foo
   lastPathComponent: bar.html
-Parsing url: http://example.com/foo/bar/baz.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes
+Parsing url: http://foo@example.com/foo/bar/baz.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes
   isValid: true
   scheme: http
+  user: foo
   host: example.com
   port: undefined
   path: /foo/bar/baz.html
@@ -43,6 +47,7 @@
 Parsing url: http://example.com//?queryParam1=value1
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: //
@@ -53,6 +58,7 @@
 Parsing url: http://example.com//foo.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: //foo.html
@@ -63,6 +69,7 @@
 Parsing url: http://example.com//foo/bar.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: //foo/bar.html
@@ -73,6 +80,7 @@
 Parsing url: http://example.com/foo//bar.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: /foo//bar.html
@@ -83,6 +91,7 @@
 Parsing url: http://example.com//foo//bar.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: //foo//bar.html
@@ -93,6 +102,7 @@
 Parsing url: http://example.com//foo/bar/baz.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: //foo/bar/baz.html
@@ -103,6 +113,7 @@
 Parsing url: http://example.com/foo//bar/baz.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: /foo//bar/baz.html
@@ -113,6 +124,7 @@
 Parsing url: http://example.com/foo/bar//baz.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: /foo/bar//baz.html
@@ -123,6 +135,7 @@
 Parsing url: http://example.com///foo/bar/baz.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: ///foo/bar/baz.html
@@ -133,6 +146,7 @@
 Parsing url: http://example.com/foo////bar/baz.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: /foo////bar/baz.html
@@ -143,6 +157,7 @@
 Parsing url: http://example.com/foo/bar/////baz.html
   isValid: true
   scheme: http
+  user: undefined
   host: example.com
   port: undefined
   path: /foo/bar/////baz.html
diff --git a/third_party/WebKit/LayoutTests/inspector/components/parsed-url.html b/third_party/WebKit/LayoutTests/inspector/components/parsed-url.html
index d539d41..90c71cd 100644
--- a/third_party/WebKit/LayoutTests/inspector/components/parsed-url.html
+++ b/third_party/WebKit/LayoutTests/inspector/components/parsed-url.html
@@ -12,6 +12,7 @@
         InspectorTest.addResult("Parsing url: " + url);
         InspectorTest.addResult("  isValid: " + parsedURL.isValid);
         InspectorTest.addResult("  scheme: " + parsedURL.scheme);
+        InspectorTest.addResult("  user: " + parsedURL.user);
         InspectorTest.addResult("  host: " + parsedURL.host);
         InspectorTest.addResult("  port: " + parsedURL.port);
         InspectorTest.addResult("  path: " + parsedURL.path);
@@ -22,9 +23,9 @@
     }
 
     parseAndDumpURL("http://example.com/?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes");
-    parseAndDumpURL("http://example.com/foo.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes");
-    parseAndDumpURL("http://example.com/foo/bar.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes");
-    parseAndDumpURL("http://example.com/foo/bar/baz.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes");
+    parseAndDumpURL("http://example.com/foo.html?queryParam1=value1@&queryParam2=value2#fragmentWith/Many//Slashes");
+    parseAndDumpURL("http://user42:Alina-!$&@example.com/foo/bar.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes");
+    parseAndDumpURL("http://foo@example.com/foo/bar/baz.html?queryParam1=value1&queryParam2=value2#fragmentWith/Many//Slashes");
 
     // Test how double (and more than double) slashes are parsed.
     parseAndDumpURL("http://example.com//?queryParam1=value1");
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-selection-text-05-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-selection-text-05-t-expected.png
index 12a8b8f..d658de5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-selection-text-05-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-selection-text-05-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png
index bd08283..c92592a3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-deco-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-deco-01-b-expected.png
index 64d5000..7dd0d46 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-deco-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/text-deco-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png
index 9d185f31..842ed82b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/batik/text/textDecoration2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/batik/text/textDecoration2-expected.png
index 4cecc93..814eb5f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/batik/text/textDecoration2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/batik/text/textDecoration2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/batik/text/textProperties-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/batik/text/textProperties-expected.png
index 071a20be..57a9e09 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/batik/text/textProperties-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/batik/text/textProperties-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/colourpicker-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/colourpicker-expected.png
index 0c07170..63ef1db 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/colourpicker-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/colourpicker-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/slider-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/slider-expected.png
index 11b2063..bc0f2b62 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/slider-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/slider-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-symbol-inside-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-symbol-inside-pattern-expected.png
index ce933b71..2c1df1e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-symbol-inside-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-symbol-inside-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-deco-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-deco-01-b-expected.png
index 1454538..e509e07 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-deco-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-deco-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-text-06-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-text-06-t-expected.png
index 5fed744..29690cf 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-text-06-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/text-selection-text-06-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/complex-synthetic-bold-space-width-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/complex-synthetic-bold-space-width-expected.png
index 3352f9f..27c2a03 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/complex-synthetic-bold-space-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/complex-synthetic-bold-space-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/webfont-synthetic-bold-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/webfont-synthetic-bold-expected.png
index 92441ea3..1ef271c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/webfont-synthetic-bold-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/webfont-synthetic-bold-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/plugins/mouse-click-plugin-clears-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/plugins/mouse-click-plugin-clears-selection-expected.txt
index 96dc06f..b8f2ae7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/plugins/mouse-click-plugin-clears-selection-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/plugins/mouse-click-plugin-clears-selection-expected.txt
@@ -1,7 +1,6 @@
 CONSOLE MESSAGE: Blink Test Plugin: initializing
 CONSOLE MESSAGE: Blink Test Plugin: DidChangeFocus(true)
 CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (52,52)
-CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (52,52)
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/complex-synthetic-bold-space-width-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/complex-synthetic-bold-space-width-expected.png
index 29f9ab059..9ae6740 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/complex-synthetic-bold-space-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/complex-synthetic-bold-space-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/complex-synthetic-bold-space-width-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/complex-synthetic-bold-space-width-expected.png
index 6843723..dd9d985 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/complex-synthetic-bold-space-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/complex-synthetic-bold-space-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/webfont-synthetic-bold-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/webfont-synthetic-bold-expected.png
index 603fb7a4..47623d2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/webfont-synthetic-bold-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/webfont-synthetic-bold-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/text-selection-text-05-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/text-selection-text-05-t-expected.png
index 285567f..6dca7eb0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/text-selection-text-05-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/text-selection-text-05-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png
index bcdbf30..34ccb568 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-deco-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-deco-01-b-expected.png
index c9283722..e365fda 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-deco-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/text-deco-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png
index a0d987bb6..828fbda 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/batik/text/textDecoration2-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/batik/text/textDecoration2-expected.png
index 0aeea9e..83fce44 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/batik/text/textDecoration2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/batik/text/textDecoration2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/batik/text/textProperties-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/batik/text/textProperties-expected.png
index ded7f2ba..d96af9c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/batik/text/textProperties-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/batik/text/textProperties-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/colourpicker-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/colourpicker-expected.png
index 94a7251..783402c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/colourpicker-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/colourpicker-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/slider-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/slider-expected.png
index 44daa1e5..ce532b1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/slider-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/slider-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-symbol-inside-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-symbol-inside-pattern-expected.png
index f0424460..acb10566 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-symbol-inside-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-symbol-inside-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/text/text-selection-deco-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/text/text-selection-deco-01-b-expected.png
index 707b3aaa..8fd6985 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/text/text-selection-deco-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/text/text-selection-deco-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/text/text-selection-text-06-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/text/text-selection-text-06-t-expected.png
index 05d22dc48..f302cf2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/text/text-selection-text-06-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/text/text-selection-text-06-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/emoticons-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/emoticons-expected.png
index 7a3147be..f3d92d1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/text/emoticons-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/emoticons-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/webfont-synthetic-bold-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/webfont-synthetic-bold-expected.png
index 2d571a4..f2a3de3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/text/webfont-synthetic-bold-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/webfont-synthetic-bold-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-selection-text-05-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-selection-text-05-t-expected.png
index 4172c83..074b1877 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-selection-text-05-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-selection-text-05-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png
index 52b151f7..81a76a21 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/animate-elem-41-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/text-deco-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/text-deco-01-b-expected.png
index b41dac6..dc9cd88 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/text-deco-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/text-deco-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-5-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-5-expected.png
index 5133aac4..f61e48d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textDecoration2-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textDecoration2-expected.png
index d9b395f..8c803b08 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textDecoration2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textDecoration2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textProperties-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textProperties-expected.png
index cbc4de6..e6b6a53 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textProperties-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textProperties-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/colourpicker-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/colourpicker-expected.png
index 5b86698..e9afeeb3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/colourpicker-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/colourpicker-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/slider-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/slider-expected.png
index 7b56686..c67f903 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/slider-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/slider-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-symbol-inside-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-symbol-inside-pattern-expected.png
index 41cfed8..a3ce4c08 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-symbol-inside-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-symbol-inside-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/text/text-selection-deco-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/text/text-selection-deco-01-b-expected.png
index 6ef58c6..9bcde2c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/text/text-selection-deco-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/text/text-selection-deco-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/text/text-selection-text-06-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/text/text-selection-text-06-t-expected.png
index dbe849e5..24dc3b94 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/text/text-selection-text-06-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/text/text-selection-text-06-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/webfont-synthetic-bold-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/webfont-synthetic-bold-expected.png
index a9476ac4..f2e8737 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/webfont-synthetic-bold-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/webfont-synthetic-bold-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/as-background-image/svg-as-background-5-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/as-background-image/svg-as-background-5-expected.png
index 2656e7c..552dad2 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
index ee312d3..915b86e 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -392,13 +392,19 @@
     setter onaddtrack
     setter onchange
     setter onremovetrack
-interface AuthenticationAssertion
+interface AuthenticatorAssertionResponse : AuthenticatorResponse
     attribute @@toStringTag
     getter authenticatorData
-    getter clientData
-    getter credential
     getter signature
     method constructor
+interface AuthenticatorAttestationResponse : AuthenticatorResponse
+    attribute @@toStringTag
+    getter attestationObject
+    method constructor
+interface AuthenticatorResponse
+    attribute @@toStringTag
+    getter clientDataJSON
+    method constructor
 interface BackgroundFetchFetch
     attribute @@toStringTag
     getter request
@@ -5066,6 +5072,11 @@
     getter promise
     getter reason
     method constructor
+interface PublicKeyCredential : Credential
+    attribute @@toStringTag
+    getter rawId
+    getter response
+    method constructor
 interface PushManager
     static getter supportedContentEncodings
     attribute @@toStringTag
@@ -6414,16 +6425,6 @@
     getter zoomAndPan
     method constructor
     setter zoomAndPan
-interface ScopedCredential
-    attribute @@toStringTag
-    getter id
-    getter type
-    method constructor
-interface ScopedCredentialInfo
-    attribute @@toStringTag
-    getter attestation
-    getter clientData
-    method constructor
 interface Screen
     attribute @@toStringTag
     getter availHeight
diff --git a/third_party/WebKit/LayoutTests/vr/requestPresent_reject_NaN_bounds.html b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_NaN_bounds.html
new file mode 100644
index 0000000..51c2614
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/vr/requestPresent_reject_NaN_bounds.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="resources/fake-vr-displays.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/device/vr/vr_service.mojom.js"></script>
+<script src="resources/mock-vr-service.js"></script>
+<canvas id="webgl-canvas"></canvas>
+<script src="resources/presentation-setup.js"></script>
+<script>
+let fakeDisplays = fakeVRDisplays();
+
+vr_test( (t) => {
+  return navigator.getVRDisplays().then( (displays) => {
+    var display = displays[0];
+
+    runWithUserGesture( () => {
+      display.requestPresent([{
+          source : webglCanvas,
+          leftBounds: [0, 0, 1, 1],
+          rightBounds: [NaN, NaN, NaN, NaN]
+        }])
+      .then( () => {
+        t.step( () => {
+          assert_unreached();
+        }, "Display should not be presenting");
+      }, (err) => {
+        t.step( () => {
+          assert_false(display.isPresenting);
+        }, "requestPresent rejected and not presenting");
+      }).then( () => {
+        t.done();
+      });
+    });
+  }, (err) => {
+    t.step( () => {
+      assert_unreached(err);
+    }, "getVRDisplays rejected");
+    t.done();
+  });
+}, [fakeDisplays["Pixel"]],
+"Test requestPresent rejects if provided a bad leftBounds");
+
+</script>
+                                                                                                    
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html
index 145283b..79b8b8b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-equalpower.html
@@ -39,6 +39,100 @@
             ;
           });
 
+      // Test that a mono source plays out on both the left and right channels
+      // when the source and listener positions are the same.
+      audit.define(
+          {
+            label: 'mono source=listener',
+            description: 'Source and listener at the same position'
+          },
+          (task, should) => {
+            // Must be stereo to verify output and only need a short duration
+            let context =
+                new OfflineAudioContext(2, 0.25 * sampleRate, sampleRate);
+
+            // Arbitrary position for source and listener.  Just so we don't use
+            // defaults positions.
+            let x = 1;
+            let y = 2;
+            let z = 3;
+
+            context.listener.setPosition(x, y, z);
+
+            let src = new OscillatorNode(context);
+            let panner = new PannerNode(context, {
+              panningModel: 'equalpower',
+              positionX: x,
+              positionY: y,
+              positionZ: z
+            });
+
+            src.connect(panner).connect(context.destination);
+
+            src.start();
+
+            context.startRendering()
+                .then(renderedBuffer => {
+                  // Verify that both channels have the same data because they
+                  // should when the source and listener are at the same
+                  // position
+                  let c0 = renderedBuffer.getChannelData(0);
+                  let c1 = renderedBuffer.getChannelData(1);
+                  should(c0, 'Left and right channels').beEqualToArray(c1);
+                })
+                .then(() => task.done());
+          });
+
+      // Test that a stereo source plays out on both the left and right channels
+      // when the source and listener positions are the same.
+      audit.define(
+          {
+            label: 'stereo source=listener',
+            description: 'Source and listener at the same position'
+          },
+          (task, should) => {
+            // Must be stereo to verify output and only need a short duration.
+            let context =
+                new OfflineAudioContext(2, 0.25 * sampleRate, sampleRate);
+
+            // Arbitrary position for source and listener.  Just so we don't use
+            // defaults positions.
+            let x = 1;
+            let y = 2;
+            let z = 3;
+
+            context.listener.setPosition(x, y, z);
+
+            let src = new OscillatorNode(context);
+            let merger = new ChannelMergerNode(context, {numberOfInputs: 2});
+            let panner = new PannerNode(context, {
+              panningModel: 'equalpower',
+              positionX: x,
+              positionY: y,
+              positionZ: z
+            });
+
+            // Make the oscillator a stereo signal (with identical signals on
+            // each channel).
+            src.connect(merger, 0, 0);
+            src.connect(merger, 0, 1);
+
+            merger.connect(panner).connect(context.destination);
+
+            src.start();
+
+            context.startRendering()
+                .then(renderedBuffer => {
+                  // Verify that both channels have the same data because they
+                  // should when the source and listener are at the same
+                  // position.
+                  let c0 = renderedBuffer.getChannelData(0);
+                  let c1 = renderedBuffer.getChannelData(1);
+                  should(c0, 'Left and right channels').beEqualToArray(c1);
+                })
+                .then(() => task.done());
+          });
+
       audit.run();
     </script>
   </body>
diff --git a/third_party/WebKit/LayoutTests/webauth/idl-expected.txt b/third_party/WebKit/LayoutTests/webauth/idl-expected.txt
new file mode 100644
index 0000000..089538e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webauth/idl-expected.txt
@@ -0,0 +1,42 @@
+This is a testharness.js-based test.
+FAIL PublicKeyCredential interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS PublicKeyCredential interface object length 
+PASS PublicKeyCredential interface object name 
+FAIL PublicKeyCredential interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS PublicKeyCredential interface: existence and properties of interface prototype object's "constructor" property 
+PASS PublicKeyCredential interface: attribute rawId 
+PASS PublicKeyCredential interface: attribute response 
+PASS AuthenticatorResponse interface: existence and properties of interface object 
+PASS AuthenticatorResponse interface object length 
+PASS AuthenticatorResponse interface object name 
+PASS AuthenticatorResponse interface: existence and properties of interface prototype object 
+PASS AuthenticatorResponse interface: existence and properties of interface prototype object's "constructor" property 
+PASS AuthenticatorResponse interface: attribute clientDataJSON 
+PASS AuthenticatorAttestationResponse interface: existence and properties of interface object 
+PASS AuthenticatorAttestationResponse interface object length 
+PASS AuthenticatorAttestationResponse interface object name 
+PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object 
+PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object's "constructor" property 
+PASS AuthenticatorAttestationResponse interface: attribute attestationObject 
+PASS AuthenticatorAssertionResponse interface: existence and properties of interface object 
+PASS AuthenticatorAssertionResponse interface object length 
+PASS AuthenticatorAssertionResponse interface object name 
+PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object 
+PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object's "constructor" property 
+PASS AuthenticatorAssertionResponse interface: attribute authenticatorData 
+PASS AuthenticatorAssertionResponse interface: attribute signature 
+PASS WebAuthentication interface: existence and properties of interface object 
+PASS WebAuthentication interface object length 
+PASS WebAuthentication interface object name 
+PASS WebAuthentication interface: existence and properties of interface prototype object 
+PASS WebAuthentication interface: existence and properties of interface prototype object's "constructor" property 
+PASS WebAuthentication interface: operation makeCredential(MakeCredentialOptions) 
+PASS WebAuthentication interface: operation getAssertion(PublicKeyCredentialRequestOptions) 
+PASS WebAuthentication must be primary interface of navigator.authentication 
+PASS Stringification of navigator.authentication 
+PASS WebAuthentication interface: navigator.authentication must inherit property "makeCredential" with the proper type (0) 
+PASS WebAuthentication interface: calling makeCredential(MakeCredentialOptions) on navigator.authentication with too few arguments must throw TypeError 
+PASS WebAuthentication interface: navigator.authentication must inherit property "getAssertion" with the proper type (1) 
+PASS WebAuthentication interface: calling getAssertion(PublicKeyCredentialRequestOptions) on navigator.authentication with too few arguments must throw TypeError 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/webauth/idl.html b/third_party/WebKit/LayoutTests/webauth/idl.html
index 8337882..46a159b 100644
--- a/third_party/WebKit/LayoutTests/webauth/idl.html
+++ b/third_party/WebKit/LayoutTests/webauth/idl.html
@@ -5,71 +5,94 @@
 <script src=../resources/idlharness.js></script>
 <script type="text/plain" id="tested">
 [SecureContext]
-interface ScopedCredentialInfo {
-    readonly attribute ArrayBuffer  clientData;
-    readonly attribute ArrayBuffer  attestation;
+interface PublicKeyCredential : Credential {
+    [SameObject] readonly attribute ArrayBuffer           rawId;
+    [SameObject] readonly attribute AuthenticatorResponse response;
 };
 
-dictionary RelyingPartyAccount {
-    required DOMString rpDisplayName;
-    required DOMString displayName;
-    required DOMString id;
-    DOMString          name;
-    DOMString          imageURL;
+partial dictionary CredentialCreationOptions {
+    MakeCredentialOptions? publicKey;
 };
 
-dictionary ScopedCredentialParameters {
-    required ScopedCredentialType  type;
+partial dictionary CredentialRequestOptions {
+    PublicKeyCredentialRequestOptions? publicKey;
+};
+
+[SecureContext]
+interface AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer clientDataJSON;
+};
+
+[SecureContext]
+interface AuthenticatorAttestationResponse : AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer attestationObject;
+};
+
+[SecureContext]
+interface AuthenticatorAssertionResponse : AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer      authenticatorData;
+    [SameObject] readonly attribute ArrayBuffer      signature;
+};
+
+dictionary PublicKeyCredentialParameters {
+    required PublicKeyCredentialType  type;
     required AlgorithmIdentifier   algorithm;
 };
 
-dictionary ScopedCredentialOptions {
-    unsigned long                             timeoutSeconds;
-    USVString                                 rpId;
-    sequence < ScopedCredentialDescriptor >   excludeList;
-    AuthenticationExtension                   extensions;
+dictionary MakeCredentialOptions {
+    required PublicKeyCredentialEntity rp;
+    required PublicKeyCredentialUserEntity user;
+
+    required BufferSource                         challenge;
+    required sequence<PublicKeyCredentialParameters> parameters;
+
+    unsigned long                        timeout;
+    sequence<PublicKeyCredentialDescriptor> excludeCredentials = [];
+    AuthenticatorSelectionCriteria       authenticatorSelection;
 };
 
-[SecureContext]
-interface AuthenticationAssertion {
-    readonly attribute ScopedCredential  credential;
-    readonly attribute ArrayBuffer       clientData;
-    readonly attribute ArrayBuffer       authenticatorData;
-    readonly attribute ArrayBuffer       signature;
+dictionary PublicKeyCredentialEntity {
+    DOMString id;
+    DOMString name;
+    USVString icon;
 };
 
-dictionary AssertionOptions {
-    unsigned long                            timeoutSeconds;
-    USVString                                rpId;
-    sequence < ScopedCredentialDescriptor >  allowList;
-    AuthenticationExtension                  extensions;
+dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
+    DOMString displayName;
 };
 
-dictionary AuthenticationExtension {
+dictionary AuthenticatorSelectionCriteria {
+    AuthenticatorAttachment    attachment;
+    boolean       requireResidentKey = false;
 };
 
-dictionary AuthenticationClientData {
+enum AuthenticatorAttachment {
+    "platform",
+    "cross-platform"
+};
+
+dictionary PublicKeyCredentialRequestOptions {
+    required BufferSource                challenge;
+    unsigned long                        timeout;
+    USVString                            rpId;
+    sequence<PublicKeyCredentialDescriptor> allowCredentials = [];
+};
+
+dictionary CollectedClientData {
     required DOMString           challenge;
     required DOMString           origin;
-    required AlgorithmIdentifier hashAlg;
-    DOMString                    tokenBinding;
-    AuthenticationExtension      extensions;
+    required DOMString           hashAlgorithm;
+    DOMString                    tokenBindingId;
 };
 
-enum ScopedCredentialType {
-    "ScopedCred"
+enum PublicKeyCredentialType {
+    "public-key"
 };
 
-[SecureContext]
-interface ScopedCredential {
-    readonly attribute ScopedCredentialType type;
-    readonly attribute ArrayBuffer          id;
-};
-
-dictionary ScopedCredentialDescriptor {
-    required ScopedCredentialType type;
-    required BufferSource   id;
-    sequence <Transport>  transports;
+dictionary PublicKeyCredentialDescriptor {
+    required PublicKeyCredentialType type;
+    required BufferSource id;
+    sequence<Transport>   transports;
 };
 
 enum Transport {
@@ -77,20 +100,17 @@
     "nfc",
     "ble"
 };
-[SecureContext]
+
 interface WebAuthentication {
-    Promise <ScopedCredentialInfo> makeCredential (
-        Account                                 accountInformation,
-        sequence < ScopedCredentialParameters > cryptoParameters,
-        BufferSource                            attestationChallenge,
-        optional ScopedCredentialOptions        options
+    Promise<AuthenticatorAttestationResponse> makeCredential (
+        MakeCredentialOptions	                publicKey
     );
 
-    Promise <AuthenticationAssertion> getAssertion (
-        BufferSource               assertionChallenge,
-        optional AssertionOptions  options
+    Promise<AuthenticatorAssertionResponse> getAssertion (
+        PublicKeyCredentialRequestOptions     publicKey
     );
 };
+
 </script>
 <script>
 (function() {
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 1f08975..6bc4c458 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -392,13 +392,19 @@
     setter onaddtrack
     setter onchange
     setter onremovetrack
-interface AuthenticationAssertion
+interface AuthenticatorAssertionResponse : AuthenticatorResponse
     attribute @@toStringTag
     getter authenticatorData
-    getter clientData
-    getter credential
     getter signature
     method constructor
+interface AuthenticatorAttestationResponse : AuthenticatorResponse
+    attribute @@toStringTag
+    getter attestationObject
+    method constructor
+interface AuthenticatorResponse
+    attribute @@toStringTag
+    getter clientDataJSON
+    method constructor
 interface BackgroundFetchFetch
     attribute @@toStringTag
     getter request
@@ -5073,6 +5079,11 @@
     getter promise
     getter reason
     method constructor
+interface PublicKeyCredential : Credential
+    attribute @@toStringTag
+    getter rawId
+    getter response
+    method constructor
 interface PushManager
     static getter supportedContentEncodings
     attribute @@toStringTag
@@ -6421,16 +6432,6 @@
     getter zoomAndPan
     method constructor
     setter zoomAndPan
-interface ScopedCredential
-    attribute @@toStringTag
-    getter id
-    getter type
-    method constructor
-interface ScopedCredentialInfo
-    attribute @@toStringTag
-    getter attestation
-    getter clientData
-    method constructor
 interface Screen
     attribute @@toStringTag
     getter availHeight
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverCallback.h b/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverCallback.h
index 4763f7c..a89f1f9c 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverCallback.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverCallback.h
@@ -7,7 +7,7 @@
 
 #include "core/CoreExport.h"
 #include "core/dom/ExecutionContext.h"
-#include "core/dom/IntersectionObserverCallback.h"
+#include "core/intersection_observer/IntersectionObserverCallback.h"
 #include "platform/bindings/DOMWrapperWorld.h"
 #include "platform/bindings/ScopedPersistent.h"
 
diff --git a/third_party/WebKit/Source/build/scripts/make_runtime_features.py b/third_party/WebKit/Source/build/scripts/make_runtime_features.py
index ed58edb..2952faa2 100755
--- a/third_party/WebKit/Source/build/scripts/make_runtime_features.py
+++ b/third_party/WebKit/Source/build/scripts/make_runtime_features.py
@@ -58,6 +58,7 @@
                 enabled_condition += ' && is%sEnabled' % dependant_name
             feature['enabled_condition'] = enabled_condition
         self._standard_features = [feature for feature in self._features if not feature['custom']]
+        self._origin_trial_features = [feature for feature in self._features if feature['origin_trial_feature_name']]
 
     def _feature_sets(self):
         # Another way to think of the status levels is as "sets of features"
@@ -70,6 +71,7 @@
             'feature_sets': self._feature_sets(),
             'input_files': self._input_files,
             'standard_features': self._standard_features,
+            'origin_trial_controlled_features': self._origin_trial_features,
         }
 
     @template_expander.use_jinja('templates/' + class_name + '.h.tmpl')
diff --git a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl
index d3ee87a..2e9c784 100644
--- a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl
@@ -32,6 +32,12 @@
 
 {% endfor %}
 
+void RuntimeEnabledFeatures::SetOriginTrialControlledFeaturesEnabled(bool enable) {
+  {% for feature in origin_trial_controlled_features %}
+  Set{{feature.name}}Enabled(enable);
+  {% endfor %}
+}
+
 void RuntimeEnabledFeatures::SetFeatureEnabledFromString(
     const std::string& name, bool enable) {
   {% for feature in standard_features %}
diff --git a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
index bd746a208..a6dca5c7 100644
--- a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
@@ -34,6 +34,7 @@
   {% for feature_set in feature_sets %}
   static void Set{{feature_set|capitalize}}FeaturesEnabled(bool);
   {% endfor %}
+  static void SetOriginTrialControlledFeaturesEnabled(bool);
 
   static void SetFeatureEnabledFromString(const std::string& name, bool isEnabled);
 
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 2d2cf84..82129b2 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -188,6 +188,7 @@
     "//third_party/WebKit/Source/core/imagebitmap",
     "//third_party/WebKit/Source/core/input",
     "//third_party/WebKit/Source/core/inspector",
+    "//third_party/WebKit/Source/core/intersection_observer",
     "//third_party/WebKit/Source/core/layout",
     "//third_party/WebKit/Source/core/layout/svg:svg_layout",
     "//third_party/WebKit/Source/core/loader",
@@ -1259,7 +1260,6 @@
     "dom/ElementVisibilityObserverTest.cpp",
     "dom/FlatTreeTraversalTest.cpp",
     "dom/IdleDeadlineTest.cpp",
-    "dom/IntersectionObserverTest.cpp",
     "dom/LayoutTreeBuilderTraversalTest.cpp",
     "dom/MockScriptElementBase.h",
     "dom/ModulatorTest.cpp",
@@ -1406,6 +1406,7 @@
     "input/ImeOnFocusTest.cpp",
     "input/TouchActionTest.cpp",
     "inspector/ProtocolParserTest.cpp",
+    "intersection_observer/IntersectionObserverTest.cpp",
     "layout/CollapsedBorderValueTest.cpp",
     "layout/LayoutBlockTest.cpp",
     "layout/LayoutBoxModelObjectTest.cpp",
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index aed067d7..9bb3bde 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -25,403 +25,404 @@
         core_global_constructors_original_interfaces,
         [ "$blink_core_output_dir/{{source_name_part}}CoreConstructors.idl" ])
 
-core_idl_files = get_path_info([
-                                 "animation/Animation.idl",
-                                 "animation/AnimationEffectReadOnly.idl",
-                                 "animation/AnimationEffectTiming.idl",
-                                 "animation/AnimationEffectTimingReadOnly.idl",
-                                 "animation/AnimationTimeline.idl",
-                                 "animation/DocumentTimeline.idl",
-                                 "animation/KeyframeEffect.idl",
-                                 "animation/KeyframeEffectReadOnly.idl",
-                                 "animation/ScrollTimeline.idl",
-                                 "clipboard/Clipboard.idl",
-                                 "clipboard/DataTransfer.idl",
-                                 "clipboard/DataTransferItemList.idl",
-                                 "css/CSS.idl",
-                                 "css/CSSConditionRule.idl",
-                                 "css/CSSFontFaceRule.idl",
-                                 "css/CSSGroupingRule.idl",
-                                 "css/CSSImportRule.idl",
-                                 "css/CSSKeyframeRule.idl",
-                                 "css/CSSKeyframesRule.idl",
-                                 "css/CSSMediaRule.idl",
-                                 "css/CSSNamespaceRule.idl",
-                                 "css/CSSPageRule.idl",
-                                 "css/CSSRule.idl",
-                                 "css/CSSRuleList.idl",
-                                 "css/CSSStyleDeclaration.idl",
-                                 "css/CSSStyleRule.idl",
-                                 "css/CSSStyleSheet.idl",
-                                 "css/CSSSupportsRule.idl",
-                                 "css/CSSViewportRule.idl",
-                                 "css/FontFace.idl",
-                                 "css/FontFaceSet.idl",
-                                 "css/FontFaceSetLoadEvent.idl",
-                                 "css/MediaList.idl",
-                                 "css/MediaQueryList.idl",
-                                 "css/MediaQueryListEvent.idl",
-                                 "css/StyleMedia.idl",
-                                 "css/StyleSheet.idl",
-                                 "css/StyleSheetList.idl",
-                                 "css/cssom/CSSImageValue.idl",
-                                 "css/cssom/CSSKeywordValue.idl",
-                                 "css/cssom/CSSMatrixComponent.idl",
-                                 "css/cssom/CSSNumericValue.idl",
-                                 "css/cssom/CSSPerspective.idl",
-                                 "css/cssom/CSSPositionValue.idl",
-                                 "css/cssom/CSSResourceValue.idl",
-                                 "css/cssom/CSSRotation.idl",
-                                 "css/cssom/CSSScale.idl",
-                                 "css/cssom/CSSSkew.idl",
-                                 "css/cssom/CSSStyleValue.idl",
-                                 "css/cssom/CSSTransformComponent.idl",
-                                 "css/cssom/CSSTransformValue.idl",
-                                 "css/cssom/CSSTranslation.idl",
-                                 "css/cssom/CSSURLImageValue.idl",
-                                 "css/cssom/CSSUnitValue.idl",
-                                 "css/cssom/CSSUnparsedValue.idl",
-                                 "css/cssom/CSSVariableReferenceValue.idl",
-                                 "css/cssom/StylePropertyMap.idl",
-                                 "css/cssom/StylePropertyMapReadonly.idl",
-                                 "dom/AccessibleNode.idl",
-                                 "dom/AccessibleNodeList.idl",
-                                 "dom/ArrayBuffer.idl",
-                                 "dom/ArrayBufferView.idl",
-                                 "dom/Attr.idl",
-                                 "dom/CDATASection.idl",
-                                 "dom/CharacterData.idl",
-                                 "dom/Comment.idl",
-                                 "dom/DOMException.idl",
-                                 "dom/DOMImplementation.idl",
-                                 "dom/DOMStringList.idl",
-                                 "dom/DOMStringMap.idl",
-                                 "dom/DOMTokenList.idl",
-                                 "dom/DataView.idl",
-                                 "dom/Document.idl",
-                                 "dom/DocumentFragment.idl",
-                                 "dom/DocumentType.idl",
-                                 "dom/Element.idl",
-                                 "dom/Float32Array.idl",
-                                 "dom/Float64Array.idl",
-                                 "dom/FrameRequestCallback.idl",
-                                 "dom/IdleDeadline.idl",
-                                 "dom/IdleRequestCallback.idl",
-                                 "dom/Int16Array.idl",
-                                 "dom/Int32Array.idl",
-                                 "dom/Int8Array.idl",
-                                 "dom/IntersectionObserver.idl",
-                                 "dom/IntersectionObserverEntry.idl",
-                                 "dom/Iterator.idl",
-                                 "dom/MessageChannel.idl",
-                                 "dom/MessagePort.idl",
-                                 "dom/MutationObserver.idl",
-                                 "dom/MutationRecord.idl",
-                                 "dom/NamedNodeMap.idl",
-                                 "dom/Node.idl",
-                                 "dom/NodeFilter.idl",
-                                 "dom/NodeIterator.idl",
-                                 "dom/NodeList.idl",
-                                 "dom/ProcessingInstruction.idl",
-                                 "dom/Range.idl",
-                                 "dom/ResizeObserver.idl",
-                                 "dom/ResizeObserverEntry.idl",
-                                 "dom/ShadowRoot.idl",
-                                 "dom/SharedArrayBuffer.idl",
-                                 "dom/StaticRange.idl",
-                                 "dom/Text.idl",
-                                 "dom/Touch.idl",
-                                 "dom/TouchList.idl",
-                                 "dom/TreeWalker.idl",
-                                 "dom/Uint16Array.idl",
-                                 "dom/Uint32Array.idl",
-                                 "dom/Uint8Array.idl",
-                                 "dom/Uint8ClampedArray.idl",
-                                 "dom/XMLDocument.idl",
-                                 "editing/Selection.idl",
-                                 "events/AnimationEvent.idl",
-                                 "events/AnimationPlaybackEvent.idl",
-                                 "events/ApplicationCacheErrorEvent.idl",
-                                 "events/BeforeUnloadEvent.idl",
-                                 "events/ClipboardEvent.idl",
-                                 "events/CompositionEvent.idl",
-                                 "events/CustomEvent.idl",
-                                 "events/DragEvent.idl",
-                                 "events/ErrorEvent.idl",
-                                 "events/Event.idl",
-                                 "events/EventTarget.idl",
-                                 "events/FocusEvent.idl",
-                                 "events/HashChangeEvent.idl",
-                                 "events/InputEvent.idl",
-                                 "events/KeyboardEvent.idl",
-                                 "events/MessageEvent.idl",
-                                 "events/MouseEvent.idl",
-                                 "events/MutationEvent.idl",
-                                 "events/PageTransitionEvent.idl",
-                                 "events/PointerEvent.idl",
-                                 "events/PopStateEvent.idl",
-                                 "events/ProgressEvent.idl",
-                                 "events/PromiseRejectionEvent.idl",
-                                 "events/ResourceProgressEvent.idl",
-                                 "events/SecurityPolicyViolationEvent.idl",
-                                 "events/TextEvent.idl",
-                                 "events/TouchEvent.idl",
-                                 "events/TransitionEvent.idl",
-                                 "events/UIEvent.idl",
-                                 "events/WheelEvent.idl",
-                                 "fileapi/Blob.idl",
-                                 "fileapi/BlobCallback.idl",
-                                 "fileapi/File.idl",
-                                 "fileapi/FileList.idl",
-                                 "fileapi/FileReader.idl",
-                                 "fileapi/FileReaderSync.idl",
-                                 "frame/BarProp.idl",
-                                 "frame/External.idl",
-                                 "frame/History.idl",
-                                 "frame/Location.idl",
-                                 "frame/VisualViewport.idl",
-                                 "geometry/DOMMatrix.idl",
-                                 "geometry/DOMMatrixReadOnly.idl",
-                                 "geometry/DOMPoint.idl",
-                                 "geometry/DOMPointReadOnly.idl",
-                                 "geometry/DOMQuad.idl",
-                                 "geometry/DOMRect.idl",
-                                 "geometry/DOMRectList.idl",
-                                 "geometry/DOMRectReadOnly.idl",
-                                 "html/FormData.idl",
-                                 "html/HTMLAllCollection.idl",
-                                 "html/HTMLAnchorElement.idl",
-                                 "html/HTMLAreaElement.idl",
-                                 "html/HTMLAudioElement.idl",
-                                 "html/HTMLBRElement.idl",
-                                 "html/HTMLBaseElement.idl",
-                                 "html/HTMLBodyElement.idl",
-                                 "html/HTMLButtonElement.idl",
-                                 "html/HTMLCollection.idl",
-                                 "html/HTMLContentElement.idl",
-                                 "html/HTMLDListElement.idl",
-                                 "html/HTMLDataListElement.idl",
-                                 "html/HTMLDetailsElement.idl",
-                                 "html/HTMLDialogElement.idl",
-                                 "html/HTMLDirectoryElement.idl",
-                                 "html/HTMLDivElement.idl",
-                                 "html/HTMLDocument.idl",
-                                 "html/HTMLElement.idl",
-                                 "html/HTMLEmbedElement.idl",
-                                 "html/HTMLFieldSetElement.idl",
-                                 "html/HTMLFontElement.idl",
-                                 "html/HTMLFormControlsCollection.idl",
-                                 "html/HTMLFormElement.idl",
-                                 "html/HTMLFrameElement.idl",
-                                 "html/HTMLFrameSetElement.idl",
-                                 "html/HTMLHRElement.idl",
-                                 "html/HTMLHeadElement.idl",
-                                 "html/HTMLHeadingElement.idl",
-                                 "html/HTMLHtmlElement.idl",
-                                 "html/HTMLImageElement.idl",
-                                 "html/HTMLLIElement.idl",
-                                 "html/HTMLLabelElement.idl",
-                                 "html/HTMLLegendElement.idl",
-                                 "html/HTMLLinkElement.idl",
-                                 "html/HTMLMapElement.idl",
-                                 "html/HTMLMarqueeElement.idl",
-                                 "html/HTMLMenuElement.idl",
-                                 "html/HTMLMetaElement.idl",
-                                 "html/HTMLMeterElement.idl",
-                                 "html/HTMLModElement.idl",
-                                 "html/HTMLOListElement.idl",
-                                 "html/HTMLObjectElement.idl",
-                                 "html/HTMLOptGroupElement.idl",
-                                 "html/HTMLOptionElement.idl",
-                                 "html/HTMLOptionsCollection.idl",
-                                 "html/HTMLOutputElement.idl",
-                                 "html/HTMLParagraphElement.idl",
-                                 "html/HTMLParamElement.idl",
-                                 "html/HTMLPictureElement.idl",
-                                 "html/HTMLPreElement.idl",
-                                 "html/HTMLProgressElement.idl",
-                                 "html/HTMLQuoteElement.idl",
-                                 "html/HTMLScriptElement.idl",
-                                 "html/HTMLSelectElement.idl",
-                                 "html/HTMLShadowElement.idl",
-                                 "html/HTMLSlotElement.idl",
-                                 "html/HTMLSourceElement.idl",
-                                 "html/HTMLSpanElement.idl",
-                                 "html/HTMLStyleElement.idl",
-                                 "html/HTMLTableCaptionElement.idl",
-                                 "html/HTMLTableCellElement.idl",
-                                 "html/HTMLTableColElement.idl",
-                                 "html/HTMLTableElement.idl",
-                                 "html/HTMLTableRowElement.idl",
-                                 "html/HTMLTableSectionElement.idl",
-                                 "html/HTMLTemplateElement.idl",
-                                 "html/HTMLTextAreaElement.idl",
-                                 "html/HTMLTitleElement.idl",
-                                 "html/HTMLTrackElement.idl",
-                                 "html/HTMLUListElement.idl",
-                                 "html/HTMLUnknownElement.idl",
-                                 "html/ImageData.idl",
-                                 "html/RadioNodeList.idl",
-                                 "html/TextMetrics.idl",
-                                 "html/TimeRanges.idl",
-                                 "html/ValidityState.idl",
-                                 "html/VoidCallback.idl",
-                                 "html/custom/CustomElementRegistry.idl",
-                                 "html/media/MediaError.idl",
-                                 "html/track/AudioTrackList.idl",
-                                 "html/track/TextTrack.idl",
-                                 "html/track/TextTrackCue.idl",
-                                 "html/track/TextTrackCueList.idl",
-                                 "html/track/TextTrackList.idl",
-                                 "html/track/TrackEvent.idl",
-                                 "html/track/VideoTrackList.idl",
-                                 "html/track/vtt/VTTCue.idl",
-                                 "html/track/vtt/VTTRegion.idl",
-                                 "imagebitmap/ImageBitmap.idl",
-                                 "input/InputDeviceCapabilities.idl",
-                                 "inspector/InspectorOverlayHost.idl",
-                                 "loader/appcache/ApplicationCache.idl",
-                                 "mojo/Mojo.idl",
-                                 "mojo/MojoHandle.idl",
-                                 "mojo/MojoWatcher.idl",
-                                 "mojo/test/MojoInterfaceInterceptor.idl",
-                                 "mojo/test/MojoInterfaceRequestEvent.idl",
-                                 "page/PagePopupController.idl",
-                                 "page/scrolling/ScrollState.idl",
-                                 "page/scrolling/ScrollStateCallback.idl",
-                                 "streams/UnderlyingSourceBase.idl",
-                                 "svg/SVGAElement.idl",
-                                 "svg/SVGAngle.idl",
-                                 "svg/SVGAnimateElement.idl",
-                                 "svg/SVGAnimateMotionElement.idl",
-                                 "svg/SVGAnimateTransformElement.idl",
-                                 "svg/SVGAnimatedAngle.idl",
-                                 "svg/SVGAnimatedBoolean.idl",
-                                 "svg/SVGAnimatedEnumeration.idl",
-                                 "svg/SVGAnimatedInteger.idl",
-                                 "svg/SVGAnimatedLength.idl",
-                                 "svg/SVGAnimatedLengthList.idl",
-                                 "svg/SVGAnimatedNumber.idl",
-                                 "svg/SVGAnimatedNumberList.idl",
-                                 "svg/SVGAnimatedPreserveAspectRatio.idl",
-                                 "svg/SVGAnimatedRect.idl",
-                                 "svg/SVGAnimatedString.idl",
-                                 "svg/SVGAnimatedTransformList.idl",
-                                 "svg/SVGAnimationElement.idl",
-                                 "svg/SVGCircleElement.idl",
-                                 "svg/SVGClipPathElement.idl",
-                                 "svg/SVGComponentTransferFunctionElement.idl",
-                                 "svg/SVGDefsElement.idl",
-                                 "svg/SVGDescElement.idl",
-                                 "svg/SVGDiscardElement.idl",
-                                 "svg/SVGElement.idl",
-                                 "svg/SVGEllipseElement.idl",
-                                 "svg/SVGFEBlendElement.idl",
-                                 "svg/SVGFEColorMatrixElement.idl",
-                                 "svg/SVGFEComponentTransferElement.idl",
-                                 "svg/SVGFECompositeElement.idl",
-                                 "svg/SVGFEConvolveMatrixElement.idl",
-                                 "svg/SVGFEDiffuseLightingElement.idl",
-                                 "svg/SVGFEDisplacementMapElement.idl",
-                                 "svg/SVGFEDistantLightElement.idl",
-                                 "svg/SVGFEDropShadowElement.idl",
-                                 "svg/SVGFEFloodElement.idl",
-                                 "svg/SVGFEFuncAElement.idl",
-                                 "svg/SVGFEFuncBElement.idl",
-                                 "svg/SVGFEFuncGElement.idl",
-                                 "svg/SVGFEFuncRElement.idl",
-                                 "svg/SVGFEGaussianBlurElement.idl",
-                                 "svg/SVGFEImageElement.idl",
-                                 "svg/SVGFEMergeElement.idl",
-                                 "svg/SVGFEMergeNodeElement.idl",
-                                 "svg/SVGFEMorphologyElement.idl",
-                                 "svg/SVGFEOffsetElement.idl",
-                                 "svg/SVGFEPointLightElement.idl",
-                                 "svg/SVGFESpecularLightingElement.idl",
-                                 "svg/SVGFESpotLightElement.idl",
-                                 "svg/SVGFETileElement.idl",
-                                 "svg/SVGFETurbulenceElement.idl",
-                                 "svg/SVGFilterElement.idl",
-                                 "svg/SVGForeignObjectElement.idl",
-                                 "svg/SVGGElement.idl",
-                                 "svg/SVGGeometryElement.idl",
-                                 "svg/SVGGradientElement.idl",
-                                 "svg/SVGGraphicsElement.idl",
-                                 "svg/SVGImageElement.idl",
-                                 "svg/SVGLength.idl",
-                                 "svg/SVGLengthList.idl",
-                                 "svg/SVGLineElement.idl",
-                                 "svg/SVGLinearGradientElement.idl",
-                                 "svg/SVGMPathElement.idl",
-                                 "svg/SVGMarkerElement.idl",
-                                 "svg/SVGMaskElement.idl",
-                                 "svg/SVGMatrix.idl",
-                                 "svg/SVGMetadataElement.idl",
-                                 "svg/SVGNumber.idl",
-                                 "svg/SVGNumberList.idl",
-                                 "svg/SVGPathElement.idl",
-                                 "svg/SVGPatternElement.idl",
-                                 "svg/SVGPoint.idl",
-                                 "svg/SVGPointList.idl",
-                                 "svg/SVGPolygonElement.idl",
-                                 "svg/SVGPolylineElement.idl",
-                                 "svg/SVGPreserveAspectRatio.idl",
-                                 "svg/SVGRadialGradientElement.idl",
-                                 "svg/SVGRect.idl",
-                                 "svg/SVGRectElement.idl",
-                                 "svg/SVGSVGElement.idl",
-                                 "svg/SVGScriptElement.idl",
-                                 "svg/SVGSetElement.idl",
-                                 "svg/SVGStopElement.idl",
-                                 "svg/SVGStringList.idl",
-                                 "svg/SVGStyleElement.idl",
-                                 "svg/SVGSwitchElement.idl",
-                                 "svg/SVGSymbolElement.idl",
-                                 "svg/SVGTSpanElement.idl",
-                                 "svg/SVGTextContentElement.idl",
-                                 "svg/SVGTextElement.idl",
-                                 "svg/SVGTextPathElement.idl",
-                                 "svg/SVGTextPositioningElement.idl",
-                                 "svg/SVGTitleElement.idl",
-                                 "svg/SVGTransform.idl",
-                                 "svg/SVGTransformList.idl",
-                                 "svg/SVGUnitTypes.idl",
-                                 "svg/SVGUseElement.idl",
-                                 "svg/SVGViewElement.idl",
-                                 "timing/MemoryInfo.idl",
-                                 "timing/Performance.idl",
-                                 "timing/PerformanceEntry.idl",
-                                 "timing/PerformanceLongTaskTiming.idl",
-                                 "timing/PerformanceMark.idl",
-                                 "timing/PerformanceMeasure.idl",
-                                 "timing/PerformanceNavigation.idl",
-                                 "timing/PerformanceNavigationTiming.idl",
-                                 "timing/PerformanceObserver.idl",
-                                 "timing/PerformanceObserverEntryList.idl",
-                                 "timing/PerformancePaintTiming.idl",
-                                 "timing/PerformanceResourceTiming.idl",
-                                 "timing/PerformanceServerTiming.idl",
-                                 "timing/PerformanceTiming.idl",
-                                 "timing/TaskAttributionTiming.idl",
-                                 "timing/WorkerPerformance.idl",
-                                 "url/URLSearchParams.idl",
-                                 "workers/SharedWorker.idl",
-                                 "workers/Worker.idl",
-                                 "workers/WorkerLocation.idl",
-                                 "workers/Worklet.idl",
-                                 "workers/WorkletGlobalScope.idl",
-                                 "xml/DOMParser.idl",
-                                 "xml/XMLSerializer.idl",
-                                 "xml/XPathEvaluator.idl",
-                                 "xml/XPathExpression.idl",
-                                 "xml/XPathNSResolver.idl",
-                                 "xml/XPathResult.idl",
-                                 "xml/XSLTProcessor.idl",
-                                 "xmlhttprequest/XMLHttpRequest.idl",
-                                 "xmlhttprequest/XMLHttpRequestEventTarget.idl",
-                                 "xmlhttprequest/XMLHttpRequestUpload.idl",
-                               ],
-                               "abspath")
+core_idl_files =
+    get_path_info([
+                    "animation/Animation.idl",
+                    "animation/AnimationEffectReadOnly.idl",
+                    "animation/AnimationEffectTiming.idl",
+                    "animation/AnimationEffectTimingReadOnly.idl",
+                    "animation/AnimationTimeline.idl",
+                    "animation/DocumentTimeline.idl",
+                    "animation/KeyframeEffect.idl",
+                    "animation/KeyframeEffectReadOnly.idl",
+                    "animation/ScrollTimeline.idl",
+                    "clipboard/Clipboard.idl",
+                    "clipboard/DataTransfer.idl",
+                    "clipboard/DataTransferItemList.idl",
+                    "css/CSS.idl",
+                    "css/CSSConditionRule.idl",
+                    "css/CSSFontFaceRule.idl",
+                    "css/CSSGroupingRule.idl",
+                    "css/CSSImportRule.idl",
+                    "css/CSSKeyframeRule.idl",
+                    "css/CSSKeyframesRule.idl",
+                    "css/CSSMediaRule.idl",
+                    "css/CSSNamespaceRule.idl",
+                    "css/CSSPageRule.idl",
+                    "css/CSSRule.idl",
+                    "css/CSSRuleList.idl",
+                    "css/CSSStyleDeclaration.idl",
+                    "css/CSSStyleRule.idl",
+                    "css/CSSStyleSheet.idl",
+                    "css/CSSSupportsRule.idl",
+                    "css/CSSViewportRule.idl",
+                    "css/FontFace.idl",
+                    "css/FontFaceSet.idl",
+                    "css/FontFaceSetLoadEvent.idl",
+                    "css/MediaList.idl",
+                    "css/MediaQueryList.idl",
+                    "css/MediaQueryListEvent.idl",
+                    "css/StyleMedia.idl",
+                    "css/StyleSheet.idl",
+                    "css/StyleSheetList.idl",
+                    "css/cssom/CSSImageValue.idl",
+                    "css/cssom/CSSKeywordValue.idl",
+                    "css/cssom/CSSMatrixComponent.idl",
+                    "css/cssom/CSSNumericValue.idl",
+                    "css/cssom/CSSPerspective.idl",
+                    "css/cssom/CSSPositionValue.idl",
+                    "css/cssom/CSSResourceValue.idl",
+                    "css/cssom/CSSRotation.idl",
+                    "css/cssom/CSSScale.idl",
+                    "css/cssom/CSSSkew.idl",
+                    "css/cssom/CSSStyleValue.idl",
+                    "css/cssom/CSSTransformComponent.idl",
+                    "css/cssom/CSSTransformValue.idl",
+                    "css/cssom/CSSTranslation.idl",
+                    "css/cssom/CSSURLImageValue.idl",
+                    "css/cssom/CSSUnitValue.idl",
+                    "css/cssom/CSSUnparsedValue.idl",
+                    "css/cssom/CSSVariableReferenceValue.idl",
+                    "css/cssom/StylePropertyMap.idl",
+                    "css/cssom/StylePropertyMapReadonly.idl",
+                    "dom/AccessibleNode.idl",
+                    "dom/AccessibleNodeList.idl",
+                    "dom/ArrayBuffer.idl",
+                    "dom/ArrayBufferView.idl",
+                    "dom/Attr.idl",
+                    "dom/CDATASection.idl",
+                    "dom/CharacterData.idl",
+                    "dom/Comment.idl",
+                    "dom/DOMException.idl",
+                    "dom/DOMImplementation.idl",
+                    "dom/DOMStringList.idl",
+                    "dom/DOMStringMap.idl",
+                    "dom/DOMTokenList.idl",
+                    "dom/DataView.idl",
+                    "dom/Document.idl",
+                    "dom/DocumentFragment.idl",
+                    "dom/DocumentType.idl",
+                    "dom/Element.idl",
+                    "dom/Float32Array.idl",
+                    "dom/Float64Array.idl",
+                    "dom/FrameRequestCallback.idl",
+                    "dom/IdleDeadline.idl",
+                    "dom/IdleRequestCallback.idl",
+                    "dom/Int16Array.idl",
+                    "dom/Int32Array.idl",
+                    "dom/Int8Array.idl",
+                    "dom/Iterator.idl",
+                    "dom/MessageChannel.idl",
+                    "dom/MessagePort.idl",
+                    "dom/MutationObserver.idl",
+                    "dom/MutationRecord.idl",
+                    "dom/NamedNodeMap.idl",
+                    "dom/Node.idl",
+                    "dom/NodeFilter.idl",
+                    "dom/NodeIterator.idl",
+                    "dom/NodeList.idl",
+                    "dom/ProcessingInstruction.idl",
+                    "dom/Range.idl",
+                    "dom/ResizeObserver.idl",
+                    "dom/ResizeObserverEntry.idl",
+                    "dom/ShadowRoot.idl",
+                    "dom/SharedArrayBuffer.idl",
+                    "dom/StaticRange.idl",
+                    "dom/Text.idl",
+                    "dom/Touch.idl",
+                    "dom/TouchList.idl",
+                    "dom/TreeWalker.idl",
+                    "dom/Uint16Array.idl",
+                    "dom/Uint32Array.idl",
+                    "dom/Uint8Array.idl",
+                    "dom/Uint8ClampedArray.idl",
+                    "dom/XMLDocument.idl",
+                    "editing/Selection.idl",
+                    "events/AnimationEvent.idl",
+                    "events/AnimationPlaybackEvent.idl",
+                    "events/ApplicationCacheErrorEvent.idl",
+                    "events/BeforeUnloadEvent.idl",
+                    "events/ClipboardEvent.idl",
+                    "events/CompositionEvent.idl",
+                    "events/CustomEvent.idl",
+                    "events/DragEvent.idl",
+                    "events/ErrorEvent.idl",
+                    "events/Event.idl",
+                    "events/EventTarget.idl",
+                    "events/FocusEvent.idl",
+                    "events/HashChangeEvent.idl",
+                    "events/InputEvent.idl",
+                    "events/KeyboardEvent.idl",
+                    "events/MessageEvent.idl",
+                    "events/MouseEvent.idl",
+                    "events/MutationEvent.idl",
+                    "events/PageTransitionEvent.idl",
+                    "events/PointerEvent.idl",
+                    "events/PopStateEvent.idl",
+                    "events/ProgressEvent.idl",
+                    "events/PromiseRejectionEvent.idl",
+                    "events/ResourceProgressEvent.idl",
+                    "events/SecurityPolicyViolationEvent.idl",
+                    "events/TextEvent.idl",
+                    "events/TouchEvent.idl",
+                    "events/TransitionEvent.idl",
+                    "events/UIEvent.idl",
+                    "events/WheelEvent.idl",
+                    "fileapi/Blob.idl",
+                    "fileapi/BlobCallback.idl",
+                    "fileapi/File.idl",
+                    "fileapi/FileList.idl",
+                    "fileapi/FileReader.idl",
+                    "fileapi/FileReaderSync.idl",
+                    "frame/BarProp.idl",
+                    "frame/External.idl",
+                    "frame/History.idl",
+                    "frame/Location.idl",
+                    "frame/VisualViewport.idl",
+                    "geometry/DOMMatrix.idl",
+                    "geometry/DOMMatrixReadOnly.idl",
+                    "geometry/DOMPoint.idl",
+                    "geometry/DOMPointReadOnly.idl",
+                    "geometry/DOMQuad.idl",
+                    "geometry/DOMRect.idl",
+                    "geometry/DOMRectList.idl",
+                    "geometry/DOMRectReadOnly.idl",
+                    "html/FormData.idl",
+                    "html/HTMLAllCollection.idl",
+                    "html/HTMLAnchorElement.idl",
+                    "html/HTMLAreaElement.idl",
+                    "html/HTMLAudioElement.idl",
+                    "html/HTMLBRElement.idl",
+                    "html/HTMLBaseElement.idl",
+                    "html/HTMLBodyElement.idl",
+                    "html/HTMLButtonElement.idl",
+                    "html/HTMLCollection.idl",
+                    "html/HTMLContentElement.idl",
+                    "html/HTMLDListElement.idl",
+                    "html/HTMLDataListElement.idl",
+                    "html/HTMLDetailsElement.idl",
+                    "html/HTMLDialogElement.idl",
+                    "html/HTMLDirectoryElement.idl",
+                    "html/HTMLDivElement.idl",
+                    "html/HTMLDocument.idl",
+                    "html/HTMLElement.idl",
+                    "html/HTMLEmbedElement.idl",
+                    "html/HTMLFieldSetElement.idl",
+                    "html/HTMLFontElement.idl",
+                    "html/HTMLFormControlsCollection.idl",
+                    "html/HTMLFormElement.idl",
+                    "html/HTMLFrameElement.idl",
+                    "html/HTMLFrameSetElement.idl",
+                    "html/HTMLHRElement.idl",
+                    "html/HTMLHeadElement.idl",
+                    "html/HTMLHeadingElement.idl",
+                    "html/HTMLHtmlElement.idl",
+                    "html/HTMLImageElement.idl",
+                    "html/HTMLLIElement.idl",
+                    "html/HTMLLabelElement.idl",
+                    "html/HTMLLegendElement.idl",
+                    "html/HTMLLinkElement.idl",
+                    "html/HTMLMapElement.idl",
+                    "html/HTMLMarqueeElement.idl",
+                    "html/HTMLMenuElement.idl",
+                    "html/HTMLMetaElement.idl",
+                    "html/HTMLMeterElement.idl",
+                    "html/HTMLModElement.idl",
+                    "html/HTMLOListElement.idl",
+                    "html/HTMLObjectElement.idl",
+                    "html/HTMLOptGroupElement.idl",
+                    "html/HTMLOptionElement.idl",
+                    "html/HTMLOptionsCollection.idl",
+                    "html/HTMLOutputElement.idl",
+                    "html/HTMLParagraphElement.idl",
+                    "html/HTMLParamElement.idl",
+                    "html/HTMLPictureElement.idl",
+                    "html/HTMLPreElement.idl",
+                    "html/HTMLProgressElement.idl",
+                    "html/HTMLQuoteElement.idl",
+                    "html/HTMLScriptElement.idl",
+                    "html/HTMLSelectElement.idl",
+                    "html/HTMLShadowElement.idl",
+                    "html/HTMLSlotElement.idl",
+                    "html/HTMLSourceElement.idl",
+                    "html/HTMLSpanElement.idl",
+                    "html/HTMLStyleElement.idl",
+                    "html/HTMLTableCaptionElement.idl",
+                    "html/HTMLTableCellElement.idl",
+                    "html/HTMLTableColElement.idl",
+                    "html/HTMLTableElement.idl",
+                    "html/HTMLTableRowElement.idl",
+                    "html/HTMLTableSectionElement.idl",
+                    "html/HTMLTemplateElement.idl",
+                    "html/HTMLTextAreaElement.idl",
+                    "html/HTMLTitleElement.idl",
+                    "html/HTMLTrackElement.idl",
+                    "html/HTMLUListElement.idl",
+                    "html/HTMLUnknownElement.idl",
+                    "html/ImageData.idl",
+                    "html/RadioNodeList.idl",
+                    "html/TextMetrics.idl",
+                    "html/TimeRanges.idl",
+                    "html/ValidityState.idl",
+                    "html/VoidCallback.idl",
+                    "html/custom/CustomElementRegistry.idl",
+                    "html/media/MediaError.idl",
+                    "html/track/AudioTrackList.idl",
+                    "html/track/TextTrack.idl",
+                    "html/track/TextTrackCue.idl",
+                    "html/track/TextTrackCueList.idl",
+                    "html/track/TextTrackList.idl",
+                    "html/track/TrackEvent.idl",
+                    "html/track/VideoTrackList.idl",
+                    "html/track/vtt/VTTCue.idl",
+                    "html/track/vtt/VTTRegion.idl",
+                    "imagebitmap/ImageBitmap.idl",
+                    "input/InputDeviceCapabilities.idl",
+                    "inspector/InspectorOverlayHost.idl",
+                    "intersection_observer/IntersectionObserver.idl",
+                    "intersection_observer/IntersectionObserverEntry.idl",
+                    "loader/appcache/ApplicationCache.idl",
+                    "mojo/Mojo.idl",
+                    "mojo/MojoHandle.idl",
+                    "mojo/MojoWatcher.idl",
+                    "mojo/test/MojoInterfaceInterceptor.idl",
+                    "mojo/test/MojoInterfaceRequestEvent.idl",
+                    "page/PagePopupController.idl",
+                    "page/scrolling/ScrollState.idl",
+                    "page/scrolling/ScrollStateCallback.idl",
+                    "streams/UnderlyingSourceBase.idl",
+                    "svg/SVGAElement.idl",
+                    "svg/SVGAngle.idl",
+                    "svg/SVGAnimateElement.idl",
+                    "svg/SVGAnimateMotionElement.idl",
+                    "svg/SVGAnimateTransformElement.idl",
+                    "svg/SVGAnimatedAngle.idl",
+                    "svg/SVGAnimatedBoolean.idl",
+                    "svg/SVGAnimatedEnumeration.idl",
+                    "svg/SVGAnimatedInteger.idl",
+                    "svg/SVGAnimatedLength.idl",
+                    "svg/SVGAnimatedLengthList.idl",
+                    "svg/SVGAnimatedNumber.idl",
+                    "svg/SVGAnimatedNumberList.idl",
+                    "svg/SVGAnimatedPreserveAspectRatio.idl",
+                    "svg/SVGAnimatedRect.idl",
+                    "svg/SVGAnimatedString.idl",
+                    "svg/SVGAnimatedTransformList.idl",
+                    "svg/SVGAnimationElement.idl",
+                    "svg/SVGCircleElement.idl",
+                    "svg/SVGClipPathElement.idl",
+                    "svg/SVGComponentTransferFunctionElement.idl",
+                    "svg/SVGDefsElement.idl",
+                    "svg/SVGDescElement.idl",
+                    "svg/SVGDiscardElement.idl",
+                    "svg/SVGElement.idl",
+                    "svg/SVGEllipseElement.idl",
+                    "svg/SVGFEBlendElement.idl",
+                    "svg/SVGFEColorMatrixElement.idl",
+                    "svg/SVGFEComponentTransferElement.idl",
+                    "svg/SVGFECompositeElement.idl",
+                    "svg/SVGFEConvolveMatrixElement.idl",
+                    "svg/SVGFEDiffuseLightingElement.idl",
+                    "svg/SVGFEDisplacementMapElement.idl",
+                    "svg/SVGFEDistantLightElement.idl",
+                    "svg/SVGFEDropShadowElement.idl",
+                    "svg/SVGFEFloodElement.idl",
+                    "svg/SVGFEFuncAElement.idl",
+                    "svg/SVGFEFuncBElement.idl",
+                    "svg/SVGFEFuncGElement.idl",
+                    "svg/SVGFEFuncRElement.idl",
+                    "svg/SVGFEGaussianBlurElement.idl",
+                    "svg/SVGFEImageElement.idl",
+                    "svg/SVGFEMergeElement.idl",
+                    "svg/SVGFEMergeNodeElement.idl",
+                    "svg/SVGFEMorphologyElement.idl",
+                    "svg/SVGFEOffsetElement.idl",
+                    "svg/SVGFEPointLightElement.idl",
+                    "svg/SVGFESpecularLightingElement.idl",
+                    "svg/SVGFESpotLightElement.idl",
+                    "svg/SVGFETileElement.idl",
+                    "svg/SVGFETurbulenceElement.idl",
+                    "svg/SVGFilterElement.idl",
+                    "svg/SVGForeignObjectElement.idl",
+                    "svg/SVGGElement.idl",
+                    "svg/SVGGeometryElement.idl",
+                    "svg/SVGGradientElement.idl",
+                    "svg/SVGGraphicsElement.idl",
+                    "svg/SVGImageElement.idl",
+                    "svg/SVGLength.idl",
+                    "svg/SVGLengthList.idl",
+                    "svg/SVGLineElement.idl",
+                    "svg/SVGLinearGradientElement.idl",
+                    "svg/SVGMPathElement.idl",
+                    "svg/SVGMarkerElement.idl",
+                    "svg/SVGMaskElement.idl",
+                    "svg/SVGMatrix.idl",
+                    "svg/SVGMetadataElement.idl",
+                    "svg/SVGNumber.idl",
+                    "svg/SVGNumberList.idl",
+                    "svg/SVGPathElement.idl",
+                    "svg/SVGPatternElement.idl",
+                    "svg/SVGPoint.idl",
+                    "svg/SVGPointList.idl",
+                    "svg/SVGPolygonElement.idl",
+                    "svg/SVGPolylineElement.idl",
+                    "svg/SVGPreserveAspectRatio.idl",
+                    "svg/SVGRadialGradientElement.idl",
+                    "svg/SVGRect.idl",
+                    "svg/SVGRectElement.idl",
+                    "svg/SVGSVGElement.idl",
+                    "svg/SVGScriptElement.idl",
+                    "svg/SVGSetElement.idl",
+                    "svg/SVGStopElement.idl",
+                    "svg/SVGStringList.idl",
+                    "svg/SVGStyleElement.idl",
+                    "svg/SVGSwitchElement.idl",
+                    "svg/SVGSymbolElement.idl",
+                    "svg/SVGTSpanElement.idl",
+                    "svg/SVGTextContentElement.idl",
+                    "svg/SVGTextElement.idl",
+                    "svg/SVGTextPathElement.idl",
+                    "svg/SVGTextPositioningElement.idl",
+                    "svg/SVGTitleElement.idl",
+                    "svg/SVGTransform.idl",
+                    "svg/SVGTransformList.idl",
+                    "svg/SVGUnitTypes.idl",
+                    "svg/SVGUseElement.idl",
+                    "svg/SVGViewElement.idl",
+                    "timing/MemoryInfo.idl",
+                    "timing/Performance.idl",
+                    "timing/PerformanceEntry.idl",
+                    "timing/PerformanceLongTaskTiming.idl",
+                    "timing/PerformanceMark.idl",
+                    "timing/PerformanceMeasure.idl",
+                    "timing/PerformanceNavigation.idl",
+                    "timing/PerformanceNavigationTiming.idl",
+                    "timing/PerformanceObserver.idl",
+                    "timing/PerformanceObserverEntryList.idl",
+                    "timing/PerformancePaintTiming.idl",
+                    "timing/PerformanceResourceTiming.idl",
+                    "timing/PerformanceServerTiming.idl",
+                    "timing/PerformanceTiming.idl",
+                    "timing/TaskAttributionTiming.idl",
+                    "timing/WorkerPerformance.idl",
+                    "url/URLSearchParams.idl",
+                    "workers/SharedWorker.idl",
+                    "workers/Worker.idl",
+                    "workers/WorkerLocation.idl",
+                    "workers/Worklet.idl",
+                    "workers/WorkletGlobalScope.idl",
+                    "xml/DOMParser.idl",
+                    "xml/XMLSerializer.idl",
+                    "xml/XPathEvaluator.idl",
+                    "xml/XPathExpression.idl",
+                    "xml/XPathNSResolver.idl",
+                    "xml/XPathResult.idl",
+                    "xml/XSLTProcessor.idl",
+                    "xmlhttprequest/XMLHttpRequest.idl",
+                    "xmlhttprequest/XMLHttpRequestEventTarget.idl",
+                    "xmlhttprequest/XMLHttpRequestUpload.idl",
+                  ],
+                  "abspath")
 
 # Files for which bindings (.cpp and .h files) will be generated.
 core_idl_with_modules_dependency_files =
@@ -525,7 +526,6 @@
                     "dom/ElementRegistrationOptions.idl",
                     "dom/GetRootNodeOptions.idl",
                     "dom/IdleRequestOptions.idl",
-                    "dom/IntersectionObserverInit.idl",
                     "dom/MutationObserverInit.idl",
                     "dom/ShadowRootInit.idl",
                     "dom/TouchInit.idl",
@@ -572,6 +572,7 @@
                     "html/track/TrackEventInit.idl",
                     "imagebitmap/ImageBitmapOptions.idl",
                     "input/InputDeviceCapabilitiesInit.idl",
+                    "intersection_observer/IntersectionObserverInit.idl",
                     "mojo/MojoCreateDataPipeOptions.idl",
                     "mojo/MojoCreateDataPipeResult.idl",
                     "mojo/MojoCreateMessagePipeResult.idl",
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserLocalContext.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserLocalContext.cpp
index 8a26dbd..1a30a06 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserLocalContext.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserLocalContext.cpp
@@ -6,13 +6,20 @@
 
 namespace blink {
 
-CSSParserLocalContext::CSSParserLocalContext() : use_alias_parsing_(false) {}
+CSSParserLocalContext::CSSParserLocalContext()
+    : use_alias_parsing_(false), current_shorthand_(CSSPropertyInvalid) {}
 
-CSSParserLocalContext::CSSParserLocalContext(bool use_alias_parsing)
-    : use_alias_parsing_(use_alias_parsing) {}
+CSSParserLocalContext::CSSParserLocalContext(bool use_alias_parsing,
+                                             CSSPropertyID current_shorthand)
+    : use_alias_parsing_(use_alias_parsing),
+      current_shorthand_(current_shorthand) {}
 
 bool CSSParserLocalContext::UseAliasParsing() const {
   return use_alias_parsing_;
 }
 
+CSSPropertyID CSSParserLocalContext::CurrentShorthand() const {
+  return current_shorthand_;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserLocalContext.h b/third_party/WebKit/Source/core/css/parser/CSSParserLocalContext.h
index a5bbefe..70c8fe3 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserLocalContext.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserLocalContext.h
@@ -5,23 +5,26 @@
 #ifndef CSSParserLocalContext_h
 #define CSSParserLocalContext_h
 
+#include "core/CSSPropertyNames.h"
 #include "platform/wtf/Allocator.h"
 
 namespace blink {
 
 // A wrapper class containing all local context when parsing a property.
-// TODO(jiameng): add info for shorthand properties into this class.
 
 class CSSParserLocalContext {
   STACK_ALLOCATED();
 
  public:
   CSSParserLocalContext();
-  explicit CSSParserLocalContext(bool use_alias_parsing);
+  CSSParserLocalContext(bool use_alias_parsing,
+                        CSSPropertyID current_shorthand);
   bool UseAliasParsing() const;
+  CSSPropertyID CurrentShorthand() const;
 
  private:
   bool use_alias_parsing_;
+  CSSPropertyID current_shorthand_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index a968158..efd3f16 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -2338,8 +2338,7 @@
       CSSPropertyDescriptor::Get(property);
   if (css_property_desc.parseShorthand) {
     return css_property_desc.parseShorthand(
-        important, range_, *context_,
-        CSSParserLocalContext(isPropertyAlias(unresolved_property)),
+        important, range_, *context_, isPropertyAlias(unresolved_property),
         *parsed_properties_);
   }
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
index d0a9b46e..6dbfc54 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
@@ -1576,7 +1576,8 @@
   if (css_property_desc.parseSingleValue) {
     return css_property_desc.parseSingleValue(
         range, context,
-        CSSParserLocalContext(isPropertyAlias(unresolved_property)));
+        CSSParserLocalContext(isPropertyAlias(unresolved_property),
+                              current_shorthand));
   }
   needs_legacy_parsing = true;
   return nullptr;
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMethods.json5 b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMethods.json5
index d3636bb..22a4508 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMethods.json5
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMethods.json5
@@ -35,7 +35,7 @@
     {
       name: "parseShorthand",
       return_type: "bool",
-      parameters: "(bool, CSSParserTokenRange&, const CSSParserContext&, const CSSParserLocalContext&, HeapVector<CSSProperty, 256>&)",
+      parameters: "(bool, CSSParserTokenRange&, const CSSParserContext&, bool, HeapVector<CSSProperty, 256>&)",
       description: "Returns true if the property can be parsed as a shorthand.",
     },
   ]
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp
index 9a52cc8..0bd62697 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderImage.cpp
@@ -15,7 +15,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   CSSValue* source = nullptr;
   CSSValue* slice = nullptr;
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderRadius.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderRadius.cpp
index 8771bfe..86923f2 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderRadius.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderRadius.cpp
@@ -6,7 +6,6 @@
 
 #include "core/css/CSSValuePair.h"
 #include "core/css/parser/CSSParserContext.h"
-#include "core/css/parser/CSSParserLocalContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSPropertyShapeUtils.h"
 
@@ -16,14 +15,14 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext& local_context,
+    bool use_alias_parsing,
     HeapVector<CSSProperty, 256>& properties) {
   CSSValue* horizontal_radii[4] = {0};
   CSSValue* vertical_radii[4] = {0};
 
   if (!CSSPropertyShapeUtils::ConsumeRadii(horizontal_radii, vertical_radii,
                                            range, context.Mode(),
-                                           local_context.UseAliasParsing()))
+                                           use_alias_parsing))
     return false;
 
   CSSPropertyParserHelpers::AddProperty(
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderSpacing.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderSpacing.cpp
index bce86b8f..9feb35c2 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderSpacing.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderSpacing.cpp
@@ -13,7 +13,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   CSSValue* horizontal_spacing =
       ConsumeLength(range, context.Mode(), kValueRangeNonNegative,
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIColumns.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIColumns.cpp
index 28d3c1a3..34f0a9e 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIColumns.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIColumns.cpp
@@ -15,7 +15,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext&,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   CSSValue* column_width = nullptr;
   CSSValue* column_count = nullptr;
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFlex.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFlex.cpp
index dec40914..6dad053 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFlex.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFlex.cpp
@@ -15,7 +15,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   static const double kUnsetValue = -1;
   double flex_grow = kUnsetValue;
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFont.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFont.cpp
index fad3b5d..f426a4b 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFont.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFont.cpp
@@ -208,7 +208,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   const CSSParserToken& token = range.Peek();
   if (token.Id() >= CSSValueCaption && token.Id() <= CSSValueStatusBar)
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFontVariant.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFontVariant.cpp
index e49f4012..e83e934 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFontVariant.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFontVariant.cpp
@@ -15,7 +15,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext&,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   if (CSSPropertyParserHelpers::IdentMatches<CSSValueNormal, CSSValueNone>(
           range.Peek().Id())) {
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIMargin.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIMargin.cpp
index cd69b20..99163a77 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIMargin.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIMargin.cpp
@@ -13,9 +13,10 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext& local_context,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   return CSSPropertyParserHelpers::ConsumeShorthandVia4LonghandAPIs(
       marginShorthand(), important, context, range, properties);
 }
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOffset.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOffset.cpp
index f7371b4..d8c92b4 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOffset.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOffset.cpp
@@ -19,7 +19,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   const CSSValue* offset_position =
       CSSPropertyAPIOffsetPosition::parseSingleValue(range, context,
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOutline.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOutline.cpp
index 311c8233..532e857 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOutline.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOutline.cpp
@@ -12,7 +12,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
       outlineShorthand(), important, context, range, properties);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOverflow.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOverflow.cpp
index eef7d1b..322972e2a 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOverflow.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIOverflow.cpp
@@ -15,7 +15,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   CSSValueID id = range.ConsumeIncludingWhitespace().Id();
   if (!CSSParserFastPaths::IsValidKeywordPropertyAndValue(CSSPropertyOverflowY,
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollPaddingBlock.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollPaddingBlock.cpp
index 925e114..05f3305 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollPaddingBlock.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollPaddingBlock.cpp
@@ -13,7 +13,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext& local_context,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   return CSSPropertyParserHelpers::ConsumeShorthandVia2LonghandAPIs(
       scrollPaddingBlockShorthand(), important, context, range, properties);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderAfter.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderAfter.cpp
index a19f0cc..70299f3 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderAfter.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderAfter.cpp
@@ -12,7 +12,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
       webkitBorderAfterShorthand(), important, context, range, properties);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderBefore.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderBefore.cpp
index 48e299a..c489b60 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderBefore.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderBefore.cpp
@@ -12,7 +12,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
       webkitBorderBeforeShorthand(), important, context, range, properties);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderEnd.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderEnd.cpp
index 1ad0489..118a11da 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderEnd.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderEnd.cpp
@@ -12,7 +12,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
       webkitBorderEndShorthand(), important, context, range, properties);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderStart.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderStart.cpp
index 3ca4c2b..d3c4d8a 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderStart.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitBorderStart.cpp
@@ -12,7 +12,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
       webkitBorderStartShorthand(), important, context, range, properties);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMarginCollapse.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMarginCollapse.cpp
index 970c165..d1fde857 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMarginCollapse.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMarginCollapse.cpp
@@ -15,7 +15,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   CSSValueID id = range.ConsumeIncludingWhitespace().Id();
   if (!CSSParserFastPaths::IsValidKeywordPropertyAndValue(
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp
index 2c7d2d0..21f31ce 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp
@@ -15,7 +15,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   CSSValue* source = nullptr;
   CSSValue* slice = nullptr;
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextEmphasis.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextEmphasis.cpp
index 3d299a1..d76dc0e 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextEmphasis.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextEmphasis.cpp
@@ -12,7 +12,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext& local_context,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
       webkitTextEmphasisShorthand(), important, context, range, properties);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextStroke.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextStroke.cpp
index fcf80b3..7f48a2d3 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextStroke.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextStroke.cpp
@@ -12,7 +12,7 @@
     bool important,
     CSSParserTokenRange& range,
     const CSSParserContext& context,
-    const CSSParserLocalContext&,
+    bool,
     HeapVector<CSSProperty, 256>& properties) {
   return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
       webkitTextStrokeShorthand(), important, context, range, properties);
diff --git a/third_party/WebKit/Source/core/dom/BUILD.gn b/third_party/WebKit/Source/core/dom/BUILD.gn
index 50d639b..11206e8 100644
--- a/third_party/WebKit/Source/core/dom/BUILD.gn
+++ b/third_party/WebKit/Source/core/dom/BUILD.gn
@@ -127,8 +127,6 @@
     "ElementData.h",
     "ElementDataCache.cpp",
     "ElementDataCache.h",
-    "ElementIntersectionObserverData.cpp",
-    "ElementIntersectionObserverData.h",
     "ElementRareData.cpp",
     "ElementRareData.h",
     "ElementShadow.cpp",
@@ -164,15 +162,6 @@
     "IgnoreDestructiveWriteCountIncrementer.h",
     "IncrementLoadEventDelayCount.cpp",
     "IncrementLoadEventDelayCount.h",
-    "IntersectionObservation.cpp",
-    "IntersectionObservation.h",
-    "IntersectionObserver.cpp",
-    "IntersectionObserver.h",
-    "IntersectionObserverCallback.h",
-    "IntersectionObserverController.cpp",
-    "IntersectionObserverController.h",
-    "IntersectionObserverEntry.cpp",
-    "IntersectionObserverEntry.h",
     "Iterator.h",
     "LayoutTreeBuilder.cpp",
     "LayoutTreeBuilder.h",
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 4da40da..dd8764c 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -81,7 +81,6 @@
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/FlatTreeTraversal.h"
 #include "core/dom/FrameRequestCallback.h"
-#include "core/dom/IntersectionObserverController.h"
 #include "core/dom/LayoutTreeBuilderTraversal.h"
 #include "core/dom/LiveNodeList.h"
 #include "core/dom/MutationObserver.h"
@@ -181,6 +180,7 @@
 #include "core/inspector/ConsoleMessage.h"
 #include "core/inspector/InspectorTraceEvents.h"
 #include "core/inspector/MainThreadDebugger.h"
+#include "core/intersection_observer/IntersectionObserverController.h"
 #include "core/layout/HitTestCanvasResult.h"
 #include "core/layout/HitTestResult.h"
 #include "core/layout/LayoutEmbeddedContent.h"
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 31d5f2c..75652d8 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -54,7 +54,6 @@
 #include "core/dom/DOMTokenList.h"
 #include "core/dom/DatasetDOMStringMap.h"
 #include "core/dom/ElementDataCache.h"
-#include "core/dom/ElementIntersectionObserverData.h"
 #include "core/dom/ElementRareData.h"
 #include "core/dom/ElementShadow.h"
 #include "core/dom/ElementShadowV0.h"
@@ -116,6 +115,7 @@
 #include "core/html/custom/V0CustomElementRegistrationContext.h"
 #include "core/html/parser/HTMLParserIdioms.h"
 #include "core/input/EventHandler.h"
+#include "core/intersection_observer/ElementIntersectionObserverData.h"
 #include "core/layout/LayoutTextFragment.h"
 #include "core/layout/api/LayoutBoxItem.h"
 #include "core/layout/api/LayoutViewItem.h"
diff --git a/third_party/WebKit/Source/core/dom/ElementRareData.h b/third_party/WebKit/Source/core/dom/ElementRareData.h
index 9404312..f20936ec 100644
--- a/third_party/WebKit/Source/core/dom/ElementRareData.h
+++ b/third_party/WebKit/Source/core/dom/ElementRareData.h
@@ -29,7 +29,6 @@
 #include "core/dom/Attr.h"
 #include "core/dom/DOMTokenList.h"
 #include "core/dom/DatasetDOMStringMap.h"
-#include "core/dom/ElementIntersectionObserverData.h"
 #include "core/dom/ElementShadow.h"
 #include "core/dom/NamedNodeMap.h"
 #include "core/dom/NodeRareData.h"
@@ -37,6 +36,7 @@
 #include "core/dom/PseudoElementData.h"
 #include "core/html/custom/CustomElementDefinition.h"
 #include "core/html/custom/V0CustomElementDefinition.h"
+#include "core/intersection_observer/ElementIntersectionObserverData.h"
 #include "platform/bindings/ScriptWrappableVisitor.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/HashSet.h"
diff --git a/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.cpp b/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.cpp
index 7fe6e4ab..eb0643e 100644
--- a/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.cpp
+++ b/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.cpp
@@ -5,8 +5,8 @@
 #include "core/dom/ElementVisibilityObserver.h"
 
 #include "core/dom/Element.h"
-#include "core/dom/IntersectionObserverEntry.h"
 #include "core/frame/LocalFrame.h"
+#include "core/intersection_observer/IntersectionObserverEntry.h"
 #include "platform/wtf/Functional.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.h b/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.h
index fbc0197..af400698 100644
--- a/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.h
+++ b/third_party/WebKit/Source/core/dom/ElementVisibilityObserver.h
@@ -8,7 +8,7 @@
 #include <limits>
 
 #include "core/CoreExport.h"
-#include "core/dom/IntersectionObserver.h"
+#include "core/intersection_observer/IntersectionObserver.h"
 #include "platform/heap/Heap.h"
 #include "platform/heap/Member.h"
 
diff --git a/third_party/WebKit/Source/core/editing/LayoutSelection.cpp b/third_party/WebKit/Source/core/editing/LayoutSelection.cpp
index 12b2592..f23f783 100644
--- a/third_party/WebKit/Source/core/editing/LayoutSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/LayoutSelection.cpp
@@ -156,11 +156,9 @@
               .DeepEquivalent();
       const PositionInFlatTree end_position =
           NextPositionOf(base, PositionMoveType::kGraphemeCluster);
-      const VisibleSelectionInFlatTree& block_cursor =
-          CreateVisibleSelection(SelectionInFlatTree::Builder()
-                                     .SetBaseAndExtent(base, end_position)
-                                     .Build());
-      return {block_cursor.Start(), block_cursor.End()};
+      return base <= end_position
+                 ? EphemeralRangeInFlatTree(base, end_position)
+                 : EphemeralRangeInFlatTree(end_position, base);
     }
   }
   NOTREACHED();
diff --git a/third_party/WebKit/Source/core/exported/BUILD.gn b/third_party/WebKit/Source/core/exported/BUILD.gn
index 17cadb6..d5c76b1 100644
--- a/third_party/WebKit/Source/core/exported/BUILD.gn
+++ b/third_party/WebKit/Source/core/exported/BUILD.gn
@@ -59,8 +59,6 @@
     "WebPagePopupImpl.cpp",
     "WebPagePopupImpl.h",
     "WebPerformance.cpp",
-    "WebPluginContainerBase.cpp",
-    "WebPluginContainerBase.h",
     "WebPluginContainerImpl.cpp",
     "WebPluginContainerImpl.h",
     "WebPluginDocument.cpp",
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerBase.cpp b/third_party/WebKit/Source/core/exported/WebPluginContainerBase.cpp
deleted file mode 100644
index 8b8f591..0000000
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerBase.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.#ifndef WebViewBase_h
-
-#include "core/exported/WebPluginContainerBase.h"
-
-namespace blink {
-
-WebPluginContainerBase::WebPluginContainerBase(LocalFrame* frame)
-    : ContextClient(frame) {}
-
-DEFINE_TRACE(WebPluginContainerBase) {
-  ContextClient::Trace(visitor);
-  PluginView::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerBase.h b/third_party/WebKit/Source/core/exported/WebPluginContainerBase.h
deleted file mode 100644
index 6854da9..0000000
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerBase.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.#ifndef WebViewBase_h
-
-#ifndef WebPluginContainerBase_h
-#define WebPluginContainerBase_h
-
-#include "core/CoreExport.h"
-#include "core/dom/ContextLifecycleObserver.h"
-#include "core/plugins/PluginView.h"
-#include "public/web/WebPluginContainer.h"
-
-namespace blink {
-
-class ResourceError;
-
-struct WebPrintParams;
-struct WebPrintPresetOptions;
-
-// WebPluginContainerBase is a temporary class the provides a layer of
-// abstraction for WebPluginContainerImpl. Mehtods that are declared public in
-// WebPluginContainerImpl that are not overrides from PluginView,
-// WebPuglinContainer or ContextClient will be declared pure virtual in
-// WebPluginContainerBase. Classes that then have a dependency on
-// WebPluginContainerImpl will then take a dependency on WebPluginContainerBase
-// instead, so we can remove cyclic dependencies in web/ and move classes from
-// web/ into core/ or modules.
-// TODO(slangley): Remove this class once WebPluginContainerImpl is in core/.
-class CORE_EXPORT WebPluginContainerBase
-    : public GarbageCollectedFinalized<WebPluginContainerBase>,
-      public PluginView,
-      NON_EXPORTED_BASE(public WebPluginContainer),
-      public ContextClient {
-  USING_GARBAGE_COLLECTED_MIXIN(WebPluginContainerBase);
-
- public:
-  virtual int PrintBegin(const WebPrintParams&) const = 0;
-  virtual void PrintPage(int page_number, GraphicsContext&, const IntRect&) = 0;
-  virtual void PrintEnd() = 0;
-  virtual bool ExecuteEditCommand(const WebString& name) = 0;
-  virtual bool ExecuteEditCommand(const WebString& name,
-                                  const WebString& value) = 0;
-  virtual bool SupportsPaginatedPrint() const = 0;
-  virtual bool IsPrintScalingDisabled() const = 0;
-  virtual bool GetPrintPresetOptionsFromDocument(
-      WebPrintPresetOptions*) const = 0;
-  virtual void DidFinishLoading() = 0;
-  virtual void DidFailLoading(const ResourceError&) = 0;
-  virtual void CalculateGeometry(IntRect& window_rect,
-                                 IntRect& clip_rect,
-                                 IntRect& unobscured_rect) = 0;
-
-  DECLARE_VIRTUAL_TRACE();
-
- protected:
-  explicit WebPluginContainerBase(LocalFrame*);
-};
-
-DEFINE_TYPE_CASTS(WebPluginContainerBase,
-                  PluginView,
-                  plugin,
-                  plugin->IsPluginContainer(),
-                  plugin.IsPluginContainer());
-// Unlike EmbeddedContentView, we need not worry about object type for
-// container. WebPluginContainerBase is the only subclass of WebPluginContainer.
-DEFINE_TYPE_CASTS(WebPluginContainerBase,
-                  WebPluginContainer,
-                  container,
-                  true,
-                  true);
-
-}  // nammespace blink
-
-#endif  // WebPluginContainerBase_h
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp
index 5f0af96..ade326a 100644
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp
@@ -691,7 +691,7 @@
 
 WebPluginContainerImpl::WebPluginContainerImpl(HTMLPlugInElement& element,
                                                WebPlugin* web_plugin)
-    : WebPluginContainerBase(element.GetDocument().GetFrame()),
+    : ContextClient(element.GetDocument().GetFrame()),
       element_(element),
       web_plugin_(web_plugin),
       web_layer_(nullptr),
@@ -731,7 +731,8 @@
 
 DEFINE_TRACE(WebPluginContainerImpl) {
   visitor->Trace(element_);
-  WebPluginContainerBase::Trace(visitor);
+  ContextClient::Trace(visitor);
+  PluginView::Trace(visitor);
 }
 
 void WebPluginContainerImpl::HandleMouseEvent(MouseEvent* event) {
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h
index aac16cd0..b4425e0 100644
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h
@@ -34,7 +34,7 @@
 
 #include "core/CoreExport.h"
 #include "core/dom/ContextLifecycleObserver.h"
-#include "core/exported/WebPluginContainerBase.h"
+#include "core/plugins/PluginView.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Compiler.h"
 #include "platform/wtf/PassRefPtr.h"
@@ -61,7 +61,12 @@
 struct WebPrintParams;
 struct WebPrintPresetOptions;
 
-class CORE_EXPORT WebPluginContainerImpl final : public WebPluginContainerBase {
+class CORE_EXPORT WebPluginContainerImpl final
+    : public GarbageCollectedFinalized<WebPluginContainerImpl>,
+      public PluginView,
+      NON_EXPORTED_BASE(public WebPluginContainer),
+      public ContextClient {
+  USING_GARBAGE_COLLECTED_MIXIN(WebPluginContainerImpl);
   USING_PRE_FINALIZER(WebPluginContainerImpl, PreFinalize);
 
  public:
@@ -142,37 +147,34 @@
   // (which means it controls the layout, number of pages etc).
   // Whether the plugin supports its own paginated print. The other print
   // interface methods are called only if this method returns true.
-  bool SupportsPaginatedPrint() const override;
+  bool SupportsPaginatedPrint() const;
   // If the plugin content should not be scaled to the printable area of
   // the page, then this method should return true.
-  bool IsPrintScalingDisabled() const override;
+  bool IsPrintScalingDisabled() const;
   // Returns true on success and sets the out parameter to the print preset
   // options for the document.
-  bool GetPrintPresetOptionsFromDocument(WebPrintPresetOptions*) const override;
+  bool GetPrintPresetOptionsFromDocument(WebPrintPresetOptions*) const;
   // Sets up printing at the specified WebPrintParams. Returns the number of
   // pages to be printed at these settings.
-  int PrintBegin(const WebPrintParams&) const override;
+  int PrintBegin(const WebPrintParams&) const;
   // Prints the page specified by pageNumber (0-based index) into the supplied
   // canvas.
-  void PrintPage(int page_number,
-                 GraphicsContext&,
-                 const IntRect& paint_rect) override;
+  void PrintPage(int page_number, GraphicsContext&, const IntRect& paint_rect);
   // Ends the print operation.
-  void PrintEnd() override;
+  void PrintEnd();
 
   // Copy the selected text.
   void Copy();
 
   // Pass the edit command to the plugin.
-  bool ExecuteEditCommand(const WebString& name) override;
-  bool ExecuteEditCommand(const WebString& name,
-                          const WebString& value) override;
+  bool ExecuteEditCommand(const WebString& name);
+  bool ExecuteEditCommand(const WebString& name, const WebString& value);
 
   // Resource load events for the plugin's source data:
   void DidReceiveResponse(const ResourceResponse&) override;
   void DidReceiveData(const char* data, int data_length) override;
-  void DidFinishLoading() override;
-  void DidFailLoading(const ResourceError&) override;
+  void DidFinishLoading();
+  void DidFailLoading(const ResourceError&);
 
   WebPluginContainerImpl* GetWebPluginContainer() const override {
     return const_cast<WebPluginContainerImpl*>(this);
@@ -218,7 +220,7 @@
 
   void CalculateGeometry(IntRect& window_rect,
                          IntRect& clip_rect,
-                         IntRect& unobscured_rect) override;
+                         IntRect& unobscured_rect);
 
   friend class WebPluginContainerTest;
 
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 1c4a936..7b66733 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -35,9 +35,6 @@
 #include "core/dom/AXObjectCache.h"
 #include "core/dom/DOMNodeIds.h"
 #include "core/dom/ElementVisibilityObserver.h"
-#include "core/dom/IntersectionObserverCallback.h"
-#include "core/dom/IntersectionObserverController.h"
-#include "core/dom/IntersectionObserverInit.h"
 #include "core/dom/ResizeObserverController.h"
 #include "core/dom/StyleChangeReason.h"
 #include "core/dom/TaskRunnerHelper.h"
@@ -64,6 +61,9 @@
 #include "core/html/parser/TextResourceDecoder.h"
 #include "core/input/EventHandler.h"
 #include "core/inspector/InspectorTraceEvents.h"
+#include "core/intersection_observer/IntersectionObserverCallback.h"
+#include "core/intersection_observer/IntersectionObserverController.h"
+#include "core/intersection_observer/IntersectionObserverInit.h"
 #include "core/layout/LayoutAnalyzer.h"
 #include "core/layout/LayoutCounter.h"
 #include "core/layout/LayoutEmbeddedContent.h"
@@ -1637,7 +1637,7 @@
     if (layout_view->UsesCompositing()) {
       if (root_layer_scrolling_enabled) {
         layout_view->Layer()->SetNeedsCompositingInputsUpdate();
-          SetNeedsPaintPropertyUpdate();
+        SetNeedsPaintPropertyUpdate();
       } else {
         layout_view->Compositor()->FrameViewDidChangeSize();
       }
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp b/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp
index 52bfe60..1fd4217 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp
@@ -4,12 +4,12 @@
 
 #include "core/frame/RemoteFrameView.h"
 
-#include "core/dom/IntersectionObserverEntry.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/RemoteFrame.h"
 #include "core/frame/RemoteFrameClient.h"
 #include "core/html/HTMLFrameOwnerElement.h"
+#include "core/intersection_observer/IntersectionObserverEntry.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LayoutEmbeddedContentItem.h"
 
diff --git a/third_party/WebKit/Source/core/intersection_observer/BUILD.gn b/third_party/WebKit/Source/core/intersection_observer/BUILD.gn
new file mode 100644
index 0000000..82a861e
--- /dev/null
+++ b/third_party/WebKit/Source/core/intersection_observer/BUILD.gn
@@ -0,0 +1,26 @@
+# 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("//third_party/WebKit/Source/core/core.gni")
+
+blink_core_sources("intersection_observer") {
+  sources = [
+    "ElementIntersectionObserverData.cpp",
+    "ElementIntersectionObserverData.h",
+    "IntersectionObservation.cpp",
+    "IntersectionObservation.h",
+    "IntersectionObserver.cpp",
+    "IntersectionObserver.h",
+    "IntersectionObserverCallback.h",
+    "IntersectionObserverController.cpp",
+    "IntersectionObserverController.h",
+    "IntersectionObserverEntry.cpp",
+    "IntersectionObserverEntry.h",
+  ]
+
+  configs += [
+    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+    "//build/config/compiler:no_size_t_to_int_warning",
+  ]
+}
diff --git a/third_party/WebKit/Source/core/dom/ElementIntersectionObserverData.cpp b/third_party/WebKit/Source/core/intersection_observer/ElementIntersectionObserverData.cpp
similarity index 88%
rename from third_party/WebKit/Source/core/dom/ElementIntersectionObserverData.cpp
rename to third_party/WebKit/Source/core/intersection_observer/ElementIntersectionObserverData.cpp
index 6da5d3b9..0996438 100644
--- a/third_party/WebKit/Source/core/dom/ElementIntersectionObserverData.cpp
+++ b/third_party/WebKit/Source/core/intersection_observer/ElementIntersectionObserverData.cpp
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/ElementIntersectionObserverData.h"
+#include "core/intersection_observer/ElementIntersectionObserverData.h"
 
 #include "core/dom/Document.h"
-#include "core/dom/IntersectionObservation.h"
-#include "core/dom/IntersectionObserver.h"
-#include "core/dom/IntersectionObserverController.h"
+#include "core/intersection_observer/IntersectionObservation.h"
+#include "core/intersection_observer/IntersectionObserver.h"
+#include "core/intersection_observer/IntersectionObserverController.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/dom/ElementIntersectionObserverData.h b/third_party/WebKit/Source/core/intersection_observer/ElementIntersectionObserverData.h
similarity index 100%
rename from third_party/WebKit/Source/core/dom/ElementIntersectionObserverData.h
rename to third_party/WebKit/Source/core/intersection_observer/ElementIntersectionObserverData.h
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp b/third_party/WebKit/Source/core/intersection_observer/IntersectionObservation.cpp
similarity index 96%
rename from third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObservation.cpp
index ed53ec8..329cf0d 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObservation.cpp
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/IntersectionObservation.h"
+#include "core/intersection_observer/IntersectionObservation.h"
 
 #include "core/dom/ElementRareData.h"
-#include "core/dom/IntersectionObserver.h"
 #include "core/frame/LocalFrame.h"
+#include "core/intersection_observer/IntersectionObserver.h"
 #include "core/layout/IntersectionGeometry.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObservation.h b/third_party/WebKit/Source/core/intersection_observer/IntersectionObservation.h
similarity index 100%
rename from third_party/WebKit/Source/core/dom/IntersectionObservation.h
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObservation.h
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
similarity index 96%
rename from third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
index 4710756..a71ce862 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
@@ -2,24 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/IntersectionObserver.h"
+#include "core/intersection_observer/IntersectionObserver.h"
 
 #include <algorithm>
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/CSSTokenizer.h"
 #include "core/dom/Element.h"
-#include "core/dom/ElementIntersectionObserverData.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
-#include "core/dom/IntersectionObserverCallback.h"
-#include "core/dom/IntersectionObserverController.h"
-#include "core/dom/IntersectionObserverEntry.h"
-#include "core/dom/IntersectionObserverInit.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/inspector/ConsoleMessage.h"
+#include "core/intersection_observer/ElementIntersectionObserverData.h"
+#include "core/intersection_observer/IntersectionObserverCallback.h"
+#include "core/intersection_observer/IntersectionObserverController.h"
+#include "core/intersection_observer/IntersectionObserverEntry.h"
+#include "core/intersection_observer/IntersectionObserverInit.h"
 #include "core/layout/LayoutView.h"
 #include "core/timing/DOMWindowPerformance.h"
 #include "core/timing/Performance.h"
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.h b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.h
similarity index 96%
rename from third_party/WebKit/Source/core/dom/IntersectionObserver.h
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.h
index 5946a85..adf4876 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserver.h
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.h
@@ -6,8 +6,8 @@
 #define IntersectionObserver_h
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "core/dom/IntersectionObservation.h"
-#include "core/dom/IntersectionObserverEntry.h"
+#include "core/intersection_observer/IntersectionObservation.h"
+#include "core/intersection_observer/IntersectionObserverEntry.h"
 #include "platform/Length.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.idl b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.idl
similarity index 100%
rename from third_party/WebKit/Source/core/dom/IntersectionObserver.idl
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.idl
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverCallback.h b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverCallback.h
similarity index 100%
rename from third_party/WebKit/Source/core/dom/IntersectionObserverCallback.h
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserverCallback.h
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverController.cpp
similarity index 95%
rename from third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserverController.cpp
index 48f06d5..5fcbf57 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverController.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/IntersectionObserverController.h"
+#include "core/intersection_observer/IntersectionObserverController.h"
 
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
@@ -21,8 +21,7 @@
 
 IntersectionObserverController::IntersectionObserverController(
     Document* document)
-    : SuspendableObject(document),
-      callback_fired_while_suspended_(false) {}
+    : SuspendableObject(document), callback_fired_while_suspended_(false) {}
 
 IntersectionObserverController::~IntersectionObserverController() {}
 
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverController.h b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverController.h
similarity index 96%
rename from third_party/WebKit/Source/core/dom/IntersectionObserverController.h
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserverController.h
index 2a5e6ca..5de6750 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserverController.h
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverController.h
@@ -5,8 +5,8 @@
 #ifndef IntersectionObserverController_h
 #define IntersectionObserverController_h
 
-#include "core/dom/IntersectionObserver.h"
 #include "core/dom/SuspendableObject.h"
+#include "core/intersection_observer/IntersectionObserver.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/HashSet.h"
 
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverEntry.cpp
similarity index 94%
rename from third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserverEntry.cpp
index f32a9fb..b20bcbb 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverEntry.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/IntersectionObserverEntry.h"
+#include "core/intersection_observer/IntersectionObserverEntry.h"
 
 #include "core/dom/Element.h"
 
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverEntry.h
similarity index 100%
rename from third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserverEntry.h
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverEntry.idl
similarity index 100%
rename from third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserverEntry.idl
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverInit.idl b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverInit.idl
similarity index 100%
rename from third_party/WebKit/Source/core/dom/IntersectionObserverInit.idl
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserverInit.idl
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverTest.cpp b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverTest.cpp
similarity index 96%
rename from third_party/WebKit/Source/core/dom/IntersectionObserverTest.cpp
rename to third_party/WebKit/Source/core/intersection_observer/IntersectionObserverTest.cpp
index 7ca9ab31..de169d3a 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserverTest.cpp
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserverTest.cpp
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/IntersectionObserver.h"
+#include "core/intersection_observer/IntersectionObserver.h"
 
-#include "core/dom/IntersectionObserverCallback.h"
-#include "core/dom/IntersectionObserverInit.h"
 #include "core/exported/WebViewBase.h"
 #include "core/frame/LocalFrameView.h"
+#include "core/intersection_observer/IntersectionObserverCallback.h"
+#include "core/intersection_observer/IntersectionObserverInit.h"
 #include "core/testing/sim/SimCompositor.h"
 #include "core/testing/sim/SimDisplayItemList.h"
 #include "core/testing/sim/SimRequest.h"
diff --git a/third_party/WebKit/Source/core/loader/PingLoader.cpp b/third_party/WebKit/Source/core/loader/PingLoader.cpp
index de46c8c..4a0057c 100644
--- a/third_party/WebKit/Source/core/loader/PingLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/PingLoader.cpp
@@ -294,6 +294,7 @@
       request.SetHTTPContentType("application/xss-auditor-report");
       break;
   }
+  request.SetKeepalive(true);
   request.SetHTTPBody(std::move(report));
   request.SetFetchCredentialsMode(
       WebURLRequest::kFetchCredentialsModeSameOrigin);
diff --git a/third_party/WebKit/Source/core/loader/PingLoaderTest.cpp b/third_party/WebKit/Source/core/loader/PingLoaderTest.cpp
index e1c904d..1e3daf9 100644
--- a/third_party/WebKit/Source/core/loader/PingLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/PingLoaderTest.cpp
@@ -133,6 +133,22 @@
   EXPECT_EQ(kResourceLoadPriorityVeryLow, request.Priority());
 }
 
+TEST_F(PingLoaderTest, ViolationPriority) {
+  SetDocumentURL(KURL(kParsedURLString, "http://localhost/foo.html"));
+
+  KURL ping_url(kParsedURLString, "https://localhost/bar.html");
+  URLTestHelpers::RegisterMockedURLLoad(
+      ping_url, testing::CoreTestDataPath("bar.html"), "text/html");
+  PingLoader::SendViolationReport(&page_holder_->GetFrame(), ping_url,
+                                  EncodedFormData::Create(),
+                                  PingLoader::kXSSAuditorViolationReport);
+  Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
+  const ResourceRequest& request = client_->PingRequest();
+  ASSERT_FALSE(request.IsNull());
+  ASSERT_EQ(request.Url(), ping_url);
+  EXPECT_EQ(kResourceLoadPriorityVeryLow, request.Priority());
+}
+
 TEST_F(PingLoaderTest, BeaconPriority) {
   SetDocumentURL(KURL(kParsedURLString, "https://localhost/foo.html"));
 
diff --git a/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js b/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js
index ba434c5..31e7fa1c 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js
@@ -37,6 +37,7 @@
     this.isValid = false;
     this.url = url;
     this.scheme = '';
+    this.user = '';
     this.host = '';
     this.port = '';
     this.path = '';
@@ -49,11 +50,12 @@
     if (match) {
       this.isValid = true;
       this.scheme = match[2].toLowerCase();
-      this.host = match[3];
-      this.port = match[4];
-      this.path = match[5] || '/';
-      this.queryParams = match[6] || '';
-      this.fragment = match[7];
+      this.user = match[3];
+      this.host = match[4];
+      this.port = match[5];
+      this.path = match[6] || '/';
+      this.queryParams = match[7] || '';
+      this.fragment = match[8];
     } else {
       if (this.url.startsWith('data:')) {
         this.scheme = 'data';
@@ -99,12 +101,14 @@
     // RegExp groups:
     // 1 - scheme, hostname, ?port
     // 2 - scheme (using the RFC3986 grammar)
-    // 3 - hostname
-    // 4 - ?port
-    // 5 - ?path
-    // 6 - ?query
-    // 7 - ?fragment
+    // 3 - ?user:password
+    // 4 - hostname
+    // 5 - ?port
+    // 6 - ?path
+    // 7 - ?query
+    // 8 - ?fragment
     var schemeRegex = /([A-Za-z][A-Za-z0-9+.-]*):\/\//;
+    var userRegex = /(?:([A-Za-z0-9\-._~%!$&'()*+,;=:]*)@)?/;
     var hostRegex = /([^\s\/:]*)/;
     var portRegex = /(?::([\d]+))?/;
     var pathRegex = /(\/[^#?]*)?/;
@@ -112,8 +116,8 @@
     var fragmentRegex = /(?:#(.*))?/;
 
     Common.ParsedURL._urlRegexInstance = new RegExp(
-        '^(' + schemeRegex.source + hostRegex.source + portRegex.source + ')' + pathRegex.source + queryRegex.source +
-        fragmentRegex.source + '$');
+        '^(' + schemeRegex.source + userRegex.source + hostRegex.source + portRegex.source + ')' + pathRegex.source +
+        queryRegex.source + fragmentRegex.source + '$');
     return Common.ParsedURL._urlRegexInstance;
   }
 
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index 0e456bb..82b80c9 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -315,10 +315,11 @@
                     "webaudio/ScriptProcessorNode.idl",
                     "webaudio/StereoPannerNode.idl",
                     "webaudio/WaveShaperNode.idl",
-                    "webauth/ScopedCredential.idl",
-                    "webauth/ScopedCredentialInfo.idl",
+                    "webauth/PublicKeyCredential.idl",
+                    "webauth/AuthenticatorAssertionResponse.idl",
+                    "webauth/AuthenticatorAttestationResponse.idl",
+                    "webauth/AuthenticatorResponse.idl",
                     "webauth/WebAuthentication.idl",
-                    "webauth/AuthenticationAssertion.idl",
                     "webdatabase/Database.idl",
                     "webdatabase/SQLError.idl",
                     "webdatabase/SQLResultSet.idl",
@@ -560,13 +561,14 @@
                     "webaudio/OfflineAudioCompletionEventInit.idl",
                     "webaudio/StereoPannerOptions.idl",
                     "webaudio/WaveShaperOptions.idl",
-                    "webauth/RelyingPartyAccount.idl",
-                    "webauth/AuthenticationAssertionOptions.idl",
-                    "webauth/AuthenticationClientData.idl",
-                    "webauth/ScopedCredentialDescriptor.idl",
-                    "webauth/ScopedCredentialOptions.idl",
-                    "webauth/ScopedCredentialParameters.idl",
-                    "webauth/AuthenticationExtensions.idl",
+                    "webauth/AuthenticatorSelectionCriteria.idl",
+                    "webauth/CollectedClientData.idl",
+                    "webauth/MakeCredentialOptions.idl",
+                    "webauth/PublicKeyCredentialDescriptor.idl",
+                    "webauth/PublicKeyCredentialEntity.idl",
+                    "webauth/PublicKeyCredentialParameters.idl",
+                    "webauth/PublicKeyCredentialRequestOptions.idl",
+                    "webauth/PublicKeyCredentialUserEntity.idl",
                     "webgl/WebGLContextAttributes.idl",
                     "webgl/WebGLContextEventInit.idl",
                     "webmidi/MIDIConnectionEventInit.idl",
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
index 832d9d1..8c61bfc 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
@@ -381,6 +381,28 @@
     return promise;
   }
 
+  for (float value : layer_.leftBounds()) {
+    if (std::isnan(value)) {
+      ForceExitPresent();
+      DOMException* exception = DOMException::Create(
+          kInvalidStateError, "Layer bounds must not contain NAN values");
+      resolver->Reject(exception);
+      ReportPresentationResult(PresentationResult::kInvalidLayerBounds);
+      return promise;
+    }
+  }
+
+  for (float value : layer_.rightBounds()) {
+    if (std::isnan(value)) {
+      ForceExitPresent();
+      DOMException* exception = DOMException::Create(
+          kInvalidStateError, "Layer bounds must not contain NAN values");
+      resolver->Reject(exception);
+      ReportPresentationResult(PresentationResult::kInvalidLayerBounds);
+      return promise;
+    }
+  }
+
   if (!pending_present_resolvers_.IsEmpty()) {
     // If we are waiting on the results of a previous requestPresent call don't
     // fire a new request, just cache the resolver and resolve it when the
@@ -710,6 +732,9 @@
   TRACE_EVENT_END0("gpu", "VRDisplay::SubmitFrame");
 
   did_submit_this_frame_ = true;
+  // Reset our frame id, since anything we'd want to do (resizing/etc) can
+  // no-longer happen to this frame.
+  vr_frame_id_ = -1;
   // If we were deferring a rAF-triggered vsync request, do this now.
   RequestVSync();
 
diff --git a/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp b/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
index 94a4364..373f4e6 100644
--- a/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
@@ -463,11 +463,16 @@
     const FloatPoint3D& listener_position,
     const FloatPoint3D& listener_forward,
     const FloatPoint3D& listener_up) {
-  double azimuth = 0.0;
-
   // Calculate the source-listener vector
   FloatPoint3D source_listener = position - listener_position;
 
+  // Quick default return if the source and listener are at the same position.
+  if (source_listener.IsZero()) {
+    *out_azimuth = 0;
+    *out_elevation = 0;
+    return;
+  }
+
   // normalize() does nothing if the length of |sourceListener| is zero.
   source_listener.Normalize();
 
@@ -484,7 +489,7 @@
 
   FloatPoint3D projected_source = source_listener - up_projection * up;
 
-  azimuth = rad2deg(projected_source.AngleBetween(listener_right));
+  double azimuth = rad2deg(projected_source.AngleBetween(listener_right));
   FixNANs(azimuth);  // avoid illegal values
 
   // Source  in front or behind the listener
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticationAssertion.h b/third_party/WebKit/Source/modules/webauth/AuthenticationAssertion.h
deleted file mode 100644
index d6603dda..0000000
--- a/third_party/WebKit/Source/modules/webauth/AuthenticationAssertion.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef AuthenticationAssertion_h
-#define AuthenticationAssertion_h
-
-#include "core/dom/DOMArrayBuffer.h"
-#include "modules/webauth/ScopedCredential.h"
-#include "platform/bindings/ScriptWrappable.h"
-
-namespace blink {
-
-class AuthenticationAssertion final
-    : public GarbageCollectedFinalized<AuthenticationAssertion>,
-      public ScriptWrappable {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static AuthenticationAssertion* Create(ScopedCredential* credential,
-                                         DOMArrayBuffer* client_data,
-                                         DOMArrayBuffer* authenticator_data,
-                                         DOMArrayBuffer* signature) {
-    return new AuthenticationAssertion(credential, client_data,
-                                       authenticator_data, signature);
-  }
-
-  AuthenticationAssertion(ScopedCredential* credential,
-                          DOMArrayBuffer* client_data,
-                          DOMArrayBuffer* authenticator_data,
-                          DOMArrayBuffer* signature)
-      : credential_(credential),
-        client_data_(client_data),
-        authenticator_data_(authenticator_data),
-        signature_(signature) {}
-
-  virtual ~AuthenticationAssertion() {}
-
-  ScopedCredential* credential() const { return credential_.Get(); }
-  DOMArrayBuffer* clientData() const { return client_data_.Get(); }
-  DOMArrayBuffer* authenticatorData() const {
-    return authenticator_data_.Get();
-  }
-  DOMArrayBuffer* signature() const { return signature_.Get(); }
-
-  DEFINE_INLINE_TRACE() {
-    visitor->Trace(credential_);
-    visitor->Trace(client_data_);
-    visitor->Trace(authenticator_data_);
-    visitor->Trace(signature_);
-  }
-
- private:
-  const Member<ScopedCredential> credential_;
-  const Member<DOMArrayBuffer> client_data_;
-  const Member<DOMArrayBuffer> authenticator_data_;
-  const Member<DOMArrayBuffer> signature_;
-};
-
-}  // namespace blink
-
-#endif  // AuthenticationAssertion_h
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticationAssertion.idl b/third_party/WebKit/Source/modules/webauth/AuthenticationAssertion.idl
deleted file mode 100644
index 16712494..0000000
--- a/third_party/WebKit/Source/modules/webauth/AuthenticationAssertion.idl
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#webauthnassertion
-
-[
-    RuntimeEnabled=WebAuth,
-    SecureContext
-] interface AuthenticationAssertion {
-    readonly attribute ScopedCredential credential;
-    readonly attribute ArrayBuffer clientData;
-    readonly attribute ArrayBuffer authenticatorData;
-    readonly attribute ArrayBuffer signature;
-};
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticationAssertionOptions.idl b/third_party/WebKit/Source/modules/webauth/AuthenticationAssertionOptions.idl
deleted file mode 100644
index 096723c9..0000000
--- a/third_party/WebKit/Source/modules/webauth/AuthenticationAssertionOptions.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#dictdef-assertionoptions
-
-dictionary AuthenticationAssertionOptions {
-    unsigned long timeoutSeconds;
-    USVString rpId;
-    sequence <ScopedCredentialDescriptor> allowList;
-    AuthenticationExtensions extensions;
-};
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticationClientData.idl b/third_party/WebKit/Source/modules/webauth/AuthenticationClientData.idl
deleted file mode 100644
index 761a7d69..0000000
--- a/third_party/WebKit/Source/modules/webauth/AuthenticationClientData.idl
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#sec-client-data
-
-dictionary AuthenticationClientData {
-    required DOMString challenge;
-    required DOMString origin;
-    required AlgorithmIdentifier hashAlg;
-    DOMString tokenBinding;
-    AuthenticationExtensions extensions;
-};
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticationExtensions.idl b/third_party/WebKit/Source/modules/webauth/AuthenticationExtensions.idl
deleted file mode 100644
index e73d3908..0000000
--- a/third_party/WebKit/Source/modules/webauth/AuthenticationExtensions.idl
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#dictdef-webauthnextensions
-
-dictionary AuthenticationExtensions {
-};
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorAssertionResponse.cpp b/third_party/WebKit/Source/modules/webauth/AuthenticatorAssertionResponse.cpp
new file mode 100644
index 0000000..541f0a2
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorAssertionResponse.cpp
@@ -0,0 +1,33 @@
+// 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 "modules/webauth/AuthenticatorAssertionResponse.h"
+
+namespace blink {
+
+AuthenticatorAssertionResponse* AuthenticatorAssertionResponse::Create(
+    DOMArrayBuffer* client_data_json,
+    DOMArrayBuffer* authenticator_data,
+    DOMArrayBuffer* signature) {
+  return new AuthenticatorAssertionResponse(client_data_json,
+                                            authenticator_data, signature);
+}
+
+AuthenticatorAssertionResponse::AuthenticatorAssertionResponse(
+    DOMArrayBuffer* client_data_json,
+    DOMArrayBuffer* authenticator_data,
+    DOMArrayBuffer* signature)
+    : AuthenticatorResponse(client_data_json),
+      authenticator_data_(authenticator_data),
+      signature_(signature) {}
+
+AuthenticatorAssertionResponse::~AuthenticatorAssertionResponse() {}
+
+DEFINE_TRACE(AuthenticatorAssertionResponse) {
+  visitor->Trace(authenticator_data_);
+  visitor->Trace(signature_);
+  AuthenticatorResponse::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorAssertionResponse.h b/third_party/WebKit/Source/modules/webauth/AuthenticatorAssertionResponse.h
new file mode 100644
index 0000000..9f1257b
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorAssertionResponse.h
@@ -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.
+
+#ifndef AuthenticatorAssertionResponse_h
+#define AuthenticatorAssertionResponse_h
+
+#include "core/dom/DOMArrayBuffer.h"
+#include "modules/ModulesExport.h"
+#include "modules/webauth/AuthenticatorResponse.h"
+#include "platform/bindings/ScriptWrappable.h"
+
+namespace blink {
+
+class MODULES_EXPORT AuthenticatorAssertionResponse final
+    : public AuthenticatorResponse {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static AuthenticatorAssertionResponse* Create(
+      DOMArrayBuffer* client_data_json,
+      DOMArrayBuffer* authenticator_data,
+      DOMArrayBuffer* signature);
+
+  virtual ~AuthenticatorAssertionResponse();
+
+  DOMArrayBuffer* authenticatorData() const {
+    return authenticator_data_.Get();
+  }
+
+  DOMArrayBuffer* signature() const { return signature_.Get(); }
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  explicit AuthenticatorAssertionResponse(DOMArrayBuffer* client_data_json,
+                                          DOMArrayBuffer* authenticator_data,
+                                          DOMArrayBuffer* signature);
+  const Member<DOMArrayBuffer> authenticator_data_;
+  const Member<DOMArrayBuffer> signature_;
+};
+
+}  // namespace blink
+
+#endif  // AuthenticatorAssertionResponse_h
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorAssertionResponse.idl b/third_party/WebKit/Source/modules/webauth/AuthenticatorAssertionResponse.idl
new file mode 100644
index 0000000..a0f7371
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorAssertionResponse.idl
@@ -0,0 +1,13 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/webauthn/#authenticatorassertionresponse
+
+[
+    RuntimeEnabled=WebAuth,
+    SecureContext
+] interface AuthenticatorAssertionResponse : AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer authenticatorData;
+    [SameObject] readonly attribute ArrayBuffer signature;
+};
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorAttestationResponse.cpp b/third_party/WebKit/Source/modules/webauth/AuthenticatorAttestationResponse.cpp
new file mode 100644
index 0000000..71a9b24
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorAttestationResponse.cpp
@@ -0,0 +1,29 @@
+// 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 "modules/webauth/AuthenticatorAttestationResponse.h"
+
+namespace blink {
+
+AuthenticatorAttestationResponse* AuthenticatorAttestationResponse::Create(
+    DOMArrayBuffer* client_data_json,
+    DOMArrayBuffer* attestation_object) {
+  return new AuthenticatorAttestationResponse(client_data_json,
+                                              attestation_object);
+}
+
+AuthenticatorAttestationResponse::AuthenticatorAttestationResponse(
+    DOMArrayBuffer* client_data_json,
+    DOMArrayBuffer* attestation_object)
+    : AuthenticatorResponse(client_data_json),
+      attestation_object_(attestation_object) {}
+
+AuthenticatorAttestationResponse::~AuthenticatorAttestationResponse() {}
+
+DEFINE_TRACE(AuthenticatorAttestationResponse) {
+  visitor->Trace(attestation_object_);
+  AuthenticatorResponse::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorAttestationResponse.h b/third_party/WebKit/Source/modules/webauth/AuthenticatorAttestationResponse.h
new file mode 100644
index 0000000..f005216
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorAttestationResponse.h
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AuthenticatorAttestationResponse_h
+#define AuthenticatorAttestationResponse_h
+
+#include "core/dom/DOMArrayBuffer.h"
+#include "modules/ModulesExport.h"
+#include "modules/webauth/AuthenticatorResponse.h"
+#include "platform/bindings/ScriptWrappable.h"
+
+namespace blink {
+
+class MODULES_EXPORT AuthenticatorAttestationResponse final
+    : public AuthenticatorResponse {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static AuthenticatorAttestationResponse* Create(
+      DOMArrayBuffer* client_data_json,
+      DOMArrayBuffer* attestation_object);
+
+  virtual ~AuthenticatorAttestationResponse();
+
+  DOMArrayBuffer* attestationObject() const {
+    return attestation_object_.Get();
+  }
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  explicit AuthenticatorAttestationResponse(DOMArrayBuffer* client_data_json,
+                                            DOMArrayBuffer* attestation_object);
+
+  const Member<DOMArrayBuffer> attestation_object_;
+};
+
+}  // namespace blink
+
+#endif  // AuthenticatorAttestationResponse_h
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorAttestationResponse.idl b/third_party/WebKit/Source/modules/webauth/AuthenticatorAttestationResponse.idl
new file mode 100644
index 0000000..36d1673ed
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorAttestationResponse.idl
@@ -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.
+
+// https://w3c.github.io/webauthn/#authenticatorattestationresponse
+
+[
+    RuntimeEnabled=WebAuth,
+    SecureContext
+] interface AuthenticatorAttestationResponse : AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer attestationObject;
+};
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorResponse.cpp b/third_party/WebKit/Source/modules/webauth/AuthenticatorResponse.cpp
new file mode 100644
index 0000000..5ecc02a
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorResponse.cpp
@@ -0,0 +1,23 @@
+// 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 "modules/webauth/AuthenticatorResponse.h"
+
+namespace blink {
+
+AuthenticatorResponse* AuthenticatorResponse::Create(
+    DOMArrayBuffer* client_data_json) {
+  return new AuthenticatorResponse(client_data_json);
+}
+
+AuthenticatorResponse::AuthenticatorResponse(DOMArrayBuffer* client_data_json)
+    : client_data_json_(client_data_json) {}
+
+AuthenticatorResponse::~AuthenticatorResponse() {}
+
+DEFINE_TRACE(AuthenticatorResponse) {
+  visitor->Trace(client_data_json_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorResponse.h b/third_party/WebKit/Source/modules/webauth/AuthenticatorResponse.h
new file mode 100644
index 0000000..5575a16
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorResponse.h
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AuthenticatorResponse_h
+#define AuthenticatorResponse_h
+
+#include "core/dom/DOMArrayBuffer.h"
+#include "modules/ModulesExport.h"
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class MODULES_EXPORT AuthenticatorResponse
+    : public GarbageCollectedFinalized<AuthenticatorResponse>,
+      public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static AuthenticatorResponse* Create(DOMArrayBuffer* client_data_json);
+
+  virtual ~AuthenticatorResponse();
+
+  DOMArrayBuffer* clientDataJSON() const { return client_data_json_.Get(); }
+
+  DECLARE_VIRTUAL_TRACE();
+
+ protected:
+  explicit AuthenticatorResponse(DOMArrayBuffer* client_data_json);
+
+ private:
+  const Member<DOMArrayBuffer> client_data_json_;
+};
+
+}  // namespace blink
+
+#endif  // AuthenticatorResponse_h
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorResponse.idl b/third_party/WebKit/Source/modules/webauth/AuthenticatorResponse.idl
new file mode 100644
index 0000000..bce5537
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorResponse.idl
@@ -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.
+
+// https://w3c.github.io/webauthn/#authenticatorresponse
+
+[
+    RuntimeEnabled=WebAuth,
+    SecureContext
+] interface AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer clientDataJSON;
+};
diff --git a/third_party/WebKit/Source/modules/webauth/AuthenticatorSelectionCriteria.idl b/third_party/WebKit/Source/modules/webauth/AuthenticatorSelectionCriteria.idl
new file mode 100644
index 0000000..8ddf682c
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/AuthenticatorSelectionCriteria.idl
@@ -0,0 +1,17 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/webauthn/#enumdef-authenticatorattachment
+
+enum AuthenticatorAttachment {
+  "platform",
+  "cross-platform"
+};
+
+// https://w3c.github.io/webauthn/#dictdef-authenticatorselectioncriteria
+
+dictionary AuthenticatorSelectionCriteria {
+  AuthenticatorAttachment attachment;
+  boolean requireResidentKey = false;
+};
diff --git a/third_party/WebKit/Source/modules/webauth/BUILD.gn b/third_party/WebKit/Source/modules/webauth/BUILD.gn
index 317a7305..4bdfda7 100644
--- a/third_party/WebKit/Source/modules/webauth/BUILD.gn
+++ b/third_party/WebKit/Source/modules/webauth/BUILD.gn
@@ -6,11 +6,16 @@
 
 blink_modules_sources("webauth") {
   sources = [
-    "AuthenticationAssertion.h",
+    "AuthenticatorAssertionResponse.cpp",
+    "AuthenticatorAssertionResponse.h",
+    "AuthenticatorAttestationResponse.cpp",
+    "AuthenticatorAttestationResponse.h",
+    "AuthenticatorResponse.cpp",
+    "AuthenticatorResponse.h",
     "NavigatorAuth.cpp",
     "NavigatorAuth.h",
-    "ScopedCredential.h",
-    "ScopedCredentialInfo.h",
+    "PublicKeyCredential.cpp",
+    "PublicKeyCredential.h",
     "WebAuthentication.cpp",
     "WebAuthentication.h",
   ]
diff --git a/third_party/WebKit/Source/modules/webauth/CollectedClientData.idl b/third_party/WebKit/Source/modules/webauth/CollectedClientData.idl
new file mode 100644
index 0000000..e26b036
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/CollectedClientData.idl
@@ -0,0 +1,13 @@
+// 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.
+
+// https://w3c.github.io/webauthn/#dictdef-collectedclientdata
+
+dictionary CollectedClientData {
+    required DOMString challenge;
+    required DOMString origin;
+    required DOMString hashAlgorithm;
+    DOMString tokenBindingId;
+    // TODO(crbug.com/733033): Add extension support
+};
diff --git a/third_party/WebKit/Source/modules/webauth/DEPS b/third_party/WebKit/Source/modules/webauth/DEPS
index 1e6ebea1..16764a92 100644
--- a/third_party/WebKit/Source/modules/webauth/DEPS
+++ b/third_party/WebKit/Source/modules/webauth/DEPS
@@ -1,4 +1,3 @@
 include_rules = [
-  "+device/usb/public/interfaces",
   "+mojo/public/cpp/bindings",
 ]
diff --git a/third_party/WebKit/Source/modules/webauth/MakeCredentialOptions.idl b/third_party/WebKit/Source/modules/webauth/MakeCredentialOptions.idl
new file mode 100644
index 0000000..5da9622
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/MakeCredentialOptions.idl
@@ -0,0 +1,16 @@
+// 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.
+
+// https://w3c.github.io/webauthn/#dictdef-makecredentialoptions
+
+dictionary MakeCredentialOptions {
+    required PublicKeyCredentialEntity rp;
+    required PublicKeyCredentialUserEntity user;
+    required BufferSource challenge;
+    required sequence<PublicKeyCredentialParameters> parameters;
+    unsigned long timeout;
+    sequence<PublicKeyCredentialDescriptor> excludeCredentials = [];
+    AuthenticatorSelectionCriteria authenticatorSelection;
+    // TODO(crbug.com/733033): Add extension support
+};
diff --git a/third_party/WebKit/Source/modules/webauth/PublicKeyCredential.cpp b/third_party/WebKit/Source/modules/webauth/PublicKeyCredential.cpp
new file mode 100644
index 0000000..36a12c5
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/PublicKeyCredential.cpp
@@ -0,0 +1,24 @@
+// 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 "modules/webauth/PublicKeyCredential.h"
+
+namespace blink {
+
+PublicKeyCredential* PublicKeyCredential::Create(
+    DOMArrayBuffer* raw_id,
+    AuthenticatorResponse* response) {
+  return new PublicKeyCredential(raw_id, response);
+}
+
+PublicKeyCredential::PublicKeyCredential(DOMArrayBuffer* raw_id,
+                                         AuthenticatorResponse* response)
+    : raw_id_(raw_id), response_(response) {}
+
+DEFINE_TRACE(PublicKeyCredential) {
+  visitor->Trace(raw_id_);
+  visitor->Trace(response_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webauth/PublicKeyCredential.h b/third_party/WebKit/Source/modules/webauth/PublicKeyCredential.h
new file mode 100644
index 0000000..d6c4e73d
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/PublicKeyCredential.h
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PublicKeyCredential_h
+#define PublicKeyCredential_h
+
+#include "core/dom/DOMArrayBuffer.h"
+#include "modules/ModulesExport.h"
+#include "modules/webauth/AuthenticatorResponse.h"
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class AuthenticatorResponse;
+
+class MODULES_EXPORT PublicKeyCredential final
+    : public GarbageCollected<PublicKeyCredential>,
+      public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static PublicKeyCredential* Create(DOMArrayBuffer* raw_id,
+                                     AuthenticatorResponse*);
+
+  DOMArrayBuffer* rawId() const { return raw_id_.Get(); }
+  AuthenticatorResponse* response() const { return response_.Get(); }
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  explicit PublicKeyCredential(DOMArrayBuffer* raw_id, AuthenticatorResponse*);
+
+  const Member<DOMArrayBuffer> raw_id_;
+  const Member<AuthenticatorResponse> response_;
+};
+
+}  // namespace blink
+
+#endif  // PublicKeyCredential_h
diff --git a/third_party/WebKit/Source/modules/webauth/PublicKeyCredential.idl b/third_party/WebKit/Source/modules/webauth/PublicKeyCredential.idl
new file mode 100644
index 0000000..c01477f
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/PublicKeyCredential.idl
@@ -0,0 +1,15 @@
+// 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.
+
+// https://w3c.github.io/webauthn/#publickeycredential
+
+[
+    RuntimeEnabled=WebAuth,
+    SecureContext,
+    Exposed=Window
+] interface PublicKeyCredential : Credential {
+    [SameObject] readonly attribute ArrayBuffer           rawId;
+    [SameObject] readonly attribute AuthenticatorResponse response;
+    // TODO(crbug.com/733033): Add extension support
+};
diff --git a/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialDescriptor.idl b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialDescriptor.idl
new file mode 100644
index 0000000..972e662
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialDescriptor.idl
@@ -0,0 +1,19 @@
+// 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.
+
+// https://w3c.github.io/webauthn/#enumdef-authenticatortransport
+
+enum Transport {
+    "usb",
+    "nfc",
+    "ble"
+};
+
+// https://w3c.github.io/webauthn/#dictdef-publickeycredentialdescriptor
+
+dictionary PublicKeyCredentialDescriptor {
+    required PublicKeyCredentialType type;
+    required BufferSource id;
+    sequence<Transport> transports;
+};
diff --git a/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialEntity.idl b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialEntity.idl
new file mode 100644
index 0000000..bfb643b
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialEntity.idl
@@ -0,0 +1,11 @@
+// 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.
+
+// https://w3c.github.io/webauthn/#dictdef-publickeycredentialentity
+
+dictionary PublicKeyCredentialEntity {
+    DOMString id;
+    DOMString name;
+    USVString icon;
+};
diff --git a/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialParameters.idl b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialParameters.idl
new file mode 100644
index 0000000..1e6a028
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialParameters.idl
@@ -0,0 +1,16 @@
+// 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.
+
+// https://w3c.github.io/webauthn/#enumdef-publickeycredentialtype
+
+enum PublicKeyCredentialType {
+    "public-key"
+};
+
+// https://w3c.github.io/webauthn/#dictdef-publickeycredentialparameters
+
+dictionary PublicKeyCredentialParameters {
+    required PublicKeyCredentialType type;
+    required AlgorithmIdentifier alg;
+};
diff --git a/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialRequestOptions.idl b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialRequestOptions.idl
new file mode 100644
index 0000000..ada0c3ad
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialRequestOptions.idl
@@ -0,0 +1,13 @@
+// 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.
+
+// https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptions
+
+dictionary PublicKeyCredentialRequestOptions {
+    required BufferSource challenge;
+    unsigned long timeout;
+    USVString rpId;
+    sequence <PublicKeyCredentialDescriptor> allowCredentials = [];
+    // TODO(crbug.com/733033): Add extension support
+};
diff --git a/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialUserEntity.idl b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialUserEntity.idl
new file mode 100644
index 0000000..51f5356
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webauth/PublicKeyCredentialUserEntity.idl
@@ -0,0 +1,9 @@
+// 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.
+
+// https://w3c.github.io/webauthn/#dictdef-publickeycredentialuserentity
+
+dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
+    DOMString displayName;
+};
diff --git a/third_party/WebKit/Source/modules/webauth/RelyingPartyAccount.idl b/third_party/WebKit/Source/modules/webauth/RelyingPartyAccount.idl
deleted file mode 100644
index fbf6f80..0000000
--- a/third_party/WebKit/Source/modules/webauth/RelyingPartyAccount.idl
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#dictdef-account
-
-dictionary RelyingPartyAccount {
-    required DOMString rpDisplayName;
-    required DOMString displayName;
-    required DOMString id;
-    DOMString name;
-    DOMString imageURL;
-};
diff --git a/third_party/WebKit/Source/modules/webauth/ScopedCredential.h b/third_party/WebKit/Source/modules/webauth/ScopedCredential.h
deleted file mode 100644
index 00537f6..0000000
--- a/third_party/WebKit/Source/modules/webauth/ScopedCredential.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ScopedCredential_h
-#define ScopedCredential_h
-
-#include "core/dom/DOMArrayBuffer.h"
-#include "platform/bindings/ScriptWrappable.h"
-
-namespace blink {
-
-class ScopedCredentialType;
-
-class ScopedCredential final
-    : public GarbageCollectedFinalized<ScopedCredential>,
-      public ScriptWrappable {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  enum class ScopedCredentialType { SCOPEDCRED };
-
-  static ScopedCredential* Create(const ScopedCredentialType type,
-                                  DOMArrayBuffer* id) {
-    return new ScopedCredential(type, id);
-  }
-
-  ScopedCredential(const ScopedCredentialType type, DOMArrayBuffer* id)
-      : type_(type), id_(id) {}
-
-  virtual ~ScopedCredential() {}
-
-  String type() const {
-    DCHECK_EQ(type_, ScopedCredentialType::SCOPEDCRED);
-    return "ScopedCred";
-  }
-
-  DOMArrayBuffer* id() const { return id_.Get(); }
-
-  ScopedCredentialType StringToCredentialType(const String& type) {
-    // There is currently only one type
-    return ScopedCredentialType::SCOPEDCRED;
-  }
-
-  DEFINE_INLINE_TRACE() { visitor->Trace(id_); }
-
- private:
-  const ScopedCredentialType type_;
-  const Member<DOMArrayBuffer> id_;
-};
-
-}  // namespace blink
-
-#endif  // ScopedCredential_h
diff --git a/third_party/WebKit/Source/modules/webauth/ScopedCredential.idl b/third_party/WebKit/Source/modules/webauth/ScopedCredential.idl
deleted file mode 100644
index 51ad326..0000000
--- a/third_party/WebKit/Source/modules/webauth/ScopedCredential.idl
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#enumdef-scopedcredentialtype
-
-enum ScopedCredentialType {
-    "ScopedCred"
-};
-
-// https://w3c.github.io/webauthn/#scopedcredential
-
-[
-    RuntimeEnabled=WebAuth,
-    SecureContext
-] interface ScopedCredential {
-    readonly attribute ScopedCredentialType type;
-    readonly attribute ArrayBuffer id;
-};
diff --git a/third_party/WebKit/Source/modules/webauth/ScopedCredentialDescriptor.idl b/third_party/WebKit/Source/modules/webauth/ScopedCredentialDescriptor.idl
deleted file mode 100644
index ccbd154..0000000
--- a/third_party/WebKit/Source/modules/webauth/ScopedCredentialDescriptor.idl
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#enumdef-externaltransport
-
-enum Transport {
-    "usb",
-    "nfc",
-    "ble"
-};
-
-// https://w3c.github.io/webauthn/#dictdef-scopedcredentialdescriptor
-
-dictionary ScopedCredentialDescriptor {
-    required ScopedCredentialType type;
-    required BufferSource id;
-    sequence<Transport> transports;
-};
diff --git a/third_party/WebKit/Source/modules/webauth/ScopedCredentialInfo.h b/third_party/WebKit/Source/modules/webauth/ScopedCredentialInfo.h
deleted file mode 100644
index 29dcb39..0000000
--- a/third_party/WebKit/Source/modules/webauth/ScopedCredentialInfo.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ScopedCredentialInfo_h
-#define ScopedCredentialInfo_h
-
-#include "core/dom/DOMArrayBuffer.h"
-#include "platform/bindings/ScriptWrappable.h"
-
-namespace blink {
-
-class ScopedCredentialInfo final
-    : public GarbageCollectedFinalized<ScopedCredentialInfo>,
-      public ScriptWrappable {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static ScopedCredentialInfo* Create(DOMArrayBuffer* client_data,
-                                      DOMArrayBuffer* attestation) {
-    return new ScopedCredentialInfo(client_data, attestation);
-  }
-
-  ScopedCredentialInfo(DOMArrayBuffer* client_data, DOMArrayBuffer* attestation)
-      : client_data_(client_data), attestation_(attestation) {}
-
-  virtual ~ScopedCredentialInfo() {}
-
-  DOMArrayBuffer* clientData() const { return client_data_.Get(); }
-  DOMArrayBuffer* attestation() const { return attestation_.Get(); }
-
-  DEFINE_INLINE_TRACE() {
-    visitor->Trace(client_data_);
-    visitor->Trace(attestation_);
-  }
-
- private:
-  const Member<DOMArrayBuffer> client_data_;
-  const Member<DOMArrayBuffer> attestation_;
-};
-
-}  // namespace blink
-
-#endif  // ScopedCredentialInfo_h
diff --git a/third_party/WebKit/Source/modules/webauth/ScopedCredentialInfo.idl b/third_party/WebKit/Source/modules/webauth/ScopedCredentialInfo.idl
deleted file mode 100644
index 87e15a2..0000000
--- a/third_party/WebKit/Source/modules/webauth/ScopedCredentialInfo.idl
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#scopedcredentialinfo
-
-[
-    RuntimeEnabled=WebAuth,
-    SecureContext
-] interface ScopedCredentialInfo {
-    readonly attribute ArrayBuffer clientData;
-    readonly attribute ArrayBuffer attestation;
-};
diff --git a/third_party/WebKit/Source/modules/webauth/ScopedCredentialOptions.idl b/third_party/WebKit/Source/modules/webauth/ScopedCredentialOptions.idl
deleted file mode 100644
index 1e2b39a..0000000
--- a/third_party/WebKit/Source/modules/webauth/ScopedCredentialOptions.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#dictdef-scopedcredentialoptions
-
-dictionary ScopedCredentialOptions {
-    unsigned long timeoutSeconds;
-    USVString rpId;
-    sequence<ScopedCredentialDescriptor> excludeList;
-    AuthenticationExtensions extensions;
-};
diff --git a/third_party/WebKit/Source/modules/webauth/ScopedCredentialParameters.idl b/third_party/WebKit/Source/modules/webauth/ScopedCredentialParameters.idl
deleted file mode 100644
index a9f73d03..0000000
--- a/third_party/WebKit/Source/modules/webauth/ScopedCredentialParameters.idl
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webauthn/#dictdef-scopedcredentialparameters
-
-dictionary ScopedCredentialParameters {
-    required ScopedCredentialType type;
-    required AlgorithmIdentifier algorithm;
-};
diff --git a/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp b/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
index 4ef1510..421a0fc1 100644
--- a/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
+++ b/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
@@ -4,38 +4,37 @@
 
 #include "modules/webauth/WebAuthentication.h"
 
-#include <stdint.h>
-
+#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "core/dom/DOMArrayBuffer.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/frame/LocalFrame.h"
-#include "modules/webauth/RelyingPartyAccount.h"
-#include "modules/webauth/ScopedCredential.h"
-#include "modules/webauth/ScopedCredentialOptions.h"
-#include "modules/webauth/ScopedCredentialParameters.h"
+#include "modules/webauth/AuthenticatorAttestationResponse.h"
+#include "modules/webauth/MakeCredentialOptions.h"
+#include "public/platform/InterfaceProvider.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 
+namespace blink {
+typedef ArrayBufferOrArrayBufferView BufferSource;
+}  // namespace blink
+
 namespace {
-const char kNoAuthenticatorError[] = "Authenticator unavailable.";
+constexpr char kNoAuthenticatorError[] = "Authenticator unavailable.";
 // Time to wait for an authenticator to successfully complete an operation.
-const int kAdjustedTimeoutLowerInSeconds = 60;
-const int kAdjustedTimeoutUpperInSeconds = 120;
+constexpr WTF::TimeDelta kAdjustedTimeoutLower = WTF::TimeDelta::FromMinutes(1);
+constexpr WTF::TimeDelta kAdjustedTimeoutUpper = WTF::TimeDelta::FromMinutes(2);
 }  // anonymous namespace
 
 namespace mojo {
-using webauth::mojom::blink::RelyingPartyAccount;
-using webauth::mojom::blink::RelyingPartyAccountPtr;
 using webauth::mojom::blink::AuthenticatorStatus;
-using webauth::mojom::blink::ScopedCredentialDescriptor;
-using webauth::mojom::blink::ScopedCredentialOptions;
-using webauth::mojom::blink::ScopedCredentialOptionsPtr;
-using webauth::mojom::blink::ScopedCredentialParameters;
-using webauth::mojom::blink::ScopedCredentialParametersPtr;
-using webauth::mojom::blink::ScopedCredentialType;
-using webauth::mojom::blink::Transport;
+using webauth::mojom::blink::MakeCredentialOptionsPtr;
+using webauth::mojom::blink::PublicKeyCredentialEntityPtr;
+using webauth::mojom::blink::PublicKeyCredentialParametersPtr;
+using webauth::mojom::blink::PublicKeyCredentialType;
+using webauth::mojom::blink::AuthenticatorTransport;
 
 // TODO(kpaulhamus): Make this a TypeConverter
 Vector<uint8_t> ConvertBufferSource(const blink::BufferSource& buffer) {
@@ -45,6 +44,7 @@
     vector.Append(static_cast<uint8_t*>(buffer.getAsArrayBuffer()->Data()),
                   buffer.getAsArrayBuffer()->ByteLength());
   } else {
+    DCHECK(buffer.isArrayBufferView());
     vector.Append(static_cast<uint8_t*>(
                       buffer.getAsArrayBufferView().View()->BaseAddress()),
                   buffer.getAsArrayBufferView().View()->byteLength());
@@ -53,86 +53,101 @@
 }
 
 // TODO(kpaulhamus): Make this a TypeConverter
-ScopedCredentialType ConvertScopedCredentialType(const String& cred_type) {
-  if (cred_type == "ScopedCred")
-    return ScopedCredentialType::SCOPEDCRED;
+PublicKeyCredentialType ConvertPublicKeyCredentialType(const String& type) {
+  if (type == "public-key")
+    return PublicKeyCredentialType::PUBLIC_KEY;
   NOTREACHED();
-  return ScopedCredentialType::SCOPEDCRED;
+  return PublicKeyCredentialType::PUBLIC_KEY;
 }
 
 // TODO(kpaulhamus): Make this a TypeConverter
-Transport ConvertTransport(const String& transport) {
+AuthenticatorTransport ConvertTransport(const String& transport) {
   if (transport == "usb")
-    return Transport::USB;
+    return AuthenticatorTransport::USB;
   if (transport == "nfc")
-    return Transport::NFC;
+    return AuthenticatorTransport::NFC;
   if (transport == "ble")
-    return Transport::BLE;
+    return AuthenticatorTransport::BLE;
   NOTREACHED();
-  return Transport::USB;
+  return AuthenticatorTransport::USB;
 }
 
 // TODO(kpaulhamus): Make this a TypeConverter
-RelyingPartyAccountPtr ConvertRelyingPartyAccount(
-    const blink::RelyingPartyAccount& account_information,
-    blink::ScriptPromiseResolver* resolver) {
-  auto mojo_account = RelyingPartyAccount::New();
-
-  mojo_account->relying_party_display_name =
-      account_information.rpDisplayName();
-  mojo_account->display_name = account_information.displayName();
-  mojo_account->id = account_information.id();
-  mojo_account->name = account_information.name();
-  mojo_account->image_url = account_information.imageURL();
-  return mojo_account;
-}
-
-// TODO(kpaulhamus): Make this a TypeConverter
-ScopedCredentialOptionsPtr ConvertScopedCredentialOptions(
-    const blink::ScopedCredentialOptions options,
-    blink::ScriptPromiseResolver* resolver) {
-  auto mojo_options = ScopedCredentialOptions::New();
-  if (options.hasRpId()) {
-    // if rpID is missing, it will later be set to the origin of the page
-    // in the secure browser process.
-    mojo_options->relying_party_id = options.rpId();
+PublicKeyCredentialEntityPtr ConvertPublicKeyCredentialUserEntity(
+    const blink::PublicKeyCredentialUserEntity& user) {
+  auto entity = webauth::mojom::blink::PublicKeyCredentialEntity::New();
+  entity->id = user.id();
+  entity->name = user.name();
+  if (user.hasIcon()) {
+    entity->icon = blink::KURL(blink::KURL(), user.icon());
   }
+  entity->display_name = user.displayName();
+  return entity;
+}
+
+// TODO(kpaulhamus): Make this a TypeConverter
+PublicKeyCredentialEntityPtr ConvertPublicKeyCredentialEntity(
+    const blink::PublicKeyCredentialEntity& rp) {
+  auto entity = webauth::mojom::blink::PublicKeyCredentialEntity::New();
+  entity->id = rp.id();
+  entity->name = rp.name();
+  if (rp.hasIcon()) {
+    entity->icon = blink::KURL(blink::KURL(), rp.icon());
+  }
+  return entity;
+}
+
+// TODO(kpaulhamus): Make this a TypeConverter
+PublicKeyCredentialParametersPtr ConvertPublicKeyCredentialParameters(
+    const blink::PublicKeyCredentialParameters parameter) {
+  auto mojo_parameter =
+      webauth::mojom::blink::PublicKeyCredentialParameters::New();
+  mojo_parameter->type = ConvertPublicKeyCredentialType(parameter.type());
+  // TODO(kpaulhamus): add AlgorithmIdentifier
+  return mojo_parameter;
+}
+
+// TODO(kpaulhamus): Make this a TypeConverter
+MakeCredentialOptionsPtr ConvertMakeCredentialOptions(
+    const blink::MakeCredentialOptions options) {
+  auto mojo_options = webauth::mojom::blink::MakeCredentialOptions::New();
+  mojo_options->relying_party = ConvertPublicKeyCredentialEntity(options.rp());
+  mojo_options->user = ConvertPublicKeyCredentialUserEntity(options.user());
+  mojo_options->challenge = ConvertBufferSource(options.challenge());
+
+  Vector<webauth::mojom::blink::PublicKeyCredentialParametersPtr> parameters;
+  for (const auto& parameter : options.parameters()) {
+    parameters.push_back(ConvertPublicKeyCredentialParameters(parameter));
+  }
+  mojo_options->crypto_parameters = std::move(parameters);
 
   // Step 4 of https://w3c.github.io/webauthn/#createCredential
-  int predicted_timeout = kAdjustedTimeoutLowerInSeconds;
-  if (options.hasTimeoutSeconds()) {
-    predicted_timeout = static_cast<int>(options.timeoutSeconds());
+  WTF::TimeDelta adjusted_timeout;
+  if (options.hasTimeout()) {
+    adjusted_timeout = WTF::TimeDelta::FromMilliseconds(options.timeout());
+  } else {
+    adjusted_timeout = kAdjustedTimeoutLower;
   }
 
-  mojo_options->adjusted_timeout = static_cast<double>(
-      std::max(kAdjustedTimeoutLowerInSeconds,
-               std::min(kAdjustedTimeoutUpperInSeconds, predicted_timeout)));
+  mojo_options->adjusted_timeout = std::max(
+      kAdjustedTimeoutLower, std::min(kAdjustedTimeoutUpper, adjusted_timeout));
 
-  if (options.hasExcludeList()) {
-    // Adds the excludeList members (which are ScopedCredentialDescriptors)
-    for (const auto& descriptor : options.excludeList()) {
-      auto mojo_descriptor = ScopedCredentialDescriptor::New();
-      mojo_descriptor->type = ConvertScopedCredentialType(descriptor.type());
+  if (options.hasExcludeCredentials()) {
+    // Adds the excludeCredentials members
+    // (which are PublicKeyCredentialDescriptors)
+    for (const auto& descriptor : options.excludeCredentials()) {
+      auto mojo_descriptor =
+          webauth::mojom::blink::PublicKeyCredentialDescriptor::New();
+      mojo_descriptor->type = ConvertPublicKeyCredentialType(descriptor.type());
       mojo_descriptor->id = ConvertBufferSource(descriptor.id());
       for (const auto& transport : descriptor.transports())
         mojo_descriptor->transports.push_back(ConvertTransport(transport));
-      mojo_options->exclude_list.push_back(std::move(mojo_descriptor));
+      mojo_options->exclude_credentials.push_back(std::move(mojo_descriptor));
     }
   }
-  // TODO(kpaulhamus): add AuthenticationExtensions;
   return mojo_options;
 }
 
-// TODO(kpaulhamus): Make this a TypeConverter
-ScopedCredentialParametersPtr ConvertScopedCredentialParameter(
-    const blink::ScopedCredentialParameters parameter,
-    blink::ScriptPromiseResolver* resolver) {
-  auto mojo_parameter = ScopedCredentialParameters::New();
-  mojo_parameter->type = ConvertScopedCredentialType(parameter.type());
-  // TODO(kpaulhamus): add AlgorithmIdentifier
-  return mojo_parameter;
-}
-
 blink::DOMException* CreateExceptionFromStatus(AuthenticatorStatus status) {
   switch (status) {
     case AuthenticatorStatus::NOT_IMPLEMENTED:
@@ -161,11 +176,18 @@
       return nullptr;
   }
 }
+
 }  // namespace mojo
 
 namespace blink {
+
 WebAuthentication::WebAuthentication(LocalFrame& frame)
-    : ContextLifecycleObserver(frame.GetDocument()) {}
+    : ContextLifecycleObserver(frame.GetDocument()) {
+  frame.GetInterfaceProvider().GetInterface(mojo::MakeRequest(&authenticator_));
+  authenticator_.set_connection_error_handler(ConvertToBaseCallback(
+      WTF::Bind(&WebAuthentication::OnAuthenticatorConnectionError,
+                WrapWeakPersistent(this))));
+}
 
 WebAuthentication::~WebAuthentication() {
   // |authenticator_| may still be valid but there should be no more
@@ -175,40 +197,25 @@
 
 ScriptPromise WebAuthentication::makeCredential(
     ScriptState* script_state,
-    const RelyingPartyAccount& account_information,
-    const HeapVector<ScopedCredentialParameters> crypto_parameters,
-    const BufferSource& attestation_challenge,
-    ScopedCredentialOptions& options) {
+    const MakeCredentialOptions& publicKey) {
   ScriptPromise promise = RejectIfNotSupported(script_state);
   if (!promise.IsEmpty())
     return promise;
 
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
 
-  Vector<uint8_t> buffer = mojo::ConvertBufferSource(attestation_challenge);
-  auto opts = mojo::ConvertScopedCredentialOptions(options, resolver);
-  Vector<webauth::mojom::blink::ScopedCredentialParametersPtr> parameters;
-  for (const auto& parameter : crypto_parameters) {
-    if (parameter.hasType()) {
-      parameters.push_back(
-          mojo::ConvertScopedCredentialParameter(parameter, resolver));
-    }
-  }
-  auto account =
-      mojo::ConvertRelyingPartyAccount(account_information, resolver);
+  auto options = mojo::ConvertMakeCredentialOptions(publicKey);
   authenticator_requests_.insert(resolver);
   authenticator_->MakeCredential(
-      std::move(account), std::move(parameters), buffer, std::move(opts),
-      ConvertToBaseCallback(WTF::Bind(&WebAuthentication::OnMakeCredential,
-                                      WrapPersistent(this),
-                                      WrapPersistent(resolver))));
+      std::move(options), ConvertToBaseCallback(WTF::Bind(
+                              &WebAuthentication::OnMakeCredential,
+                              WrapPersistent(this), WrapPersistent(resolver))));
   return resolver->Promise();
 }
 
 ScriptPromise WebAuthentication::getAssertion(
     ScriptState* script_state,
-    const BufferSource& assertion_challenge,
-    const AuthenticationAssertionOptions& options) {
+    const PublicKeyCredentialRequestOptions& publicKey) {
   NOTREACHED();
   return ScriptPromise();
 }
@@ -220,7 +227,7 @@
 void WebAuthentication::OnMakeCredential(
     ScriptPromiseResolver* resolver,
     webauth::mojom::blink::AuthenticatorStatus status,
-    webauth::mojom::blink::ScopedCredentialInfoPtr credential) {
+    webauth::mojom::blink::PublicKeyCredentialInfoPtr credential) {
   if (!MarkRequestComplete(resolver))
     return;
 
@@ -232,33 +239,37 @@
     return;
   }
 
-  if (credential->client_data.IsEmpty() || credential->attestation.IsEmpty()) {
+  if (credential->client_data_json.IsEmpty() ||
+      credential->response->attestation_object.IsEmpty()) {
     resolver->Reject(
-        DOMException::Create(kNotFoundError, "No credential returned."));
-    return;
+        DOMException::Create(kNotFoundError, "No credentials returned."));
   }
 
-  DOMArrayBuffer* clientDataBuffer = DOMArrayBuffer::Create(
-      static_cast<void*>(&credential->client_data.front()),
-      credential->client_data.size());
+  DOMArrayBuffer* client_data_buffer = DOMArrayBuffer::Create(
+      static_cast<void*>(&credential->client_data_json.front()),
+      credential->client_data_json.size());
 
-  DOMArrayBuffer* attestationBuffer = DOMArrayBuffer::Create(
-      static_cast<void*>(&credential->attestation.front()),
-      credential->attestation.size());
+  // Return AuthenticatorAttestationResponse
+  DOMArrayBuffer* attestation_buffer = DOMArrayBuffer::Create(
+      static_cast<void*>(&credential->response->attestation_object.front()),
+      credential->response->attestation_object.size());
 
-  ScopedCredentialInfo* scopedCredential =
-      ScopedCredentialInfo::Create(clientDataBuffer, attestationBuffer);
-  resolver->Resolve(scopedCredential);
+  AuthenticatorAttestationResponse* attestation_response =
+      AuthenticatorAttestationResponse::Create(client_data_buffer,
+                                               attestation_buffer);
+  resolver->Resolve(attestation_response);
 }
 
 ScriptPromise WebAuthentication::RejectIfNotSupported(
     ScriptState* script_state) {
+  LocalFrame* frame =
+      ToDocument(ExecutionContext::From(script_state))->GetFrame();
   if (!authenticator_) {
-    if (!GetFrame()) {
+    if (!frame) {
       return ScriptPromise::RejectWithDOMException(
           script_state, DOMException::Create(kNotSupportedError));
     }
-    GetFrame()->GetInterfaceProvider().GetInterface(
+    frame->GetInterfaceProvider().GetInterface(
         mojo::MakeRequest(&authenticator_));
 
     authenticator_.set_connection_error_handler(ConvertToBaseCallback(
diff --git a/third_party/WebKit/Source/modules/webauth/WebAuthentication.h b/third_party/WebKit/Source/modules/webauth/WebAuthentication.h
index 0c0c2b3d..a981d77c 100644
--- a/third_party/WebKit/Source/modules/webauth/WebAuthentication.h
+++ b/third_party/WebKit/Source/modules/webauth/WebAuthentication.h
@@ -5,25 +5,20 @@
 #ifndef WebAuthentication_h
 #define WebAuthentication_h
 
-#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
-#include "bindings/core/v8/ScriptPromise.h"
 #include "core/dom/ContextLifecycleObserver.h"
-#include "core/dom/DOMArrayBuffer.h"
-#include "modules/webauth/AuthenticationAssertionOptions.h"
-#include "modules/webauth/ScopedCredentialInfo.h"
 #include "platform/bindings/ScriptWrappable.h"
+#include "platform/heap/Handle.h"
 #include "public/platform/modules/webauth/authenticator.mojom-blink.h"
 
 namespace blink {
 
-class RelyingPartyAccount;
-class AuthenticationAssertionOptions;
-class ScopedCredentialOptions;
-class ScopedCredentialParameters;
+class LocalFrame;
+class MakeCredentialOptions;
+class PublicKeyCredentialRequestOptions;
+class ScriptState;
+class ScriptPromise;
 class ScriptPromiseResolver;
 
-typedef ArrayBufferOrArrayBufferView BufferSource;
-
 class WebAuthentication final
     : public GarbageCollectedFinalized<WebAuthentication>,
       public ScriptWrappable,
@@ -39,20 +34,16 @@
   virtual ~WebAuthentication();
 
   // WebAuthentication.idl
-  ScriptPromise makeCredential(ScriptState*,
-                               const RelyingPartyAccount&,
-                               const HeapVector<ScopedCredentialParameters>,
-                               const BufferSource&,
-                               ScopedCredentialOptions&);
+  ScriptPromise makeCredential(ScriptState*, const MakeCredentialOptions&);
+
   ScriptPromise getAssertion(ScriptState*,
-                             const BufferSource&,
-                             const AuthenticationAssertionOptions&);
+                             const PublicKeyCredentialRequestOptions&);
 
   webauth::mojom::blink::Authenticator* Authenticator() const {
     return authenticator_.get();
   }
 
-  // ContextLifecycleObserver overrides.
+  // ContextLifecycleObserver override
   void ContextDestroyed(ExecutionContext*) override;
 
   DECLARE_VIRTUAL_TRACE();
@@ -62,12 +53,11 @@
 
   void OnMakeCredential(ScriptPromiseResolver*,
                         webauth::mojom::blink::AuthenticatorStatus,
-                        webauth::mojom::blink::ScopedCredentialInfoPtr);
+                        webauth::mojom::blink::PublicKeyCredentialInfoPtr);
   ScriptPromise RejectIfNotSupported(ScriptState*);
   void OnAuthenticatorConnectionError();
   bool MarkRequestComplete(ScriptPromiseResolver*);
   void Cleanup();
-
   webauth::mojom::blink::AuthenticatorPtr authenticator_;
   HeapHashSet<Member<ScriptPromiseResolver>> authenticator_requests_;
 };
diff --git a/third_party/WebKit/Source/modules/webauth/WebAuthentication.idl b/third_party/WebKit/Source/modules/webauth/WebAuthentication.idl
index fb2b489..c0967ea 100644
--- a/third_party/WebKit/Source/modules/webauth/WebAuthentication.idl
+++ b/third_party/WebKit/Source/modules/webauth/WebAuthentication.idl
@@ -2,12 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/webauthn/#webauthentication
-
 [
     RuntimeEnabled=WebAuth,
     SecureContext
 ] interface WebAuthentication {
-    [CallWith=ScriptState] Promise<sequence<ScopedCredentialInfo>> makeCredential(RelyingPartyAccount accountInformation, sequence<ScopedCredentialParameters> cryptoParameters, BufferSource attestationChallenge, optional ScopedCredentialOptions options);
-    [CallWith=ScriptState] Promise<sequence<WebAuthnAssertion>> getAssertion(BufferSource assertionChallenge, optional AuthenticationAssertionOptions options);
+    [CallWith=ScriptState] Promise<AuthenticatorAttestationResponse> makeCredential(MakeCredentialOptions publicKey);
+    [CallWith=ScriptState] Promise<AuthenticatorAssertionResponse> getAssertion(PublicKeyCredentialRequestOptions publicKey);
 };
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
index 1ef03ecb..9e3ab06 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
@@ -13,6 +13,7 @@
 #include "platform/graphics/ImageBuffer.h"
 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
 #include "platform/graphics/paint/PaintRecorder.h"
+#include "platform/wtf/CheckedNumeric.h"
 #include "platform/wtf/PassRefPtr.h"
 #include "platform/wtf/PtrUtil.h"
 
@@ -305,7 +306,11 @@
 void RecordingImageBufferSurface::DidDraw(const FloatRect& rect) {
   did_record_draw_commands_in_current_frame_ = true;
   IntRect pixel_bounds = EnclosingIntRect(rect);
-  current_frame_pixel_count_ += pixel_bounds.Width() * pixel_bounds.Height();
+  CheckedNumeric<int> pixel_count = pixel_bounds.Width();
+  pixel_count *= pixel_bounds.Height();
+  pixel_count += current_frame_pixel_count_;
+  current_frame_pixel_count_ =
+      pixel_count.ValueOrDefault(std::numeric_limits<int>::max());
 }
 
 bool RecordingImageBufferSurface::FinalizeFrameInternal(
@@ -369,13 +374,18 @@
   if (fallback_surface_)
     return fallback_surface_->IsExpensiveToPaint();
 
+  CheckedNumeric<int> overdraw_limit_checked = size().Width();
+  overdraw_limit_checked *= size().Height();
+  overdraw_limit_checked *=
+      CanvasHeuristicParameters::kExpensiveOverdrawThreshold;
+  int overdraw_limit =
+      overdraw_limit_checked.ValueOrDefault(std::numeric_limits<int>::max());
+
   if (did_record_draw_commands_in_current_frame_) {
     if (current_frame_has_expensive_op_)
       return true;
 
-    if (current_frame_pixel_count_ >=
-        (size().Width() * size().Height() *
-         CanvasHeuristicParameters::kExpensiveOverdrawThreshold))
+    if (current_frame_pixel_count_ >= overdraw_limit)
       return true;
 
     if (frame_was_cleared_)
@@ -386,9 +396,7 @@
     if (previous_frame_has_expensive_op_)
       return true;
 
-    if (previous_frame_pixel_count_ >=
-        (size().Width() * size().Height() *
-         CanvasHeuristicParameters::kExpensiveOverdrawThreshold))
+    if (previous_frame_pixel_count_ >= overdraw_limit)
       return true;
   }
 
diff --git a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp
index 73e4d80..cd297127e 100644
--- a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp
@@ -7,10 +7,10 @@
 #include "cc/layers/layer.h"
 #include "cc/layers/solid_color_layer.h"
 #include "cc/layers/surface_layer.h"
-#include "cc/surfaces/sequence_surface_reference_factory.h"
-#include "cc/surfaces/surface_sequence.h"
+#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "platform/graphics/GraphicsLayer.h"
 #include "platform/mojo/MojoHelper.h"
 #include "platform/wtf/Functional.h"
@@ -26,7 +26,7 @@
 
 namespace {
 class SequenceSurfaceReferenceFactoryImpl
-    : public cc::SequenceSurfaceReferenceFactory {
+    : public viz::SequenceSurfaceReferenceFactory {
  public:
   SequenceSurfaceReferenceFactoryImpl(base::WeakPtr<SurfaceLayerBridge> bridge)
       : bridge_(bridge) {}
@@ -36,12 +36,12 @@
 
   // cc::SequenceSurfaceReferenceFactory implementation:
   void RequireSequence(const viz::SurfaceId& id,
-                       const cc::SurfaceSequence& sequence) const override {
+                       const viz::SurfaceSequence& sequence) const override {
     DCHECK(bridge_);
     bridge_->RequireCallback(id, sequence);
   }
 
-  void SatisfySequence(const cc::SurfaceSequence& sequence) const override {
+  void SatisfySequence(const viz::SurfaceSequence& sequence) const override {
     if (bridge_)
       bridge_->SatisfyCallback(sequence);
   }
@@ -85,12 +85,12 @@
   }
 }
 
-void SurfaceLayerBridge::SatisfyCallback(const cc::SurfaceSequence& sequence) {
+void SurfaceLayerBridge::SatisfyCallback(const viz::SurfaceSequence& sequence) {
   service_->Satisfy(sequence);
 }
 
 void SurfaceLayerBridge::RequireCallback(const viz::SurfaceId& surface_id,
-                                         const cc::SurfaceSequence& sequence) {
+                                         const viz::SurfaceSequence& sequence) {
   service_->Require(surface_id, sequence);
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h
index 6c2757b..9647aff 100644
--- a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h
@@ -8,8 +8,8 @@
 #include <memory>
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "cc/surfaces/surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "platform/PlatformExport.h"
 #include "public/platform/WebSurfaceLayerBridge.h"
@@ -48,8 +48,8 @@
 
   // Implementation of blink::mojom::blink::OffscreenCanvasSurfaceClient
   void OnSurfaceCreated(const viz::SurfaceInfo&) override;
-  void SatisfyCallback(const cc::SurfaceSequence&);
-  void RequireCallback(const viz::SurfaceId&, const cc::SurfaceSequence&);
+  void SatisfyCallback(const viz::SurfaceSequence&);
+  void RequireCallback(const viz::SurfaceId&, const viz::SurfaceSequence&);
 
   // Implementation of WebSurfaceLayerBridge.
   WebLayer* GetWebLayer() const override { return web_layer_.get(); }
@@ -62,7 +62,7 @@
   scoped_refptr<cc::Layer> cc_layer_;
   std::unique_ptr<WebLayer> web_layer_;
 
-  scoped_refptr<cc::SurfaceReferenceFactory> ref_factory_;
+  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory_;
   base::WeakPtrFactory<SurfaceLayerBridge> weak_factory_;
 
   SurfaceLayerBridgeObserver* observer_;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
index 49a7bc7..f4b39b74 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
@@ -62,6 +62,16 @@
 
 struct CrossThreadResourceRequestData;
 
+// A ResourceRequest is a "request" object for ResourceLoader. Conceptually
+// it is https://fetch.spec.whatwg.org/#concept-request, but it contains
+// a lot of blink specific fields. WebURLRequest is the "public version"
+// of this class and WebURLLoader needs it. See WebURLRequest and
+// WrappedResourceRequest.
+//
+// There are cases where we need to copy a request across threads, and
+// CrossThreadResourceRequestData is a struct for the purpose. When you add a
+// member variable to this class, do not forget to add the corresponding
+// one in CrossThreadResourceRequestData and write copying logic.
 class PLATFORM_EXPORT ResourceRequest final {
   DISALLOW_NEW();
 
@@ -381,6 +391,14 @@
   double navigation_start_ = 0;
 };
 
+// This class is needed to copy a ResourceRequest across threads, because it
+// has some members which cannot be transferred across threads (AtomicString
+// for example).
+// There are some rules / restrictions:
+//  - This struct cannot contain an object that cannot be transferred across
+//    threads (e.g., AtomicString)
+//  - Non-simple members need explicit copying (e.g., String::IsolatedCopy,
+//    KURL::Copy) rather than the copy constructor or the assignment operator.
 struct CrossThreadResourceRequestData {
   WTF_MAKE_NONCOPYABLE(CrossThreadResourceRequestData);
   USING_FAST_MALLOC(CrossThreadResourceRequestData);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceResponse.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceResponse.h
index 813f7172..a7057ea 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceResponse.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceResponse.h
@@ -46,6 +46,15 @@
 
 struct CrossThreadResourceResponseData;
 
+// A ResourceResponse is a "response" object used in blink. Conceptually
+// it is https://fetch.spec.whatwg.org/#concept-response, but it contains
+// a lot of blink specific fields. WebURLResponse is the "public version"
+// of this class and public classes (i.e., classes in public/platform) use it.
+//
+// There are cases where we need to copy a response across threads, and
+// CrossThreadResourceResponseData is a struct for the purpose. When you add a
+// member variable to this class, do not forget to add the corresponding
+// one in CrossThreadResourceResponseData and write copying logic.
 class PLATFORM_EXPORT ResourceResponse final {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
@@ -530,6 +539,14 @@
   return !(a == b);
 }
 
+// This class is needed to copy a ResourceResponse across threads, because it
+// has some members which cannot be transferred across threads (AtomicString
+// for example).
+// There are some rules / restrictions:
+//  - This struct cannot contain an object that cannot be transferred across
+//    threads (e.g., AtomicString)
+//  - Non-simple members need explicit copying (e.g., String::IsolatedCopy,
+//    KURL::Copy) rather than the copy constructor or the assignment operator.
 struct CrossThreadResourceResponseData {
   WTF_MAKE_NONCOPYABLE(CrossThreadResourceResponseData);
   USING_FAST_MALLOC(CrossThreadResourceResponseData);
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit.py
index 37025c1..2b31e1c3 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit.py
@@ -73,7 +73,7 @@
     def subject(self):
         return self.host.executive.run_command([
             'git', 'show', '--format=%s', '--no-patch', self.sha
-        ], cwd=self.absolute_chromium_dir)
+        ], cwd=self.absolute_chromium_dir).strip()
 
     def body(self):
         return self.host.executive.run_command([
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common.py
index 7f69c7b..4f2760bf 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common.py
@@ -84,8 +84,9 @@
     message = chromium_commit.message()
     if 'NOEXPORT=true' in message or 'No-Export: true' in message or message.startswith('Import'):
         return False
+
     patch = chromium_commit.format_patch()
-    if not (patch and local_wpt.test_patch(patch, chromium_commit)):
+    if not patch:
         return False
 
     # If there's a corresponding closed PR, then this commit should not
@@ -94,6 +95,10 @@
     pull_request = wpt_github.pr_for_chromium_commit(chromium_commit)
     if pull_request and pull_request.state == 'closed':
         return False
+
+    if not local_wpt.test_patch(patch, chromium_commit):
+        return False
+
     return True
 
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py
index 489d193b..6d0149d8 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py
@@ -138,11 +138,12 @@
             self.run(['git', 'apply', '-'], input=patch)
             self.run(['git', 'add', '.'])
             output = self.run(['git', 'diff', 'origin/master'])
-        except ScriptError:
-            _log.debug('Patch did not apply cleanly for the following commit, skipping:')
+        except ScriptError as e:
+            _log.info('Patch did not apply cleanly for the following commit:')
             if chromium_commit:
-                _log.debug('Commit: %s', chromium_commit.url())
-                _log.debug('Commit subject: "%s"', chromium_commit.subject())
+                _log.info('Commit: %s', chromium_commit.url())
+                _log.info('Commit subject: "%s"', chromium_commit.subject())
+                _log.info('Message: %s\n\n', e.message)
             output = ''
 
         self.clean()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
index b2f099f..1edc01a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
@@ -236,7 +236,7 @@
         # so we fall back to trying to use commit position here, although
         # commit position is not correct sometimes (https://crbug.com/737178).
         # TODO(qyearsley): Remove this fallback after full Gerrit migration.
-        pull_request = self.pr_with_position(chromium_commit.position)
+        return self.pr_with_position(chromium_commit.position)
 
     def pr_with_change_id(self, target_change_id):
         for pull_request in self.all_pull_requests():
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 4a105f3..bc23e84 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -656,7 +656,7 @@
     "//base:base",
     "//cc:cc",
     "//cc/paint:paint",
-    "//cc/surfaces:surface_id",
+    "//components/viz/common",
     "//device/screen_orientation/public/interfaces:interfaces_shared_cpp_sources",
     "//media/midi:mojo_shared_cpp_sources",
     "//mojo/public/cpp/bindings:bindings",
diff --git a/third_party/WebKit/public/platform/modules/webauth/authenticator.mojom b/third_party/WebKit/public/platform/modules/webauth/authenticator.mojom
index bafa09d..3becca76 100644
--- a/third_party/WebKit/public/platform/modules/webauth/authenticator.mojom
+++ b/third_party/WebKit/public/platform/modules/webauth/authenticator.mojom
@@ -5,9 +5,12 @@
 [JavaPackage="org.chromium.webauth.mojom"]
 module webauth.mojom;
 
+import "mojo/common/time.mojom";
+import "url/mojo/url.mojom";
+
 // This file describes the communication between the WebAuthentication renderer
-// implementation and browser-side implementations to create scoped credentials
-// and use already-created credentials to get assertions.
+// implementation and browser-side implementations to create public key
+// credentials and use already-created credentials to get assertions.
 // See https://w3c.github.io/webauthn/.
 
 enum AuthenticatorStatus {
@@ -22,79 +25,112 @@
 
 // The public key and attestation that is returned by an authenticator's 
 // call to makeCredential.
-struct ScopedCredentialInfo {
+struct PublicKeyCredentialInfo {
+  // The base64url encoding of |raw_id|.
+  string id;
+
+  // An identifier for the credential.
+  array<uint8> raw_id;
+
   // A blob of data containing the JSON serialization of client data passed
   // to the authenticator.
-  array<uint8> client_data;
-  // A blob of data returned from the authenticator.
-  array<uint8> attestation;
+  array<uint8> client_data_json;
+
+  // The response data from the authenticator.
+  AuthenticatorResponse response;
 };
 
-// Information about the relying party and the user account held by that 
-// relying party. This information is used by the authenticator to create 
-// or retrieve an appropriate scoped credential for this account.
+// Contains the authenticator's response to the request to either
+// create a public key credential, or generate an authentication assertion.
+struct AuthenticatorResponse {
+  // A blob of data returned by the authenticator after creating a credential.
+  array<uint8> attestation_object;
+
+  // A blob of data returned by the authenticator after generating an assertion.
+  array<uint8> authenticator_data;
+
+  // Cryptographic signature proving possession of the credential private key.
+  array<uint8> signature;
+};
+
+// Information about the relying party and the account held by the user at 
+// that relying party. This information is used by the authenticator to create
+// or retrieve an appropriate public key credential for this account.
 // These fields take arbitrary input.
-struct RelyingPartyAccount {
-  // Friendly name of the Relying Party, e.g. "Acme Corporation"
-  string relying_party_display_name;
-  // Friendly name associated with the user account, e.g. "John P. Smith"
-  string display_name;
-  // Identifier for the account, corresponding to no more than one credential 
-  // per authenticator and Relying Party.
+struct PublicKeyCredentialEntity {
+  // A unique identifier for the entity. An ASCII serialization of an origin
+  // for a relying party, and an arbitrary string specified by the relying party
+  // for user accounts.
   string id;
-  // Detailed name for the account, e.g. john.p.smith@example.com
-  string? name;
-  // User image, if any.
-  // TODO(kpaulhamus): make this url.mojom.Url in a followup CL
-  string? image_url;
+
+  // Friendly name associated with the entity intended for display.
+  // e.g. "Acme Corporation" for a relying party and "john.p.smith@example.com"
+  // or "+14255551234" for a user.
+  string name;
+
+  // Image associated with the entity.
+  // For example, this could be a user’s avatar or a relying party's logo.
+  url.mojom.Url? icon;
+
+  // Contains a friendly name for the user account (e.g., "John P. Smith").
+  string? display_name;
 };
 
-// Parameters that are used to generate an appropriate scoped credential.
-struct ScopedCredentialParameters {
-  ScopedCredentialType type;
+// Parameters that are used to generate an appropriate public key credential.
+struct PublicKeyCredentialParameters {
+  PublicKeyCredentialType type;
   // TODO(kpaulhamus): add AlgorithmIdentifier algorithm;
 };
 
-// Optional parameters that are used during makeCredential. 
-struct ScopedCredentialOptions {
-  //TODO(kpaulhamus): Make this mojo.common.mojom.TimeDelta in followup CL
-  double adjusted_timeout;
-  string? relying_party_id;
-  array<ScopedCredentialDescriptor> exclude_list;
-  // TODO(kpaulhamus): add Extensions
+// Parameters passed into calls to MakeCredential.
+struct MakeCredentialOptions {
+  // Relying party information. 
+  // Corresponds to |rp| in MakeCredentialOptions.idl.
+  PublicKeyCredentialEntity relying_party;
+
+  // Information about the user.
+  PublicKeyCredentialEntity user;
+  
+  // A blob passed from the the relying party server.
+  array<uint8> challenge; 
+
+  array<PublicKeyCredentialParameters> crypto_parameters;
+
+  mojo.common.mojom.TimeDelta adjusted_timeout;
+
+  array<PublicKeyCredentialDescriptor> exclude_credentials;
+
+  // TODO(kpaulhamus): add AuthenticatorSelectionCriteria  
 };
 
-enum ScopedCredentialType {
-  SCOPEDCRED,
+enum PublicKeyCredentialType {
+  PUBLIC_KEY,
 };
 
 // Describes the credentials that the relying party already knows about for
-// the given account. If any of these are known to the authenticator, 
+// the given account. If any of these are known to the authenticator,
 // it should not create a new credential.
-struct ScopedCredentialDescriptor {
-  ScopedCredentialType type;
-  // Blob representing a credential key handle. Up to 255 bytes for 
+struct PublicKeyCredentialDescriptor {
+  PublicKeyCredentialType type;
+
+  // Blob representing a credential key handle. Up to 255 bytes for
   // U2F authenticators.
   array<uint8> id;
-  array<Transport> transports;
+
+  array<AuthenticatorTransport> transports;
 };
 
-enum Transport {
+enum AuthenticatorTransport {
   USB,
   NFC,
   BLE,
 };
 
-// Interface to direct authenticators to create or use a scoped credential.
+// Interface to direct authenticators to create or use a public key credential.
 interface Authenticator {
-  // Gets the credential info for a new credential created by an authenticator
-  // for the given relying party and account. 
-  // |attestation_challenge| is a blob passed from the relying party server.
-  // [ScopedCredentialInfo] will only be set if status == SUCCESS. 
-  MakeCredential(RelyingPartyAccount account_information,
-                 array<ScopedCredentialParameters> crypto_parameters,
-                 array<uint8> attestation_challenge,
-                 ScopedCredentialOptions options)
-      => (AuthenticatorStatus status, 
-          ScopedCredentialInfo? scoped_credential);
+  // Gets the credential info for a new public key credential created by an
+  // authenticator for the given |MakeCredentialOptions|
+  // [PublicKeyCredentialInfo] will only be set if status == SUCCESS.   
+  MakeCredential(MakeCredentialOptions options)
+      => (AuthenticatorStatus status, PublicKeyCredentialInfo? credential);
 };
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index 62abb57..c3e07e2 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Friday July 07 2017
+Date: Wednesday July 12 2017
 Branch: master
-Commit: 4e16f7070354fa91c1a617ee18335e580a0b8c8c
+Commit: b578d59623ddb0f3f76efe5e160aff253b40d19b
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni
index fe97770..a975c9f 100644
--- a/third_party/libvpx/libvpx_srcs.gni
+++ b/third_party/libvpx/libvpx_srcs.gni
@@ -222,7 +222,6 @@
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_ethread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_frame_scale.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_job_queue.h",
@@ -680,7 +679,6 @@
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_ethread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_frame_scale.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_job_queue.h",
@@ -1141,7 +1139,6 @@
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_ethread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_frame_scale.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_job_queue.h",
@@ -1509,7 +1506,6 @@
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_ethread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_frame_scale.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_job_queue.h",
@@ -1596,6 +1592,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sad_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subpel_variance_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subtract_neon.c",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sum_neon.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/transpose_neon.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/vpx_convolve_neon.c",
@@ -1892,7 +1889,6 @@
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_ethread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_frame_scale.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_job_queue.h",
@@ -1957,6 +1953,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/add_noise.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct_neon.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/mem_neon.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sum_neon.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/transpose_neon.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/avg.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/bitreader.c",
@@ -2327,7 +2324,6 @@
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_ethread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_frame_scale.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_job_queue.h",
@@ -2417,6 +2413,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sad_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subpel_variance_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subtract_neon.c",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sum_neon.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/transpose_neon.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/vpx_convolve8_neon.c",
@@ -2702,7 +2699,6 @@
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_ethread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_frame_scale.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_job_queue.h",
@@ -3042,7 +3038,6 @@
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_ethread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_frame_scale.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_job_queue.h",
@@ -3382,7 +3377,6 @@
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_ethread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_extend.h",
-  "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_firstpass.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_frame_scale.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_job_queue.h",
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vp9_rtcd.h b/third_party/libvpx/source/config/ios/arm-neon/vp9_rtcd.h
index 3b104550..a0f86ea 100644
--- a/third_party/libvpx/source/config/ios/arm-neon/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm-neon/vp9_rtcd.h
@@ -63,9 +63,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vpx_config.asm b/third_party/libvpx/source/config/ios/arm-neon/vpx_config.asm
index f73f4aa3..b1bf106 100644
--- a/third_party/libvpx/source/config/ios/arm-neon/vpx_config.asm
+++ b/third_party/libvpx/source/config/ios/arm-neon/vpx_config.asm
@@ -81,6 +81,7 @@
 .set CONFIG_BETTER_HW_COMPATIBILITY ,  0
 .set CONFIG_EXPERIMENTAL ,  0
 .set CONFIG_SIZE_LIMIT ,  1
+.set CONFIG_ALWAYS_ADJUST_BPM ,  0
 .set CONFIG_SPATIAL_SVC ,  0
 .set CONFIG_FP_MB_STATS ,  0
 .set CONFIG_EMULATE_HARDWARE ,  0
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vpx_config.h b/third_party/libvpx/source/config/ios/arm-neon/vpx_config.h
index fe0b2b1..b33278b 100644
--- a/third_party/libvpx/source/config/ios/arm-neon/vpx_config.h
+++ b/third_party/libvpx/source/config/ios/arm-neon/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
index b978840..c694f53 100644
--- a/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
@@ -470,7 +470,8 @@
 #define vpx_sad16x32_avg vpx_sad16x32_avg_neon
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x32x4d vpx_sad16x32x4d_c
+void vpx_sad16x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad16x32x4d vpx_sad16x32x4d_neon
 
 unsigned int vpx_sad16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad16x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -484,7 +485,8 @@
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
 
 void vpx_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x8x4d vpx_sad16x8x4d_c
+void vpx_sad16x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad16x8x4d vpx_sad16x8x4d_neon
 
 void vpx_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
@@ -498,7 +500,8 @@
 #define vpx_sad32x16_avg vpx_sad32x16_avg_neon
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x16x4d vpx_sad32x16x4d_c
+void vpx_sad32x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad32x16x4d vpx_sad32x16x4d_neon
 
 unsigned int vpx_sad32x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -508,16 +511,10 @@
 unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad32x32_avg vpx_sad32x32_avg_neon
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x4d vpx_sad32x32x4d_neon
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad32x64 vpx_sad32x64_neon
@@ -527,7 +524,8 @@
 #define vpx_sad32x64_avg vpx_sad32x64_avg_neon
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x64x4d vpx_sad32x64x4d_c
+void vpx_sad32x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad32x64x4d vpx_sad32x64x4d_neon
 
 unsigned int vpx_sad4x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad4x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -541,7 +539,8 @@
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
 
 void vpx_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x4x4d vpx_sad4x4x4d_c
+void vpx_sad4x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad4x4x4d vpx_sad4x4x4d_neon
 
 void vpx_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
@@ -555,10 +554,8 @@
 #define vpx_sad4x8_avg vpx_sad4x8_avg_neon
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x4d vpx_sad4x8x4d_c
-
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
+void vpx_sad4x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad4x8x4d vpx_sad4x8x4d_neon
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -569,7 +566,8 @@
 #define vpx_sad64x32_avg vpx_sad64x32_avg_neon
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x32x4d vpx_sad64x32x4d_c
+void vpx_sad64x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad64x32x4d vpx_sad64x32x4d_neon
 
 unsigned int vpx_sad64x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -579,16 +577,10 @@
 unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad64x64_avg vpx_sad64x64_avg_neon
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x4d vpx_sad64x64x4d_neon
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_neon
@@ -601,7 +593,8 @@
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
 
 void vpx_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x16x4d vpx_sad8x16x4d_c
+void vpx_sad8x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x16x4d vpx_sad8x16x4d_neon
 
 void vpx_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
@@ -615,10 +608,8 @@
 #define vpx_sad8x4_avg vpx_sad8x4_avg_neon
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x4d vpx_sad8x4x4d_c
-
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
+void vpx_sad8x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x4x4d vpx_sad8x4x4d_neon
 
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -632,7 +623,8 @@
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
 
 void vpx_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x8x4d vpx_sad8x8x4d_c
+void vpx_sad8x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x8x4d vpx_sad8x8x4d_neon
 
 void vpx_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x8 vpx_sad8x8x8_c
diff --git a/third_party/libvpx/source/config/ios/arm64/vp9_rtcd.h b/third_party/libvpx/source/config/ios/arm64/vp9_rtcd.h
index 3b104550..a0f86ea 100644
--- a/third_party/libvpx/source/config/ios/arm64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm64/vp9_rtcd.h
@@ -63,9 +63,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/ios/arm64/vpx_config.asm b/third_party/libvpx/source/config/ios/arm64/vpx_config.asm
index e8df0a874..8400bb4 100644
--- a/third_party/libvpx/source/config/ios/arm64/vpx_config.asm
+++ b/third_party/libvpx/source/config/ios/arm64/vpx_config.asm
@@ -81,6 +81,7 @@
 .set CONFIG_BETTER_HW_COMPATIBILITY ,  0
 .set CONFIG_EXPERIMENTAL ,  0
 .set CONFIG_SIZE_LIMIT ,  1
+.set CONFIG_ALWAYS_ADJUST_BPM ,  0
 .set CONFIG_SPATIAL_SVC ,  0
 .set CONFIG_FP_MB_STATS ,  0
 .set CONFIG_EMULATE_HARDWARE ,  0
diff --git a/third_party/libvpx/source/config/ios/arm64/vpx_config.h b/third_party/libvpx/source/config/ios/arm64/vpx_config.h
index a7e4859..a3db07d 100644
--- a/third_party/libvpx/source/config/ios/arm64/vpx_config.h
+++ b/third_party/libvpx/source/config/ios/arm64/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
index b978840..c694f53 100644
--- a/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
@@ -470,7 +470,8 @@
 #define vpx_sad16x32_avg vpx_sad16x32_avg_neon
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x32x4d vpx_sad16x32x4d_c
+void vpx_sad16x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad16x32x4d vpx_sad16x32x4d_neon
 
 unsigned int vpx_sad16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad16x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -484,7 +485,8 @@
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
 
 void vpx_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x8x4d vpx_sad16x8x4d_c
+void vpx_sad16x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad16x8x4d vpx_sad16x8x4d_neon
 
 void vpx_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
@@ -498,7 +500,8 @@
 #define vpx_sad32x16_avg vpx_sad32x16_avg_neon
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x16x4d vpx_sad32x16x4d_c
+void vpx_sad32x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad32x16x4d vpx_sad32x16x4d_neon
 
 unsigned int vpx_sad32x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -508,16 +511,10 @@
 unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad32x32_avg vpx_sad32x32_avg_neon
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x4d vpx_sad32x32x4d_neon
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad32x64 vpx_sad32x64_neon
@@ -527,7 +524,8 @@
 #define vpx_sad32x64_avg vpx_sad32x64_avg_neon
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x64x4d vpx_sad32x64x4d_c
+void vpx_sad32x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad32x64x4d vpx_sad32x64x4d_neon
 
 unsigned int vpx_sad4x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad4x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -541,7 +539,8 @@
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
 
 void vpx_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x4x4d vpx_sad4x4x4d_c
+void vpx_sad4x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad4x4x4d vpx_sad4x4x4d_neon
 
 void vpx_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
@@ -555,10 +554,8 @@
 #define vpx_sad4x8_avg vpx_sad4x8_avg_neon
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x4d vpx_sad4x8x4d_c
-
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
+void vpx_sad4x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad4x8x4d vpx_sad4x8x4d_neon
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -569,7 +566,8 @@
 #define vpx_sad64x32_avg vpx_sad64x32_avg_neon
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x32x4d vpx_sad64x32x4d_c
+void vpx_sad64x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad64x32x4d vpx_sad64x32x4d_neon
 
 unsigned int vpx_sad64x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -579,16 +577,10 @@
 unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad64x64_avg vpx_sad64x64_avg_neon
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x4d vpx_sad64x64x4d_neon
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_neon
@@ -601,7 +593,8 @@
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
 
 void vpx_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x16x4d vpx_sad8x16x4d_c
+void vpx_sad8x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x16x4d vpx_sad8x16x4d_neon
 
 void vpx_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
@@ -615,10 +608,8 @@
 #define vpx_sad8x4_avg vpx_sad8x4_avg_neon
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x4d vpx_sad8x4x4d_c
-
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
+void vpx_sad8x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x4x4d vpx_sad8x4x4d_neon
 
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -632,7 +623,8 @@
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
 
 void vpx_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x8x4d vpx_sad8x8x4d_c
+void vpx_sad8x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x8x4d vpx_sad8x8x4d_neon
 
 void vpx_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x8 vpx_sad8x8x8_c
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp9_rtcd.h
index 015772d..8de66ff9 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp9_rtcd.h
@@ -63,9 +63,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm
index 0c8a1ea1..a07e4df 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm
@@ -78,6 +78,7 @@
 .equ CONFIG_BETTER_HW_COMPATIBILITY ,  0
 .equ CONFIG_EXPERIMENTAL ,  0
 .equ CONFIG_SIZE_LIMIT ,  1
+.equ CONFIG_ALWAYS_ADJUST_BPM ,  0
 .equ CONFIG_SPATIAL_SVC ,  0
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h
index 086348a3..c7576b6 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
index 068a03a..a607a57 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
@@ -470,7 +470,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad16x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x32x4d vpx_sad16x32x4d_c
+void vpx_sad16x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad16x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 unsigned int vpx_sad16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad16x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -484,7 +485,8 @@
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
 
 void vpx_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x8x4d vpx_sad16x8x4d_c
+void vpx_sad16x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad16x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 void vpx_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
@@ -498,7 +500,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad32x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x16x4d vpx_sad32x16x4d_c
+void vpx_sad32x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad32x16x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 unsigned int vpx_sad32x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -508,16 +511,10 @@
 unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_sad32x64)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -527,7 +524,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad32x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x64x4d vpx_sad32x64x4d_c
+void vpx_sad32x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad32x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 unsigned int vpx_sad4x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad4x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -541,7 +539,8 @@
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
 
 void vpx_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x4x4d vpx_sad4x4x4d_c
+void vpx_sad4x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad4x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 void vpx_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
@@ -555,10 +554,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad4x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x4d vpx_sad4x8x4d_c
-
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
+void vpx_sad4x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad4x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -569,7 +566,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad64x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x32x4d vpx_sad64x32x4d_c
+void vpx_sad64x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad64x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 unsigned int vpx_sad64x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -579,16 +577,10 @@
 unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_sad8x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -601,7 +593,8 @@
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
 
 void vpx_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x16x4d vpx_sad8x16x4d_c
+void vpx_sad8x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad8x16x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 void vpx_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
@@ -615,10 +608,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad8x4_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x4d vpx_sad8x4x4d_c
-
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
+void vpx_sad8x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad8x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -632,7 +623,8 @@
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
 
 void vpx_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x8x4d vpx_sad8x8x4d_c
+void vpx_sad8x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+RTCD_EXTERN void (*vpx_sad8x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
 void vpx_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x8 vpx_sad8x8x8_c
@@ -1053,14 +1045,20 @@
     if (flags & HAS_NEON) vpx_sad16x32 = vpx_sad16x32_neon;
     vpx_sad16x32_avg = vpx_sad16x32_avg_c;
     if (flags & HAS_NEON) vpx_sad16x32_avg = vpx_sad16x32_avg_neon;
+    vpx_sad16x32x4d = vpx_sad16x32x4d_c;
+    if (flags & HAS_NEON) vpx_sad16x32x4d = vpx_sad16x32x4d_neon;
     vpx_sad16x8 = vpx_sad16x8_c;
     if (flags & HAS_NEON) vpx_sad16x8 = vpx_sad16x8_neon;
     vpx_sad16x8_avg = vpx_sad16x8_avg_c;
     if (flags & HAS_NEON) vpx_sad16x8_avg = vpx_sad16x8_avg_neon;
+    vpx_sad16x8x4d = vpx_sad16x8x4d_c;
+    if (flags & HAS_NEON) vpx_sad16x8x4d = vpx_sad16x8x4d_neon;
     vpx_sad32x16 = vpx_sad32x16_c;
     if (flags & HAS_NEON) vpx_sad32x16 = vpx_sad32x16_neon;
     vpx_sad32x16_avg = vpx_sad32x16_avg_c;
     if (flags & HAS_NEON) vpx_sad32x16_avg = vpx_sad32x16_avg_neon;
+    vpx_sad32x16x4d = vpx_sad32x16x4d_c;
+    if (flags & HAS_NEON) vpx_sad32x16x4d = vpx_sad32x16x4d_neon;
     vpx_sad32x32 = vpx_sad32x32_c;
     if (flags & HAS_NEON) vpx_sad32x32 = vpx_sad32x32_neon;
     vpx_sad32x32_avg = vpx_sad32x32_avg_c;
@@ -1071,18 +1069,26 @@
     if (flags & HAS_NEON) vpx_sad32x64 = vpx_sad32x64_neon;
     vpx_sad32x64_avg = vpx_sad32x64_avg_c;
     if (flags & HAS_NEON) vpx_sad32x64_avg = vpx_sad32x64_avg_neon;
+    vpx_sad32x64x4d = vpx_sad32x64x4d_c;
+    if (flags & HAS_NEON) vpx_sad32x64x4d = vpx_sad32x64x4d_neon;
     vpx_sad4x4 = vpx_sad4x4_c;
     if (flags & HAS_NEON) vpx_sad4x4 = vpx_sad4x4_neon;
     vpx_sad4x4_avg = vpx_sad4x4_avg_c;
     if (flags & HAS_NEON) vpx_sad4x4_avg = vpx_sad4x4_avg_neon;
+    vpx_sad4x4x4d = vpx_sad4x4x4d_c;
+    if (flags & HAS_NEON) vpx_sad4x4x4d = vpx_sad4x4x4d_neon;
     vpx_sad4x8 = vpx_sad4x8_c;
     if (flags & HAS_NEON) vpx_sad4x8 = vpx_sad4x8_neon;
     vpx_sad4x8_avg = vpx_sad4x8_avg_c;
     if (flags & HAS_NEON) vpx_sad4x8_avg = vpx_sad4x8_avg_neon;
+    vpx_sad4x8x4d = vpx_sad4x8x4d_c;
+    if (flags & HAS_NEON) vpx_sad4x8x4d = vpx_sad4x8x4d_neon;
     vpx_sad64x32 = vpx_sad64x32_c;
     if (flags & HAS_NEON) vpx_sad64x32 = vpx_sad64x32_neon;
     vpx_sad64x32_avg = vpx_sad64x32_avg_c;
     if (flags & HAS_NEON) vpx_sad64x32_avg = vpx_sad64x32_avg_neon;
+    vpx_sad64x32x4d = vpx_sad64x32x4d_c;
+    if (flags & HAS_NEON) vpx_sad64x32x4d = vpx_sad64x32x4d_neon;
     vpx_sad64x64 = vpx_sad64x64_c;
     if (flags & HAS_NEON) vpx_sad64x64 = vpx_sad64x64_neon;
     vpx_sad64x64_avg = vpx_sad64x64_avg_c;
@@ -1093,14 +1099,20 @@
     if (flags & HAS_NEON) vpx_sad8x16 = vpx_sad8x16_neon;
     vpx_sad8x16_avg = vpx_sad8x16_avg_c;
     if (flags & HAS_NEON) vpx_sad8x16_avg = vpx_sad8x16_avg_neon;
+    vpx_sad8x16x4d = vpx_sad8x16x4d_c;
+    if (flags & HAS_NEON) vpx_sad8x16x4d = vpx_sad8x16x4d_neon;
     vpx_sad8x4 = vpx_sad8x4_c;
     if (flags & HAS_NEON) vpx_sad8x4 = vpx_sad8x4_neon;
     vpx_sad8x4_avg = vpx_sad8x4_avg_c;
     if (flags & HAS_NEON) vpx_sad8x4_avg = vpx_sad8x4_avg_neon;
+    vpx_sad8x4x4d = vpx_sad8x4x4d_c;
+    if (flags & HAS_NEON) vpx_sad8x4x4d = vpx_sad8x4x4d_neon;
     vpx_sad8x8 = vpx_sad8x8_c;
     if (flags & HAS_NEON) vpx_sad8x8 = vpx_sad8x8_neon;
     vpx_sad8x8_avg = vpx_sad8x8_avg_c;
     if (flags & HAS_NEON) vpx_sad8x8_avg = vpx_sad8x8_avg_neon;
+    vpx_sad8x8x4d = vpx_sad8x8x4d_c;
+    if (flags & HAS_NEON) vpx_sad8x8x4d = vpx_sad8x8x4d_neon;
     vpx_satd = vpx_satd_c;
     if (flags & HAS_NEON) vpx_satd = vpx_satd_neon;
     vpx_sub_pixel_avg_variance16x16 = vpx_sub_pixel_avg_variance16x16_c;
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon/vp9_rtcd.h
index 3b104550..a0f86ea 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon/vp9_rtcd.h
@@ -63,9 +63,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm
index 363449e..a2ac8c9 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm
@@ -78,6 +78,7 @@
 .equ CONFIG_BETTER_HW_COMPATIBILITY ,  0
 .equ CONFIG_EXPERIMENTAL ,  0
 .equ CONFIG_SIZE_LIMIT ,  1
+.equ CONFIG_ALWAYS_ADJUST_BPM ,  0
 .equ CONFIG_SPATIAL_SVC ,  0
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h
index fe0b2b1..b33278b 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
index b978840..c694f53 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
@@ -470,7 +470,8 @@
 #define vpx_sad16x32_avg vpx_sad16x32_avg_neon
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x32x4d vpx_sad16x32x4d_c
+void vpx_sad16x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad16x32x4d vpx_sad16x32x4d_neon
 
 unsigned int vpx_sad16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad16x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -484,7 +485,8 @@
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
 
 void vpx_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x8x4d vpx_sad16x8x4d_c
+void vpx_sad16x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad16x8x4d vpx_sad16x8x4d_neon
 
 void vpx_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
@@ -498,7 +500,8 @@
 #define vpx_sad32x16_avg vpx_sad32x16_avg_neon
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x16x4d vpx_sad32x16x4d_c
+void vpx_sad32x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad32x16x4d vpx_sad32x16x4d_neon
 
 unsigned int vpx_sad32x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -508,16 +511,10 @@
 unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad32x32_avg vpx_sad32x32_avg_neon
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x4d vpx_sad32x32x4d_neon
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad32x64 vpx_sad32x64_neon
@@ -527,7 +524,8 @@
 #define vpx_sad32x64_avg vpx_sad32x64_avg_neon
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x64x4d vpx_sad32x64x4d_c
+void vpx_sad32x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad32x64x4d vpx_sad32x64x4d_neon
 
 unsigned int vpx_sad4x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad4x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -541,7 +539,8 @@
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
 
 void vpx_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x4x4d vpx_sad4x4x4d_c
+void vpx_sad4x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad4x4x4d vpx_sad4x4x4d_neon
 
 void vpx_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
@@ -555,10 +554,8 @@
 #define vpx_sad4x8_avg vpx_sad4x8_avg_neon
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x4d vpx_sad4x8x4d_c
-
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
+void vpx_sad4x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad4x8x4d vpx_sad4x8x4d_neon
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -569,7 +566,8 @@
 #define vpx_sad64x32_avg vpx_sad64x32_avg_neon
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x32x4d vpx_sad64x32x4d_c
+void vpx_sad64x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad64x32x4d vpx_sad64x32x4d_neon
 
 unsigned int vpx_sad64x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -579,16 +577,10 @@
 unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad64x64_avg vpx_sad64x64_avg_neon
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x4d vpx_sad64x64x4d_neon
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_neon
@@ -601,7 +593,8 @@
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
 
 void vpx_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x16x4d vpx_sad8x16x4d_c
+void vpx_sad8x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x16x4d vpx_sad8x16x4d_neon
 
 void vpx_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
@@ -615,10 +608,8 @@
 #define vpx_sad8x4_avg vpx_sad8x4_avg_neon
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x4d vpx_sad8x4x4d_c
-
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
+void vpx_sad8x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x4x4d vpx_sad8x4x4d_neon
 
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -632,7 +623,8 @@
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
 
 void vpx_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x8x4d vpx_sad8x8x4d_c
+void vpx_sad8x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x8x4d vpx_sad8x8x4d_neon
 
 void vpx_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x8 vpx_sad8x8x8_c
diff --git a/third_party/libvpx/source/config/linux/arm/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm/vp9_rtcd.h
index e259775c..21a448a 100644
--- a/third_party/libvpx/source/config/linux/arm/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm/vp9_rtcd.h
@@ -60,9 +60,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_config.asm b/third_party/libvpx/source/config/linux/arm/vpx_config.asm
index 8fc0fd44..701dd45 100644
--- a/third_party/libvpx/source/config/linux/arm/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm/vpx_config.asm
@@ -78,6 +78,7 @@
 .equ CONFIG_BETTER_HW_COMPATIBILITY ,  0
 .equ CONFIG_EXPERIMENTAL ,  0
 .equ CONFIG_SIZE_LIMIT ,  1
+.equ CONFIG_ALWAYS_ADJUST_BPM ,  0
 .equ CONFIG_SPATIAL_SVC ,  0
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_config.h b/third_party/libvpx/source/config/linux/arm/vpx_config.h
index 0421e45..234efbf 100644
--- a/third_party/libvpx/source/config/linux/arm/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h
index 9eda39e..38baa0a7 100644
--- a/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h
@@ -412,15 +412,9 @@
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad32x32_avg vpx_sad32x32_avg_c
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x4d vpx_sad32x32x4d_c
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad32x64 vpx_sad32x64_c
 
@@ -454,9 +448,6 @@
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad64x32 vpx_sad64x32_c
 
@@ -472,15 +463,9 @@
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad64x64_avg vpx_sad64x64_avg_c
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x4d vpx_sad64x64x4d_c
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_c
 
@@ -505,9 +490,6 @@
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x8 vpx_sad8x8_c
 
diff --git a/third_party/libvpx/source/config/linux/arm64/vp9_rtcd.h b/third_party/libvpx/source/config/linux/arm64/vp9_rtcd.h
index 3b104550..a0f86ea 100644
--- a/third_party/libvpx/source/config/linux/arm64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm64/vp9_rtcd.h
@@ -63,9 +63,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_config.asm b/third_party/libvpx/source/config/linux/arm64/vpx_config.asm
index b237ea68..060b6035 100644
--- a/third_party/libvpx/source/config/linux/arm64/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm64/vpx_config.asm
@@ -78,6 +78,7 @@
 .equ CONFIG_BETTER_HW_COMPATIBILITY ,  0
 .equ CONFIG_EXPERIMENTAL ,  0
 .equ CONFIG_SIZE_LIMIT ,  1
+.equ CONFIG_ALWAYS_ADJUST_BPM ,  0
 .equ CONFIG_SPATIAL_SVC ,  0
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_config.h b/third_party/libvpx/source/config/linux/arm64/vpx_config.h
index a7e4859..a3db07d 100644
--- a/third_party/libvpx/source/config/linux/arm64/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm64/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
index b978840..c694f53 100644
--- a/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
@@ -470,7 +470,8 @@
 #define vpx_sad16x32_avg vpx_sad16x32_avg_neon
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x32x4d vpx_sad16x32x4d_c
+void vpx_sad16x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad16x32x4d vpx_sad16x32x4d_neon
 
 unsigned int vpx_sad16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad16x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -484,7 +485,8 @@
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
 
 void vpx_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad16x8x4d vpx_sad16x8x4d_c
+void vpx_sad16x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad16x8x4d vpx_sad16x8x4d_neon
 
 void vpx_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
@@ -498,7 +500,8 @@
 #define vpx_sad32x16_avg vpx_sad32x16_avg_neon
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x16x4d vpx_sad32x16x4d_c
+void vpx_sad32x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad32x16x4d vpx_sad32x16x4d_neon
 
 unsigned int vpx_sad32x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -508,16 +511,10 @@
 unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad32x32_avg vpx_sad32x32_avg_neon
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x4d vpx_sad32x32x4d_neon
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad32x64 vpx_sad32x64_neon
@@ -527,7 +524,8 @@
 #define vpx_sad32x64_avg vpx_sad32x64_avg_neon
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x64x4d vpx_sad32x64x4d_c
+void vpx_sad32x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad32x64x4d vpx_sad32x64x4d_neon
 
 unsigned int vpx_sad4x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad4x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -541,7 +539,8 @@
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
 
 void vpx_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x4x4d vpx_sad4x4x4d_c
+void vpx_sad4x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad4x4x4d vpx_sad4x4x4d_neon
 
 void vpx_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
@@ -555,10 +554,8 @@
 #define vpx_sad4x8_avg vpx_sad4x8_avg_neon
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x4d vpx_sad4x8x4d_c
-
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
+void vpx_sad4x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad4x8x4d vpx_sad4x8x4d_neon
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -569,7 +566,8 @@
 #define vpx_sad64x32_avg vpx_sad64x32_avg_neon
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x32x4d vpx_sad64x32x4d_c
+void vpx_sad64x32x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad64x32x4d vpx_sad64x32x4d_neon
 
 unsigned int vpx_sad64x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -579,16 +577,10 @@
 unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad64x64_avg vpx_sad64x64_avg_neon
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x4d vpx_sad64x64x4d_neon
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_neon
@@ -601,7 +593,8 @@
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
 
 void vpx_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x16x4d vpx_sad8x16x4d_c
+void vpx_sad8x16x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x16x4d vpx_sad8x16x4d_neon
 
 void vpx_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
@@ -615,10 +608,8 @@
 #define vpx_sad8x4_avg vpx_sad8x4_avg_neon
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x4d vpx_sad8x4x4d_c
-
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
+void vpx_sad8x4x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x4x4d vpx_sad8x4x4d_neon
 
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -632,7 +623,8 @@
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
 
 void vpx_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x8x4d vpx_sad8x8x4d_c
+void vpx_sad8x8x4d_neon(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
+#define vpx_sad8x8x4d vpx_sad8x8x4d_neon
 
 void vpx_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x8 vpx_sad8x8x8_c
diff --git a/third_party/libvpx/source/config/linux/generic/vp9_rtcd.h b/third_party/libvpx/source/config/linux/generic/vp9_rtcd.h
index 0e14191a..a4a5510 100644
--- a/third_party/libvpx/source/config/linux/generic/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/generic/vp9_rtcd.h
@@ -60,9 +60,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_config.asm b/third_party/libvpx/source/config/linux/generic/vpx_config.asm
index 51c18da..a1af6955 100644
--- a/third_party/libvpx/source/config/linux/generic/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/generic/vpx_config.asm
@@ -78,6 +78,7 @@
 .equ CONFIG_BETTER_HW_COMPATIBILITY ,  0
 .equ CONFIG_EXPERIMENTAL ,  0
 .equ CONFIG_SIZE_LIMIT ,  1
+.equ CONFIG_ALWAYS_ADJUST_BPM ,  0
 .equ CONFIG_SPATIAL_SVC ,  0
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_config.h b/third_party/libvpx/source/config/linux/generic/vpx_config.h
index 5517a40..be4ac641 100644
--- a/third_party/libvpx/source/config/linux/generic/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/generic/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
index a09ed559..e8379173f 100644
--- a/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
@@ -928,15 +928,9 @@
 unsigned int vpx_highbd_sad16x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x16_avg vpx_highbd_sad16x16_avg_c
 
-void vpx_highbd_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x3 vpx_highbd_sad16x16x3_c
-
 void vpx_highbd_sad16x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x16x4d vpx_highbd_sad16x16x4d_c
 
-void vpx_highbd_sad16x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x8 vpx_highbd_sad16x16x8_c
-
 unsigned int vpx_highbd_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad16x32 vpx_highbd_sad16x32_c
 
@@ -952,15 +946,9 @@
 unsigned int vpx_highbd_sad16x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x8_avg vpx_highbd_sad16x8_avg_c
 
-void vpx_highbd_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x3 vpx_highbd_sad16x8x3_c
-
 void vpx_highbd_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x8x4d vpx_highbd_sad16x8x4d_c
 
-void vpx_highbd_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x8 vpx_highbd_sad16x8x8_c
-
 unsigned int vpx_highbd_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x16 vpx_highbd_sad32x16_c
 
@@ -976,15 +964,9 @@
 unsigned int vpx_highbd_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad32x32_avg vpx_highbd_sad32x32_avg_c
 
-void vpx_highbd_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x3 vpx_highbd_sad32x32x3_c
-
 void vpx_highbd_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad32x32x4d vpx_highbd_sad32x32x4d_c
 
-void vpx_highbd_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x8 vpx_highbd_sad32x32x8_c
-
 unsigned int vpx_highbd_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x64 vpx_highbd_sad32x64_c
 
@@ -1000,15 +982,9 @@
 unsigned int vpx_highbd_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad4x4_avg vpx_highbd_sad4x4_avg_c
 
-void vpx_highbd_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x3 vpx_highbd_sad4x4x3_c
-
 void vpx_highbd_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x4x4d vpx_highbd_sad4x4x4d_c
 
-void vpx_highbd_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x8 vpx_highbd_sad4x4x8_c
-
 unsigned int vpx_highbd_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad4x8 vpx_highbd_sad4x8_c
 
@@ -1018,9 +994,6 @@
 void vpx_highbd_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x8x4d vpx_highbd_sad4x8x4d_c
 
-void vpx_highbd_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x8x8 vpx_highbd_sad4x8x8_c
-
 unsigned int vpx_highbd_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad64x32 vpx_highbd_sad64x32_c
 
@@ -1036,30 +1009,18 @@
 unsigned int vpx_highbd_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad64x64_avg vpx_highbd_sad64x64_avg_c
 
-void vpx_highbd_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x3 vpx_highbd_sad64x64x3_c
-
 void vpx_highbd_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad64x64x4d vpx_highbd_sad64x64x4d_c
 
-void vpx_highbd_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x8 vpx_highbd_sad64x64x8_c
-
 unsigned int vpx_highbd_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x16 vpx_highbd_sad8x16_c
 
 unsigned int vpx_highbd_sad8x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x16_avg vpx_highbd_sad8x16_avg_c
 
-void vpx_highbd_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x3 vpx_highbd_sad8x16x3_c
-
 void vpx_highbd_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x16x4d vpx_highbd_sad8x16x4d_c
 
-void vpx_highbd_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x8 vpx_highbd_sad8x16x8_c
-
 unsigned int vpx_highbd_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x4 vpx_highbd_sad8x4_c
 
@@ -1069,24 +1030,15 @@
 void vpx_highbd_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x4x4d vpx_highbd_sad8x4x4d_c
 
-void vpx_highbd_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x4x8 vpx_highbd_sad8x4x8_c
-
 unsigned int vpx_highbd_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x8 vpx_highbd_sad8x8_c
 
 unsigned int vpx_highbd_sad8x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x8_avg vpx_highbd_sad8x8_avg_c
 
-void vpx_highbd_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x3 vpx_highbd_sad8x8x3_c
-
 void vpx_highbd_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x8x4d vpx_highbd_sad8x8x4d_c
 
-void vpx_highbd_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x8 vpx_highbd_sad8x8x8_c
-
 void vpx_highbd_subtract_block_c(int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride, int bd);
 #define vpx_highbd_subtract_block vpx_highbd_subtract_block_c
 
@@ -1288,15 +1240,9 @@
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad32x32_avg vpx_sad32x32_avg_c
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x4d vpx_sad32x32x4d_c
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad32x64 vpx_sad32x64_c
 
@@ -1330,9 +1276,6 @@
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad64x32 vpx_sad64x32_c
 
@@ -1348,15 +1291,9 @@
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad64x64_avg vpx_sad64x64_avg_c
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x4d vpx_sad64x64x4d_c
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_c
 
@@ -1381,9 +1318,6 @@
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x8 vpx_sad8x8_c
 
diff --git a/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h
index c178d19..2609a0d 100644
--- a/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h
@@ -71,11 +71,6 @@
 void vp9_filter_by_weight8x8_sse2(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 RTCD_EXTERN void (*vp9_filter_by_weight8x8)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx3(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx8(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-RTCD_EXTERN int (*vp9_full_search_sad)(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vp9_fwht4x4_sse2(const int16_t *input, tran_low_t *output, int stride);
 RTCD_EXTERN void (*vp9_fwht4x4)(const int16_t *input, tran_low_t *output, int stride);
@@ -181,9 +176,6 @@
     if (flags & HAS_SSE2) vp9_filter_by_weight16x16 = vp9_filter_by_weight16x16_sse2;
     vp9_filter_by_weight8x8 = vp9_filter_by_weight8x8_c;
     if (flags & HAS_SSE2) vp9_filter_by_weight8x8 = vp9_filter_by_weight8x8_sse2;
-    vp9_full_search_sad = vp9_full_search_sad_c;
-    if (flags & HAS_SSE3) vp9_full_search_sad = vp9_full_search_sadx3;
-    if (flags & HAS_SSE4_1) vp9_full_search_sad = vp9_full_search_sadx8;
     vp9_fwht4x4 = vp9_fwht4x4_c;
     if (flags & HAS_SSE2) vp9_fwht4x4 = vp9_fwht4x4_sse2;
     vp9_highbd_block_error = vp9_highbd_block_error_c;
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_config.asm b/third_party/libvpx/source/config/linux/ia32/vpx_config.asm
index e1a65cd..f4375a0f 100644
--- a/third_party/libvpx/source/config/linux/ia32/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/ia32/vpx_config.asm
@@ -75,6 +75,7 @@
 %define CONFIG_BETTER_HW_COMPATIBILITY 0
 %define CONFIG_EXPERIMENTAL 0
 %define CONFIG_SIZE_LIMIT 1
+%define CONFIG_ALWAYS_ADJUST_BPM 0
 %define CONFIG_SPATIAL_SVC 0
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_config.h b/third_party/libvpx/source/config/linux/ia32/vpx_config.h
index ef070b20..65d869f 100644
--- a/third_party/libvpx/source/config/linux/ia32/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/ia32/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
index 71cbee6..de7b9a4 100644
--- a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
@@ -1149,16 +1149,10 @@
 unsigned int vpx_highbd_sad16x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad16x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x3 vpx_highbd_sad16x16x3_c
-
 void vpx_highbd_sad16x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad16x16x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad16x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x8 vpx_highbd_sad16x16x8_c
-
 unsigned int vpx_highbd_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad16x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad16x32)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1179,16 +1173,10 @@
 unsigned int vpx_highbd_sad16x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad16x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x3 vpx_highbd_sad16x8x3_c
-
 void vpx_highbd_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad16x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x8 vpx_highbd_sad16x8x8_c
-
 unsigned int vpx_highbd_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad32x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1209,16 +1197,10 @@
 unsigned int vpx_highbd_sad32x32_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x3 vpx_highbd_sad32x32x3_c
-
 void vpx_highbd_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x8 vpx_highbd_sad32x32x8_c
-
 unsigned int vpx_highbd_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad32x64)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1237,16 +1219,10 @@
 unsigned int vpx_highbd_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad4x4_avg vpx_highbd_sad4x4_avg_c
 
-void vpx_highbd_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x3 vpx_highbd_sad4x4x3_c
-
 void vpx_highbd_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad4x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad4x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x8 vpx_highbd_sad4x4x8_c
-
 unsigned int vpx_highbd_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad4x8 vpx_highbd_sad4x8_c
 
@@ -1257,9 +1233,6 @@
 void vpx_highbd_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad4x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x8x8 vpx_highbd_sad4x8x8_c
-
 unsigned int vpx_highbd_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad64x32)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1280,16 +1253,10 @@
 unsigned int vpx_highbd_sad64x64_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x3 vpx_highbd_sad64x64x3_c
-
 void vpx_highbd_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x8 vpx_highbd_sad64x64x8_c
-
 unsigned int vpx_highbd_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1298,16 +1265,10 @@
 unsigned int vpx_highbd_sad8x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x3 vpx_highbd_sad8x16x3_c
-
 void vpx_highbd_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad8x16x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x8 vpx_highbd_sad8x16x8_c
-
 unsigned int vpx_highbd_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x4_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x4)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1320,9 +1281,6 @@
 void vpx_highbd_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad8x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x4x8 vpx_highbd_sad8x4x8_c
-
 unsigned int vpx_highbd_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x8)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1331,16 +1289,10 @@
 unsigned int vpx_highbd_sad8x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x3 vpx_highbd_sad8x8x3_c
-
 void vpx_highbd_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad8x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x8 vpx_highbd_sad8x8x8_c
-
 void vpx_highbd_subtract_block_c(int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride, int bd);
 #define vpx_highbd_subtract_block vpx_highbd_subtract_block_c
 
@@ -1618,17 +1570,11 @@
 unsigned int vpx_sad32x32_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1675,9 +1621,6 @@
 void vpx_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad4x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1702,17 +1645,11 @@
 unsigned int vpx_sad64x64_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_sad8x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1745,9 +1682,6 @@
 void vpx_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad8x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_sad8x8)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
diff --git a/third_party/libvpx/source/config/linux/mips64el/vp9_rtcd.h b/third_party/libvpx/source/config/linux/mips64el/vp9_rtcd.h
index c7f905e..9937e41 100644
--- a/third_party/libvpx/source/config/linux/mips64el/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/mips64el/vp9_rtcd.h
@@ -60,9 +60,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/linux/mips64el/vpx_config.h b/third_party/libvpx/source/config/linux/mips64el/vpx_config.h
index 90df213..6d0fb9c8 100644
--- a/third_party/libvpx/source/config/linux/mips64el/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/mips64el/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h
index 76a1dfb7..ad1d5d25 100644
--- a/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h
@@ -412,15 +412,9 @@
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad32x32_avg vpx_sad32x32_avg_c
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x4d vpx_sad32x32x4d_c
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad32x64 vpx_sad32x64_c
 
@@ -454,9 +448,6 @@
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad64x32 vpx_sad64x32_c
 
@@ -472,15 +463,9 @@
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad64x64_avg vpx_sad64x64_avg_c
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x4d vpx_sad64x64x4d_c
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_c
 
@@ -505,9 +490,6 @@
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x8 vpx_sad8x8_c
 
diff --git a/third_party/libvpx/source/config/linux/mipsel/vp9_rtcd.h b/third_party/libvpx/source/config/linux/mipsel/vp9_rtcd.h
index c7f905e..9937e41 100644
--- a/third_party/libvpx/source/config/linux/mipsel/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/mipsel/vp9_rtcd.h
@@ -60,9 +60,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/linux/mipsel/vpx_config.h b/third_party/libvpx/source/config/linux/mipsel/vpx_config.h
index 765664b9..1054bcd9 100644
--- a/third_party/libvpx/source/config/linux/mipsel/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/mipsel/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h
index 76a1dfb7..ad1d5d25 100644
--- a/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h
@@ -412,15 +412,9 @@
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad32x32_avg vpx_sad32x32_avg_c
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x4d vpx_sad32x32x4d_c
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad32x64 vpx_sad32x64_c
 
@@ -454,9 +448,6 @@
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad64x32 vpx_sad64x32_c
 
@@ -472,15 +463,9 @@
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad64x64_avg vpx_sad64x64_avg_c
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x4d vpx_sad64x64x4d_c
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_c
 
@@ -505,9 +490,6 @@
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x8 vpx_sad8x8_c
 
diff --git a/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h b/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h
index 56d5840..415d6be 100644
--- a/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h
@@ -71,11 +71,6 @@
 void vp9_filter_by_weight8x8_sse2(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_sse2
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx3(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx8(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-RTCD_EXTERN int (*vp9_full_search_sad)(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vp9_fwht4x4_sse2(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_sse2
@@ -168,9 +163,6 @@
     if (flags & HAS_AVX) vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
     vp9_fdct8x8_quant = vp9_fdct8x8_quant_c;
     if (flags & HAS_SSSE3) vp9_fdct8x8_quant = vp9_fdct8x8_quant_ssse3;
-    vp9_full_search_sad = vp9_full_search_sad_c;
-    if (flags & HAS_SSE3) vp9_full_search_sad = vp9_full_search_sadx3;
-    if (flags & HAS_SSE4_1) vp9_full_search_sad = vp9_full_search_sadx8;
     vp9_quantize_fp = vp9_quantize_fp_sse2;
     if (flags & HAS_SSSE3) vp9_quantize_fp = vp9_quantize_fp_ssse3;
     vp9_quantize_fp_32x32 = vp9_quantize_fp_32x32_c;
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_config.asm b/third_party/libvpx/source/config/linux/x64/vpx_config.asm
index 78bc5cd..d780d20 100644
--- a/third_party/libvpx/source/config/linux/x64/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/x64/vpx_config.asm
@@ -75,6 +75,7 @@
 %define CONFIG_BETTER_HW_COMPATIBILITY 0
 %define CONFIG_EXPERIMENTAL 0
 %define CONFIG_SIZE_LIMIT 1
+%define CONFIG_ALWAYS_ADJUST_BPM 0
 %define CONFIG_SPATIAL_SVC 0
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_config.h b/third_party/libvpx/source/config/linux/x64/vpx_config.h
index a30e3e53..f946228 100644
--- a/third_party/libvpx/source/config/linux/x64/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/x64/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
index 5c8ad21..5c944f5 100644
--- a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
@@ -1156,16 +1156,10 @@
 unsigned int vpx_highbd_sad16x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x16_avg vpx_highbd_sad16x16_avg_sse2
 
-void vpx_highbd_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x3 vpx_highbd_sad16x16x3_c
-
 void vpx_highbd_sad16x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x16x4d vpx_highbd_sad16x16x4d_sse2
 
-void vpx_highbd_sad16x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x8 vpx_highbd_sad16x16x8_c
-
 unsigned int vpx_highbd_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad16x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad16x32 vpx_highbd_sad16x32_sse2
@@ -1186,16 +1180,10 @@
 unsigned int vpx_highbd_sad16x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x8_avg vpx_highbd_sad16x8_avg_sse2
 
-void vpx_highbd_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x3 vpx_highbd_sad16x8x3_c
-
 void vpx_highbd_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x8x4d vpx_highbd_sad16x8x4d_sse2
 
-void vpx_highbd_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x8 vpx_highbd_sad16x8x8_c
-
 unsigned int vpx_highbd_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x16 vpx_highbd_sad32x16_sse2
@@ -1216,16 +1204,10 @@
 unsigned int vpx_highbd_sad32x32_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad32x32_avg vpx_highbd_sad32x32_avg_sse2
 
-void vpx_highbd_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x3 vpx_highbd_sad32x32x3_c
-
 void vpx_highbd_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad32x32x4d vpx_highbd_sad32x32x4d_sse2
 
-void vpx_highbd_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x8 vpx_highbd_sad32x32x8_c
-
 unsigned int vpx_highbd_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x64 vpx_highbd_sad32x64_sse2
@@ -1244,16 +1226,10 @@
 unsigned int vpx_highbd_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad4x4_avg vpx_highbd_sad4x4_avg_c
 
-void vpx_highbd_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x3 vpx_highbd_sad4x4x3_c
-
 void vpx_highbd_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad4x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x4x4d vpx_highbd_sad4x4x4d_sse2
 
-void vpx_highbd_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x8 vpx_highbd_sad4x4x8_c
-
 unsigned int vpx_highbd_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad4x8 vpx_highbd_sad4x8_c
 
@@ -1264,9 +1240,6 @@
 void vpx_highbd_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x8x4d vpx_highbd_sad4x8x4d_sse2
 
-void vpx_highbd_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x8x8 vpx_highbd_sad4x8x8_c
-
 unsigned int vpx_highbd_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad64x32 vpx_highbd_sad64x32_sse2
@@ -1287,16 +1260,10 @@
 unsigned int vpx_highbd_sad64x64_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad64x64_avg vpx_highbd_sad64x64_avg_sse2
 
-void vpx_highbd_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x3 vpx_highbd_sad64x64x3_c
-
 void vpx_highbd_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad64x64x4d vpx_highbd_sad64x64x4d_sse2
 
-void vpx_highbd_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x8 vpx_highbd_sad64x64x8_c
-
 unsigned int vpx_highbd_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x16 vpx_highbd_sad8x16_sse2
@@ -1305,16 +1272,10 @@
 unsigned int vpx_highbd_sad8x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x16_avg vpx_highbd_sad8x16_avg_sse2
 
-void vpx_highbd_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x3 vpx_highbd_sad8x16x3_c
-
 void vpx_highbd_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x16x4d vpx_highbd_sad8x16x4d_sse2
 
-void vpx_highbd_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x8 vpx_highbd_sad8x16x8_c
-
 unsigned int vpx_highbd_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x4_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x4 vpx_highbd_sad8x4_sse2
@@ -1327,9 +1288,6 @@
 void vpx_highbd_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x4x4d vpx_highbd_sad8x4x4d_sse2
 
-void vpx_highbd_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x4x8 vpx_highbd_sad8x4x8_c
-
 unsigned int vpx_highbd_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x8 vpx_highbd_sad8x8_sse2
@@ -1338,16 +1296,10 @@
 unsigned int vpx_highbd_sad8x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x8_avg vpx_highbd_sad8x8_avg_sse2
 
-void vpx_highbd_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x3 vpx_highbd_sad8x8x3_c
-
 void vpx_highbd_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x8x4d vpx_highbd_sad8x8x4d_sse2
 
-void vpx_highbd_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x8 vpx_highbd_sad8x8x8_c
-
 void vpx_highbd_subtract_block_c(int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride, int bd);
 #define vpx_highbd_subtract_block vpx_highbd_subtract_block_c
 
@@ -1629,17 +1581,11 @@
 unsigned int vpx_sad32x32_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1686,9 +1632,6 @@
 void vpx_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_sse2
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1713,17 +1656,11 @@
 unsigned int vpx_sad64x64_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_sse2
@@ -1756,9 +1693,6 @@
 void vpx_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_sse2
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x8 vpx_sad8x8_sse2
diff --git a/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h
index c178d19..2609a0d 100644
--- a/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h
@@ -71,11 +71,6 @@
 void vp9_filter_by_weight8x8_sse2(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 RTCD_EXTERN void (*vp9_filter_by_weight8x8)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx3(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx8(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-RTCD_EXTERN int (*vp9_full_search_sad)(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vp9_fwht4x4_sse2(const int16_t *input, tran_low_t *output, int stride);
 RTCD_EXTERN void (*vp9_fwht4x4)(const int16_t *input, tran_low_t *output, int stride);
@@ -181,9 +176,6 @@
     if (flags & HAS_SSE2) vp9_filter_by_weight16x16 = vp9_filter_by_weight16x16_sse2;
     vp9_filter_by_weight8x8 = vp9_filter_by_weight8x8_c;
     if (flags & HAS_SSE2) vp9_filter_by_weight8x8 = vp9_filter_by_weight8x8_sse2;
-    vp9_full_search_sad = vp9_full_search_sad_c;
-    if (flags & HAS_SSE3) vp9_full_search_sad = vp9_full_search_sadx3;
-    if (flags & HAS_SSE4_1) vp9_full_search_sad = vp9_full_search_sadx8;
     vp9_fwht4x4 = vp9_fwht4x4_c;
     if (flags & HAS_SSE2) vp9_fwht4x4 = vp9_fwht4x4_sse2;
     vp9_highbd_block_error = vp9_highbd_block_error_c;
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_config.asm b/third_party/libvpx/source/config/mac/ia32/vpx_config.asm
index e1a65cd..f4375a0f 100644
--- a/third_party/libvpx/source/config/mac/ia32/vpx_config.asm
+++ b/third_party/libvpx/source/config/mac/ia32/vpx_config.asm
@@ -75,6 +75,7 @@
 %define CONFIG_BETTER_HW_COMPATIBILITY 0
 %define CONFIG_EXPERIMENTAL 0
 %define CONFIG_SIZE_LIMIT 1
+%define CONFIG_ALWAYS_ADJUST_BPM 0
 %define CONFIG_SPATIAL_SVC 0
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_config.h b/third_party/libvpx/source/config/mac/ia32/vpx_config.h
index ef070b20..65d869f 100644
--- a/third_party/libvpx/source/config/mac/ia32/vpx_config.h
+++ b/third_party/libvpx/source/config/mac/ia32/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
index 71cbee6..de7b9a4 100644
--- a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
@@ -1149,16 +1149,10 @@
 unsigned int vpx_highbd_sad16x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad16x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x3 vpx_highbd_sad16x16x3_c
-
 void vpx_highbd_sad16x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad16x16x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad16x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x8 vpx_highbd_sad16x16x8_c
-
 unsigned int vpx_highbd_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad16x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad16x32)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1179,16 +1173,10 @@
 unsigned int vpx_highbd_sad16x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad16x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x3 vpx_highbd_sad16x8x3_c
-
 void vpx_highbd_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad16x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x8 vpx_highbd_sad16x8x8_c
-
 unsigned int vpx_highbd_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad32x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1209,16 +1197,10 @@
 unsigned int vpx_highbd_sad32x32_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x3 vpx_highbd_sad32x32x3_c
-
 void vpx_highbd_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x8 vpx_highbd_sad32x32x8_c
-
 unsigned int vpx_highbd_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad32x64)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1237,16 +1219,10 @@
 unsigned int vpx_highbd_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad4x4_avg vpx_highbd_sad4x4_avg_c
 
-void vpx_highbd_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x3 vpx_highbd_sad4x4x3_c
-
 void vpx_highbd_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad4x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad4x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x8 vpx_highbd_sad4x4x8_c
-
 unsigned int vpx_highbd_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad4x8 vpx_highbd_sad4x8_c
 
@@ -1257,9 +1233,6 @@
 void vpx_highbd_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad4x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x8x8 vpx_highbd_sad4x8x8_c
-
 unsigned int vpx_highbd_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad64x32)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1280,16 +1253,10 @@
 unsigned int vpx_highbd_sad64x64_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x3 vpx_highbd_sad64x64x3_c
-
 void vpx_highbd_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x8 vpx_highbd_sad64x64x8_c
-
 unsigned int vpx_highbd_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1298,16 +1265,10 @@
 unsigned int vpx_highbd_sad8x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x3 vpx_highbd_sad8x16x3_c
-
 void vpx_highbd_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad8x16x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x8 vpx_highbd_sad8x16x8_c
-
 unsigned int vpx_highbd_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x4_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x4)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1320,9 +1281,6 @@
 void vpx_highbd_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad8x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x4x8 vpx_highbd_sad8x4x8_c
-
 unsigned int vpx_highbd_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x8)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1331,16 +1289,10 @@
 unsigned int vpx_highbd_sad8x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x3 vpx_highbd_sad8x8x3_c
-
 void vpx_highbd_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad8x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x8 vpx_highbd_sad8x8x8_c
-
 void vpx_highbd_subtract_block_c(int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride, int bd);
 #define vpx_highbd_subtract_block vpx_highbd_subtract_block_c
 
@@ -1618,17 +1570,11 @@
 unsigned int vpx_sad32x32_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1675,9 +1621,6 @@
 void vpx_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad4x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1702,17 +1645,11 @@
 unsigned int vpx_sad64x64_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_sad8x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1745,9 +1682,6 @@
 void vpx_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad8x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_sad8x8)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
diff --git a/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h b/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h
index 56d5840..415d6be 100644
--- a/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h
@@ -71,11 +71,6 @@
 void vp9_filter_by_weight8x8_sse2(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_sse2
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx3(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx8(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-RTCD_EXTERN int (*vp9_full_search_sad)(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vp9_fwht4x4_sse2(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_sse2
@@ -168,9 +163,6 @@
     if (flags & HAS_AVX) vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
     vp9_fdct8x8_quant = vp9_fdct8x8_quant_c;
     if (flags & HAS_SSSE3) vp9_fdct8x8_quant = vp9_fdct8x8_quant_ssse3;
-    vp9_full_search_sad = vp9_full_search_sad_c;
-    if (flags & HAS_SSE3) vp9_full_search_sad = vp9_full_search_sadx3;
-    if (flags & HAS_SSE4_1) vp9_full_search_sad = vp9_full_search_sadx8;
     vp9_quantize_fp = vp9_quantize_fp_sse2;
     if (flags & HAS_SSSE3) vp9_quantize_fp = vp9_quantize_fp_ssse3;
     vp9_quantize_fp_32x32 = vp9_quantize_fp_32x32_c;
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_config.asm b/third_party/libvpx/source/config/mac/x64/vpx_config.asm
index 78bc5cd..d780d20 100644
--- a/third_party/libvpx/source/config/mac/x64/vpx_config.asm
+++ b/third_party/libvpx/source/config/mac/x64/vpx_config.asm
@@ -75,6 +75,7 @@
 %define CONFIG_BETTER_HW_COMPATIBILITY 0
 %define CONFIG_EXPERIMENTAL 0
 %define CONFIG_SIZE_LIMIT 1
+%define CONFIG_ALWAYS_ADJUST_BPM 0
 %define CONFIG_SPATIAL_SVC 0
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_config.h b/third_party/libvpx/source/config/mac/x64/vpx_config.h
index a30e3e53..f946228 100644
--- a/third_party/libvpx/source/config/mac/x64/vpx_config.h
+++ b/third_party/libvpx/source/config/mac/x64/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
index 5c8ad21..5c944f5 100644
--- a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
@@ -1156,16 +1156,10 @@
 unsigned int vpx_highbd_sad16x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x16_avg vpx_highbd_sad16x16_avg_sse2
 
-void vpx_highbd_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x3 vpx_highbd_sad16x16x3_c
-
 void vpx_highbd_sad16x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x16x4d vpx_highbd_sad16x16x4d_sse2
 
-void vpx_highbd_sad16x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x8 vpx_highbd_sad16x16x8_c
-
 unsigned int vpx_highbd_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad16x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad16x32 vpx_highbd_sad16x32_sse2
@@ -1186,16 +1180,10 @@
 unsigned int vpx_highbd_sad16x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x8_avg vpx_highbd_sad16x8_avg_sse2
 
-void vpx_highbd_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x3 vpx_highbd_sad16x8x3_c
-
 void vpx_highbd_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x8x4d vpx_highbd_sad16x8x4d_sse2
 
-void vpx_highbd_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x8 vpx_highbd_sad16x8x8_c
-
 unsigned int vpx_highbd_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x16 vpx_highbd_sad32x16_sse2
@@ -1216,16 +1204,10 @@
 unsigned int vpx_highbd_sad32x32_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad32x32_avg vpx_highbd_sad32x32_avg_sse2
 
-void vpx_highbd_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x3 vpx_highbd_sad32x32x3_c
-
 void vpx_highbd_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad32x32x4d vpx_highbd_sad32x32x4d_sse2
 
-void vpx_highbd_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x8 vpx_highbd_sad32x32x8_c
-
 unsigned int vpx_highbd_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x64 vpx_highbd_sad32x64_sse2
@@ -1244,16 +1226,10 @@
 unsigned int vpx_highbd_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad4x4_avg vpx_highbd_sad4x4_avg_c
 
-void vpx_highbd_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x3 vpx_highbd_sad4x4x3_c
-
 void vpx_highbd_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad4x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x4x4d vpx_highbd_sad4x4x4d_sse2
 
-void vpx_highbd_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x8 vpx_highbd_sad4x4x8_c
-
 unsigned int vpx_highbd_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad4x8 vpx_highbd_sad4x8_c
 
@@ -1264,9 +1240,6 @@
 void vpx_highbd_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x8x4d vpx_highbd_sad4x8x4d_sse2
 
-void vpx_highbd_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x8x8 vpx_highbd_sad4x8x8_c
-
 unsigned int vpx_highbd_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad64x32 vpx_highbd_sad64x32_sse2
@@ -1287,16 +1260,10 @@
 unsigned int vpx_highbd_sad64x64_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad64x64_avg vpx_highbd_sad64x64_avg_sse2
 
-void vpx_highbd_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x3 vpx_highbd_sad64x64x3_c
-
 void vpx_highbd_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad64x64x4d vpx_highbd_sad64x64x4d_sse2
 
-void vpx_highbd_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x8 vpx_highbd_sad64x64x8_c
-
 unsigned int vpx_highbd_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x16 vpx_highbd_sad8x16_sse2
@@ -1305,16 +1272,10 @@
 unsigned int vpx_highbd_sad8x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x16_avg vpx_highbd_sad8x16_avg_sse2
 
-void vpx_highbd_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x3 vpx_highbd_sad8x16x3_c
-
 void vpx_highbd_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x16x4d vpx_highbd_sad8x16x4d_sse2
 
-void vpx_highbd_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x8 vpx_highbd_sad8x16x8_c
-
 unsigned int vpx_highbd_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x4_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x4 vpx_highbd_sad8x4_sse2
@@ -1327,9 +1288,6 @@
 void vpx_highbd_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x4x4d vpx_highbd_sad8x4x4d_sse2
 
-void vpx_highbd_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x4x8 vpx_highbd_sad8x4x8_c
-
 unsigned int vpx_highbd_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x8 vpx_highbd_sad8x8_sse2
@@ -1338,16 +1296,10 @@
 unsigned int vpx_highbd_sad8x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x8_avg vpx_highbd_sad8x8_avg_sse2
 
-void vpx_highbd_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x3 vpx_highbd_sad8x8x3_c
-
 void vpx_highbd_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x8x4d vpx_highbd_sad8x8x4d_sse2
 
-void vpx_highbd_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x8 vpx_highbd_sad8x8x8_c
-
 void vpx_highbd_subtract_block_c(int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride, int bd);
 #define vpx_highbd_subtract_block vpx_highbd_subtract_block_c
 
@@ -1629,17 +1581,11 @@
 unsigned int vpx_sad32x32_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1686,9 +1632,6 @@
 void vpx_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_sse2
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1713,17 +1656,11 @@
 unsigned int vpx_sad64x64_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_sse2
@@ -1756,9 +1693,6 @@
 void vpx_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_sse2
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x8 vpx_sad8x8_sse2
diff --git a/third_party/libvpx/source/config/nacl/vp9_rtcd.h b/third_party/libvpx/source/config/nacl/vp9_rtcd.h
index 0e14191a..a4a5510 100644
--- a/third_party/libvpx/source/config/nacl/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/nacl/vp9_rtcd.h
@@ -60,9 +60,6 @@
 void vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_c
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-#define vp9_full_search_sad vp9_full_search_sad_c
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_c
 
diff --git a/third_party/libvpx/source/config/nacl/vpx_config.h b/third_party/libvpx/source/config/nacl/vpx_config.h
index 5517a40..be4ac641 100644
--- a/third_party/libvpx/source/config/nacl/vpx_config.h
+++ b/third_party/libvpx/source/config/nacl/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
index a09ed559..e8379173f 100644
--- a/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
@@ -928,15 +928,9 @@
 unsigned int vpx_highbd_sad16x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x16_avg vpx_highbd_sad16x16_avg_c
 
-void vpx_highbd_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x3 vpx_highbd_sad16x16x3_c
-
 void vpx_highbd_sad16x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x16x4d vpx_highbd_sad16x16x4d_c
 
-void vpx_highbd_sad16x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x8 vpx_highbd_sad16x16x8_c
-
 unsigned int vpx_highbd_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad16x32 vpx_highbd_sad16x32_c
 
@@ -952,15 +946,9 @@
 unsigned int vpx_highbd_sad16x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x8_avg vpx_highbd_sad16x8_avg_c
 
-void vpx_highbd_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x3 vpx_highbd_sad16x8x3_c
-
 void vpx_highbd_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x8x4d vpx_highbd_sad16x8x4d_c
 
-void vpx_highbd_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x8 vpx_highbd_sad16x8x8_c
-
 unsigned int vpx_highbd_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x16 vpx_highbd_sad32x16_c
 
@@ -976,15 +964,9 @@
 unsigned int vpx_highbd_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad32x32_avg vpx_highbd_sad32x32_avg_c
 
-void vpx_highbd_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x3 vpx_highbd_sad32x32x3_c
-
 void vpx_highbd_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad32x32x4d vpx_highbd_sad32x32x4d_c
 
-void vpx_highbd_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x8 vpx_highbd_sad32x32x8_c
-
 unsigned int vpx_highbd_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x64 vpx_highbd_sad32x64_c
 
@@ -1000,15 +982,9 @@
 unsigned int vpx_highbd_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad4x4_avg vpx_highbd_sad4x4_avg_c
 
-void vpx_highbd_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x3 vpx_highbd_sad4x4x3_c
-
 void vpx_highbd_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x4x4d vpx_highbd_sad4x4x4d_c
 
-void vpx_highbd_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x8 vpx_highbd_sad4x4x8_c
-
 unsigned int vpx_highbd_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad4x8 vpx_highbd_sad4x8_c
 
@@ -1018,9 +994,6 @@
 void vpx_highbd_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x8x4d vpx_highbd_sad4x8x4d_c
 
-void vpx_highbd_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x8x8 vpx_highbd_sad4x8x8_c
-
 unsigned int vpx_highbd_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad64x32 vpx_highbd_sad64x32_c
 
@@ -1036,30 +1009,18 @@
 unsigned int vpx_highbd_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad64x64_avg vpx_highbd_sad64x64_avg_c
 
-void vpx_highbd_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x3 vpx_highbd_sad64x64x3_c
-
 void vpx_highbd_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad64x64x4d vpx_highbd_sad64x64x4d_c
 
-void vpx_highbd_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x8 vpx_highbd_sad64x64x8_c
-
 unsigned int vpx_highbd_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x16 vpx_highbd_sad8x16_c
 
 unsigned int vpx_highbd_sad8x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x16_avg vpx_highbd_sad8x16_avg_c
 
-void vpx_highbd_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x3 vpx_highbd_sad8x16x3_c
-
 void vpx_highbd_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x16x4d vpx_highbd_sad8x16x4d_c
 
-void vpx_highbd_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x8 vpx_highbd_sad8x16x8_c
-
 unsigned int vpx_highbd_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x4 vpx_highbd_sad8x4_c
 
@@ -1069,24 +1030,15 @@
 void vpx_highbd_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x4x4d vpx_highbd_sad8x4x4d_c
 
-void vpx_highbd_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x4x8 vpx_highbd_sad8x4x8_c
-
 unsigned int vpx_highbd_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x8 vpx_highbd_sad8x8_c
 
 unsigned int vpx_highbd_sad8x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x8_avg vpx_highbd_sad8x8_avg_c
 
-void vpx_highbd_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x3 vpx_highbd_sad8x8x3_c
-
 void vpx_highbd_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x8x4d vpx_highbd_sad8x8x4d_c
 
-void vpx_highbd_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x8 vpx_highbd_sad8x8x8_c
-
 void vpx_highbd_subtract_block_c(int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride, int bd);
 #define vpx_highbd_subtract_block vpx_highbd_subtract_block_c
 
@@ -1288,15 +1240,9 @@
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad32x32_avg vpx_sad32x32_avg_c
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x4d vpx_sad32x32x4d_c
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad32x64 vpx_sad32x64_c
 
@@ -1330,9 +1276,6 @@
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad64x32 vpx_sad64x32_c
 
@@ -1348,15 +1291,9 @@
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_sad64x64_avg vpx_sad64x64_avg_c
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x4d vpx_sad64x64x4d_c
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_c
 
@@ -1381,9 +1318,6 @@
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x8 vpx_sad8x8_c
 
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 81ea8fb8..ea225a1 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -1,7 +1,7 @@
 #define VERSION_MAJOR  1
 #define VERSION_MINOR  6
 #define VERSION_PATCH  1
-#define VERSION_EXTRA  "923-g4e16f7070"
+#define VERSION_EXTRA  "946-gb578d5962"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.6.1-923-g4e16f7070"
-#define VERSION_STRING      " v1.6.1-923-g4e16f7070"
+#define VERSION_STRING_NOSP "v1.6.1-946-gb578d5962"
+#define VERSION_STRING      " v1.6.1-946-gb578d5962"
diff --git a/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h b/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h
index c178d19..2609a0d 100644
--- a/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h
@@ -71,11 +71,6 @@
 void vp9_filter_by_weight8x8_sse2(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 RTCD_EXTERN void (*vp9_filter_by_weight8x8)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx3(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx8(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-RTCD_EXTERN int (*vp9_full_search_sad)(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vp9_fwht4x4_sse2(const int16_t *input, tran_low_t *output, int stride);
 RTCD_EXTERN void (*vp9_fwht4x4)(const int16_t *input, tran_low_t *output, int stride);
@@ -181,9 +176,6 @@
     if (flags & HAS_SSE2) vp9_filter_by_weight16x16 = vp9_filter_by_weight16x16_sse2;
     vp9_filter_by_weight8x8 = vp9_filter_by_weight8x8_c;
     if (flags & HAS_SSE2) vp9_filter_by_weight8x8 = vp9_filter_by_weight8x8_sse2;
-    vp9_full_search_sad = vp9_full_search_sad_c;
-    if (flags & HAS_SSE3) vp9_full_search_sad = vp9_full_search_sadx3;
-    if (flags & HAS_SSE4_1) vp9_full_search_sad = vp9_full_search_sadx8;
     vp9_fwht4x4 = vp9_fwht4x4_c;
     if (flags & HAS_SSE2) vp9_fwht4x4 = vp9_fwht4x4_sse2;
     vp9_highbd_block_error = vp9_highbd_block_error_c;
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_config.asm b/third_party/libvpx/source/config/win/ia32/vpx_config.asm
index 78c75c4..f917264f 100644
--- a/third_party/libvpx/source/config/win/ia32/vpx_config.asm
+++ b/third_party/libvpx/source/config/win/ia32/vpx_config.asm
@@ -75,6 +75,7 @@
 %define CONFIG_BETTER_HW_COMPATIBILITY 0
 %define CONFIG_EXPERIMENTAL 0
 %define CONFIG_SIZE_LIMIT 1
+%define CONFIG_ALWAYS_ADJUST_BPM 0
 %define CONFIG_SPATIAL_SVC 0
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_config.h b/third_party/libvpx/source/config/win/ia32/vpx_config.h
index d374b64..a2476d0 100644
--- a/third_party/libvpx/source/config/win/ia32/vpx_config.h
+++ b/third_party/libvpx/source/config/win/ia32/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
index 71cbee6..de7b9a4 100644
--- a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
@@ -1149,16 +1149,10 @@
 unsigned int vpx_highbd_sad16x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad16x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x3 vpx_highbd_sad16x16x3_c
-
 void vpx_highbd_sad16x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad16x16x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad16x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x8 vpx_highbd_sad16x16x8_c
-
 unsigned int vpx_highbd_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad16x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad16x32)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1179,16 +1173,10 @@
 unsigned int vpx_highbd_sad16x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad16x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x3 vpx_highbd_sad16x8x3_c
-
 void vpx_highbd_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad16x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x8 vpx_highbd_sad16x8x8_c
-
 unsigned int vpx_highbd_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad32x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1209,16 +1197,10 @@
 unsigned int vpx_highbd_sad32x32_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x3 vpx_highbd_sad32x32x3_c
-
 void vpx_highbd_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x8 vpx_highbd_sad32x32x8_c
-
 unsigned int vpx_highbd_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad32x64)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1237,16 +1219,10 @@
 unsigned int vpx_highbd_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad4x4_avg vpx_highbd_sad4x4_avg_c
 
-void vpx_highbd_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x3 vpx_highbd_sad4x4x3_c
-
 void vpx_highbd_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad4x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad4x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x8 vpx_highbd_sad4x4x8_c
-
 unsigned int vpx_highbd_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad4x8 vpx_highbd_sad4x8_c
 
@@ -1257,9 +1233,6 @@
 void vpx_highbd_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad4x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x8x8 vpx_highbd_sad4x8x8_c
-
 unsigned int vpx_highbd_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad64x32)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1280,16 +1253,10 @@
 unsigned int vpx_highbd_sad64x64_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x3 vpx_highbd_sad64x64x3_c
-
 void vpx_highbd_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x8 vpx_highbd_sad64x64x8_c
-
 unsigned int vpx_highbd_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1298,16 +1265,10 @@
 unsigned int vpx_highbd_sad8x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x3 vpx_highbd_sad8x16x3_c
-
 void vpx_highbd_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad8x16x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x8 vpx_highbd_sad8x16x8_c
-
 unsigned int vpx_highbd_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x4_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x4)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1320,9 +1281,6 @@
 void vpx_highbd_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad8x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x4x8 vpx_highbd_sad8x4x8_c
-
 unsigned int vpx_highbd_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x8)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1331,16 +1289,10 @@
 unsigned int vpx_highbd_sad8x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_highbd_sad8x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_highbd_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x3 vpx_highbd_sad8x8x3_c
-
 void vpx_highbd_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_highbd_sad8x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_highbd_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x8 vpx_highbd_sad8x8x8_c
-
 void vpx_highbd_subtract_block_c(int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride, int bd);
 #define vpx_highbd_subtract_block vpx_highbd_subtract_block_c
 
@@ -1618,17 +1570,11 @@
 unsigned int vpx_sad32x32_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1675,9 +1621,6 @@
 void vpx_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad4x8x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1702,17 +1645,11 @@
 unsigned int vpx_sad64x64_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_sad8x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1745,9 +1682,6 @@
 void vpx_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad8x4x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 RTCD_EXTERN unsigned int (*vpx_sad8x8)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
diff --git a/third_party/libvpx/source/config/win/x64/vp9_rtcd.h b/third_party/libvpx/source/config/win/x64/vp9_rtcd.h
index 56d5840..415d6be 100644
--- a/third_party/libvpx/source/config/win/x64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/win/x64/vp9_rtcd.h
@@ -71,11 +71,6 @@
 void vp9_filter_by_weight8x8_sse2(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int src_weight);
 #define vp9_filter_by_weight8x8 vp9_filter_by_weight8x8_sse2
 
-int vp9_full_search_sad_c(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx3(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-int vp9_full_search_sadx8(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-RTCD_EXTERN int (*vp9_full_search_sad)(const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv);
-
 void vp9_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vp9_fwht4x4_sse2(const int16_t *input, tran_low_t *output, int stride);
 #define vp9_fwht4x4 vp9_fwht4x4_sse2
@@ -168,9 +163,6 @@
     if (flags & HAS_AVX) vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
     vp9_fdct8x8_quant = vp9_fdct8x8_quant_c;
     if (flags & HAS_SSSE3) vp9_fdct8x8_quant = vp9_fdct8x8_quant_ssse3;
-    vp9_full_search_sad = vp9_full_search_sad_c;
-    if (flags & HAS_SSE3) vp9_full_search_sad = vp9_full_search_sadx3;
-    if (flags & HAS_SSE4_1) vp9_full_search_sad = vp9_full_search_sadx8;
     vp9_quantize_fp = vp9_quantize_fp_sse2;
     if (flags & HAS_SSSE3) vp9_quantize_fp = vp9_quantize_fp_ssse3;
     vp9_quantize_fp_32x32 = vp9_quantize_fp_32x32_c;
diff --git a/third_party/libvpx/source/config/win/x64/vpx_config.asm b/third_party/libvpx/source/config/win/x64/vpx_config.asm
index 943d9fbdc..0cbec22 100644
--- a/third_party/libvpx/source/config/win/x64/vpx_config.asm
+++ b/third_party/libvpx/source/config/win/x64/vpx_config.asm
@@ -75,6 +75,7 @@
 %define CONFIG_BETTER_HW_COMPATIBILITY 0
 %define CONFIG_EXPERIMENTAL 0
 %define CONFIG_SIZE_LIMIT 1
+%define CONFIG_ALWAYS_ADJUST_BPM 0
 %define CONFIG_SPATIAL_SVC 0
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/win/x64/vpx_config.h b/third_party/libvpx/source/config/win/x64/vpx_config.h
index 31b75328..490454d 100644
--- a/third_party/libvpx/source/config/win/x64/vpx_config.h
+++ b/third_party/libvpx/source/config/win/x64/vpx_config.h
@@ -87,6 +87,7 @@
 #define CONFIG_BETTER_HW_COMPATIBILITY 0
 #define CONFIG_EXPERIMENTAL 0
 #define CONFIG_SIZE_LIMIT 1
+#define CONFIG_ALWAYS_ADJUST_BPM 0
 #define CONFIG_SPATIAL_SVC 0
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
diff --git a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
index 5c8ad21..5c944f5 100644
--- a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
@@ -1156,16 +1156,10 @@
 unsigned int vpx_highbd_sad16x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x16_avg vpx_highbd_sad16x16_avg_sse2
 
-void vpx_highbd_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x3 vpx_highbd_sad16x16x3_c
-
 void vpx_highbd_sad16x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x16x4d vpx_highbd_sad16x16x4d_sse2
 
-void vpx_highbd_sad16x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x16x8 vpx_highbd_sad16x16x8_c
-
 unsigned int vpx_highbd_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad16x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad16x32 vpx_highbd_sad16x32_sse2
@@ -1186,16 +1180,10 @@
 unsigned int vpx_highbd_sad16x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad16x8_avg vpx_highbd_sad16x8_avg_sse2
 
-void vpx_highbd_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x3 vpx_highbd_sad16x8x3_c
-
 void vpx_highbd_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad16x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad16x8x4d vpx_highbd_sad16x8x4d_sse2
 
-void vpx_highbd_sad16x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad16x8x8 vpx_highbd_sad16x8x8_c
-
 unsigned int vpx_highbd_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x16 vpx_highbd_sad32x16_sse2
@@ -1216,16 +1204,10 @@
 unsigned int vpx_highbd_sad32x32_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad32x32_avg vpx_highbd_sad32x32_avg_sse2
 
-void vpx_highbd_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x3 vpx_highbd_sad32x32x3_c
-
 void vpx_highbd_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad32x32x4d vpx_highbd_sad32x32x4d_sse2
 
-void vpx_highbd_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad32x32x8 vpx_highbd_sad32x32x8_c
-
 unsigned int vpx_highbd_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad32x64 vpx_highbd_sad32x64_sse2
@@ -1244,16 +1226,10 @@
 unsigned int vpx_highbd_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad4x4_avg vpx_highbd_sad4x4_avg_c
 
-void vpx_highbd_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x3 vpx_highbd_sad4x4x3_c
-
 void vpx_highbd_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad4x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x4x4d vpx_highbd_sad4x4x4d_sse2
 
-void vpx_highbd_sad4x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x4x8 vpx_highbd_sad4x4x8_c
-
 unsigned int vpx_highbd_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad4x8 vpx_highbd_sad4x8_c
 
@@ -1264,9 +1240,6 @@
 void vpx_highbd_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad4x8x4d vpx_highbd_sad4x8x4d_sse2
 
-void vpx_highbd_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad4x8x8 vpx_highbd_sad4x8x8_c
-
 unsigned int vpx_highbd_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad64x32 vpx_highbd_sad64x32_sse2
@@ -1287,16 +1260,10 @@
 unsigned int vpx_highbd_sad64x64_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad64x64_avg vpx_highbd_sad64x64_avg_sse2
 
-void vpx_highbd_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x3 vpx_highbd_sad64x64x3_c
-
 void vpx_highbd_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad64x64x4d vpx_highbd_sad64x64x4d_sse2
 
-void vpx_highbd_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad64x64x8 vpx_highbd_sad64x64x8_c
-
 unsigned int vpx_highbd_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x16 vpx_highbd_sad8x16_sse2
@@ -1305,16 +1272,10 @@
 unsigned int vpx_highbd_sad8x16_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x16_avg vpx_highbd_sad8x16_avg_sse2
 
-void vpx_highbd_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x3 vpx_highbd_sad8x16x3_c
-
 void vpx_highbd_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x16x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x16x4d vpx_highbd_sad8x16x4d_sse2
 
-void vpx_highbd_sad8x16x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x16x8 vpx_highbd_sad8x16x8_c
-
 unsigned int vpx_highbd_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x4_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x4 vpx_highbd_sad8x4_sse2
@@ -1327,9 +1288,6 @@
 void vpx_highbd_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x4x4d vpx_highbd_sad8x4x4d_sse2
 
-void vpx_highbd_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x4x8 vpx_highbd_sad8x4x8_c
-
 unsigned int vpx_highbd_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_highbd_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_highbd_sad8x8 vpx_highbd_sad8x8_sse2
@@ -1338,16 +1296,10 @@
 unsigned int vpx_highbd_sad8x8_avg_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 #define vpx_highbd_sad8x8_avg vpx_highbd_sad8x8_avg_sse2
 
-void vpx_highbd_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x3 vpx_highbd_sad8x8x3_c
-
 void vpx_highbd_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_highbd_sad8x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t* const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_highbd_sad8x8x4d vpx_highbd_sad8x8x4d_sse2
 
-void vpx_highbd_sad8x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_highbd_sad8x8x8 vpx_highbd_sad8x8x8_c
-
 void vpx_highbd_subtract_block_c(int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride, int bd);
 #define vpx_highbd_subtract_block vpx_highbd_subtract_block_c
 
@@ -1629,17 +1581,11 @@
 unsigned int vpx_sad32x32_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x3 vpx_sad32x32x3_c
-
 void vpx_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad32x32x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad32x32x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad32x32x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad32x32x8 vpx_sad32x32x8_c
-
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad32x64_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1686,9 +1632,6 @@
 void vpx_sad4x8x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_sse2
 
-void vpx_sad4x8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad4x8x8 vpx_sad4x8x8_c
-
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad64x32_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
@@ -1713,17 +1656,11 @@
 unsigned int vpx_sad64x64_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 RTCD_EXTERN unsigned int (*vpx_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
-void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x3 vpx_sad64x64x3_c
-
 void vpx_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 void vpx_sad64x64x4d_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 RTCD_EXTERN void (*vpx_sad64x64x4d)(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 
-void vpx_sad64x64x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad64x64x8 vpx_sad64x64x8_c
-
 unsigned int vpx_sad8x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x16_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x16 vpx_sad8x16_sse2
@@ -1756,9 +1693,6 @@
 void vpx_sad8x4x4d_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_sse2
 
-void vpx_sad8x4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
-#define vpx_sad8x4x8 vpx_sad8x4x8_c
-
 unsigned int vpx_sad8x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 unsigned int vpx_sad8x8_sse2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 #define vpx_sad8x8 vpx_sad8x8_sse2
diff --git a/third_party/protobuf/README.chromium b/third_party/protobuf/README.chromium
index d5d87ca..83ba438 100644
--- a/third_party/protobuf/README.chromium
+++ b/third_party/protobuf/README.chromium
@@ -86,3 +86,7 @@
   removed in C++11 mode.
 
   Fixed in https://github.com/google/protobuf/pull/1549
+
+- 0012-add-map-include.patch
+
+  Workaround for gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81347
diff --git a/third_party/protobuf/patches/0012-add-map-include.patch b/third_party/protobuf/patches/0012-add-map-include.patch
new file mode 100644
index 0000000..b71ab92
--- /dev/null
+++ b/third_party/protobuf/patches/0012-add-map-include.patch
@@ -0,0 +1,11 @@
+diff -ru protobuf2/src/google/protobuf/descriptor.h protobuf/src/google/protobuf/descriptor.h
+--- protobuf2/src/google/protobuf/descriptor.h	2017-07-06 15:32:27.892104861 -0700
++++ protobuf/src/google/protobuf/descriptor.h	2017-07-06 15:19:07.042709476 -0700
+@@ -54,6 +54,7 @@
+ #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
+ #define GOOGLE_PROTOBUF_DESCRIPTOR_H__
+ 
++#include <map>
+ #include <memory>
+ #ifndef _SHARED_PTR_H
+ #include <google/protobuf/stubs/shared_ptr.h>
diff --git a/third_party/protobuf/src/google/protobuf/descriptor.h b/third_party/protobuf/src/google/protobuf/descriptor.h
index 3ecc0a9..a1ba53d 100644
--- a/third_party/protobuf/src/google/protobuf/descriptor.h
+++ b/third_party/protobuf/src/google/protobuf/descriptor.h
@@ -54,6 +54,7 @@
 #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
 #define GOOGLE_PROTOBUF_DESCRIPTOR_H__
 
+#include <map>
 #include <memory>
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
diff --git a/tools/gn/xcode_writer.cc b/tools/gn/xcode_writer.cc
index fbcc069..a4c97ad 100644
--- a/tools/gn/xcode_writer.cc
+++ b/tools/gn/xcode_writer.cc
@@ -13,6 +13,7 @@
 
 #include "base/environment.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -168,6 +169,46 @@
     xctest_module_to_application_target->insert(std::make_pair(
         xctest_module_target, xctest_application_targets->back()));
   }
+
+  DCHECK_EQ(xctest_module_targets.size(), xctest_application_targets->size());
+  DCHECK_EQ(xctest_module_targets.size(),
+            xctest_module_to_application_target->size());
+}
+
+// Adds |base_pbxtarget| as a dependency of |dependent_pbxtarget| in the
+// generated Xcode project.
+void AddPBXTargetDependency(const PBXTarget* base_pbxtarget,
+                            PBXTarget* dependent_pbxtarget,
+                            const PBXProject* project) {
+  auto container_item_proxy =
+      base::MakeUnique<PBXContainerItemProxy>(project, base_pbxtarget);
+  auto dependency = base::MakeUnique<PBXTargetDependency>(
+      base_pbxtarget, std::move(container_item_proxy));
+
+  dependent_pbxtarget->AddDependency(std::move(dependency));
+}
+
+// Adds the corresponding test rig application target as dependency of xctest
+// module target in the generated Xcode project.
+void AddDependencyTargetForXCModuleTargets(
+    const std::vector<const Target*>& targets,
+    const TargetToPBXTarget& bundle_target_to_pbxtarget,
+    const PBXProject* project) {
+  for (const Target* target : targets) {
+    if (!IsXCTestModuleTarget(target))
+      continue;
+
+    const Target* test_application_target =
+        FindXCTestApplicationTarget(target, targets);
+    const PBXTarget* test_application_pbxtarget =
+        bundle_target_to_pbxtarget.at(test_application_target);
+    PBXTarget* module_pbxtarget = bundle_target_to_pbxtarget.at(target);
+    DCHECK(test_application_pbxtarget);
+    DCHECK(module_pbxtarget);
+
+    AddPBXTargetDependency(test_application_pbxtarget, module_pbxtarget,
+                           project);
+  }
 }
 
 // Searches the list of xctest files recursively under |target|.
@@ -221,6 +262,8 @@
     xctest_files_per_application_target->insert(
         std::make_pair(target, xctest_files_per_target[target]));
   }
+  DCHECK_EQ(application_targets.size(),
+            xctest_files_per_application_target->size());
 }
 
 // Add all source files for indexing, both private and public.
@@ -263,6 +306,27 @@
   }
 }
 
+// Add xctest files to the "Compiler Sources" of corresponding xctest native
+// targets.
+void AddXCTestFilesToXCTestModuleTarget(
+    const Target::FileList& xctest_file_list,
+    PBXNativeTarget* native_target,
+    PBXProject* project,
+    SourceDir source_dir,
+    const BuildSettings* build_settings) {
+  for (const SourceFile& source : xctest_file_list) {
+    std::string source_path = RebasePath(source.value(), source_dir,
+                                         build_settings->root_path_utf8());
+
+    // Test files need to be known to Xcode for proper indexing and for
+    // discovery of tests function for XCTest, but the compilation is done
+    // via ninja and thus must prevent Xcode from compiling the files by
+    // adding '-help' as per file compiler flag.
+    project->AddSourceFile(source_path, source_path, CompilerFlags::HELP,
+                           native_target);
+  }
+}
+
 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor {
  public:
   CollectPBXObjectsPerClassHelper() {}
@@ -464,12 +528,7 @@
   std::unique_ptr<PBXProject> main_project(
       new PBXProject("products", config_name, source_path, attributes));
 
-  SourceDir source_dir("//");
-  AddSourceFilesToProjectForIndexing(all_targets, main_project.get(),
-                                     source_dir, build_settings);
-
-  // Filter xctest module and application targets and find list of xctest files
-  // recursively under them.
+  // Filter xctest module and application targets.
   std::vector<const Target*> xctest_module_targets;
   FilterXCTestModuleTargets(targets, &xctest_module_targets);
 
@@ -480,21 +539,21 @@
   FindXCTestApplicationTargets(xctest_module_targets, targets,
                                &xctest_application_targets,
                                &xctest_module_to_application_target);
-  DCHECK_EQ(xctest_module_targets.size(), xctest_application_targets.size());
-  DCHECK_EQ(xctest_module_targets.size(),
-            xctest_module_to_application_target.size());
 
+  // Find list of xctest files recursively under them, and the files will be
+  // used for proper indexing and for discovery of tests function for XCTest.
   TargetToFileList xctest_files_per_application_target;
   FindXCTestFilesForApplicationTargets(xctest_application_targets,
                                        &xctest_files_per_application_target);
-  DCHECK_EQ(xctest_application_targets.size(),
-            xctest_files_per_application_target.size());
 
+  std::vector<const Target*> bundle_targets;
   TargetToPBXTarget bundle_target_to_pbxtarget;
 
   std::string build_path;
   std::unique_ptr<base::Environment> env(base::Environment::Create());
-
+  SourceDir source_dir("//");
+  AddSourceFilesToProjectForIndexing(all_targets, main_project.get(),
+                                     source_dir, build_settings);
   main_project->AddAggregateTarget(
       "All", GetBuildScript(root_target, ninja_extra_args, env.get()));
 
@@ -544,15 +603,18 @@
           xcode_extra_attributes["DEBUG_INFORMATION_FORMAT"] = "dwarf";
         }
 
-        PBXNativeTarget* native_target = main_project->AddNativeTarget(
-            pbxtarget_name, std::string(),
+        const std::string& target_output_name =
             RebasePath(target->bundle_data()
                            .GetBundleRootDirOutput(target->settings())
                            .value(),
-                       build_settings->build_dir()),
+                       build_settings->build_dir());
+        PBXNativeTarget* native_target = main_project->AddNativeTarget(
+            pbxtarget_name, std::string(), target_output_name,
             target->bundle_data().product_type(),
             GetBuildScript(pbxtarget_name, ninja_extra_args, env.get()),
             xcode_extra_attributes);
+
+        bundle_targets.push_back(target);
         bundle_target_to_pbxtarget.insert(
             std::make_pair(target, native_target));
 
@@ -560,23 +622,14 @@
           continue;
 
         // Add xctest files to the "Compiler Sources" of corresponding xctest
-        // native targets.
+        // native targets for proper indexing and for discovery of tests
+        // function for XCTest.
         const Target::FileList& xctest_file_list =
             xctest_files_per_application_target
                 [xctest_module_to_application_target[target]];
-
-        for (const SourceFile& source : xctest_file_list) {
-          std::string source_path = RebasePath(
-              source.value(), source_dir, build_settings->root_path_utf8());
-
-          // Test files need to be known to Xcode for proper indexing and for
-          // discovery of tests function for XCTest, but the compilation is done
-          // via ninja and thus must prevent Xcode from compiling the files by
-          // adding '-help' as per file compiler flag.
-          main_project->AddSourceFile(source_path, source_path,
-                                      CompilerFlags::HELP, native_target);
-        }
-
+        AddXCTestFilesToXCTestModuleTarget(xctest_file_list, native_target,
+                                           main_project.get(), source_dir,
+                                           build_settings);
         break;
       }
 
@@ -585,30 +638,12 @@
     }
   }
 
-  // Add corresponding application target as dependency of xctest module target
-  // so that application target is re-compiled when compiling xctest module
-  // target.
-  for (const Target* target : targets) {
-    if (target->output_type() != Target::CREATE_BUNDLE)
-      continue;
-    if (!IsXCTestModuleTarget(target))
-      continue;
-
-    const Target* application_target =
-        FindXCTestApplicationTarget(target, targets);
-    PBXTarget* application_pbxtarget =
-        bundle_target_to_pbxtarget[application_target];
-    DCHECK(application_pbxtarget);
-    PBXTarget* xctest_module_pbxtarget = bundle_target_to_pbxtarget[target];
-    DCHECK(xctest_module_pbxtarget);
-
-    std::unique_ptr<PBXContainerItemProxy> container_item_proxy(
-        new PBXContainerItemProxy(main_project.get(), application_pbxtarget));
-    std::unique_ptr<PBXTargetDependency> dependency(new PBXTargetDependency(
-        application_pbxtarget, std::move(container_item_proxy)));
-
-    xctest_module_pbxtarget->AddDependency(std::move(dependency));
-  }
+  // For XCTest, tests are compiled into the application bundle, thus adding
+  // the corresponding test rig application target as a dependency of xctest
+  // module target in the generated Xcode project so that the application target
+  // is re-compiled when compiling the xctest module target.
+  AddDependencyTargetForXCModuleTargets(
+      bundle_targets, bundle_target_to_pbxtarget, main_project.get());
 
   projects_.push_back(std::move(main_project));
 }
diff --git a/tools/idl_parser/idl_lexer.py b/tools/idl_parser/idl_lexer.py
index 6428df8..c983404 100755
--- a/tools/idl_parser/idl_lexer.py
+++ b/tools/idl_parser/idl_lexer.py
@@ -42,6 +42,7 @@
       'string',
 
     # Symbol and keywords types
+      'SPECIAL_COMMENT',
       'identifier',
 
     # MultiChar operators
@@ -142,6 +143,14 @@
     self.AddLines(t.value.count('\n'))
     return t
 
+  # A Javadoc style comment:  /** xxx */
+  # Unlike t_COMMENT, this is NOT ignored.
+  # Also note that this should be defined before t_COMMENT.
+  def t_SPECIAL_COMMENT(self, t):
+    r'/\*\*(.|\n)+?\*/'
+    self.AddLines(t.value.count('\n'))
+    return t
+
   # A C or C++ style comment:  /* xxx */ or //
   # This token is ignored.
   def t_COMMENT(self, t):
diff --git a/tools/idl_parser/idl_node.py b/tools/idl_parser/idl_node.py
index e50fc4e1..4d0af54 100755
--- a/tools/idl_parser/idl_node.py
+++ b/tools/idl_parser/idl_node.py
@@ -157,7 +157,7 @@
             self.out.extend(proplist)
 
     if filter_nodes == None:
-      filter_nodes = ['Comment', 'Copyright']
+      filter_nodes = ['SpecialComment']
 
     search = DumpTreeSearch(accept_props)
     self.Traverse(search, filter_nodes)
diff --git a/tools/idl_parser/idl_parser.py b/tools/idl_parser/idl_parser.py
index 8f2c120..c8e433e 100755
--- a/tools/idl_parser/idl_parser.py
+++ b/tools/idl_parser/idl_parser.py
@@ -53,6 +53,7 @@
   'Unexpected ")" after ",".' : 'Missing argument.',
   'Unexpected "}" after ",".' : 'Trailing comma in block.',
   'Unexpected "}" after "{".' : 'Unexpected empty block.',
+  'Unexpected comment after "}".' : 'Unexpected trailing comment.',
   'Unexpected "{" after keyword "enum".' : 'Enum missing name.',
   'Unexpected "{" after keyword "struct".' : 'Struct missing name.',
   'Unexpected "{" after keyword "interface".' : 'Interface missing name.',
@@ -101,6 +102,8 @@
     return 'value %s' % t.value
   if t.type == 'string' :
     return 'string "%s"' % t.value
+  if t.type == 'SPECIAL_COMMENT':
+    return 'comment'
   if t.type == t.value:
     return '"%s"' % t.value
   if t.type == ',':
@@ -110,6 +113,28 @@
   return 'keyword "%s"' % t.value
 
 
+# TODO(bashi): Consider moving this out of idl_parser.
+def ExtractSpecialComment(comment):
+  if not comment.startswith('/**'):
+    raise ValueError('Special comment must start with /**')
+  if not comment.endswith('*/'):
+    raise ValueError('Special comment must end with */')
+
+  # Remove comment markers
+  lines = []
+  for line in comment[2:-2].split('\n'):
+    # Remove characters until start marker for this line '*' if found
+    # otherwise it will be blank.
+    offs = line.find('*')
+    if offs >= 0:
+      line = line[offs + 1:].rstrip()
+    else:
+      # TODO(bashi): We may want to keep |line| as is.
+      line = ''
+    lines.append(line)
+  return '\n'.join(lines)
+
+
 #
 # IDL Parser
 #
@@ -196,7 +221,7 @@
 class IDLParser(object):
   def p_Definitions(self, p):
     """Definitions : ExtendedAttributeList Definition Definitions
-           | """
+                   | """
     if len(p) > 1:
       p[2].AddChildren(p[1])
       p[0] = ListFromConcat(p[2], p[3])
@@ -689,12 +714,21 @@
     """SetlikeRest : SETLIKE '<' Type '>' ';'"""
     p[0] = self.BuildProduction('Setlike', p, 2, p[3])
 
+  # This rule has custom additions (i.e. SpecialComments).
   def p_ExtendedAttributeList(self, p):
-    """ExtendedAttributeList : '[' ExtendedAttribute ExtendedAttributes ']'
+    """ExtendedAttributeList : SpecialComments '[' ExtendedAttribute ExtendedAttributes ']'
+                             | '[' ExtendedAttribute ExtendedAttributes ']'
+                             | SpecialComments
                              | """
-    if len(p) > 3:
+    if len(p) > 5:
+      items = ListFromConcat(p[3], p[4])
+      attribs = self.BuildProduction('ExtAttributes', p, 2, items)
+      p[0] = ListFromConcat(p[1], attribs)
+    elif len(p) > 4:
       items = ListFromConcat(p[2], p[3])
       p[0] = self.BuildProduction('ExtAttributes', p, 1, items)
+    elif len(p) > 1:
+      p[0] = p[1]
 
   # Error recovery for ExtendedAttributeList
   def p_ExtendedAttributeListError(self, p):
@@ -1012,6 +1046,14 @@
     """RecordType : RECORD '<' error ',' Type '>'"""
     p[0] = self.BuildError(p, 'RecordType')
 
+  # Blink extension: Treat special comments (/** ... */) as AST nodes to
+  # annotate other nodes. Currently they are used for testing.
+  def p_SpecialComments(self, p):
+    """SpecialComments : SPECIAL_COMMENT SpecialComments
+                       | """
+    if len(p) > 1:
+      p[0] = ListFromConcat(self.BuildSpecialComment(p, 1), p[2])
+
 #
 # Parser Errors
 #
@@ -1101,6 +1143,11 @@
     childlist.append(self.BuildAttribute('NAME', p[index]))
     return self.BuildProduction(cls, p, index, childlist)
 
+  def BuildSpecialComment(self, p, index):
+    name = ExtractSpecialComment(p[index])
+    childlist = [self.BuildAttribute('NAME', name)]
+    return self.BuildProduction('SpecialComment', p, index, childlist)
+
 #
 # BuildError
 #
diff --git a/tools/idl_parser/idl_parser_test.py b/tools/idl_parser/idl_parser_test.py
index 59a5cf23..e8078eb 100755
--- a/tools/idl_parser/idl_parser_test.py
+++ b/tools/idl_parser/idl_parser_test.py
@@ -21,7 +21,7 @@
     self.filenames = glob.glob('test_parser/*_web.idl')
 
   def _TestNode(self, node):
-    comments = node.GetListOf('Comment')
+    comments = node.GetListOf('SpecialComment')
     for comment in comments:
       check, value = ParseCommentTest(comment.GetName())
       if check == 'BUILD':
@@ -52,7 +52,7 @@
       self.assertTrue(len(children) > 2, 'Expecting children in %s.' %
                       filename)
 
-      for node in filenode.GetChildren()[2:]:
+      for node in filenode.GetChildren():
         self._TestNode(node)
 
 
diff --git a/tools/idl_parser/test_parser/callback_web.idl b/tools/idl_parser/test_parser/callback_web.idl
index b16b6b5..eac5e89 100644
--- a/tools/idl_parser/test_parser/callback_web.idl
+++ b/tools/idl_parser/test_parser/callback_web.idl
@@ -30,7 +30,7 @@
 */
 
 
-/* TREE
+/** TREE
  *Callback(VoidFunc)
  *  Type()
  *    PrimitiveType(void)
@@ -38,7 +38,7 @@
  */
 callback VoidFunc = void();
 
-/* TREE
+/** TREE
  *Callback(VoidFuncLongErr)
  *  Type()
  *    PrimitiveType(void)
@@ -47,7 +47,7 @@
  */
 callback VoidFuncLongErr = void ( long );
 
-/* TREE
+/** TREE
  *Callback(VoidFuncLong)
  *  Type()
  *    PrimitiveType(void)
@@ -58,7 +58,7 @@
  */
 callback VoidFuncLong = void ( long L1 );
 
-/* TREE
+/** TREE
  *Callback(VoidFuncLongArray)
  *  Type()
  *    PrimitiveType(void)
@@ -70,7 +70,7 @@
  */
 callback VoidFuncLongArray = void ( long[] L1 );
 
-/* TREE
+/** TREE
  *Callback(VoidFuncLongArray5)
  *  Type()
  *    PrimitiveType(void)
@@ -83,7 +83,7 @@
 callback VoidFuncLongArray5 = void ( long[5] L1 );
 
 
-/* TREE
+/** TREE
  *Callback(VoidFuncLongArray54)
  *  Type()
  *    PrimitiveType(void)
@@ -100,7 +100,7 @@
 callback VoidFuncLongArray54 = void ( long[5] L1, long long [4] L2 );
 
 
-/* TREE
+/** TREE
  *Callback(VoidFuncLongIdent)
  *  Type()
  *    PrimitiveType(void)
diff --git a/tools/idl_parser/test_parser/dictionary_web.idl b/tools/idl_parser/test_parser/dictionary_web.idl
index 8351246..7e31ccda 100644
--- a/tools/idl_parser/test_parser/dictionary_web.idl
+++ b/tools/idl_parser/test_parser/dictionary_web.idl
@@ -30,26 +30,26 @@
 */
 
 
-/* TREE
+/** TREE
  *Dictionary(MyDict)
  */
 dictionary MyDict { };
 
-/* TREE
+/** TREE
  *Dictionary(MyDictInherit)
  *  Inherit(Foo)
  */
 dictionary MyDictInherit : Foo {};
 
-/* TREE
+/** TREE
  *Dictionary(MyDictPartial)
  */
 partial dictionary MyDictPartial { };
 
-/* ERROR Unexpected ":" after identifier "MyDictInherit". */
+/** ERROR Unexpected ":" after identifier "MyDictInherit". */
 partial dictionary MyDictInherit : Foo {};
 
-/* TREE
+/** TREE
  *Dictionary(MyDictBig)
  *  Key(setString)
  *    Type()
@@ -69,7 +69,7 @@
   long unsetLong;
 };
 
-/* TREE
+/** TREE
  *Dictionary(MyDictRequired)
  *  Key(setLong)
  *    Type()
@@ -79,12 +79,12 @@
   required long setLong;
 };
 
-/* ERROR Unexpected "{" after keyword "dictionary". */
+/** ERROR Unexpected "{" after keyword "dictionary". */
 dictionary {
   DOMString? setString = null;
 };
 
-/* TREE
+/** TREE
  *Dictionary(MyDictionaryInvalidOptional)
  *  Key(mandatory)
  *    Type()
@@ -96,12 +96,12 @@
   sequence<DOMString> optional;
 };
 
-/* ERROR Unexpected identifier "NoColon" after identifier "ForParent". */
+/** ERROR Unexpected identifier "NoColon" after identifier "ForParent". */
 dictionary ForParent NoColon {
   DOMString? setString = null;
 };
 
-/* TREE
+/** TREE
  *Dictionary(MyDictNull)
  *  Key(setString)
  *    Type()
@@ -112,7 +112,7 @@
   DOMString? setString = null;
 };
 
-/* ERROR Unexpected keyword "attribute" after "{". */
+/** ERROR Unexpected keyword "attribute" after "{". */
 dictionary MyDictUnexpectedAttribute {
   attribute DOMString foo = "";
 };
diff --git a/tools/idl_parser/test_parser/enum_web.idl b/tools/idl_parser/test_parser/enum_web.idl
index e3107c0..14e31f9 100644
--- a/tools/idl_parser/test_parser/enum_web.idl
+++ b/tools/idl_parser/test_parser/enum_web.idl
@@ -29,45 +29,45 @@
 symatics should exist.  This is an exact match.
 */
 
-/* TREE
+/** TREE
  *Enum(MealType1)
  *  EnumItem(rice)
  *  EnumItem(noodles)
  *  EnumItem(other)
 */
 enum MealType1 {
-  /* BUILD EnumItem (rice) */
+  /** BUILD EnumItem (rice) */
   "rice",
-  /* BUILD EnumItem (noodles) */
+  /** BUILD EnumItem (noodles) */
   "noodles",
-  /* BUILD EnumItem(other) */
+  /** BUILD EnumItem(other) */
   "other"
 };
 
-/* BUILD Error(Enum missing name.) */
-/* ERROR Enum missing name. */
+/** BUILD Error(Enum missing name.) */
+/** ERROR Enum missing name. */
 enum {
   "rice",
   "noodles",
   "other"
 };
 
-/* TREE
+/** TREE
  *Enum(MealType2)
  *  EnumItem(rice)
  *  EnumItem(noodles)
  *  EnumItem(other)
 */
 enum MealType2 {
-  /* BUILD EnumItem(rice) */
+  /** BUILD EnumItem(rice) */
   "rice",
-  /* BUILD EnumItem(noodles) */
+  /** BUILD EnumItem(noodles) */
   "noodles",
-  /* BUILD EnumItem(other) */
+  /** BUILD EnumItem(other) */
   "other"
 };
 
-/* TREE
+/** TREE
  *Enum(TrailingComma)
  *  EnumItem(rice)
  *  EnumItem(noodles)
@@ -79,45 +79,45 @@
   "other",
 };
 
-/* BUILD Error(Unexpected string "noodles" after string "rice".) */
-/* ERROR Unexpected string "noodles" after string "rice". */
+/** BUILD Error(Unexpected string "noodles" after string "rice".) */
+/** ERROR Unexpected string "noodles" after string "rice". */
 enum MissingComma {
   "rice"
   "noodles",
   "other"
 };
 
-/* BUILD Error(Unexpected "," after ",".) */
-/* ERROR Unexpected "," after ",". */
+/** BUILD Error(Unexpected "," after ",".) */
+/** ERROR Unexpected "," after ",". */
 enum ExtraComma {
   "rice",
   "noodles",
   ,"other",
 };
 
-/* BUILD Error(Unexpected keyword "interface" after "{".) */
-/* ERROR Unexpected keyword "interface" after "{". */
+/** BUILD Error(Unexpected keyword "interface" after "{".) */
+/** ERROR Unexpected keyword "interface" after "{". */
 enum ExtraComma {
   interface,
   "noodles",
   ,"other",
 };
 
-/* BUILD Error(Unexpected identifier "somename" after "{".) */
-/* ERROR Unexpected identifier "somename" after "{". */
+/** BUILD Error(Unexpected identifier "somename" after "{".) */
+/** ERROR Unexpected identifier "somename" after "{". */
 enum ExtraComma {
   somename,
   "noodles",
   ,"other",
 };
 
-/* BUILD Enum(MealType3) */
+/** BUILD Enum(MealType3) */
 enum MealType3 {
-  /* BUILD EnumItem(rice) */
+  /** BUILD EnumItem(rice) */
   "rice",
-  /* BUILD EnumItem(noodles) */
+  /** BUILD EnumItem(noodles) */
   "noodles",
-  /* BUILD EnumItem(other) */
+  /** BUILD EnumItem(other) */
   "other"
 };
 
diff --git a/tools/idl_parser/test_parser/implements_web.idl b/tools/idl_parser/test_parser/implements_web.idl
index 252dd4b..44bf6776 100644
--- a/tools/idl_parser/test_parser/implements_web.idl
+++ b/tools/idl_parser/test_parser/implements_web.idl
@@ -29,24 +29,24 @@
 symatics should exist.  This is an exact match.
 */
 
-/* BUILD Implements(A) */
-/* PROP REFERENCE=B */
+/** BUILD Implements(A) */
+/** PROP REFERENCE=B */
 A implements B;
 
-/* ERROR Unexpected ";" after keyword "implements". */
+/** ERROR Unexpected ";" after keyword "implements". */
 A implements;
 
-/* BUILD Implements(B) */
-/* PROP REFERENCE=C */
+/** BUILD Implements(B) */
+/** PROP REFERENCE=C */
 B implements C;
 
-/* ERROR Unexpected keyword "implements" after "]". */
+/** ERROR Unexpected keyword "implements" after "]". */
 [foo] implements B;
 
-/* BUILD Implements(D) */
-/* PROP REFERENCE=E */
+/** BUILD Implements(D) */
+/** PROP REFERENCE=E */
 D implements E;
 
-/* ERROR Unexpected keyword "implements" after comment. */
+/** ERROR Unexpected keyword "implements" after comment. */
 implements C;
 
diff --git a/tools/idl_parser/test_parser/interface_web.idl b/tools/idl_parser/test_parser/interface_web.idl
index 0f6b6bfe..9e96a13 100644
--- a/tools/idl_parser/test_parser/interface_web.idl
+++ b/tools/idl_parser/test_parser/interface_web.idl
@@ -30,26 +30,26 @@
 */
 
 
-/* TREE
+/** TREE
  *Interface(MyIFace)
  */
 interface MyIFace { };
 
-/* TREE
+/** TREE
  *Interface(MyIFaceInherit)
  *  Inherit(Foo)
  */
 interface MyIFaceInherit : Foo {};
 
-/* TREE
+/** TREE
  *Interface(MyIFacePartial)
  */
 partial interface MyIFacePartial { };
 
-/* ERROR Unexpected ":" after identifier "MyIFaceInherit". */
+/** ERROR Unexpected ":" after identifier "MyIFaceInherit". */
 partial interface MyIFaceInherit : Foo {};
 
-/* TREE
+/** TREE
  *Interface(MyIFaceMissingArgument)
  *  Operation(foo)
  *    Arguments()
@@ -64,14 +64,14 @@
   void foo(DOMString arg, );
 };
 
-/* TREE
+/** TREE
  *Error(Unexpected keyword "double" after keyword "readonly".)
  */
 interface MyIFaceMissingAttribute {
   readonly double foo;
 };
 
-/* TREE
+/** TREE
  *Interface(MyIFaceContainsUnresolvedConflictDiff)
  *  Operation(foo)
  *    Arguments()
@@ -88,7 +88,7 @@
 >>>>>> theirs
 };
 
-/* TREE
+/** TREE
  *Interface(MyIFaceWrongRecordKeyType)
  *  Operation(foo)
  *    Arguments()
@@ -102,7 +102,7 @@
   void foo(record<int, ByteString> arg);
 };
 
-/* TREE
+/** TREE
  *Interface(MyIFaceBig)
  *  Const(setString)
  *    StringType(DOMString)
@@ -112,7 +112,7 @@
   const DOMString? setString = null;
 };
 
-/* TREE
+/** TREE
  *Interface(MyIfaceEmptySequenceDefalutValue)
  *  Operation(foo)
  *    Arguments()
@@ -129,7 +129,7 @@
   void foo(optional sequence<DOMString> arg = []);
 };
 
-/* TREE
+/** TREE
  *Interface(MyIfaceWithRecords)
  *  Operation(foo)
  *    Arguments()
@@ -160,7 +160,7 @@
   double bar(int arg1, record<ByteString, float> arg2);
 };
 
-/* TREE
+/** TREE
  *Interface(MyIFaceBig2)
  *  Const(nullValue)
  *    StringType(DOMString)
@@ -207,7 +207,7 @@
 };
 
 
-/* TREE
+/** TREE
  *Interface(MyIFaceSpecials)
  *  Operation(set)
  *    Arguments()
@@ -239,7 +239,7 @@
   long long [5][6] GetFiveSix(SomeType arg);
 };
 
-/* TREE
+/** TREE
  *Interface(MyIFaceStringifiers)
  *  Stringifier()
  *  Stringifier()
@@ -264,7 +264,7 @@
   stringifier attribute DOMString stringValue;
 };
 
-/* TREE
+/** TREE
  *Interface(MyExtendedAttributeInterface)
  *  Operation(method)
  *    Arguments()
@@ -283,7 +283,7 @@
   [Attr, MethodIdentList=(Foo, Bar)] void method();
 };
 
-/* TREE
+/** TREE
  *Interface(MyIfacePromise)
  *  Operation(method1)
  *    Arguments()
@@ -317,7 +317,7 @@
   Promise method4();
 };
 
-/* TREE
+/** TREE
  *Interface(MyIfaceIterable)
  *  Iterable()
  *    Type()
@@ -333,7 +333,7 @@
   iterable<double, DOMString>;
 };
 
-/* TREE
+/** TREE
  *Interface(MyIfaceMaplike)
  *  Maplike()
  *    Type()
@@ -351,7 +351,7 @@
   maplike<double, boolean>;
 };
 
-/* TREE
+/** TREE
  *Interface(MyIfaceSetlike)
  *  Setlike()
  *    Type()
@@ -365,7 +365,7 @@
   setlike<double>;
 };
 
-/* TREE
+/** TREE
  *Interface(MyIfaceSerializer)
  *  Serializer()
  *  Serializer()
@@ -411,7 +411,7 @@
   serializer = [name1, name2];
 };
 
-/* TREE
+/** TREE
  *Interface(MyIfaceFrozenArray)
  *  Attribute(foo)
  *    Type()
@@ -423,7 +423,7 @@
   readonly attribute FrozenArray<DOMString> foo;
 };
 
-/* TREE
+/** TREE
  *Interface(MyIfaceUnion)
  *  Attribute(foo)
  *    Type()
diff --git a/tools/idl_parser/test_parser/typedef_web.idl b/tools/idl_parser/test_parser/typedef_web.idl
index 6e651c1e..330634f 100644
--- a/tools/idl_parser/test_parser/typedef_web.idl
+++ b/tools/idl_parser/test_parser/typedef_web.idl
@@ -30,14 +30,14 @@
 */
 
 
-/* TREE
+/** TREE
  *Typedef(MyLong)
  *  Type()
  *    PrimitiveType(long)
  */
 typedef long MyLong;
 
-/* TREE
+/** TREE
  *Typedef(MyLong)
  *  ExtAttributes()
  *    ExtAttribute(foo)
@@ -46,7 +46,7 @@
  */
 typedef [foo] long MyLong;
 
-/* TREE
+/** TREE
  *Typedef(MyLongArray)
  *  Type()
  *    PrimitiveType(long)
@@ -54,7 +54,7 @@
  */
 typedef long[] MyLongArray;
 
-/* TREE
+/** TREE
  *Typedef(MyLongSizedArray)
  *  Type()
  *    PrimitiveType(long)
@@ -62,7 +62,7 @@
  */
 typedef long[4] MyLongSizedArray;
 
-/* TREE
+/** TREE
  *Typedef(MyLongSizedArrayArray)
  *  Type()
  *    PrimitiveType(long)
@@ -71,7 +71,7 @@
  */
 typedef long[4][5] MyLongSizedArrayArray;
 
-/* TREE
+/** TREE
  *Typedef(MyLongArraySizedArray)
  *  Type()
  *    PrimitiveType(long)
@@ -80,7 +80,7 @@
  */
 typedef long[][5] MyLongArraySizedArray;
 
-/* TREE
+/** TREE
  *Typedef(MyTypeFive)
  *  Type()
  *    Typeref(MyType)
@@ -88,7 +88,7 @@
  */
 typedef MyType[5] MyTypeFive;
 
-/* TREE
+/** TREE
  *Typedef(MyTypeUnsizedFive)
  *  Type()
  *    Typeref(MyType)
@@ -97,98 +97,98 @@
  */
 typedef MyType[][5] MyTypeUnsizedFive;
 
-/* TREE
+/** TREE
  *Typedef(MyLongLong)
  *  Type()
  *    PrimitiveType(long long)
  */
 typedef long long MyLongLong;
 
-/* TREE
+/** TREE
  *Typedef(MyULong)
  *  Type()
  *    PrimitiveType(unsigned long)
  */
 typedef unsigned long MyULong;
 
-/* TREE
+/** TREE
  *Typedef(MyULongLong)
  *  Type()
  *    PrimitiveType(unsigned long long)
  */
 typedef unsigned long long MyULongLong;
 
-/* TREE
+/** TREE
  *Typedef(MyString)
  *  Type()
  *    StringType(DOMString)
  */
 typedef DOMString MyString;
 
-/* TREE
+/** TREE
  *Typedef(MyObject)
  *  Type()
  *    PrimitiveType(object)
  */
 typedef object MyObject;
 
-/* TREE
+/** TREE
  *Typedef(MyDate)
  *  Type()
  *    PrimitiveType(Date)
  */
 typedef Date MyDate;
 
-/* TREE
+/** TREE
  *Typedef(MyFloat)
  *  Type()
  *    PrimitiveType(float)
  */
 typedef float MyFloat;
 
-/* TREE
+/** TREE
  *Typedef(MyUFloat)
  *  Type()
  *    PrimitiveType(float)
  */
 typedef unrestricted float MyUFloat;
 
-/* TREE
+/** TREE
  *Typedef(MyDouble)
  *  Type()
  *    PrimitiveType(double)
  */
 typedef double MyDouble;
 
-/* TREE
+/** TREE
  *Typedef(MyUDouble)
  *  Type()
  *    PrimitiveType(double)
  */
 typedef unrestricted double MyUDouble;
 
-/* TREE
+/** TREE
  *Typedef(MyBool)
  *  Type()
  *    PrimitiveType(boolean)
  */
 typedef boolean MyBool;
 
-/* TREE
+/** TREE
  *Typedef(MyByte)
  *  Type()
  *    PrimitiveType(byte)
  */
 typedef byte MyByte;
 
-/* TREE
+/** TREE
  *Typedef(MyOctet)
  *  Type()
  *    PrimitiveType(octet)
  */
 typedef octet MyOctet;
 
-/* TREE
+/** TREE
  *Typedef(MyRecord)
  *  Type()
  *    Record()
@@ -198,7 +198,7 @@
  */
 typedef record<ByteString, int> MyRecord;
 
-/* TREE
+/** TREE
  *Typedef(MyInvalidRecord)
  *  Type()
  *    Error(Unexpected keyword "double" after "<".)
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 23972014..7335448 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -9,6 +9,10 @@
 for sets of canned configurations and analyze them.
 """
 
+# TODO(thomasanderson): Remove this comment.  It is added to
+# workaround https://crbug.com/736215 for CL
+# https://codereview.chromium.org/2974603002/
+
 from __future__ import print_function
 
 import argparse
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index fa38969..b48fa8ea 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -120,7 +120,8 @@
       'Chromium Mac 10.9 Goma Canary (dbg)': 'debug_bot',
       'Chromium Mac 10.9 Goma Canary (dbg)(clobber)': 'debug_bot',
       'Chromium Mac Goma Canary LocalOutputCache': 'release_bot',
-      'Chromium Win 10 GCE Tests': 'release_bot_x86_minimal_symbols',
+      'Chromium Win 10 GCE Tests (Win 7 Build)': 'release_bot_x86_minimal_symbols',
+      'Chromium Win 10 GCE Tests (Win 10 Build)': 'release_bot_x86_minimal_symbols',
       'Chromium Win PGO Builder': {
         '1': 'official_optimize_chrome_pgo_phase_1_x86',
         '2': 'official_optimize_chrome_pgo_phase_2_x86',
@@ -328,6 +329,7 @@
 
     'chromium.memory': {
       'Linux ASan LSan Builder': 'asan_lsan_release_trybot',
+      'Linux CFI': 'cfi_full_cfi_diag_thin_lto_release_static_dcheck_always_on_goma',
       'Linux Chromium OS ASan LSan Builder': 'asan_lsan_chromeos_release_trybot',
       'Linux ChromiumOS MSan Builder': 'chromeos_msan_release_bot',
       'Linux MSan Builder': 'msan_release_bot',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index da01bc4..7d9f392 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -1292,6 +1292,24 @@
   <int value="5" label="INSUFFICIENT_RESOURCES"/>
 </enum>
 
+<enum name="AshNightLightScheduleType">
+  <summary>Defines the possible Night Light schedule types</summary>
+  <int value="0" label="None"/>
+  <int value="1" label="Sunset to Sunrise"/>
+  <int value="2" label="Custom Schedule"/>
+</enum>
+
+<enum name="AshNightLightTemperatureRanges">
+  <summary>
+    Defines the ranges in which the value of the color temperature may reside
+  </summary>
+  <int value="0" label="[0 to 20) (coldest)"/>
+  <int value="1" label="[20 to 40)"/>
+  <int value="2" label="[40 to 60)"/>
+  <int value="3" label="[60 to 80)"/>
+  <int value="4" label="[80 to 100) (warmest)"/>
+</enum>
+
 <enum name="AsyncDNSConfigParsePosix">
   <int value="0" label="OK"/>
   <int value="1" label="RES_INIT_FAILED"/>
@@ -22383,6 +22401,17 @@
 </enum>
 
 <enum name="LoginCustomFlags">
+<!--
+Values in LoginCustomFlags are:  value=(uint32_t)MD5(label).
+This enum is verified by AboutFlagsHistogramTest unit test.
+To add a new entry, add it with any unique value and run test to compute valid
+value. After that run tools/metrics/histograms/validate_format.py to find out
+where the value should be inserted to maintain ordering.
+Don't remove entries when removing a flag, they are still used to decode data
+from previous Chrome versions.
+-->
+
+  <summary>Chrome flags that lead to Chrome restart on Chrome OS.</summary>
   <int value="-2146613579" label="V8Future:disabled"/>
   <int value="-2143961262" label="D3DVsync:disabled"/>
   <int value="-2143328006"
@@ -23040,17 +23069,6 @@
   <int value="0" label="BAD_FLAG_FORMAT">
     Command-line flag doesn't start with two dashes.
   </int>
-<!--
-Values in LoginCustomFlags are:  value=(uint32_t)MD5(label).
-This enum is verified by AboutFlagsHistogramTest unit test.
-To add a new entry, add it with any unique value and run test to compute valid
-value. After that run tools/metrics/histograms/validate_format.py to find out
-where the value should be inserted to maintain ordering.
-Don't remove entries when removing a flag, they are still used to decode data
-from previous Chrome versions.
--->
-
-  <summary>Chrome flags that lead to Chrome restart on Chrome OS.</summary>
   <int value="7444737" label="NTPSuggestionsStandaloneUI:disabled"/>
   <int value="7533886" label="disable-offer-store-unmasked-wallet-cards"/>
   <int value="10458238" label="disable-print-preview-simplify"/>
@@ -23307,9 +23325,7 @@
   <int value="939603162" label="BackgroundLoadingForDownloads:disabled"/>
   <int value="941036016" label="ContentSuggestionsSettings:disabled"/>
   <int value="943319566" label="enable-intent-picker"/>
-  <int value="946688335" label="OmniboxSpareRenderer:disabled"/>
   <int value="952558794" label="enable-remote-assistance"/>
-  <int value="979445973" label="OmniboxSpareRenderer:enabled"/>
   <int value="980396200" label="enable-new-korean-ime"/>
   <int value="981818901" label="AppBanners:enabled"/>
   <int value="982032277" label="NTPOfflineBadge:disabled"/>
@@ -23592,6 +23608,7 @@
   <int value="1862207743" label="enable-android-spellchecker"/>
   <int value="1865068568" label="disable-audio-support-for-desktop-share"/>
   <int value="1865799183" label="javascript-harmony"/>
+  <int value="1865963858" label="tls13-variant"/>
   <int value="1866079109" label="team-drives"/>
   <int value="1867085340" label="brotli-encoding:enabled"/>
   <int value="1872185826" label="LocationHardReload:enabled"/>
@@ -33489,6 +33506,15 @@
   <int value="6" label="Google Docs and Drive"/>
 </enum>
 
+<enum name="ServiceWorkerStartForNavigationHintResult">
+  <int value="0" label="STARTED"/>
+  <int value="1" label="ALREADY_RUNNING"/>
+  <int value="2" label="NO_SERVICE_WORKER_REGISTRATION"/>
+  <int value="3" label="NO_ACTIVE_SERVICE_WORKER_VERSION"/>
+  <int value="4" label="NO_FETCH_HANDLER"/>
+  <int value="5" label="FAILED"/>
+</enum>
+
 <enum name="ServiceWorkerStatusCode">
   <int value="0" label="SERVICE_WORKER_OK"/>
   <int value="1" label="SERVICE_WORKER_ERROR_FAILED"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 18de1086..3126c3a 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -2254,6 +2254,24 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.NightLight.ScheduleType" enum="AshNightLightScheduleType">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    The selected Night Light schedule type. Emitted when the user changes the
+    Night Light schedule type from the Display System Settings.
+  </summary>
+</histogram>
+
+<histogram name="Ash.NightLight.Temperature"
+    enum="AshNightLightTemperatureRanges">
+  <owner>afakhry@chromium.org</owner>
+  <summary>
+    The ranges in which the selected values of the Night Light color temperature
+    reside. Emitted when the user drags the Night Light color temperature slider
+    to change its value from the Display System Settings.
+  </summary>
+</histogram>
+
 <histogram name="Ash.NumberOfVisibleWindowsInPrimaryDisplay" units="Windows">
   <owner>tdanderson@google.com</owner>
   <owner>bruthig@google.com</owner>
@@ -69817,6 +69835,14 @@
   </summary>
 </histogram>
 
+<histogram name="ServiceWorker.StartForNavigationHint.Result"
+    enum="ServiceWorkerStartForNavigationHintResult">
+  <owner>horo@chromium.org</owner>
+  <summary>
+    The result of starting a service worker for a navigation hint.
+  </summary>
+</histogram>
+
 <histogram name="ServiceWorker.StartHintPrecision" enum="BooleanEnabled">
   <owner>horo@chromium.org</owner>
   <summary>
@@ -92489,6 +92515,17 @@
   <affected-histogram name="Net.BidirectionalStream.TimeToSendStart"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="Net.HttpJob.TotalTimeSuccess.Priorities"
+    separator=".">
+  <suffix name="Priority0" label="THROTTLED or MINIMUM_PRIORITY"/>
+  <suffix name="Priority1" label="IDLE"/>
+  <suffix name="Priority2" label="LOWEST or DEFAULT_PRIORITY"/>
+  <suffix name="Priority3" label="LOW"/>
+  <suffix name="Priority4" label="MEDIUM"/>
+  <suffix name="Priority5" label="HIGHEST or MAXIMUM_PRIORITY"/>
+  <affected-histogram name="Net.HttpJob.TotalTimeSuccess"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="Net.QuicClientHelloRejectReasons.QuicIsSecureOrNot"
     separator=".">
   <owner>rch@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 7e2c8da..07d6aeb 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -395,6 +395,34 @@
   </metric>
 </event>
 
+<event name="Intervention.DocumentWrite.ScriptBlock" singular="True">
+  <owner>bmcquade@chromium.org</owner>
+  <summary>
+    Recorded for page loads where the document.write script block intervention
+    could apply.
+  </summary>
+  <metric name="Disabled.Reload">
+    <summary>
+      Records '1' if the document.write script block intervention could have
+      applied, but was disabled due to the page being reloaded.
+    </summary>
+  </metric>
+  <metric name="ParseTiming.ParseBlockedOnScriptExecutionFromDocumentWrite">
+    <summary>
+      Measures the time in milliseconds that the HTML parser spent blocked on
+      the execution of scripts inserted from document.write, for main frame
+      documents that finished parsing.
+    </summary>
+  </metric>
+  <metric name="ParseTiming.ParseBlockedOnScriptLoadFromDocumentWrite">
+    <summary>
+      Measures the time in milliseconds that the HTML parser spent blocked on
+      the load of scripts inserted from document.write, for main frame documents
+      that finished parsing.
+    </summary>
+  </metric>
+</event>
+
 <event name="LocalNetworkRequests">
   <owner>uthakore@chromium.org</owner>
   <summary>
@@ -650,6 +678,22 @@
   </metric>
 </event>
 
+<event name="PageLoad.FromGoogleSearch" singular="True">
+  <owner>bmcquade@chromium.org</owner>
+  <owner>mushan@chromium.org</owner>
+  <summary>
+    Recorded for page loads that were navigated to via Google Search.
+  </summary>
+</event>
+
+<event name="PageLoad.ServiceWorkerControlled" singular="True">
+  <owner>bmcquade@chromium.org</owner>
+  <owner>falken@chromium.org</owner>
+  <summary>
+    Recorded for page loads controlled by a service worker.
+  </summary>
+</event>
+
 <event name="PasswordForm">
   <owner>battre@chromium.org</owner>
   <summary>
@@ -806,6 +850,30 @@
   </summary>
 </event>
 
+<event name="SubresourceFilter" singular="True">
+  <owner>bmcquade@chromium.org</owner>
+  <owner>csharrison@chromium.org</owner>
+  <summary>
+    Recorded for page loads where subresource filtering policy was evaluated.
+  </summary>
+  <metric name="ActivationDecision">
+    <summary>
+      Enum that records the policy decision to activate subresource filtering
+      for a page load. 0 = Unknown, 1 = Activated, 2 = Disabled, 3 = Unsupported
+      scheme, 4 = URL whitelisted, 5 = Activation conditions not met.
+      'Activated' indicates that subresource filtering was activated. All other
+      reasons indicate that subresource filtering was not activated.
+    </summary>
+  </metric>
+  <metric name="DryRun">
+    <summary>
+      Records '1' if subresource filtering was activated in dry run mode. In dry
+      run mode, subresource filtering policy is evaluated against resources
+      loaded on the page, but subresource filtering is not actually applied.
+    </summary>
+  </metric>
+</event>
+
 <event name="Translate">
   <owner>hamelphi@chromium.org</owner>
   <summary>
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index b088686..d2cba5c 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -61,7 +61,7 @@
     "//base",
     "//cc",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
+    "//components/viz/common",
     "//components/viz/service",
     "//skia",
     "//ui/base",
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index 5ff7cec..0ad11643 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -119,7 +119,6 @@
       "views/apps_container_view.h",
       "views/apps_grid_view.cc",
       "views/apps_grid_view.h",
-      "views/apps_grid_view_delegate.h",
       "views/apps_grid_view_folder_delegate.h",
       "views/contents_view.cc",
       "views/contents_view.h",
diff --git a/ui/app_list/vector_icons/BUILD.gn b/ui/app_list/vector_icons/BUILD.gn
index 87a6c2c..9951785 100644
--- a/ui/app_list/vector_icons/BUILD.gn
+++ b/ui/app_list/vector_icons/BUILD.gn
@@ -16,6 +16,8 @@
     "ic_badge_play.icon",
     "ic_badge_rating.1x.icon",
     "ic_badge_rating.icon",
+    "ic_close.1x.icon",
+    "ic_close.icon",
     "ic_google_black.1x.icon",
     "ic_google_black.icon",
     "ic_mic_black.1x.icon",
diff --git a/ui/app_list/vector_icons/ic_close.1x.icon b/ui/app_list/vector_icons/ic_close.1x.icon
new file mode 100644
index 0000000..3a5801a
--- /dev/null
+++ b/ui/app_list/vector_icons/ic_close.1x.icon
@@ -0,0 +1,19 @@
+// 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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 19, 6.41f,
+LINE_TO, 17.59f, 5,
+LINE_TO, 12, 10.59f,
+LINE_TO, 6.41f, 5,
+LINE_TO, 5, 6.41f,
+LINE_TO, 10.59f, 12,
+LINE_TO, 5, 17.59f,
+LINE_TO, 6.41f, 19,
+LINE_TO, 12, 13.41f,
+LINE_TO, 17.59f, 19,
+LINE_TO, 19, 17.59f,
+LINE_TO, 13.41f, 12,
+CLOSE,
+END
diff --git a/ui/app_list/vector_icons/ic_close.icon b/ui/app_list/vector_icons/ic_close.icon
new file mode 100644
index 0000000..a4e83b22
--- /dev/null
+++ b/ui/app_list/vector_icons/ic_close.icon
@@ -0,0 +1,19 @@
+// 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.
+
+CANVAS_DIMENSIONS, 48,
+MOVE_TO, 38, 12.82f,
+LINE_TO, 35.18f, 10,
+LINE_TO, 24, 21.18f,
+LINE_TO, 12.82f, 10,
+LINE_TO, 10, 12.82f,
+LINE_TO, 21.18f, 24,
+LINE_TO, 10, 35.18f,
+LINE_TO, 12.82f, 38,
+LINE_TO, 24, 26.82f,
+LINE_TO, 35.18f, 38,
+LINE_TO, 38, 35.18f,
+LINE_TO, 26.82f, 24,
+CLOSE,
+END
diff --git a/ui/app_list/views/app_list_main_view.h b/ui/app_list/views/app_list_main_view.h
index f345a60..98bdaec 100644
--- a/ui/app_list/views/app_list_main_view.h
+++ b/ui/app_list/views/app_list_main_view.h
@@ -12,7 +12,6 @@
 #include "base/timer/timer.h"
 #include "ui/app_list/app_list_export.h"
 #include "ui/app_list/app_list_model_observer.h"
-#include "ui/app_list/views/apps_grid_view_delegate.h"
 #include "ui/app_list/views/search_box_view_delegate.h"
 #include "ui/app_list/views/search_result_list_view_delegate.h"
 #include "ui/views/view.h"
@@ -31,7 +30,6 @@
 // AppListMainView contains the normal view of the app list, which is shown
 // when the user is signed in.
 class APP_LIST_EXPORT AppListMainView : public views::View,
-                                        public AppsGridViewDelegate,
                                         public AppListModelObserver,
                                         public SearchBoxViewDelegate,
                                         public SearchResultListViewDelegate {
@@ -75,9 +73,14 @@
   void OnCustomLauncherPageEnabledStateChanged(bool enabled) override;
   void OnSearchEngineIsGoogleChanged(bool is_google) override;
 
-  // Overridden from AppsGridViewDelegate:
-  void ActivateApp(AppListItem* item, int event_flags) override;
-  void CancelDragInActiveFolder() override;
+  // Invoked when an item is activated on the grid view. |event_flags| contains
+  // the flags of the keyboard/mouse event that triggers the activation request.
+  void ActivateApp(AppListItem* item, int event_flags);
+
+  // Called by the root grid view to cancel a drag that started inside a folder.
+  // This can occur when the root grid is visible for a reparent and its model
+  // changes, necessitating a cancel of the drag operation.
+  void CancelDragInActiveFolder();
 
  private:
   // Adds the ContentsView.
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 9c2d47a..5a938b91 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -22,7 +22,6 @@
 #include "ui/app_list/views/app_list_folder_view.h"
 #include "ui/app_list/views/app_list_item_view.h"
 #include "ui/app_list/views/app_list_main_view.h"
-#include "ui/app_list/views/apps_grid_view_delegate.h"
 #include "ui/app_list/views/contents_view.h"
 #include "ui/app_list/views/indicator_chip_view.h"
 #include "ui/app_list/views/page_switcher_horizontal.h"
diff --git a/ui/app_list/views/apps_grid_view_delegate.h b/ui/app_list/views/apps_grid_view_delegate.h
deleted file mode 100644
index cce6de78..0000000
--- a/ui/app_list/views/apps_grid_view_delegate.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_APP_LIST_VIEWS_APPS_GRID_VIEW_DELEGATE_H_
-#define UI_APP_LIST_VIEWS_APPS_GRID_VIEW_DELEGATE_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class AppListItem;
-
-class APP_LIST_EXPORT AppsGridViewDelegate {
- public:
-  // Invoked when an item is activated on the grid view. |event_flags| contains
-  // the flags of the keyboard/mouse event that triggers the activation request.
-  virtual void ActivateApp(AppListItem* item, int event_flags) = 0;
-
-  // Called by the root grid view to cancel a drag that started inside a folder.
-  // This can occur when the root grid is visible for a reparent and its model
-  // changes, necessitating a cancel of the drag operation.
-  virtual void CancelDragInActiveFolder() = 0;
-
- protected:
-  virtual ~AppsGridViewDelegate() {}
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_DELEGATE_H_
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 844aef68..8d5bf841 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -62,6 +62,7 @@
 constexpr int kBackgroundBorderCornerRadiusSearchResult = 4;
 constexpr int kGoogleIconSize = 24;
 constexpr int kMicIconSize = 24;
+constexpr int kCloseIconSize = 24;
 
 // Default color used when wallpaper customized color is not available for
 // searchbox, #000 at 87% opacity.
@@ -171,13 +172,8 @@
                              AppListView* app_list_view)
     : delegate_(delegate),
       view_delegate_(view_delegate),
-      model_(nullptr),
       content_container_(new views::View),
-      google_icon_(nullptr),
-      back_button_(nullptr),
-      speech_button_(nullptr),
       search_box_(new views::Textfield),
-      contents_view_(nullptr),
       app_list_view_(app_list_view),
       focused_view_(FOCUS_SEARCH_BOX),
       is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
@@ -233,6 +229,15 @@
   content_container_->AddChildView(search_box_);
   layout->SetFlexForView(search_box_, 1);
 
+  if (is_fullscreen_app_list_enabled_) {
+    close_button_ = new SearchBoxImageButton(this);
+    close_button_->SetImage(views::ImageButton::STATE_NORMAL,
+                            gfx::CreateVectorIcon(kIcCloseIcon, kCloseIconSize,
+                                                  kDefaultSearchboxColor));
+    close_button_->SetVisible(false);
+    content_container_->AddChildView(close_button_);
+  }
+
   view_delegate_->GetSpeechUI()->AddObserver(this);
   ModelChanged();
 }
@@ -288,6 +293,10 @@
   return static_cast<views::ImageButton*>(back_button_);
 }
 
+bool SearchBoxView::IsCloseButtonVisible() const {
+  return close_button_ && close_button_->visible();
+}
+
 // Returns true if set internally, i.e. if focused_view_ != CONTENTS_VIEW.
 // Note: because we always want to be able to type in the edit box, this is only
 // a faux-focus so that buttons can respond to the ENTER key.
@@ -296,6 +305,8 @@
     back_button_->SetSelected(false);
   if (speech_button_)
     speech_button_->SetSelected(false);
+  if (close_button_)
+    close_button_->SetSelected(false);
 
   switch (focused_view_) {
     case FOCUS_BACK_BUTTON:
@@ -309,18 +320,23 @@
       } else {
         focused_view_ = speech_button_ && speech_button_->visible()
                             ? FOCUS_MIC_BUTTON
-                            : FOCUS_CONTENTS_VIEW;
+                            : (close_button_ && close_button_->visible()
+                                   ? FOCUS_CLOSE_BUTTON
+                                   : FOCUS_CONTENTS_VIEW);
       }
       break;
     case FOCUS_MIC_BUTTON:
+    case FOCUS_CLOSE_BUTTON:
       focused_view_ = move_backwards ? FOCUS_SEARCH_BOX : FOCUS_CONTENTS_VIEW;
       break;
     case FOCUS_CONTENTS_VIEW:
-      focused_view_ =
-          move_backwards
-              ? (speech_button_ && speech_button_->visible() ? FOCUS_MIC_BUTTON
-                                                             : FOCUS_SEARCH_BOX)
-              : FOCUS_CONTENTS_VIEW;
+      if (move_backwards) {
+        focused_view_ = speech_button_ && speech_button_->visible()
+                            ? FOCUS_MIC_BUTTON
+                            : (close_button_ && close_button_->visible()
+                                   ? FOCUS_CLOSE_BUTTON
+                                   : FOCUS_SEARCH_BOX);
+      }
       break;
     default:
       DCHECK(false);
@@ -344,6 +360,10 @@
       if (speech_button_)
         speech_button_->SetSelected(true);
       break;
+    case FOCUS_CLOSE_BUTTON:
+      if (close_button_)
+        close_button_->SetSelected(true);
+      break;
     default:
       break;
   }
@@ -359,6 +379,8 @@
     back_button_->SetSelected(false);
   if (speech_button_)
     speech_button_->SetSelected(false);
+  if (close_button_)
+    close_button_->SetSelected(false);
   focused_view_ = on_contents ? FOCUS_CONTENTS_VIEW : FOCUS_SEARCH_BOX;
 }
 
@@ -396,6 +418,11 @@
                                                  : kDefaultSearchboxColor);
   search_box_->SetCursorEnabled(active);
   search_box_->SchedulePaint();
+
+  if (speech_button_)
+    speech_button_->SetVisible(!active);
+  close_button_->SetVisible(active);
+  content_container_->Layout();
 }
 
 void SearchBoxView::HandleSearchBoxEvent(ui::LocatedEvent* located_event) {
@@ -441,6 +468,8 @@
   search_box_->SetEnabled(enabled());
   if (speech_button_)
     speech_button_->SetEnabled(enabled());
+  if (close_button_)
+    close_button_->SetEnabled(enabled());
 }
 
 const char* SearchBoxView::GetClassName() const {
@@ -511,6 +540,10 @@
         speech_button_->OnKeyPressed(key_event))
       return true;
 
+    if (focused_view_ == FOCUS_CLOSE_BUTTON && close_button_ &&
+        close_button_->OnKeyPressed(key_event))
+      return true;
+
     const bool handled = contents_view_ && contents_view_->visible() &&
                          contents_view_->OnKeyPressed(key_event);
 
@@ -539,6 +572,10 @@
         speech_button_->OnKeyReleased(key_event))
       return true;
 
+    if (focused_view_ == FOCUS_CLOSE_BUTTON && close_button_ &&
+        close_button_->OnKeyReleased(key_event))
+      return true;
+
     return contents_view_ && contents_view_->visible() &&
            contents_view_->OnKeyReleased(key_event);
   }
@@ -562,6 +599,8 @@
     delegate_->BackButtonPressed();
   else if (speech_button_ && sender == speech_button_)
     view_delegate_->StartSpeechRecognition();
+  else if (close_button_ && sender == close_button_)
+    ClearSearch();
   else
     NOTREACHED();
 }
@@ -602,7 +641,7 @@
     if (speech_button_) {
       // Deleting a view will detach it from its parent.
       delete speech_button_;
-      speech_button_ = NULL;
+      speech_button_ = nullptr;
     }
   }
   Layout();
@@ -645,6 +684,11 @@
       gfx::CreateVectorIcon(
           kIcMicBlackIcon, kMicIconSize,
           dark_muted_available ? dark_muted : kDefaultSearchboxColor));
+  close_button_->SetImage(
+      views::Button::STATE_NORMAL,
+      gfx::CreateVectorIcon(
+          kIcCloseIcon, kCloseIconSize,
+          dark_muted_available ? dark_muted : kDefaultSearchboxColor));
   search_box_->set_placeholder_text_color(
       dark_muted_available ? dark_muted : kDefaultSearchboxColor);
 
diff --git a/ui/app_list/views/search_box_view.h b/ui/app_list/views/search_box_view.h
index 088a9abb..63e124f2 100644
--- a/ui/app_list/views/search_box_view.h
+++ b/ui/app_list/views/search_box_view.h
@@ -28,6 +28,7 @@
   FOCUS_BACK_BUTTON,    // Back button, only responds to ENTER
   FOCUS_SEARCH_BOX,     // Nothing else has partial focus
   FOCUS_MIC_BUTTON,     // Mic button, only responds to ENTER
+  FOCUS_CLOSE_BUTTON,   // Close button, only responds to ENTER
   FOCUS_CONTENTS_VIEW,  // Something outside the SearchBox is selected
 };
 
@@ -67,6 +68,7 @@
 
   views::ImageButton* back_button();
   views::Textfield* search_box() { return search_box_; }
+  bool IsCloseButtonVisible() const;
 
   void set_contents_view(views::View* contents_view) {
     contents_view_ = contents_view;
@@ -143,15 +145,17 @@
 
   SearchBoxViewDelegate* delegate_;     // Not owned.
   AppListViewDelegate* view_delegate_;  // Not owned.
-  AppListModel* model_;                 // Owned by the profile-keyed service.
+  AppListModel* model_ = nullptr;       // Owned by the profile-keyed service.
 
-  views::View* content_container_;        // Owned by views hierarchy.
-  views::ImageView* google_icon_;         // Owned by views hierarchy.
-  SearchBoxImageButton* back_button_;     // Owned by views hierarchy.
-  SearchBoxImageButton* speech_button_;   // Owned by views hierarchy.
-  views::Textfield* search_box_;          // Owned by views hierarchy.
-  views::View* contents_view_;            // Owned by views hierarchy.
-  app_list::AppListView* app_list_view_;  // Owned by views hierarchy.
+  // Owned by views hierarchy.
+  views::View* content_container_;
+  views::ImageView* google_icon_ = nullptr;
+  SearchBoxImageButton* back_button_ = nullptr;
+  SearchBoxImageButton* speech_button_ = nullptr;
+  SearchBoxImageButton* close_button_ = nullptr;
+  views::Textfield* search_box_;
+  views::View* contents_view_ = nullptr;
+  app_list::AppListView* app_list_view_;
 
   SearchBoxFocus focused_view_;  // Which element has TAB'd focus.
 
diff --git a/ui/app_list/views/search_box_view_unittest.cc b/ui/app_list/views/search_box_view_unittest.cc
index e24ac556..69cd479 100644
--- a/ui/app_list/views/search_box_view_unittest.cc
+++ b/ui/app_list/views/search_box_view_unittest.cc
@@ -9,7 +9,10 @@
 
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "ui/app_list/app_list_features.h"
 #include "ui/app_list/test/app_list_test_view_delegate.h"
+#include "ui/app_list/views/app_list_view.h"
 #include "ui/app_list/views/search_box_view_delegate.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/test/widget_test.h"
@@ -43,16 +46,31 @@
 };
 
 class SearchBoxViewTest : public views::test::WidgetTest,
-                          public SearchBoxViewDelegate {
+                          public SearchBoxViewDelegate,
+                          public testing::WithParamInterface<bool> {
  public:
-  SearchBoxViewTest() : query_changed_count_(0) {}
-  ~SearchBoxViewTest() override {}
+  SearchBoxViewTest() = default;
+  ~SearchBoxViewTest() override = default;
 
   // Overridden from testing::Test:
   void SetUp() override {
     views::test::WidgetTest::SetUp();
+
+    if (testing::UnitTest::GetInstance()->current_test_info()->value_param()) {
+      // Current test is parameterized.
+      test_with_fullscreen_ = GetParam();
+      if (test_with_fullscreen_) {
+        scoped_feature_list_.InitAndEnableFeature(
+            features::kEnableFullscreenAppList);
+      }
+    }
+
+    gfx::NativeView parent = GetContext();
+    app_list_view_ = new AppListView(&view_delegate_);
+    app_list_view_->Initialize(parent, 0, false, false);
+
     widget_ = CreateTopLevelPlatformWidget();
-    view_ = new SearchBoxView(this, &view_delegate_);
+    view_ = new SearchBoxView(this, &view_delegate_, app_list_view_);
     counter_view_ = new KeyPressCounterView();
     widget_->GetContentsView()->AddChildView(view_);
     widget_->GetContentsView()->AddChildView(counter_view_);
@@ -60,6 +78,7 @@
   }
 
   void TearDown() override {
+    app_list_view_->GetWidget()->Close();
     widget_->CloseNow();
     views::test::WidgetTest::TearDown();
   }
@@ -67,6 +86,8 @@
  protected:
   SearchBoxView* view() { return view_; }
 
+  bool test_with_fullscreen() { return test_with_fullscreen_; }
+
   void SetLongAutoLaunchTimeout() {
     // Sets a long timeout that lasts longer than the test run.
     view_delegate_.set_auto_launch_timeout(base::TimeDelta::FromDays(1));
@@ -120,14 +141,21 @@
   AppListTestViewDelegate view_delegate_;
   views::Widget* widget_;
   SearchBoxView* view_;
+  AppListView* app_list_view_ = nullptr;
   KeyPressCounterView* counter_view_;
   base::string16 last_query_;
-  int query_changed_count_;
+  int query_changed_count_ = 0;
+  bool test_with_fullscreen_ = false;
+  base::test::ScopedFeatureList scoped_feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchBoxViewTest);
 };
 
-TEST_F(SearchBoxViewTest, Basic) {
+// Instantiate the Boolean which is used to toggle the Fullscreen app list in
+// the parameterized tests.
+INSTANTIATE_TEST_CASE_P(, SearchBoxViewTest, testing::Bool());
+
+TEST_P(SearchBoxViewTest, Basic) {
   KeyPress(ui::VKEY_A);
   EXPECT_EQ("a", GetLastQueryAndReset());
   EXPECT_EQ(1, GetQueryChangedCountAndReset());
@@ -142,7 +170,7 @@
   EXPECT_TRUE(GetLastQueryAndReset().empty());
 }
 
-TEST_F(SearchBoxViewTest, CancelAutoLaunch) {
+TEST_P(SearchBoxViewTest, CancelAutoLaunch) {
   SetLongAutoLaunchTimeout();
   ASSERT_NE(base::TimeDelta(), GetAutoLaunchTimeout());
 
@@ -164,5 +192,16 @@
   EXPECT_EQ(base::TimeDelta(), GetAutoLaunchTimeout());
 }
 
+TEST_P(SearchBoxViewTest, CloseButtonTest) {
+  if (!test_with_fullscreen())
+    return;
+
+  KeyPress(ui::VKEY_A);
+  EXPECT_TRUE(view()->IsCloseButtonVisible());
+
+  view()->ClearSearch();
+  EXPECT_FALSE(view()->IsCloseButtonVisible());
+}
+
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/aura/local/window_port_local.cc b/ui/aura/local/window_port_local.cc
index 8b987fc..aeb7ebf 100644
--- a/ui/aura/local/window_port_local.cc
+++ b/ui/aura/local/window_port_local.cc
@@ -130,7 +130,7 @@
   DCHECK_EQ(surface_id.frame_sink_id(), frame_sink_id_);
   local_surface_id_ = surface_id.local_surface_id();
   viz::SurfaceInfo surface_info(surface_id, 1.0f, surface_size);
-  scoped_refptr<cc::SurfaceReferenceFactory> reference_factory =
+  scoped_refptr<viz::SurfaceReferenceFactory> reference_factory =
       aura::Env::GetInstance()
           ->context_factory_private()
           ->GetFrameSinkManager()
diff --git a/ui/aura/mus/client_surface_embedder.h b/ui/aura/mus/client_surface_embedder.h
index 2c63b03e..eda967fe 100644
--- a/ui/aura/mus/client_surface_embedder.h
+++ b/ui/aura/mus/client_surface_embedder.h
@@ -6,7 +6,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "cc/surfaces/surface_reference_factory.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
 #include "ui/gfx/geometry/insets.h"
 
 namespace gfx {
@@ -64,7 +64,7 @@
 
   gfx::Insets client_area_insets_;
 
-  scoped_refptr<cc::SurfaceReferenceFactory> ref_factory_;
+  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ClientSurfaceEmbedder);
 };
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index 4612fd1..a992c272 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -87,7 +87,6 @@
     "//cc/animation",
     "//cc/paint",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
     "//cc/surfaces:surfaces",
     "//components/viz/common",
     "//components/viz/host",
@@ -213,7 +212,7 @@
     "//cc",
     "//cc:test_support",
     "//cc/surfaces",
-    "//cc/surfaces:surface_id",
+    "//components/viz/common",
     "//mojo/edk/system",
     "//skia",
     "//testing/gmock",
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 7917df9..3664ff58 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -18,9 +18,9 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "cc/output/begin_frame_args.h"
-#include "cc/surfaces/surface_sequence.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/compositor/compositor_animation_observer.h"
 #include "ui/compositor/compositor_export.h"
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 6646e58..6219155 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -687,7 +687,7 @@
 
 void Layer::SetShowPrimarySurface(
     const viz::SurfaceInfo& surface_info,
-    scoped_refptr<cc::SurfaceReferenceFactory> ref_factory) {
+    scoped_refptr<viz::SurfaceReferenceFactory> ref_factory) {
   DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR);
 
   if (!surface_layer_) {
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index 3f69b63..9cf998d 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -21,8 +21,8 @@
 #include "cc/layers/layer_client.h"
 #include "cc/layers/surface_layer.h"
 #include "cc/layers/texture_layer_client.h"
-#include "cc/surfaces/sequence_surface_reference_factory.h"
 #include "components/viz/common/quads/texture_mailbox.h"
+#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/compositor/compositor.h"
@@ -304,7 +304,7 @@
   // Begins showing content from a surface with a particular ID.
   void SetShowPrimarySurface(
       const viz::SurfaceInfo& surface_info,
-      scoped_refptr<cc::SurfaceReferenceFactory> surface_ref);
+      scoped_refptr<viz::SurfaceReferenceFactory> surface_ref);
 
   // In the event that the primary surface is not yet available in the
   // display compositor, the fallback surface will be used.
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index 5bd37a2..ed147083 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -26,11 +26,11 @@
 #include "cc/layers/layer.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
-#include "cc/surfaces/sequence_surface_reference_factory.h"
-#include "cc/surfaces/surface_reference_factory.h"
-#include "cc/surfaces/surface_sequence.h"
 #include "cc/test/pixel_test_utils.h"
+#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
+#include "components/viz/common/surfaces/surface_sequence.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "ui/compositor/compositor_observer.h"
@@ -1734,7 +1734,8 @@
 
 namespace {
 
-class TestSurfaceReferenceFactory : public cc::SequenceSurfaceReferenceFactory {
+class TestSurfaceReferenceFactory
+    : public viz::SequenceSurfaceReferenceFactory {
  public:
   TestSurfaceReferenceFactory() = default;
 
@@ -1742,9 +1743,9 @@
   ~TestSurfaceReferenceFactory() override = default;
 
   // cc::SequenceSurfaceReferenceFactory implementation:
-  void SatisfySequence(const cc::SurfaceSequence& seq) const override {}
+  void SatisfySequence(const viz::SurfaceSequence& seq) const override {}
   void RequireSequence(const viz::SurfaceId& id,
-                       const cc::SurfaceSequence& seq) const override {}
+                       const viz::SurfaceSequence& seq) const override {}
 
   DISALLOW_COPY_AND_ASSIGN(TestSurfaceReferenceFactory);
 };
@@ -1784,7 +1785,7 @@
 
 TEST_F(LayerWithDelegateTest, ExternalContentMirroring) {
   std::unique_ptr<Layer> layer(CreateLayer(LAYER_SOLID_COLOR));
-  scoped_refptr<cc::SurfaceReferenceFactory> reference_factory(
+  scoped_refptr<viz::SurfaceReferenceFactory> reference_factory(
       new TestSurfaceReferenceFactory());
 
   viz::SurfaceId surface_id(
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index 6da150c1..2512c511 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -1097,7 +1097,7 @@
   *is_touching_scrolling_layer = false;
   EventDisposition result = DROP_EVENT;
   for (size_t i = 0; i < touch_event.touches_length; ++i) {
-    if (touch_event.GetType() == WebInputEvent::kTouchStart)
+    if (touch_event.touch_start_or_first_touch_move)
       DCHECK(white_listed_touch_action);
     else
       DCHECK(!white_listed_touch_action);
@@ -1169,7 +1169,7 @@
   cc::TouchAction white_listed_touch_action = cc::kTouchActionAuto;
   EventDisposition result = HitTestTouchEvent(
       touch_event, &is_touching_scrolling_layer, &white_listed_touch_action);
-  // TODO(hayleyferr) : Send |white_listed_touch_action| to browser.
+  client_->SetWhiteListedTouchAction(white_listed_touch_action);
 
   // If |result| is still DROP_EVENT look at the touch end handler as
   // we may not want to discard the entire touch sequence. Note this
@@ -1197,8 +1197,11 @@
   if (touch_result_ == kEventDispositionUndefined ||
       touch_event.touch_start_or_first_touch_move) {
     bool is_touching_scrolling_layer;
-    return HitTestTouchEvent(touch_event, &is_touching_scrolling_layer,
-                             nullptr);
+    cc::TouchAction white_listed_touch_action = cc::kTouchActionAuto;
+    EventDisposition result = HitTestTouchEvent(
+        touch_event, &is_touching_scrolling_layer, &white_listed_touch_action);
+    client_->SetWhiteListedTouchAction(white_listed_touch_action);
+    return result;
   }
   return static_cast<EventDisposition>(touch_result_);
 }
diff --git a/ui/events/blink/input_handler_proxy_client.h b/ui/events/blink/input_handler_proxy_client.h
index 42d73d0c..ee17a9f 100644
--- a/ui/events/blink/input_handler_proxy_client.h
+++ b/ui/events/blink/input_handler_proxy_client.h
@@ -60,6 +60,8 @@
   virtual void GenerateScrollBeginAndSendToMainThread(
       const blink::WebGestureEvent& update_event) = 0;
 
+  virtual void SetWhiteListedTouchAction(cc::TouchAction touch_action) = 0;
+
  protected:
   virtual ~InputHandlerProxyClient() {}
 };
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 36f79965..7de08a0 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -319,6 +319,7 @@
                     const gfx::PointF& causal_event_viewport_point));
   void DidStopFlinging() override {}
   void DidAnimateForInput() override {}
+  MOCK_METHOD1(SetWhiteListedTouchAction, void(cc::TouchAction touch_action));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockInputHandlerProxyClient);
@@ -2471,6 +2472,7 @@
                       WebInputEvent::kTimeStampForTesting);
 
   touch.touches_length = 3;
+  touch.touch_start_or_first_touch_move = true;
   touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 0, 0);
   touch.touches[1] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10);
   touch.touches[2] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, -10, 10);
@@ -2543,13 +2545,19 @@
   EXPECT_CALL(mock_input_handler_,
               EventListenerTypeForTouchStartOrMoveAt(testing::_, testing::_))
       .Times(2)
-      .WillRepeatedly(testing::Return(
-          cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
+      .WillRepeatedly(testing::Invoke([](const gfx::Point&,
+                                         cc::TouchAction* touch_action) {
+        *touch_action = cc::kTouchActionPanUp;
+        return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
+      }));
+  EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(cc::kTouchActionPanUp))
+      .WillOnce(testing::Return());
 
   WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers,
                       WebInputEvent::kTimeStampForTesting);
 
   touch.touches_length = 3;
+  touch.touch_start_or_first_touch_move = true;
   touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStateStationary, 0, 0);
   touch.touches[1] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10);
   touch.touches[2] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, -10, 10);
@@ -2568,15 +2576,23 @@
       mock_input_handler_,
       EventListenerTypeForTouchStartOrMoveAt(
           testing::Property(&gfx::Point::x, testing::Eq(0)), testing::_))
-      .WillOnce(testing::Return(
-          cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
+      .WillOnce(testing::Invoke([](const gfx::Point&,
+                                   cc::TouchAction* touch_action) {
+        *touch_action = cc::kTouchActionAuto;
+        return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
+      }));
   EXPECT_CALL(
       mock_input_handler_,
       EventListenerTypeForTouchStartOrMoveAt(
           testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_))
       .WillOnce(
-          testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType::
-                              HANDLER_ON_SCROLLING_LAYER));
+          testing::Invoke([](const gfx::Point&, cc::TouchAction* touch_action) {
+            *touch_action = cc::kTouchActionPanY;
+            return cc::InputHandler::TouchStartOrMoveEventListenerType::
+                HANDLER_ON_SCROLLING_LAYER;
+          }));
+  EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(cc::kTouchActionPanY))
+      .WillOnce(testing::Return());
   // Since the second touch point hits a touch-region, there should be no
   // hit-testing for the third touch point.
 
@@ -2584,6 +2600,7 @@
                       WebInputEvent::kTimeStampForTesting);
 
   touch.touches_length = 3;
+  touch.touch_start_or_first_touch_move = true;
   touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 0, 0);
   touch.touches[1] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10);
   touch.touches[2] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, -10, 10);
@@ -2604,13 +2621,25 @@
       .WillRepeatedly(testing::Return(cc::EventListenerProperties::kPassive));
   EXPECT_CALL(mock_input_handler_,
               EventListenerTypeForTouchStartOrMoveAt(testing::_, testing::_))
-      .WillRepeatedly(testing::Return(
-          cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
+      .Times(3)
+      .WillOnce(testing::Invoke([](const gfx::Point&,
+                                   cc::TouchAction* touch_action) {
+        *touch_action = cc::kTouchActionPanRight;
+        return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
+      }))
+      .WillRepeatedly(testing::Invoke([](const gfx::Point&,
+                                         cc::TouchAction* touch_action) {
+        *touch_action = cc::kTouchActionPanX;
+        return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
+      }));
+  EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(cc::kTouchActionPanRight))
+      .WillOnce(testing::Return());
 
   WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers,
                       WebInputEvent::kTimeStampForTesting);
 
   touch.touches_length = 3;
+  touch.touch_start_or_first_touch_move = true;
   touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 0, 0);
   touch.touches[1] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10);
   touch.touches[2] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, -10, 10);
@@ -2636,17 +2665,24 @@
       .WillOnce(testing::Return(cc::EventListenerProperties::kBlocking));
   EXPECT_CALL(mock_input_handler_,
               EventListenerTypeForTouchStartOrMoveAt(testing::_, testing::_))
-      .WillOnce(testing::Return(
-          cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
+      .WillOnce(testing::Invoke([](const gfx::Point&,
+                                   cc::TouchAction* touch_action) {
+        *touch_action = cc::kTouchActionNone;
+        return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
+      }));
+  EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(cc::kTouchActionNone))
+      .WillOnce(testing::Return());
 
   WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers,
                       WebInputEvent::kTimeStampForTesting);
   touch.touches_length = 1;
   touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 0, 0);
+  touch.touch_start_or_first_touch_move = true;
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(touch));
 
   touch.SetType(WebInputEvent::kTouchMove);
   touch.touches_length = 1;
+  touch.touch_start_or_first_touch_move = false;
   touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10);
   EXPECT_EQ(InputHandlerProxy::DROP_EVENT,
             input_handler_->HandleInputEvent(touch));
@@ -2667,10 +2703,13 @@
               EventListenerTypeForTouchStartOrMoveAt(testing::_, testing::_))
       .WillOnce(testing::Return(
           cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
+  EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(testing::_))
+      .WillOnce(testing::Return());
 
   WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers,
                       WebInputEvent::kTimeStampForTesting);
   touch.touches_length = 1;
+  touch.touch_start_or_first_touch_move = true;
   touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 0, 0);
   EXPECT_EQ(InputHandlerProxy::DID_HANDLE_NON_BLOCKING,
             input_handler_->HandleInputEvent(touch));
@@ -2679,6 +2718,8 @@
               EventListenerTypeForTouchStartOrMoveAt(testing::_, testing::_))
       .WillOnce(testing::Return(
           cc::InputHandler::TouchStartOrMoveEventListenerType::HANDLER));
+  EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(testing::_))
+      .WillOnce(testing::Return());
 
   touch.SetType(WebInputEvent::kTouchMove);
   touch.touches_length = 1;
@@ -3454,6 +3495,7 @@
                             WebInputEvent::kNoModifiers,
                             WebInputEvent::kTimeStampForTesting);
   touch_start.touches_length = 1;
+  touch_start.touch_start_or_first_touch_move = true;
   touch_start.touches[0] =
       CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10);
 
@@ -3476,6 +3518,8 @@
       mock_input_handler_,
       GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove))
       .WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
+  EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(testing::_))
+      .WillOnce(testing::Return());
 
   expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
   EXPECT_EQ(expected_disposition_,
@@ -3506,6 +3550,8 @@
       .WillOnce(
           testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType::
                               HANDLER_ON_SCROLLING_LAYER));
+  EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(testing::_))
+      .WillOnce(testing::Return());
 
   expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
   EXPECT_EQ(expected_disposition_,
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index 435632bb..6767190 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -195,7 +195,9 @@
 }
 
 void GLSurface::SetRelyOnImplicitSync() {
-  NOTIMPLEMENTED();
+  // Some GLSurface derived classes might not implement this workaround while
+  // still being allocated on devices where the workaround is enabled.
+  // It is fine to ignore this call in those cases.
 }
 
 GLSurface* GLSurface::GetCurrent() {
diff --git a/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js b/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js
index af3db5f..8827041 100644
--- a/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js
+++ b/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js
@@ -199,6 +199,9 @@
    * @private
    */
   onIronActivate_: function(event) {
-    this.selectImage_(event.detail.item, true /* activate */);
+    var type = event.detail.item.dataset.type;
+    // When clicking on the 'old' (current) image, do not activate (discard) it.
+    var activate = type != CrPicture.SelectionTypes.OLD;
+    this.selectImage_(event.detail.item, activate);
   },
 });
diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
index ef1106a2..4c2f75e 100644
--- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
+++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
@@ -62,11 +62,6 @@
         padding: 16px;
       }
 
-      :host ::content .button-container .cancel-button {
-        -webkit-margin-end: 8px;
-        color: var(--paper-grey-600);
-      }
-
       :host ::content .footer {
         border-bottom-left-radius: inherit;
         border-bottom-right-radius: inherit;
diff --git a/ui/webui/resources/cr_elements/shared_style_css.html b/ui/webui/resources/cr_elements/shared_style_css.html
index e861984..8968826 100644
--- a/ui/webui/resources/cr_elements/shared_style_css.html
+++ b/ui/webui/resources/cr_elements/shared_style_css.html
@@ -36,6 +36,8 @@
         --paper-button-flat-keyboard-focus: {
           background: rgba(0, 0, 0, .12);
         };
+        -webkit-margin-end: 8px;
+        color: var(--paper-grey-600);
       }
 
       .action-button,
diff --git a/ui/webui/resources/js/webui_resource_test.js b/ui/webui/resources/js/webui_resource_test.js
index 12b3c37..cb0c060 100644
--- a/ui/webui/resources/js/webui_resource_test.js
+++ b/ui/webui/resources/js/webui_resource_test.js
@@ -195,7 +195,6 @@
     endTests(cleanTestRun);
   }
   if (!done) {
-    domAutomationController.setAutomationId(1);
     domAutomationController.send('PENDING');
   }
 }
@@ -208,7 +207,6 @@
  * @param {boolean} success Indicates if the test completed successfully.
  */
 function endTests(success) {
-  domAutomationController.setAutomationId(1);
   domAutomationController.send(success ? 'SUCCESS' : 'FAILURE');
 }