diff --git a/DEPS b/DEPS
index 546fb8a..07393db 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'e353f66bffaddba256e13396900babed11d17038',
+  'v8_revision': '75378bf9b92ebcd66c37f4b621ae4cd1c0c23b5d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -199,7 +199,7 @@
     Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0',
 
   'src/third_party/webgl/src':
-    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f7157c2751220a8f0def9f3f7f6ff37392ac83f0',
+    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '239528772a1362d0e0c2d1cb2f256f19d6e0c1c1',
 
   'src/third_party/webdriver/pylib':
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
diff --git a/android_webview/browser/aw_contents_client_bridge_base.cc b/android_webview/browser/aw_contents_client_bridge_base.cc
index 3e96bed..ee26d4e 100644
--- a/android_webview/browser/aw_contents_client_bridge_base.cc
+++ b/android_webview/browser/aw_contents_client_bridge_base.cc
@@ -4,6 +4,7 @@
 
 #include "android_webview/browser/aw_contents_client_bridge_base.h"
 
+#include "base/memory/ptr_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -44,7 +45,7 @@
     WebContents* web_contents,
     AwContentsClientBridgeBase* handler) {
   web_contents->SetUserData(kAwContentsClientBridgeBase,
-                            new UserData(handler));
+                            base::MakeUnique<UserData>(handler));
 }
 
 // static
diff --git a/android_webview/browser/aw_login_delegate.cc b/android_webview/browser/aw_login_delegate.cc
index 7ce8e70..a088ed9 100644
--- a/android_webview/browser/aw_login_delegate.cc
+++ b/android_webview/browser/aw_login_delegate.cc
@@ -7,6 +7,7 @@
 #include "android_webview/browser/aw_browser_context.h"
 #include "base/android/jni_android.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/supports_user_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
@@ -52,7 +53,7 @@
 
     if (count == NULL) {
       count = new UrlRequestAuthAttemptsData();
-      request->SetUserData(kAuthAttemptsKey, count);
+      request->SetUserData(kAuthAttemptsKey, base::WrapUnique(count));
     }
 
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
diff --git a/android_webview/browser/aw_print_manager.cc b/android_webview/browser/aw_print_manager.cc
index fe86fbf30..41ed748 100644
--- a/android_webview/browser/aw_print_manager.cc
+++ b/android_webview/browser/aw_print_manager.cc
@@ -4,6 +4,7 @@
 
 #include "android_webview/browser/aw_print_manager.h"
 
+#include "base/memory/ptr_util.h"
 #include "components/printing/browser/print_manager_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
@@ -20,7 +21,7 @@
     const PrintManager::PdfWritingDoneCallback& callback) {
   AwPrintManager* print_manager =
       new AwPrintManager(contents, settings, file_descriptor, callback);
-  contents->SetUserData(UserDataKey(), print_manager);
+  contents->SetUserData(UserDataKey(), base::WrapUnique(print_manager));
   return print_manager;
 }
 
diff --git a/android_webview/browser/aw_render_thread_context_provider.cc b/android_webview/browser/aw_render_thread_context_provider.cc
index 563bce6..a3ed6c8d 100644
--- a/android_webview/browser/aw_render_thread_context_provider.cc
+++ b/android_webview/browser/aw_render_thread_context_provider.cc
@@ -6,12 +6,15 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/command_line.h"
 #include "base/lazy_instance.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/output/context_cache_controller.h"
 #include "cc/output/managed_memory_policy.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
 #include "gpu/command_buffer/client/gles2_lib.h"
+#include "gpu/command_buffer/client/gles2_trace_implementation.h"
+#include "gpu/command_buffer/client/gpu_switches.h"
 #include "gpu/command_buffer/client/shared_memory_limits.h"
 #include "gpu/ipc/gl_in_process_context.h"
 #include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h"
@@ -69,6 +72,14 @@
   context_->GetImplementation()->SetLostContextCallback(base::Bind(
       &AwRenderThreadContextProvider::OnLostContext, base::Unretained(this)));
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableGpuClientTracing)) {
+    // This wraps the real GLES2Implementation and we should always use this
+    // instead when it's present.
+    trace_impl_.reset(new gpu::gles2::GLES2TraceImplementation(
+        context_->GetImplementation()));
+  }
+
   cache_controller_.reset(
       new cc::ContextCacheController(context_->GetImplementation(), nullptr));
 }
@@ -98,7 +109,8 @@
 
 gpu::gles2::GLES2Interface* AwRenderThreadContextProvider::ContextGL() {
   DCHECK(main_thread_checker_.CalledOnValidThread());
-
+  if (trace_impl_)
+    return trace_impl_.get();
   return context_->GetImplementation();
 }
 
diff --git a/android_webview/browser/aw_render_thread_context_provider.h b/android_webview/browser/aw_render_thread_context_provider.h
index c146b9a..44301a31 100644
--- a/android_webview/browser/aw_render_thread_context_provider.h
+++ b/android_webview/browser/aw_render_thread_context_provider.h
@@ -22,7 +22,10 @@
 
 namespace gpu {
 class GLInProcessContext;
-}
+namespace gles2 {
+class GLES2TraceImplementation;
+}  // namespace gles2
+}  // namespace gpu
 
 namespace android_webview {
 
@@ -59,6 +62,7 @@
   base::ThreadChecker main_thread_checker_;
 
   std::unique_ptr<gpu::GLInProcessContext> context_;
+  std::unique_ptr<gpu::gles2::GLES2TraceImplementation> trace_impl_;
   sk_sp<class GrContext> gr_context_;
   std::unique_ptr<cc::ContextCacheController> cache_controller_;
 
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc
index b95001f..c1e6c61 100644
--- a/android_webview/browser/browser_view_renderer.cc
+++ b/android_webview/browser/browser_view_renderer.cc
@@ -135,8 +135,9 @@
 
 void BrowserViewRenderer::RegisterWithWebContents(
     content::WebContents* web_contents) {
-  web_contents->SetUserData(kBrowserViewRendererUserDataKey,
-                            new BrowserViewRendererUserData(this));
+  web_contents->SetUserData(
+      kBrowserViewRendererUserDataKey,
+      base::MakeUnique<BrowserViewRendererUserData>(this));
 }
 
 void BrowserViewRenderer::TrimMemory() {
diff --git a/android_webview/browser/net/aw_request_interceptor.cc b/android_webview/browser/net/aw_request_interceptor.cc
index eb85643..6db70fd 100644
--- a/android_webview/browser/net/aw_request_interceptor.cc
+++ b/android_webview/browser/net/aw_request_interceptor.cc
@@ -174,7 +174,7 @@
                                          referrer.spec(), true);
   }
   request->SetUserData(kRequestAlreadyHasJobDataKey,
-                       new base::SupportsUserData::Data());
+                       base::MakeUnique<base::SupportsUserData::Data>());
   return new AndroidStreamReaderURLRequestJob(
       request, network_delegate,
       base::MakeUnique<ShouldInterceptRequestAdaptor>(
diff --git a/android_webview/common/crash_reporter/crash_keys.cc b/android_webview/common/crash_reporter/crash_keys.cc
index 8924532e..52626d2 100644
--- a/android_webview/common/crash_reporter/crash_keys.cc
+++ b/android_webview/common/crash_reporter/crash_keys.cc
@@ -120,13 +120,6 @@
       {"newframe_replicated_origin", kSmallSize},
       {"newframe_oopifs_possible", kSmallSize},
 
-      // Temporary for https://crbug.com/630103.
-      {"origin_mismatch_url", kLargeSize},
-      {"origin_mismatch_origin", kMediumSize},
-      {"origin_mismatch_transition", kSmallSize},
-      {"origin_mismatch_redirects", kSmallSize},
-      {"origin_mismatch_same_page", kSmallSize},
-
       // Temporary for https://crbug.com/612711.
       {"aci_wrong_sp_extension_id", kSmallSize},
 
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index 2cc39b9..6d8e291 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -16,6 +16,7 @@
 import android.os.Build;
 import android.os.Looper;
 import android.os.Process;
+import android.os.StrictMode;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.util.Log;
@@ -247,8 +248,15 @@
         System.loadLibrary("webviewchromium_plat_support");
 
         // Use shared preference to check for package downgrade.
-        mWebViewPrefs = ContextUtils.getApplicationContext().getSharedPreferences(
-                CHROMIUM_PREFS_NAME, Context.MODE_PRIVATE);
+        // Since N, getSharedPreferences creates the preference dir if it doesn't exist,
+        // causing a disk write.
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            mWebViewPrefs = ContextUtils.getApplicationContext().getSharedPreferences(
+                    CHROMIUM_PREFS_NAME, Context.MODE_PRIVATE);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
         int lastVersion = mWebViewPrefs.getInt(VERSION_CODE_PREF, 0);
         int currentVersion = packageInfo.versionCode;
         if (!versionCodeGE(currentVersion, lastVersion)) {
diff --git a/android_webview/native/android_protocol_handler.cc b/android_webview/native/android_protocol_handler.cc
index b90feaad..b59a840 100644
--- a/android_webview/native/android_protocol_handler.cc
+++ b/android_webview/native/android_protocol_handler.cc
@@ -41,7 +41,7 @@
 
 void MarkRequestAsFailed(net::URLRequest* request) {
   request->SetUserData(kPreviouslyFailedKey,
-                       new base::SupportsUserData::Data());
+                       base::MakeUnique<base::SupportsUserData::Data>());
 }
 
 bool HasRequestPreviouslyFailed(net::URLRequest* request) {
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index f357a4a9..184c6878 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -210,7 +210,7 @@
   icon_helper_.reset(new IconHelper(web_contents_.get()));
   icon_helper_->SetListener(this);
   web_contents_->SetUserData(android_webview::kAwContentsUserDataKey,
-                             new AwContentsUserData(this));
+                             base::MakeUnique<AwContentsUserData>(this));
   browser_view_renderer_.RegisterWithWebContents(web_contents_.get());
 
   CompositorID compositor_id;
@@ -1239,8 +1239,9 @@
   AwRendererPriorityManager* manager = static_cast<AwRendererPriorityManager*>(
       rph->GetUserData(kComputedRendererPriorityUserDataKey));
   if (manager == nullptr) {
+    manager = new AwRendererPriorityManager(rph);
     rph->SetUserData(kComputedRendererPriorityUserDataKey,
-                     manager = new AwRendererPriorityManager(rph));
+                     base::WrapUnique(manager));
   }
   return manager;
 }
diff --git a/android_webview/native/aw_settings.cc b/android_webview/native/aw_settings.cc
index 03656fe..e596533 100644
--- a/android_webview/native/aw_settings.cc
+++ b/android_webview/native/aw_settings.cc
@@ -11,6 +11,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/supports_user_data.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
@@ -80,7 +81,7 @@
       renderer_prefs_initialized_(false),
       aw_settings_(env, obj) {
   web_contents->SetUserData(kAwSettingsUserDataKey,
-                            new AwSettingsUserData(this));
+                            base::MakeUnique<AwSettingsUserData>(this));
 }
 
 AwSettings::~AwSettings() {
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
index 85b7148..3c3c362 100644
--- a/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
@@ -2537,7 +2537,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/base/BUILD.gn b/base/BUILD.gn
index aa1225f4..a5efd6e2 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1106,6 +1106,10 @@
     }
   }
 
+  if (!is_mac && is_posix) {
+    sources += [ "memory/shared_memory_handle_posix.cc" ]
+  }
+
   all_dependent_configs = []
   defines = []
   data = []
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
index 1cadb25..9358b719 100644
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -68,8 +68,7 @@
             // already finished.
             if (sDirPathFetchTask.cancel(false)) {
                 // Allow disk access here because we have no other choice.
-                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-                StrictMode.allowThreadDiskWrites();
+                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
                 try {
                     // sDirPathFetchTask did not complete. We have to run the code it was supposed
                     // to be responsible for synchronously on the UI thread.
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc
index 99d2991..89d67af8 100644
--- a/base/memory/discardable_shared_memory.cc
+++ b/base/memory/discardable_shared_memory.cc
@@ -224,9 +224,10 @@
 // Pin pages if supported.
 #if defined(OS_ANDROID)
   SharedMemoryHandle handle = shared_memory_.handle();
-  if (SharedMemory::IsHandleValid(handle)) {
-    if (ashmem_pin_region(
-            handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+  if (handle.IsValid()) {
+    if (ashmem_pin_region(handle.GetHandle(),
+                          AlignToPageSize(sizeof(SharedState)) + offset,
+                          length)) {
       return PURGED;
     }
   }
@@ -251,9 +252,10 @@
 // Unpin pages if supported.
 #if defined(OS_ANDROID)
   SharedMemoryHandle handle = shared_memory_.handle();
-  if (SharedMemory::IsHandleValid(handle)) {
-    if (ashmem_unpin_region(
-            handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+  if (handle.IsValid()) {
+    if (ashmem_unpin_region(handle.GetHandle(),
+                            AlignToPageSize(sizeof(SharedState)) + offset,
+                            length)) {
       DPLOG(ERROR) << "ashmem_unpin_region() failed";
     }
   }
diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h
index 6f78003..d3daa80 100644
--- a/base/memory/shared_memory.h
+++ b/base/memory/shared_memory.h
@@ -307,7 +307,8 @@
 
   int readonly_mapped_file_;
 #elif defined(OS_POSIX)
-  int                mapped_file_;
+  // The OS primitive that backs the shared memory region.
+  SharedMemoryHandle shm_;
   int                readonly_mapped_file_;
 #endif
   size_t             mapped_size_;
diff --git a/base/memory/shared_memory_android.cc b/base/memory/shared_memory_android.cc
index 6f1d9cb..49289f7 100644
--- a/base/memory/shared_memory_android.cc
+++ b/base/memory/shared_memory_android.cc
@@ -18,21 +18,22 @@
 // are closed, the memory buffer will go away.
 
 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
-  DCHECK_EQ(-1, mapped_file_ );
+  DCHECK(!shm_.IsValid());
 
   if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
     return false;
 
   // "name" is just a label in ashmem. It is visible in /proc/pid/maps.
-  mapped_file_ = ashmem_create_region(
+  int fd = ashmem_create_region(
       options.name_deprecated == NULL ? "" : options.name_deprecated->c_str(),
       options.size);
-  if (-1 == mapped_file_) {
+  shm_ = SharedMemoryHandle::ImportHandle(fd);
+  if (!shm_.IsValid()) {
     DLOG(ERROR) << "Shared memory creation failed";
     return false;
   }
 
-  int err = ashmem_set_prot_region(mapped_file_,
+  int err = ashmem_set_prot_region(shm_.GetHandle(),
                                    PROT_READ | PROT_WRITE | PROT_EXEC);
   if (err < 0) {
     DLOG(ERROR) << "Error " << err << " when setting protection of ashmem";
@@ -41,7 +42,7 @@
 
   // Android doesn't appear to have a way to drop write access on an ashmem
   // segment for a single descriptor.  http://crbug.com/320865
-  readonly_mapped_file_ = dup(mapped_file_);
+  readonly_mapped_file_ = dup(shm_.GetHandle());
   if (-1 == readonly_mapped_file_) {
     DPLOG(ERROR) << "dup() failed";
     return false;
diff --git a/base/memory/shared_memory_handle.h b/base/memory/shared_memory_handle.h
index dc33eea..4af796bfa 100644
--- a/base/memory/shared_memory_handle.h
+++ b/base/memory/shared_memory_handle.h
@@ -27,14 +27,10 @@
 
 // SharedMemoryHandle is a platform specific type which represents
 // the underlying OS handle to a shared memory segment.
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
-typedef FileDescriptor SharedMemoryHandle;
-#elif defined(OS_WIN)
 class BASE_EXPORT SharedMemoryHandle {
  public:
   // The default constructor returns an invalid SharedMemoryHandle.
   SharedMemoryHandle();
-  SharedMemoryHandle(HANDLE h, base::ProcessId pid);
 
   // Standard copy constructor. The new instance shares the underlying OS
   // primitives.
@@ -44,46 +40,23 @@
   // OS primitives.
   SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
 
-  // Comparison operators.
-  bool operator==(const SharedMemoryHandle& handle) const;
-  bool operator!=(const SharedMemoryHandle& handle) const;
-
-  // Closes the underlying OS resources.
+  // Closes the underlying OS resource.
+  // The fact that this method needs to be "const" is an artifact of the
+  // original interface for base::SharedMemory::CloseHandle.
+  // TODO(erikchen): This doesn't clear the underlying reference, which seems
+  // like a bug, but is how this class has always worked. Fix this:
+  // https://crbug.com/716072.
   void Close() const;
 
-  // Whether the underlying OS primitive is valid.
-  bool IsValid() const;
-
-  // Whether |pid_| is the same as the current process's id.
-  bool BelongsToCurrentProcess() const;
-
-  // Whether handle_ needs to be duplicated into the destination process when
-  // an instance of this class is passed over a Chrome IPC channel.
-  bool NeedsBrokering() const;
-
+  // Whether ownership of the underlying OS resource is implicitly passed to
+  // the IPC subsystem during serialization.
   void SetOwnershipPassesToIPC(bool ownership_passes);
   bool OwnershipPassesToIPC() const;
 
-  HANDLE GetHandle() const;
-  base::ProcessId GetPID() const;
+  // Whether the underlying OS resource is valid.
+  bool IsValid() const;
 
- private:
-  HANDLE handle_;
-
-  // The process in which |handle_| is valid and can be used. If |handle_| is
-  // invalid, this will be kNullProcessId.
-  base::ProcessId pid_;
-
-  // Whether passing this object as a parameter to an IPC message passes
-  // ownership of |handle_| to the IPC stack. This is meant to mimic the
-  // behavior of the |auto_close| parameter of FileDescriptor. This member only
-  // affects attachment-brokered SharedMemoryHandles.
-  // Defaults to |false|.
-  bool ownership_passes_to_ipc_;
-};
-#else
-class BASE_EXPORT SharedMemoryHandle {
- public:
+#if defined(OS_MACOSX) && !defined(OS_IOS)
   enum Type {
     // The SharedMemoryHandle is backed by a POSIX fd.
     POSIX,
@@ -91,9 +64,6 @@
     MACH,
   };
 
-  // The default constructor returns an invalid SharedMemoryHandle.
-  SharedMemoryHandle();
-
   // Constructs a SharedMemoryHandle backed by the components of a
   // FileDescriptor. The newly created instance has the same ownership semantics
   // as base::FileDescriptor. This typically means that the SharedMemoryHandle
@@ -113,24 +83,12 @@
                      mach_vm_size_t size,
                      base::ProcessId pid);
 
-  // Standard copy constructor. The new instance shares the underlying OS
-  // primitives.
-  SharedMemoryHandle(const SharedMemoryHandle& handle);
-
-  // Standard assignment operator. The updated instance shares the underlying
-  // OS primitives.
-  SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
-
-  // Duplicates the underlying OS resources.
-  SharedMemoryHandle Duplicate() const;
-
   // Comparison operators.
   bool operator==(const SharedMemoryHandle& handle) const;
   bool operator!=(const SharedMemoryHandle& handle) const;
 
-  // Whether the underlying OS primitive is valid. Once the SharedMemoryHandle
-  // is backed by a valid OS primitive, it becomes immutable.
-  bool IsValid() const;
+  // Duplicates the underlying OS resources.
+  SharedMemoryHandle Duplicate() const;
 
   // Exposed so that the SharedMemoryHandle can be transported between
   // processes.
@@ -145,14 +103,49 @@
   // On success, |memory| is an output variable that contains the start of the
   // mapped memory.
   bool MapAt(off_t offset, size_t bytes, void** memory, bool read_only);
+#elif defined(OS_WIN)
+  SharedMemoryHandle(HANDLE h, base::ProcessId pid);
 
-  // Closes the underlying OS primitive.
-  void Close() const;
+  // Comparison operators.
+  bool operator==(const SharedMemoryHandle& handle) const;
+  bool operator!=(const SharedMemoryHandle& handle) const;
 
-  void SetOwnershipPassesToIPC(bool ownership_passes);
-  bool OwnershipPassesToIPC() const;
+  // Whether |pid_| is the same as the current process's id.
+  bool BelongsToCurrentProcess() const;
+
+  // Whether handle_ needs to be duplicated into the destination process when
+  // an instance of this class is passed over a Chrome IPC channel.
+  bool NeedsBrokering() const;
+
+  HANDLE GetHandle() const;
+  base::ProcessId GetPID() const;
+#else
+  // This constructor is deprecated, as it fails to propagate the GUID, which
+  // will be added in the near future.
+  // TODO(rockot): Remove this constructor once Mojo supports GUIDs.
+  // https://crbug.com/713763.
+  explicit SharedMemoryHandle(const base::FileDescriptor& file_descriptor);
+
+  // Creates a SharedMemoryHandle from an |fd| supplied from an external
+  // service.
+  static SharedMemoryHandle ImportHandle(int fd);
+
+  // Returns the underlying OS resource.
+  int GetHandle() const;
+
+  // Takes ownership of the OS resource.
+  void SetHandle(int fd);
+
+  // Invalidates [but doesn't close] the underlying OS resource. This will leak
+  // unless the caller is careful.
+  int Release();
+
+  // Duplicates the underlying OS resource.
+  SharedMemoryHandle Duplicate() const;
+#endif
 
  private:
+#if defined(OS_MACOSX) && !defined(OS_IOS)
   friend class SharedMemory;
 
   // Shared code between copy constructor and operator=.
@@ -183,8 +176,23 @@
       bool ownership_passes_to_ipc_;
     };
   };
-};
+#elif defined(OS_WIN)
+  HANDLE handle_;
+
+  // The process in which |handle_| is valid and can be used. If |handle_| is
+  // invalid, this will be kNullProcessId.
+  base::ProcessId pid_;
+
+  // Whether passing this object as a parameter to an IPC message passes
+  // ownership of |handle_| to the IPC stack. This is meant to mimic the
+  // behavior of the |auto_close| parameter of FileDescriptor. This member only
+  // affects attachment-brokered SharedMemoryHandles.
+  // Defaults to |false|.
+  bool ownership_passes_to_ipc_;
+#else
+  FileDescriptor file_descriptor_;
 #endif
+};
 
 }  // namespace base
 
diff --git a/base/memory/shared_memory_handle_posix.cc b/base/memory/shared_memory_handle_posix.cc
new file mode 100644
index 0000000..3e9a403
--- /dev/null
+++ b/base/memory/shared_memory_handle_posix.cc
@@ -0,0 +1,73 @@
+// 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/memory/shared_memory_handle.h"
+
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace base {
+
+SharedMemoryHandle::SharedMemoryHandle() = default;
+SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle) =
+    default;
+SharedMemoryHandle& SharedMemoryHandle::operator=(
+    const SharedMemoryHandle& handle) = default;
+
+SharedMemoryHandle::SharedMemoryHandle(
+    const base::FileDescriptor& file_descriptor)
+    : file_descriptor_(file_descriptor) {}
+
+// static
+SharedMemoryHandle SharedMemoryHandle::ImportHandle(int fd) {
+  SharedMemoryHandle handle;
+  handle.file_descriptor_.fd = fd;
+  handle.file_descriptor_.auto_close = false;
+  return handle;
+}
+
+int SharedMemoryHandle::GetHandle() const {
+  return file_descriptor_.fd;
+}
+
+void SharedMemoryHandle::SetHandle(int handle) {
+  file_descriptor_.fd = handle;
+}
+
+bool SharedMemoryHandle::IsValid() const {
+  return file_descriptor_.fd >= 0;
+}
+
+void SharedMemoryHandle::Close() const {
+  if (IGNORE_EINTR(close(file_descriptor_.fd)) < 0)
+    PLOG(ERROR) << "close";
+}
+
+int SharedMemoryHandle::Release() {
+  int old_fd = file_descriptor_.fd;
+  file_descriptor_.fd = -1;
+  return old_fd;
+}
+
+SharedMemoryHandle SharedMemoryHandle::Duplicate() const {
+  if (!IsValid())
+    return SharedMemoryHandle();
+
+  int duped_handle = HANDLE_EINTR(dup(file_descriptor_.fd));
+  if (duped_handle < 0)
+    return SharedMemoryHandle();
+  return SharedMemoryHandle(FileDescriptor(duped_handle, true));
+}
+
+void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
+  file_descriptor_.auto_close = ownership_passes;
+}
+
+bool SharedMemoryHandle::OwnershipPassesToIPC() const {
+  return file_descriptor_.auto_close;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_nacl.cc b/base/memory/shared_memory_nacl.cc
index 945fc613..74d3fca 100644
--- a/base/memory/shared_memory_nacl.cc
+++ b/base/memory/shared_memory_nacl.cc
@@ -18,20 +18,14 @@
 namespace base {
 
 SharedMemory::SharedMemory()
-    : mapped_file_(-1),
-      mapped_size_(0),
-      memory_(NULL),
-      read_only_(false),
-      requested_size_(0) {
-}
+    : mapped_size_(0), memory_(NULL), read_only_(false), requested_size_(0) {}
 
 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
-    : mapped_file_(handle.fd),
+    : shm_(handle),
       mapped_size_(0),
       memory_(NULL),
       read_only_(read_only),
-      requested_size_(0) {
-}
+      requested_size_(0) {}
 
 SharedMemory::~SharedMemory() {
   Unmap();
@@ -40,7 +34,7 @@
 
 // static
 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
-  return handle.fd >= 0;
+  return handle.IsValid();
 }
 
 // static
@@ -50,18 +44,14 @@
 
 // static
 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
-  DCHECK_GE(handle.fd, 0);
-  if (close(handle.fd) < 0)
-    DPLOG(ERROR) << "close";
+  DCHECK(handle.IsValid());
+  handle.Close();
 }
 
 // static
 SharedMemoryHandle SharedMemory::DuplicateHandle(
     const SharedMemoryHandle& handle) {
-  int duped_handle = HANDLE_EINTR(dup(handle.fd));
-  if (duped_handle < 0)
-    return base::SharedMemory::NULLHandle();
-  return base::FileDescriptor(duped_handle, true);
+  return handle.Duplicate();
 }
 
 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
@@ -83,7 +73,7 @@
 }
 
 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
-  if (mapped_file_ == -1)
+  if (!shm_.IsValid())
     return false;
 
   if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
@@ -93,7 +83,7 @@
     return false;
 
   memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
-                 MAP_SHARED, mapped_file_, offset);
+                 MAP_SHARED, shm_.GetHandle(), offset);
 
   bool mmap_succeeded = memory_ != MAP_FAILED && memory_ != NULL;
   if (mmap_succeeded) {
@@ -119,22 +109,24 @@
 }
 
 SharedMemoryHandle SharedMemory::handle() const {
-  return FileDescriptor(mapped_file_, false);
+  SharedMemoryHandle handle_copy = shm_;
+  handle_copy.SetOwnershipPassesToIPC(false);
+  return handle_copy;
 }
 
 SharedMemoryHandle SharedMemory::TakeHandle() {
-  FileDescriptor handle(mapped_file_, true);
-  mapped_file_ = -1;
+  SharedMemoryHandle handle_copy = shm_;
+  handle_copy.SetOwnershipPassesToIPC(true);
+  shm_ = SharedMemoryHandle();
   memory_ = nullptr;
   mapped_size_ = 0;
-  return handle;
+  return handle_copy;
 }
 
 void SharedMemory::Close() {
-  if (mapped_file_ > 0) {
-    if (close(mapped_file_) < 0)
-      DPLOG(ERROR) << "close";
-    mapped_file_ = -1;
+  if (shm_.IsValid()) {
+    shm_.Close();
+    shm_ = SharedMemoryHandle();
   }
 }
 
@@ -147,20 +139,14 @@
     // drop permissions.
     return false;
   }
-  const int new_fd = dup(mapped_file_);
-  if (new_fd < 0) {
-    DPLOG(ERROR) << "dup() failed.";
-    return false;
-  }
 
-  new_handle->fd = new_fd;
-  new_handle->auto_close = true;
+  *new_handle = shm_.Duplicate();
 
   if (close_self) {
     Unmap();
     Close();
   }
-  return true;
+  return new_handle->IsValid();
 }
 
 }  // namespace base
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
index 6b1ee5d7..997b3f4 100644
--- a/base/memory/shared_memory_posix.cc
+++ b/base/memory/shared_memory_posix.cc
@@ -33,22 +33,19 @@
 namespace base {
 
 SharedMemory::SharedMemory()
-    : mapped_file_(-1),
-      readonly_mapped_file_(-1),
+    : readonly_mapped_file_(-1),
       mapped_size_(0),
       memory_(NULL),
       read_only_(false),
-      requested_size_(0) {
-}
+      requested_size_(0) {}
 
 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
-    : mapped_file_(handle.fd),
+    : shm_(handle),
       readonly_mapped_file_(-1),
       mapped_size_(0),
       memory_(NULL),
       read_only_(read_only),
-      requested_size_(0) {
-}
+      requested_size_(0) {}
 
 SharedMemory::~SharedMemory() {
   Unmap();
@@ -57,7 +54,7 @@
 
 // static
 bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
-  return handle.fd >= 0;
+  return handle.IsValid();
 }
 
 // static
@@ -67,9 +64,8 @@
 
 // static
 void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
-  DCHECK_GE(handle.fd, 0);
-  if (IGNORE_EINTR(close(handle.fd)) < 0)
-    DPLOG(ERROR) << "close";
+  DCHECK(handle.IsValid());
+  handle.Close();
 }
 
 // static
@@ -80,16 +76,13 @@
 // static
 SharedMemoryHandle SharedMemory::DuplicateHandle(
     const SharedMemoryHandle& handle) {
-  int duped_handle = HANDLE_EINTR(dup(handle.fd));
-  if (duped_handle < 0)
-    return base::SharedMemory::NULLHandle();
-  return base::FileDescriptor(duped_handle, true);
+  return handle.Duplicate();
 }
 
 // static
 int SharedMemory::GetFdFromSharedMemoryHandle(
     const SharedMemoryHandle& handle) {
-  return handle.fd;
+  return handle.GetHandle();
 }
 
 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
@@ -102,7 +95,7 @@
     const SharedMemoryHandle& handle,
     size_t* size) {
   struct stat st;
-  if (fstat(handle.fd, &st) != 0)
+  if (fstat(handle.GetHandle(), &st) != 0)
     return false;
   if (st.st_size < 0)
     return false;
@@ -117,7 +110,7 @@
 // In case we want to delete it later, it may be useful to save the value
 // of mem_filename after FilePathForMemoryName().
 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
-  DCHECK_EQ(-1, mapped_file_);
+  DCHECK(!shm_.IsValid());
   if (options.size == 0) return false;
 
   if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
@@ -224,8 +217,11 @@
     return false;
   }
 
-  return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_,
-                        &readonly_mapped_file_);
+  int mapped_file = -1;
+  bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd),
+                               &mapped_file, &readonly_mapped_file_);
+  shm_ = SharedMemoryHandle::ImportHandle(mapped_file);
+  return result;
 }
 
 // Our current implementation of shmem is with mmap()ing of files.
@@ -257,13 +253,16 @@
     DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
     return false;
   }
-  return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_,
-                        &readonly_mapped_file_);
+  int mapped_file = -1;
+  bool result = PrepareMapFile(std::move(fp), std::move(readonly_fd),
+                               &mapped_file, &readonly_mapped_file_);
+  shm_ = SharedMemoryHandle::ImportHandle(mapped_file);
+  return result;
 }
 #endif  // !defined(OS_ANDROID)
 
 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
-  if (mapped_file_ == -1)
+  if (!shm_.IsValid())
     return false;
 
   if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
@@ -277,7 +276,7 @@
   // ashmem-determined size.
   if (bytes == 0) {
     DCHECK_EQ(0, offset);
-    int ashmem_bytes = ashmem_get_size_region(mapped_file_);
+    int ashmem_bytes = ashmem_get_size_region(shm_.GetHandle());
     if (ashmem_bytes < 0)
       return false;
     bytes = ashmem_bytes;
@@ -285,7 +284,7 @@
 #endif
 
   memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
-                 MAP_SHARED, mapped_file_, offset);
+                 MAP_SHARED, shm_.GetHandle(), offset);
 
   bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL;
   if (mmap_succeeded) {
@@ -313,22 +312,22 @@
 }
 
 SharedMemoryHandle SharedMemory::handle() const {
-  return FileDescriptor(mapped_file_, false);
+  return shm_;
 }
 
 SharedMemoryHandle SharedMemory::TakeHandle() {
-  FileDescriptor handle(mapped_file_, true);
-  mapped_file_ = -1;
+  SharedMemoryHandle handle_copy = shm_;
+  handle_copy.SetOwnershipPassesToIPC(true);
+  shm_ = SharedMemoryHandle();
   memory_ = nullptr;
   mapped_size_ = 0;
-  return handle;
+  return handle_copy;
 }
 
 void SharedMemory::Close() {
-  if (mapped_file_ > 0) {
-    if (IGNORE_EINTR(close(mapped_file_)) < 0)
-      PLOG(ERROR) << "close";
-    mapped_file_ = -1;
+  if (shm_.IsValid()) {
+    shm_.Close();
+    shm_ = SharedMemoryHandle();
   }
   if (readonly_mapped_file_ > 0) {
     if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0)
@@ -369,7 +368,7 @@
   int handle_to_dup = -1;
   switch(share_mode) {
     case SHARE_CURRENT_MODE:
-      handle_to_dup = mapped_file_;
+      handle_to_dup = shm_.GetHandle();
       break;
     case SHARE_READONLY:
       // We could imagine re-opening the file from /dev/fd, but that can't make
@@ -389,8 +388,8 @@
     return false;
   }
 
-  new_handle->fd = new_fd;
-  new_handle->auto_close = true;
+  new_handle->SetHandle(new_fd);
+  new_handle->SetOwnershipPassesToIPC(true);
 
   if (close_self) {
     Unmap();
@@ -411,7 +410,8 @@
   // crbug.com/604726#c41.
   base::ThreadRestrictions::ScopedAllowIO allow_io;
   struct stat file_stat;
-  if (HANDLE_EINTR(::fstat(static_cast<int>(handle().fd), &file_stat)) != 0)
+  if (HANDLE_EINTR(
+          ::fstat(static_cast<int>(handle().GetHandle()), &file_stat)) != 0)
     return false;
   id->first = file_stat.st_dev;
   id->second = file_stat.st_ino;
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc
index d87fad0..2da99e8 100644
--- a/base/memory/shared_memory_unittest.cc
+++ b/base/memory/shared_memory_unittest.cc
@@ -221,7 +221,7 @@
   memory.Close();
 
   EXPECT_EQ(ptr, memory.memory());
-  EXPECT_EQ(SharedMemory::NULLHandle(), memory.handle());
+  EXPECT_TRUE(!memory.handle().IsValid());
 
   for (size_t i = 0; i < kDataSize; i++) {
     EXPECT_EQ('G', ptr[i]);
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index 6b38d55..7a668547 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -1156,11 +1156,7 @@
   if (fd == -1)
     return false;
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
   SharedMemoryHandle shm_handle(FileDescriptor(fd, true));
-#else
-  SharedMemoryHandle shm_handle(fd, true);
-#endif
 
   bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
   DCHECK(result);
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 489ef078..7bc43b6 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -6,7 +6,6 @@
 import("//build/config/chrome_build.gni")
 import("//build/config/chromecast_build.gni")
 import("//build/config/compiler/compiler.gni")
-import("//build/config/nacl/config.gni")
 import("//build/toolchain/cc_wrapper.gni")
 import("//build/toolchain/toolchain.gni")
 import("//build_overrides/build.gni")
@@ -23,6 +22,12 @@
 if (is_ios) {
   import("//build/config/ios/ios_sdk.gni")
 }
+if (is_nacl) {
+  # To keep NaCl variables out of builds that don't include NaCl, all
+  # variables defined in nacl/config.gni referenced here should be protected by
+  # is_nacl conditions.
+  import("//build/config/nacl/config.gni")
+}
 
 declare_args() {
   # Default to warnings as errors for default workflow, where we catch
@@ -1492,7 +1497,7 @@
 # optimization and link-time code generation which is very expensive and should
 # be used sparingly.
 config("optimize_max") {
-  if (is_nacl_irt) {
+  if (is_nacl && is_nacl_irt) {
     # The NaCl IRT is a special case and always wants its own config.
     # Various components do:
     #   if (!is_debug) {
@@ -1539,7 +1544,7 @@
 # TODO(crbug.com/621335) - rework how all of these configs are related
 # so that we don't need this disclaimer.
 config("optimize_speed") {
-  if (is_nacl_irt) {
+  if (is_nacl && is_nacl_irt) {
     # The NaCl IRT is a special case and always wants its own config.
     # Various components do:
     #   if (!is_debug) {
@@ -1585,7 +1590,7 @@
 # The default optimization applied to all targets. This will be equivalent to
 # either "optimize" or "no_optimize", depending on the build flags.
 config("default_optimization") {
-  if (is_nacl_irt) {
+  if (is_nacl && is_nacl_irt) {
     # The NaCl IRT is a special case and always wants its own config.
     # It gets optimized the same way regardless of the type of build.
     configs = [ "//build/config/nacl:irt_optimize" ]
diff --git a/cc/benchmarks/rasterize_and_record_benchmark.cc b/cc/benchmarks/rasterize_and_record_benchmark.cc
index 6314fdef..c19dac1e 100644
--- a/cc/benchmarks/rasterize_and_record_benchmark.cc
+++ b/cc/benchmarks/rasterize_and_record_benchmark.cc
@@ -139,6 +139,7 @@
     return;
 
   ContentLayerClient* painter = layer->client();
+  RecordingSource recording_source;
 
   for (int mode_index = 0; mode_index < RecordingSource::RECORDING_MODE_COUNT;
        mode_index++) {
@@ -158,11 +159,8 @@
 
       do {
         display_list = painter->PaintContentsToDisplayList(painting_control);
-        if (display_list->ShouldBeAnalyzedForSolidColor()) {
-          gfx::Size layer_size = layer->paint_properties().bounds;
-          skia::AnalysisCanvas canvas(layer_size.width(), layer_size.height());
-          display_list->Raster(&canvas, nullptr, gfx::Rect(layer_size), 1.f);
-        }
+        recording_source.UpdateDisplayItemList(
+            display_list, painter->GetApproximateUnsharedMemoryUsage());
 
         if (memory_used) {
           // Verify we are recording the same thing each time.
diff --git a/chrome/android/java/res/layout/bottom_sheet_bottom_nav.xml b/chrome/android/java/res/layout/bottom_sheet_bottom_nav.xml
index ea08da3d..ee27426 100644
--- a/chrome/android/java/res/layout/bottom_sheet_bottom_nav.xml
+++ b/chrome/android/java/res/layout/bottom_sheet_bottom_nav.xml
@@ -10,7 +10,7 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/bottom_nav_height"
     android:layout_gravity="start|bottom"
-    android:background="@color/appbar_background"
+    android:background="@color/default_primary_color"
     app:menu="@menu/bottom_sheet_nav_menu"
     app:itemIconTint="@color/bottom_nav_tint"
     app:itemTextColor="@color/bottom_nav_tint"
diff --git a/chrome/android/java/res/layout/selectable_list_layout.xml b/chrome/android/java/res/layout/selectable_list_layout.xml
index 55eef22..de9117d 100644
--- a/chrome/android/java/res/layout/selectable_list_layout.xml
+++ b/chrome/android/java/res/layout/selectable_list_layout.xml
@@ -9,7 +9,7 @@
         android:inflatedId="@+id/action_bar"
         android:layout_width="match_parent"
         android:layout_height="?attr/actionBarSize"
-        android:background="@color/appbar_background" />
+        android:background="@color/default_primary_color" />
 
     <FrameLayout
         android:id="@+id/list_content"
diff --git a/chrome/android/java/res/values-sw720dp-v17/colors.xml b/chrome/android/java/res/values-sw720dp-v17/colors.xml
deleted file mode 100644
index f13876d0..0000000
--- a/chrome/android/java/res/values-sw720dp-v17/colors.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<resources>
-    <!-- Colors common to secondary activities like the BookmarkActivity and the DownloadManagerUi -->
-    <color name="appbar_background">@android:color/white</color>
-</resources>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index d6ba3ab..b50eaf43 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -179,9 +179,6 @@
     <color name="webapp_url_bar_bg">#fafafa</color>
     <color name="webapp_url_bar_separator">#e1e1e1</color>
 
-    <!-- Colors common to secondary activities like the BookmarkActivity and the DownloadManagerUi -->
-    <color name="appbar_background">@color/default_primary_color</color>
-
     <!-- Bookmark UI colors -->
     <color name="bookmark_detail_text">#212121</color>
     <color name="bookmark_detail_section">#7C7B79</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index a9ecaf1..953b54f8 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -201,8 +201,9 @@
     <!-- Full Screen Dimensions -->
     <!-- Should match toolbar_height_no_shadow -->
     <dimen name="control_container_height">56dp</dimen>
-    <dimen name="bottom_control_container_height">64dp</dimen>
-    <dimen name="bottom_toolbar_top_margin">8dp</dimen>
+    <dimen name="bottom_control_container_height">56dp</dimen>
+    <dimen name="bottom_toolbar_top_margin">2dp</dimen>
+    <dimen name="bottom_toolbar_url_bar_top_margin">4dp</dimen>
     <dimen name="custom_tabs_control_container_height">56dp</dimen>
     <dimen name="webapp_control_container_height">22dp</dimen>
 
@@ -245,10 +246,10 @@
     <dimen name="toolbar_shadow_height">8dp</dimen>
     <dimen name="toolbar_progress_bar_height">2dp</dimen>
     <dimen name="toolbar_button_width">48dp</dimen>
-    <dimen name="toolbar_handle_height">4dp</dimen>
-    <dimen name="toolbar_handle_width">40dp</dimen>
-    <dimen name="toolbar_handle_corner_radius">2dp</dimen>
-    <dimen name="toolbar_handle_margin_top">14dp</dimen>
+    <dimen name="toolbar_handle_height">3dp</dimen>
+    <dimen name="toolbar_handle_width">24dp</dimen>
+    <dimen name="toolbar_handle_corner_radius">1.5dp</dimen>
+    <dimen name="toolbar_handle_margin_top">12dp</dimen>
 
     <dimen name="toolbar_edge_padding">8dp</dimen>
     <dimen name="location_bar_google_g_width">24dp</dimen>
@@ -256,6 +257,7 @@
     <!-- location_bar_google_g_width + 2 * location_bar_google_g_margin -->
     <dimen name="location_bar_google_g_container_width">40dp</dimen>
     <dimen name="location_bar_vertical_margin">8dp</dimen>
+    <dimen name="bottom_location_bar_vertical_margin">9dp</dimen>
     <dimen name="location_bar_url_text_size">16sp</dimen>
     <dimen name="location_bar_incognito_badge_padding">7dp</dimen>
     <dimen name="location_bar_icon_width">32dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/LauncherShortcutActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/LauncherShortcutActivity.java
index e010017..0c9e1a3a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/LauncherShortcutActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/LauncherShortcutActivity.java
@@ -65,8 +65,7 @@
         }
 
         // This system call is often modified by OEMs and not actionable. http://crbug.com/619646.
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             startActivity(newIntent);
         } finally {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
index 7de210cf..00c02a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -278,7 +278,7 @@
 
     private boolean isAnchorAtBottom(View anchorView, Rect visibleDisplayFrame) {
         anchorView.getLocationOnScreen(mTempLocation);
-        return (mTempLocation[1] + anchorView.getHeight()) == visibleDisplayFrame.bottom;
+        return (mTempLocation[1] + anchorView.getHeight()) >= visibleDisplayFrame.bottom;
     }
 
     private void setPopupOffset(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
index 3a5360ff..191c0f48 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
@@ -84,8 +84,7 @@
     // TODO(crbug.com/635567): Fix this properly.
     @SuppressLint("DefaultLocale")
     static SharedPreferences getWidgetState(Context context, int widgetId) {
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             return context.getSharedPreferences(
                     String.format("widgetState-%d", widgetId),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchQuickActionControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchQuickActionControl.java
index 327d5d6..abc03f1188 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchQuickActionControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchQuickActionControl.java
@@ -215,8 +215,7 @@
 
         // On KitKat, calling PackageManager#resolveActivity() causes disk reads and writes.
         // Temporarily allow this while resolving the intent.
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             possibleDefaultActivity = packageManager.resolveActivity(mIntent, 0);
         } finally {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 9f65633..ddfdb2a1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -133,19 +133,19 @@
     private static class PageLoadMetricsObserver implements PageLoadMetrics.Observer {
         private final CustomTabsConnection mConnection;
         private final CustomTabsSessionToken mSession;
-        private final Tab mTab;
+        private final WebContents mWebContents;
 
         public PageLoadMetricsObserver(CustomTabsConnection connection,
                 CustomTabsSessionToken session, Tab tab) {
             mConnection = connection;
             mSession = session;
-            mTab = tab;
+            mWebContents = tab.getWebContents();
         }
 
         @Override
         public void onFirstContentfulPaint(
                 WebContents webContents, long navigationStartTick, long firstContentfulPaintMs) {
-            if (webContents != mTab.getWebContents()) return;
+            if (webContents != mWebContents) return;
 
             mConnection.notifyPageLoadMetric(mSession, PageLoadMetrics.FIRST_CONTENTFUL_PAINT,
                     navigationStartTick, firstContentfulPaintMs);
@@ -154,7 +154,7 @@
         @Override
         public void onLoadEventStart(
                 WebContents webContents, long navigationStartTick, long loadEventStartMs) {
-            if (webContents != mTab.getWebContents()) return;
+            if (webContents != mWebContents) return;
 
             mConnection.notifyPageLoadMetric(mSession, PageLoadMetrics.LOAD_EVENT_START,
                     navigationStartTick, loadEventStartMs);
@@ -1019,8 +1019,7 @@
         intent.putExtra(ChromeLauncherActivity.EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT, false);
 
         boolean willChromeHandleIntent = getIntentDataProvider().isOpenedByChrome();
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             willChromeHandleIntent |= ExternalNavigationDelegateImpl
                     .willChromeHandleIntent(intent, true);
@@ -1046,7 +1045,6 @@
             tab.detachAndStartReparenting(intent, startActivityOptions, finalizeCallback);
         } else {
             // Temporarily allowing disk access while fixing. TODO: http://crbug.com/581860
-            StrictMode.allowThreadDiskReads();
             StrictMode.allowThreadDiskWrites();
             try {
                 if (mIntentDataProvider.isInfoPage()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicy.java
index 2c787ba..9ff5333f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicy.java
@@ -77,8 +77,7 @@
             if (sStateDirectory == null) {
                 sStateDirectory = new File(
                         TabPersistentStore.getOrCreateBaseStateDirectory(), SAVED_STATE_DIRECTORY);
-                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-                StrictMode.allowThreadDiskWrites();
+                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
                 try {
                     if (!sStateDirectory.exists() && !sStateDirectory.mkdirs()) {
                         Log.e(TAG, "Failed to create state folder: " + sStateDirectory);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index 7a09378..a466b92 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -418,8 +418,7 @@
         }
 
         // This system call is often modified by OEMs and not actionable. http://crbug.com/619646.
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             startActivity(newIntent);
         } catch (SecurityException ex) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
index 37f89e62..9cbad92 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
@@ -262,8 +262,7 @@
      */
     protected int checkGooglePlayServicesAvailable(final Context context) {
         // Temporarily allowing disk access. TODO: Fix. See http://crbug.com/577190
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             long time = SystemClock.elapsedRealtime();
             int isAvailable =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
index 2d9a8352..9610a5e9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -343,7 +343,6 @@
         boolean activityWasLaunched;
         // Only touches disk on Kitkat. See http://crbug.com/617725 for more context.
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
-        StrictMode.allowThreadDiskReads();
         try {
             forcePdfViewerAsIntentHandlerIfNeeded(intent);
             if (proxy) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
index bda7caa..e407791 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
@@ -105,8 +105,7 @@
         String formattedTime = "";
 
         // Temporarily allowing disk access. TODO: Fix. See http://crbug.com/577185
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             long time = SystemClock.elapsedRealtime();
             formattedTime = DateFormat.getTimeFormat(mContext).format(new Date());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ManageSpaceActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ManageSpaceActivity.java
index 5fe5f3a..601394a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ManageSpaceActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ManageSpaceActivity.java
@@ -120,8 +120,7 @@
 
         // Allow reading/writing to disk to check whether the last attempt was successful before
         // kicking off the browser process initialization.
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             String productVersion = AboutChromePreferences.getApplicationVersion(
                     this, ChromeVersionInfo.getProductVersion());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
index 6875659..28a43075 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -29,6 +29,7 @@
 import org.chromium.chrome.browser.widget.FadingShadowView;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController;
+import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver;
 import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
 
@@ -48,6 +49,8 @@
     private final ContextMenuManager mContextMenuManager;
     private final SuggestionsUiDelegateImpl mSuggestionsManager;
     private final TileGroup.Delegate mTileGroupDelegate;
+    private final BottomSheet mBottomSheet;
+    private final BottomSheetObserver mBottomSheetObserver;
 
     public SuggestionsBottomSheetContent(final ChromeActivity activity, final BottomSheet sheet,
             TabModelSelector tabModelSelector, SnackbarManager snackbarManager) {
@@ -86,7 +89,7 @@
         mRecyclerView.init(uiConfig, mContextMenuManager, adapter);
 
         final SuggestionsSource suggestionsSource = mSuggestionsManager.getSuggestionsSource();
-        activity.getBottomSheet().addObserver(new EmptyBottomSheetObserver() {
+        mBottomSheetObserver = new EmptyBottomSheetObserver() {
             @Override
             public void onSheetOpened() {
                 mRecyclerView.scrollToPosition(0);
@@ -96,7 +99,9 @@
                 adapter.refreshSuggestions();
                 suggestionsSource.onNtpInitialized();
             }
-        });
+        };
+        mBottomSheet = activity.getBottomSheet();
+        mBottomSheet.addObserver(mBottomSheetObserver);
         adapter.refreshSuggestions();
         suggestionsSource.onNtpInitialized();
 
@@ -150,6 +155,7 @@
 
     @Override
     public void destroy() {
+        mBottomSheet.removeObserver(mBottomSheetObserver);
         mSuggestionsManager.onDestroy();
         mTileGroupDelegate.destroy();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
index 9290e217..5849cee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
@@ -134,8 +134,7 @@
             if (sStateDirectory == null) {
                 sStateDirectory = new File(
                         TabPersistentStore.getOrCreateBaseStateDirectory(), SAVED_STATE_DIRECTORY);
-                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-                StrictMode.allowThreadDiskWrites();
+                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
                 try {
                     if (!sStateDirectory.exists() && !sStateDirectory.mkdirs()) {
                         Log.e(TAG, "Failed to create state folder: " + sStateDirectory);
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 26b0d8cb..dc8f17e 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
@@ -117,6 +117,8 @@
                 context.getResources(), R.drawable.toolbar_handle_dark);
         mHandleLight = ApiCompatibilityUtils.getDrawable(
                 context.getResources(), R.drawable.toolbar_handle_light);
+        mLocationBarVerticalMargin =
+                getResources().getDimensionPixelOffset(R.dimen.bottom_location_bar_vertical_margin);
     }
 
     /**
@@ -208,6 +210,11 @@
     public void onFinishInflate() {
         super.onFinishInflate();
 
+        // Add extra top margin to the URL bar to compensate for the change to location bar's
+        // vertical margin in the constructor.
+        ((MarginLayoutParams) mLocationBar.findViewById(R.id.url_bar).getLayoutParams()).topMargin =
+                getResources().getDimensionPixelSize(R.dimen.bottom_toolbar_url_bar_top_margin);
+
         // Exclude the location bar from the list of browsing mode views. This prevents its
         // visibility from changing during transitions.
         mBrowsingModeViews.remove(mLocationBar);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 73b52ad..65fe01f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -225,8 +225,8 @@
     private final Point mNtpSearchBoxTranslation = new Point();
 
     private final int mToolbarSidePadding;
-    private final int mLocationBarVerticalMargin;
     private final int mLocationBarBackgroundCornerRadius;
+    protected int mLocationBarVerticalMargin;
 
     private ValueAnimator mBrandColorTransitionAnimation;
     private boolean mBrandColorTransitionActive;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApiImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApiImpl.java
index e73a1f3..e356018 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApiImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApiImpl.java
@@ -82,10 +82,9 @@
     public Boolean isDaydreamCurrentViewer() {
         DaydreamApi daydreamApi = DaydreamApi.create(mContext);
         if (daydreamApi == null) return false;
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
         // If this is the first time any app reads the daydream config file, daydream may create its
         // config directory... crbug.com/686104
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         int type = GvrApi.ViewerType.CARDBOARD;
         try {
             type = daydreamApi.getCurrentViewerType();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index 95ffc65..a1b06a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -208,8 +208,7 @@
         File tabFile = new File(activityDirectory, tabFileName);
 
         // Temporarily allowing disk access while fixing. TODO: http://crbug.com/525781
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             long time = SystemClock.elapsedRealtime();
             TabState.saveState(tabFile, getActivityTab().getState(), false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java
index 77575eb6..fd0edbde 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java
@@ -160,8 +160,7 @@
      */
     File getWebappDirectory(Context context, String webappId) {
         // Temporarily allowing disk access while fixing. TODO: http://crbug.com/525781
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             long time = SystemClock.elapsedRealtime();
             File webappDirectory = new File(getBaseWebappDirectory(context), webappId);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 19bde1f..9d99441 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -1065,6 +1065,14 @@
     }
 
     /**
+     * Removes an observer to the bottom sheet.
+     * @param observer The observer to remove.
+     */
+    public void removeObserver(BottomSheetObserver observer) {
+        mObservers.removeObserver(observer);
+    }
+
+    /**
      * Gets the target state of the sheet based on the sheet's height and velocity.
      * @param sheetHeight The current height of the sheet.
      * @param yVelocity The current Y velocity of the sheet. This is only used for determining the
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
index 2e77e27..f77b0144 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
@@ -245,7 +245,7 @@
 
     private void updateVisuals(boolean isIncognitoTabModelSelected) {
         setBackgroundResource(isIncognitoTabModelSelected ? R.color.incognito_primary_color
-                                                          : R.color.appbar_background);
+                                                          : R.color.default_primary_color);
 
         ColorStateList tint = ApiCompatibilityUtils.getColorStateList(getResources(),
                 isIncognitoTabModelSelected ? R.color.bottom_nav_tint_incognito
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
index d94bab3..add383a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
@@ -177,8 +177,9 @@
 
         if (mDrawerLayout != null) initActionBarDrawerToggle();
 
-        normalBackgroundColorResId = normalBackgroundColorResId != null ? normalBackgroundColorResId
-                : R.color.appbar_background;
+        normalBackgroundColorResId = normalBackgroundColorResId != null
+                ? normalBackgroundColorResId
+                : R.color.default_primary_color;
         mNormalBackgroundColor =
                 ApiCompatibilityUtils.getColor(getResources(), normalBackgroundColorResId);
         setBackgroundColor(mNormalBackgroundColor);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SearchGeolocationDisclosureInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SearchGeolocationDisclosureInfoBarTest.java
index 103f8a7..248e48d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SearchGeolocationDisclosureInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SearchGeolocationDisclosureInfoBarTest.java
@@ -23,7 +23,7 @@
 /** Tests for the SearchGeolocationDisclosureInfobar. */
 public class SearchGeolocationDisclosureInfoBarTest
         extends ChromeActivityTestCaseBase<ChromeActivity> {
-    private static final String SEARCH_PAGE = "/chrome/test/data/empty.html";
+    private static final String SEARCH_PAGE = "/chrome/test/data/android/google.html";
     private static final String ENABLE_NEW_DISCLOSURE_FEATURE =
             "enable-features=ConsistentOmniboxGeolocation";
     private static final String DISABLE_NEW_DISCLOSURE_FEATURE =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java
index beaa0cec..512e239 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java
@@ -134,8 +134,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mOldPolicy = StrictMode.allowThreadDiskReads();
-                StrictMode.allowThreadDiskWrites();
+                mOldPolicy = StrictMode.allowThreadDiskWrites();
             }
         });
         mTestServer = EmbeddedTestServer.createAndStartServer(getInstrumentation().getContext());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java
index 124bae6..ba254ed 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java
@@ -81,8 +81,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mOldPolicy = StrictMode.allowThreadDiskReads();
-                StrictMode.allowThreadDiskWrites();
+                mOldPolicy = StrictMode.allowThreadDiskWrites();
             }
         });
         mTestServer = EmbeddedTestServer.createAndStartServer(getInstrumentation().getContext());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/shape_detection/ShapeDetectionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/shape_detection/ShapeDetectionTest.java
index dfbf24d9..3f64ccb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/shape_detection/ShapeDetectionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/shape_detection/ShapeDetectionTest.java
@@ -91,8 +91,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mOldPolicy = StrictMode.allowThreadDiskReads();
-                StrictMode.allowThreadDiskWrites();
+                mOldPolicy = StrictMode.allowThreadDiskWrites();
             }
         });
     }
diff --git a/chrome/android/webapk/libs/client/BUILD.gn b/chrome/android/webapk/libs/client/BUILD.gn
index 8d22e4e..6ca8f1ee6 100644
--- a/chrome/android/webapk/libs/client/BUILD.gn
+++ b/chrome/android/webapk/libs/client/BUILD.gn
@@ -30,7 +30,7 @@
   ]
   defines = [
     "CURRENT_RUNTIME_DEX_VERSION_VALUE=$runtime_library_version",
-    "CURRENT_SHELL_APK_VERSION_VALUE=$shell_apk_version",
+    "CURRENT_SHELL_APK_VERSION_VALUE=$expected_shell_apk_version",
   ]
 }
 
diff --git a/chrome/android/webapk/shell_apk/BUILD.gn b/chrome/android/webapk/shell_apk/BUILD.gn
index 14ba1a8..2a9adc89 100644
--- a/chrome/android/webapk/shell_apk/BUILD.gn
+++ b/chrome/android/webapk/shell_apk/BUILD.gn
@@ -54,7 +54,7 @@
   output = shell_apk_manifest
 
   variables = [
-    "shell_apk_version=$shell_apk_version",
+    "shell_apk_version=$template_shell_apk_version",
     "manifest_package=org.chromium.webapk",
     "runtime_host=$webapk_runtime_host",
     "start_url=$webapk_start_url",
@@ -81,7 +81,7 @@
   output = shell_apk_manifest_javatests
 
   variables = [
-    "shell_apk_version=$shell_apk_version",
+    "shell_apk_version=$template_shell_apk_version",
     "manifest_package=org.chromium.webapk.test",
     "runtime_host=org.chromium.chrome",
     "start_url=https://www.template.com/home_page",
diff --git a/chrome/android/webapk/shell_apk/shell_apk_version.gni b/chrome/android/webapk/shell_apk/shell_apk_version.gni
index 46d2071..c4d66ff 100644
--- a/chrome/android/webapk/shell_apk/shell_apk_version.gni
+++ b/chrome/android/webapk/shell_apk/shell_apk_version.gni
@@ -3,5 +3,13 @@
 # found in the LICENSE file.
 
 # Must be incremented whenever code in //chrome/android/webapk/shell_apk
-# (including AndroidManifest.xml) is updated.
-shell_apk_version = 3
+# (including AndroidManifest.xml) is updated. This version should be incremented
+# prior to uploading a new ShellAPK to the WebAPK Minting Server.
+# Does not affect Chrome.apk
+template_shell_apk_version = 4
+
+# The ShellAPK version expected by Chrome. Chrome will try to update the WebAPK
+# if the WebAPK's ShellAPK version is less than |expected_shell_apk_version|.
+# The version should be incremented after a new ShellAPK has been uploaded to
+# the WebAPK Minting Server.
+expected_shell_apk_version = 3
diff --git a/chrome/app/chrome_crash_reporter_client_win.cc b/chrome/app/chrome_crash_reporter_client_win.cc
index 8898a38..a0343ab 100644
--- a/chrome/app/chrome_crash_reporter_client_win.cc
+++ b/chrome/app/chrome_crash_reporter_client_win.cc
@@ -183,13 +183,6 @@
       {"newframe_replicated_origin", kSmallSize},
       {"newframe_oopifs_possible", kSmallSize},
 
-      // Temporary for https://crbug.com/630103.
-      {"origin_mismatch_url", crash_keys::kLargeSize},
-      {"origin_mismatch_origin", crash_keys::kMediumSize},
-      {"origin_mismatch_transition", crash_keys::kSmallSize},
-      {"origin_mismatch_redirects", crash_keys::kSmallSize},
-      {"origin_mismatch_same_page", crash_keys::kSmallSize},
-
       // Temporary for https://crbug.com/612711.
       {"aci_wrong_sp_extension_id", kSmallSize},
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 03684e01..69cf741 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3539,13 +3539,10 @@
 
       <!-- Extension/App disabled notification -->
       <message name="IDS_EXTENSION_DISABLED_ERROR_LABEL" desc="Text displayed when an extension was disabled due to a new upgrade requiring an explicit permission check from the user.">
-        The newest version of the extension "<ph name="EXTENSION_NAME">$1<ex>Flashblock</ex></ph>" requires more permissions, so it has been disabled.
-      </message>
-      <message name="IDS_APP_DISABLED_ERROR_LABEL" desc="Text displayed when an app was disabled due to a new upgrade requiring an explicit permission check from the user.">
-        The newest version of the app "<ph name="APP_NAME">$1<ex>Pandora</ex></ph>" requires more permissions, so it has been disabled.
+        To re-enable it, accept the new permissions:
       </message>
       <message name="IDS_EXTENSION_DISABLED_ERROR_TITLE" desc="Title of the notification that an extension or app was disabled due to a new upgrade requiring an explicit permission check from the user.">
-        <ph name="EXTENSION_NAME">$1<ex>Adblock</ex></ph> requires new permissions
+        <ph name="EXTENSION_NAME">$1<ex>Adblock</ex></ph> is disabled
       </message>
       <message name="IDS_EXTENSION_IS_BLACKLISTED" desc="Text displayed in an infobar when an extension is blacklisted and prevented from being installed.">
         Google has flagged "<ph name="EXTENSION_NAME">$1<ex>Google Talk</ex></ph>" as malicious and installation has been prevented.
@@ -4723,6 +4720,9 @@
       <message name="IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON" desc="Text for the allow button on the extension permissions prompt">
         Allow
       </message>
+      <message name="IDS_EXTENSION_PROMPT_PERMISSIONS_ACCEPT_BUTTON" desc="Text for the accept permissions button on the extension permissions prompt">
+        Accept permissions
+      </message>
       <message name="IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON" desc="Text for the deny button on the extension permissions prompt">
         Deny
       </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 8b342cb..c959c658 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -952,6 +952,8 @@
     "predictors/autocomplete_action_predictor_factory.h",
     "predictors/autocomplete_action_predictor_table.cc",
     "predictors/autocomplete_action_predictor_table.h",
+    "predictors/glowplug_key_value_table.cc",
+    "predictors/glowplug_key_value_table.h",
     "predictors/predictor_database.cc",
     "predictors/predictor_database.h",
     "predictors/predictor_database_factory.cc",
diff --git a/chrome/browser/android/vr_shell/textures/ui_texture.cc b/chrome/browser/android/vr_shell/textures/ui_texture.cc
index 3b074323..b5edf11c 100644
--- a/chrome/browser/android/vr_shell/textures/ui_texture.cc
+++ b/chrome/browser/android/vr_shell/textures/ui_texture.cc
@@ -44,6 +44,10 @@
   gfx::Font default_font(kDefaultFontFamily, size);
   std::vector<gfx::Font> fonts{default_font};
 
+  std::set<wchar_t> characters;
+  for (base::i18n::UTF16CharIterator it(&text); !it.end(); it.Advance()) {
+    characters.insert(it.get());
+  }
   // TODO(acondor): Obtain fallback fonts with gfx::GetFallbackFonts
   // (which is not implemented for android yet) in order to avoid
   // querying per character.
@@ -51,10 +55,10 @@
   sk_sp<SkFontMgr> font_mgr(SkFontMgr::RefDefault());
   std::set<std::string> names;
   // TODO(acondor): Query BrowserProcess to obtain the application locale.
-  for (base::i18n::UTF16CharIterator it(&text); !it.end(); it.Advance()) {
+  for (wchar_t character : characters) {
     sk_sp<SkTypeface> tf(font_mgr->matchFamilyStyleCharacter(
-        default_font.GetFontName().c_str(), SkFontStyle(), nullptr, 0,
-        it.get()));
+        kDefaultFontFamily, SkFontStyle(), nullptr, 0, character));
+
     // TODO(acondor): How should we handle no matching font?
     if (!tf)
       continue;
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
index 2edc30d4..11e93b83 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
@@ -141,7 +141,7 @@
 }
 
 bool EPKPChallengeKeyBase::IsExtensionWhitelisted() const {
-  if (chromeos::ProfileHelper::IsSigninProfile(profile_)) {
+  if (!chromeos::ProfileHelper::Get()->GetUserByProfile(profile_)) {
     // Only allow remote attestation for apps that were force-installed on the
     // login/signin screen.
     // TODO(drcrash): Use a separate device-wide policy for the API.
@@ -340,7 +340,7 @@
   }
 
   // Check whether the user is managed unless the signin profile is used.
-  if (!chromeos::ProfileHelper::IsSigninProfile(profile_) &&
+  if (chromeos::ProfileHelper::Get()->GetUserByProfile(profile_) &&
       !IsUserAffiliated()) {
     callback_.Run(false, kUserNotManaged);
     return;
@@ -443,6 +443,8 @@
     "Key registration failed.";
 const char EPKPChallengeUserKey::kUserPolicyDisabledError[] =
     "Remote attestation is not enabled for your account.";
+const char EPKPChallengeUserKey::kUserKeyNotAvailable[] =
+    "User keys cannot be challenged in this profile.";
 
 const char EPKPChallengeUserKey::kKeyName[] = "attest-ent-user";
 
@@ -477,6 +479,12 @@
   profile_ = ChromeExtensionFunctionDetails(caller.get()).GetProfile();
   extension_ = scoped_refptr<const Extension>(caller->extension());
 
+  // Check if user keys are available in this profile.
+  if (!chromeos::ProfileHelper::Get()->GetUserByProfile(profile_)) {
+    callback_.Run(false, EPKPChallengeUserKey::kUserKeyNotAvailable);
+    return;
+  }
+
   // Check if RA is enabled in the user policy.
   if (!IsRemoteAttestationEnabledForUser()) {
     callback_.Run(false, kUserPolicyDisabledError);
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
index 1092ba4..7aae829 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
@@ -209,6 +209,7 @@
  public:
   static const char kGetCertificateFailedError[];
   static const char kKeyRegistrationFailedError[];
+  static const char kUserKeyNotAvailable[];
   static const char kUserPolicyDisabledError[];
 
   EPKPChallengeUserKey();
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
index 01494f6..c487110 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
@@ -409,8 +409,9 @@
  protected:
   static const char kArgs[];
 
-  EPKPChallengeUserKeyTest()
-      : EPKPChallengeKeyTestBase(ProfileType::USER_PROFILE),
+  explicit EPKPChallengeUserKeyTest(
+      ProfileType profile_type = ProfileType::USER_PROFILE)
+      : EPKPChallengeKeyTestBase(profile_type),
         impl_(&mock_cryptohome_client_,
               &mock_async_method_caller_,
               &mock_attestation_flow_,
@@ -423,8 +424,10 @@
   void SetUp() override {
     EPKPChallengeKeyTestBase::SetUp();
 
-    // Set the user preferences.
-    prefs_->SetBoolean(prefs::kAttestationEnabled, true);
+    if (profile_type_ == ProfileType::USER_PROFILE) {
+      // Set the user preferences.
+      prefs_->SetBoolean(prefs::kAttestationEnabled, true);
+    }
   }
 
   // Returns an error string for the given code.
@@ -578,6 +581,19 @@
             utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
 }
 
+class EPKPChallengeUserKeySigninProfileTest : public EPKPChallengeUserKeyTest {
+ protected:
+  EPKPChallengeUserKeySigninProfileTest()
+      : EPKPChallengeUserKeyTest(ProfileType::SIGNIN_PROFILE) {}
+};
+
+TEST_F(EPKPChallengeUserKeySigninProfileTest, UserKeyNotAvailable) {
+  settings_helper_.SetBoolean(chromeos::kDeviceAttestationEnabled, false);
+
+  EXPECT_EQ(EPKPChallengeUserKey::kUserKeyNotAvailable,
+            utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
+}
+
 class EPKPChallengeMachineKeyUnmanagedUserTest
     : public EPKPChallengeMachineKeyTest {
  protected:
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc
index 8f66dccf..a940570 100644
--- a/chrome/browser/extensions/extension_disabled_ui.cc
+++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -52,10 +52,6 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia_operations.h"
 
-using extensions::Extension;
-using extensions::PermissionMessage;
-using extensions::PermissionMessages;
-
 namespace {
 
 static const int kIconSize = extension_misc::EXTENSION_ICON_SMALL;
@@ -64,11 +60,12 @@
 
 // ExtensionDisabledGlobalError -----------------------------------------------
 
-class ExtensionDisabledGlobalError
-    : public GlobalErrorWithStandardBubble,
-      public content::NotificationObserver,
-      public extensions::ExtensionUninstallDialog::Delegate,
-      public extensions::ExtensionRegistryObserver {
+namespace extensions {
+
+class ExtensionDisabledGlobalError : public GlobalErrorWithStandardBubble,
+                                     public content::NotificationObserver,
+                                     public ExtensionUninstallDialog::Delegate,
+                                     public ExtensionRegistryObserver {
  public:
   ExtensionDisabledGlobalError(ExtensionService* service,
                                const Extension* extension,
@@ -106,7 +103,7 @@
   // ExtensionRegistryObserver:
   void OnExtensionLoaded(content::BrowserContext* browser_context,
                          const Extension* extension) override;
-  void OnShutdown(extensions::ExtensionRegistry* registry) override;
+  void OnShutdown(ExtensionRegistry* registry) override;
 
   void RemoveGlobalError();
 
@@ -124,15 +121,15 @@
   };
   UserResponse user_response_;
 
-  std::unique_ptr<extensions::ExtensionUninstallDialog> uninstall_dialog_;
+  std::unique_ptr<ExtensionUninstallDialog> uninstall_dialog_;
 
   // Helper to get menu command ID assigned for this extension's error.
-  extensions::ExtensionInstallErrorMenuItemIdProvider id_provider_;
+  ExtensionInstallErrorMenuItemIdProvider id_provider_;
 
   content::NotificationRegistrar registrar_;
 
-  ScopedObserver<extensions::ExtensionRegistry,
-                 extensions::ExtensionRegistryObserver> registry_observer_;
+  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
+      registry_observer_;
 };
 
 // TODO(yoz): create error at startup for disabled extensions.
@@ -148,18 +145,13 @@
       user_response_(IGNORED),
       registry_observer_(this) {
   if (icon_.IsEmpty()) {
-    icon_ = gfx::Image(
-        gfx::ImageSkiaOperations::CreateResizedImage(
-            extension_->is_app() ?
-                extensions::util::GetDefaultAppIcon() :
-                extensions::util::GetDefaultExtensionIcon(),
-            skia::ImageOperations::RESIZE_BEST,
-            gfx::Size(kIconSize, kIconSize)));
+    icon_ = gfx::Image(gfx::ImageSkiaOperations::CreateResizedImage(
+        extension_->is_app() ? util::GetDefaultAppIcon()
+                             : util::GetDefaultExtensionIcon(),
+        skia::ImageOperations::RESIZE_BEST, gfx::Size(kIconSize, kIconSize)));
   }
-  registry_observer_.Add(
-      extensions::ExtensionRegistry::Get(service->profile()));
-  registrar_.Add(this,
-                 extensions::NOTIFICATION_EXTENSION_REMOVED,
+  registry_observer_.Add(ExtensionRegistry::Get(service->profile()));
+  registrar_.Add(this, NOTIFICATION_EXTENSION_REMOVED,
                  content::Source<Profile>(service->profile()));
 }
 
@@ -215,8 +207,15 @@
 std::vector<base::string16>
 ExtensionDisabledGlobalError::GetBubbleViewMessages() {
   std::vector<base::string16> messages;
+
+  std::unique_ptr<const PermissionSet> granted_permissions =
+      ExtensionPrefs::Get(service_->GetBrowserContext())
+          ->GetGrantedPermissions(extension_->id());
+
   PermissionMessages permission_warnings =
-      extension_->permissions_data()->GetPermissionMessages();
+      extension_->permissions_data()->GetNewPermissionMessages(
+          *granted_permissions);
+
   if (is_remote_install_) {
     if (!permission_warnings.empty())
       messages.push_back(
@@ -224,12 +223,8 @@
   } else {
     // TODO(treib): If NeedCustodianApprovalForPermissionIncrease, add an extra
     // message for supervised users. crbug.com/461261
-    messages.push_back(l10n_util::GetStringFUTF16(
-        extension_->is_app() ? IDS_APP_DISABLED_ERROR_LABEL
-                             : IDS_EXTENSION_DISABLED_ERROR_LABEL,
-        base::UTF8ToUTF16(extension_->name())));
-    messages.push_back(l10n_util::GetStringUTF16(
-        IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO));
+    messages.push_back(
+        l10n_util::GetStringUTF16(IDS_EXTENSION_DISABLED_ERROR_LABEL));
   }
   for (const PermissionMessage& msg : permission_warnings) {
     messages.push_back(l10n_util::GetStringFUTF16(IDS_EXTENSION_PERMISSION_LINE,
@@ -239,8 +234,7 @@
 }
 
 base::string16 ExtensionDisabledGlobalError::GetBubbleViewAcceptButtonLabel() {
-  if (extensions::util::IsExtensionSupervised(extension_,
-                                              service_->profile())) {
+  if (util::IsExtensionSupervised(extension_, service_->profile())) {
     // TODO(treib): Probably use a new string here once we get UX design.
     // For now, just use "OK". crbug.com/461261
     return l10n_util::GetStringUTF16(IDS_OK);
@@ -251,18 +245,18 @@
             ? IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_APP
             : IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_EXTENSION);
   }
-  return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON);
+  return l10n_util::GetStringUTF16(
+      IDS_EXTENSION_PROMPT_PERMISSIONS_ACCEPT_BUTTON);
 }
 
 base::string16 ExtensionDisabledGlobalError::GetBubbleViewCancelButtonLabel() {
-  if (extensions::util::IsExtensionSupervised(extension_,
-                                              service_->profile())) {
+  if (util::IsExtensionSupervised(extension_, service_->profile())) {
     // The supervised user can't approve the update, and hence there is no
     // "cancel" button. Return an empty string such that the "cancel" button
     // is not shown in the dialog.
     return base::string16();
   }
-  return l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL);
+  return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON);
 }
 
 void ExtensionDisabledGlobalError::OnBubbleViewDidClose(Browser* browser) {
@@ -283,8 +277,7 @@
 
 void ExtensionDisabledGlobalError::BubbleViewAcceptButtonPressed(
     Browser* browser) {
-  if (extensions::util::IsExtensionSupervised(extension_,
-                                              service_->profile())) {
+  if (util::IsExtensionSupervised(extension_, service_->profile())) {
     return;
   }
   user_response_ = REENABLE;
@@ -300,19 +293,17 @@
   // For custodian-installed extensions, this button should not exist because
   // there is only an "OK" button.
   // Supervised users may never remove custodian-installed extensions.
-  DCHECK(!extensions::util::IsExtensionSupervised(extension_,
-                                                  service_->profile()));
-  uninstall_dialog_.reset(extensions::ExtensionUninstallDialog::Create(
+  DCHECK(!util::IsExtensionSupervised(extension_, service_->profile()));
+  uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
       service_->profile(), browser->window()->GetNativeWindow(), this));
   user_response_ = UNINSTALL;
   // Delay showing the uninstall dialog, so that this function returns
   // immediately, to close the bubble properly. See crbug.com/121544.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&extensions::ExtensionUninstallDialog::ConfirmUninstall,
-                     uninstall_dialog_->AsWeakPtr(), extension_,
-                     extensions::UNINSTALL_REASON_EXTENSION_DISABLED,
-                     extensions::UNINSTALL_SOURCE_PERMISSIONS_INCREASE));
+      FROM_HERE, base::Bind(&ExtensionUninstallDialog::ConfirmUninstall,
+                            uninstall_dialog_->AsWeakPtr(), extension_,
+                            UNINSTALL_REASON_EXTENSION_DISABLED,
+                            UNINSTALL_SOURCE_PERMISSIONS_INCREASE));
 }
 
 bool ExtensionDisabledGlobalError::ShouldCloseOnDeactivate() const {
@@ -341,7 +332,7 @@
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
   // The error is invalidated if the extension has been loaded or removed.
-  DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_REMOVED, type);
+  DCHECK_EQ(NOTIFICATION_EXTENSION_REMOVED, type);
   const Extension* extension = content::Details<const Extension>(details).ptr();
   if (extension != extension_)
     return;
@@ -356,9 +347,8 @@
   RemoveGlobalError();
 }
 
-void ExtensionDisabledGlobalError::OnShutdown(
-    extensions::ExtensionRegistry* registry) {
-  DCHECK_EQ(extensions::ExtensionRegistry::Get(service_->profile()), registry);
+void ExtensionDisabledGlobalError::OnShutdown(ExtensionRegistry* registry) {
+  DCHECK_EQ(ExtensionRegistry::Get(service_->profile()), registry);
   registry_observer_.RemoveAll();
 }
 
@@ -375,8 +365,6 @@
 
 // Globals --------------------------------------------------------------------
 
-namespace extensions {
-
 void AddExtensionDisabledErrorWithIcon(base::WeakPtr<ExtensionService> service,
                                        const std::string& extension_id,
                                        bool is_remote_install,
@@ -394,7 +382,7 @@
 void AddExtensionDisabledError(ExtensionService* service,
                                const Extension* extension,
                                bool is_remote_install) {
-  extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
+  ExtensionResource image = IconsInfo::GetIconResource(
       extension, kIconSize, ExtensionIconSet::MATCH_BIGGER);
   gfx::Size size(kIconSize, kIconSize);
   ImageLoader::Get(service->profile())
diff --git a/chrome/browser/predictors/glowplug_key_value_table.cc b/chrome/browser/predictors/glowplug_key_value_table.cc
new file mode 100644
index 0000000..c5656b17
--- /dev/null
+++ b/chrome/browser/predictors/glowplug_key_value_table.cc
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/predictors/glowplug_key_value_table.h"
+
+#include "third_party/protobuf/src/google/protobuf/message_lite.h"
+
+namespace predictors {
+
+namespace internal {
+
+void BindDataToStatement(const std::string& key,
+                         const google::protobuf::MessageLite& data,
+                         sql::Statement* statement) {
+  int size = data.ByteSize();
+  DCHECK_GT(size, 0);
+  std::vector<char> proto_buffer(size);
+  data.SerializeToArray(&proto_buffer[0], size);
+
+  statement->BindString(0, key);
+  statement->BindBlob(1, &proto_buffer[0], size);
+}
+
+std::string GetSelectAllSql(const std::string& table_name) {
+  return base::StringPrintf("SELECT * FROM %s", table_name.c_str());
+}
+std::string GetReplaceSql(const std::string& table_name) {
+  return base::StringPrintf("REPLACE INTO %s (key, proto) VALUES (?,?)",
+                            table_name.c_str());
+}
+std::string GetDeleteSql(const std::string& table_name) {
+  return base::StringPrintf("DELETE FROM %s WHERE key=?", table_name.c_str());
+}
+std::string GetDeleteAllSql(const std::string& table_name) {
+  return base::StringPrintf("DELETE FROM %s", table_name.c_str());
+}
+
+}  // namespace internal
+}  // namespace predictors
diff --git a/chrome/browser/predictors/glowplug_key_value_table.h b/chrome/browser/predictors/glowplug_key_value_table.h
new file mode 100644
index 0000000..afa7ffa
--- /dev/null
+++ b/chrome/browser/predictors/glowplug_key_value_table.h
@@ -0,0 +1,102 @@
+// 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_PREDICTORS_GLOWPLUG_KEY_VALUE_TABLE_H_
+#define CHROME_BROWSER_PREDICTORS_GLOWPLUG_KEY_VALUE_TABLE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/strings/stringprintf.h"
+#include "sql/statement.h"
+
+namespace google {
+namespace protobuf {
+class MessageLite;
+}
+}
+
+namespace predictors {
+
+namespace internal {
+
+void BindDataToStatement(const std::string& key,
+                         const google::protobuf::MessageLite& data,
+                         sql::Statement* statement);
+
+std::string GetSelectAllSql(const std::string& table_name);
+std::string GetReplaceSql(const std::string& table_name);
+std::string GetDeleteSql(const std::string& table_name);
+std::string GetDeleteAllSql(const std::string& table_name);
+
+}  // namespace internal
+
+template <typename T>
+class GlowplugKeyValueTable {
+ public:
+  GlowplugKeyValueTable(const std::string& table_name, sql::Connection* db);
+  // Virtual for testing.
+  virtual void GetAllData(std::map<std::string, T>* data_map) const;
+  virtual void UpdateData(const std::string& key, const T& data);
+  virtual void DeleteData(const std::vector<std::string>& keys);
+  virtual void DeleteAllData();
+
+ private:
+  const std::string table_name_;
+  sql::Connection* db_;
+
+  DISALLOW_COPY_AND_ASSIGN(GlowplugKeyValueTable);
+};
+
+template <typename T>
+GlowplugKeyValueTable<T>::GlowplugKeyValueTable(const std::string& table_name,
+                                                sql::Connection* db)
+    : table_name_(table_name), db_(db) {}
+
+template <typename T>
+void GlowplugKeyValueTable<T>::GetAllData(
+    std::map<std::string, T>* data_map) const {
+  sql::Statement reader(db_->GetUniqueStatement(
+      ::predictors::internal::GetSelectAllSql(table_name_).c_str()));
+  while (reader.Step()) {
+    auto it = data_map->emplace(reader.ColumnString(0), T()).first;
+    int size = reader.ColumnByteLength(1);
+    const void* blob = reader.ColumnBlob(1);
+    DCHECK(blob);
+    it->second.ParseFromArray(blob, size);
+  }
+}
+
+template <typename T>
+void GlowplugKeyValueTable<T>::UpdateData(const std::string& key,
+                                          const T& data) {
+  sql::Statement inserter(db_->GetUniqueStatement(
+      ::predictors::internal::GetReplaceSql(table_name_).c_str()));
+  ::predictors::internal::BindDataToStatement(key, data, &inserter);
+  inserter.Run();
+}
+
+template <typename T>
+void GlowplugKeyValueTable<T>::DeleteData(
+    const std::vector<std::string>& keys) {
+  auto statement = db_->GetUniqueStatement(
+      ::predictors::internal::GetDeleteSql(table_name_).c_str());
+  for (const auto& key : keys) {
+    sql::Statement deleter(statement);
+    deleter.BindString(0, key);
+    deleter.Run();
+  }
+}
+
+template <typename T>
+void GlowplugKeyValueTable<T>::DeleteAllData() {
+  sql::Statement deleter(db_->GetUniqueStatement(
+      ::predictors::internal::GetDeleteAllSql(table_name_).c_str()));
+  deleter.Run();
+}
+
+}  // namespace predictors
+
+#endif  // CHROME_BROWSER_PREDICTORS_GLOWPLUG_KEY_VALUE_TABLE_H_
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
index 1dc5d74..cb6f4cdb 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
@@ -36,38 +36,6 @@
     "key TEXT, "
     "proto BLOB, "
     "PRIMARY KEY(key))";
-const char kInsertProtoStatementTemplate[] =
-    "INSERT INTO %s (key, proto) VALUES (?,?)";
-const char kDeleteProtoStatementTemplate[] = "DELETE FROM %s WHERE key=?";
-const char kSelectAllStatementTemplate[] = "SELECT * FROM %s";
-
-void BindProtoDataToStatement(const std::string& key,
-                              const MessageLite& data,
-                              sql::Statement* statement) {
-  int size = data.ByteSize();
-  DCHECK_GT(size, 0);
-  std::vector<char> proto_buffer(size);
-  data.SerializeToArray(&proto_buffer[0], size);
-
-  statement->BindString(0, key);
-  statement->BindBlob(1, &proto_buffer[0], size);
-}
-
-bool StepAndInitializeProtoData(sql::Statement* statement,
-                                std::string* key,
-                                MessageLite* data) {
-  if (!statement->Step())
-    return false;
-
-  *key = statement->ColumnString(0);
-
-  int size = statement->ColumnByteLength(1);
-  const void* blob = statement->ColumnBlob(1);
-  DCHECK(blob);
-  data->ParseFromArray(blob, size);
-
-  return true;
-}
 
 predictors::ResourceData::ResourceType PrecacheResourceTypeToResourceType(
     precache::PrecacheResource::Type resource_type) {
@@ -192,12 +160,12 @@
   manifest_map->clear();
   origin_data_map->clear();
 
-  GetAllResourceDataHelper(PREFETCH_KEY_TYPE_URL, url_data_map);
-  GetAllResourceDataHelper(PREFETCH_KEY_TYPE_HOST, host_data_map);
-  GetAllRedirectDataHelper(PREFETCH_KEY_TYPE_URL, url_redirect_data_map);
-  GetAllRedirectDataHelper(PREFETCH_KEY_TYPE_HOST, host_redirect_data_map);
-  GetAllManifestDataHelper(manifest_map);
-  GetAllOriginDataHelper(origin_data_map);
+  url_resource_table_->GetAllData(url_data_map);
+  host_resource_table_->GetAllData(host_data_map);
+  url_redirect_table_->GetAllData(url_redirect_data_map);
+  host_redirect_table_->GetAllData(host_redirect_data_map);
+  manifest_table_->GetAllData(manifest_map);
+  origin_table_->GetAllData(origin_data_map);
 }
 
 void ResourcePrefetchPredictorTables::UpdateResourceData(
@@ -208,8 +176,10 @@
   if (CantAccessDatabase())
     return;
 
-  UpdateDataHelper(key_type, PrefetchDataType::RESOURCE, data.primary_key(),
-                   data);
+  if (key_type == PREFETCH_KEY_TYPE_URL)
+    url_resource_table_->UpdateData(data.primary_key(), data);
+  else
+    host_resource_table_->UpdateData(data.primary_key(), data);
 }
 
 void ResourcePrefetchPredictorTables::UpdateRedirectData(
@@ -220,8 +190,10 @@
   if (CantAccessDatabase())
     return;
 
-  UpdateDataHelper(key_type, PrefetchDataType::REDIRECT, data.primary_key(),
-                   data);
+  if (key_type == PREFETCH_KEY_TYPE_URL)
+    url_redirect_table_->UpdateData(data.primary_key(), data);
+  else
+    host_redirect_table_->UpdateData(data.primary_key(), data);
 }
 
 void ResourcePrefetchPredictorTables::UpdateManifestData(
@@ -232,8 +204,7 @@
   if (CantAccessDatabase())
     return;
 
-  UpdateDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::MANIFEST, host,
-                   manifest_data);
+  manifest_table_->UpdateData(host, manifest_data);
 }
 
 void ResourcePrefetchPredictorTables::UpdateOriginData(
@@ -243,8 +214,7 @@
   if (CantAccessDatabase())
     return;
 
-  UpdateDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::ORIGIN,
-                   origin_data.host(), origin_data);
+  origin_table_->UpdateData(origin_data.host(), origin_data);
 }
 
 void ResourcePrefetchPredictorTables::DeleteResourceData(
@@ -257,9 +227,9 @@
   DCHECK(!urls.empty() || !hosts.empty());
 
   if (!urls.empty())
-    DeleteDataHelper(PREFETCH_KEY_TYPE_URL, PrefetchDataType::RESOURCE, urls);
+    url_resource_table_->DeleteData(urls);
   if (!hosts.empty())
-    DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::RESOURCE, hosts);
+    host_resource_table_->DeleteData(hosts);
 }
 
 void ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint(
@@ -269,7 +239,10 @@
   if (CantAccessDatabase())
     return;
 
-  DeleteDataHelper(key_type, PrefetchDataType::RESOURCE, {key});
+  if (key_type == PREFETCH_KEY_TYPE_URL)
+    url_resource_table_->DeleteData({key});
+  else
+    host_resource_table_->DeleteData({key});
 }
 
 void ResourcePrefetchPredictorTables::DeleteRedirectData(
@@ -282,9 +255,9 @@
   DCHECK(!urls.empty() || !hosts.empty());
 
   if (!urls.empty())
-    DeleteDataHelper(PREFETCH_KEY_TYPE_URL, PrefetchDataType::REDIRECT, urls);
+    url_redirect_table_->DeleteData(urls);
   if (!hosts.empty())
-    DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::REDIRECT, hosts);
+    host_redirect_table_->DeleteData(hosts);
 }
 
 void ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint(
@@ -294,7 +267,10 @@
   if (CantAccessDatabase())
     return;
 
-  DeleteDataHelper(key_type, PrefetchDataType::REDIRECT, {key});
+  if (key_type == PREFETCH_KEY_TYPE_URL)
+    url_redirect_table_->DeleteData({key});
+  else
+    host_redirect_table_->DeleteData({key});
 }
 
 void ResourcePrefetchPredictorTables::DeleteManifestData(
@@ -303,7 +279,7 @@
   if (CantAccessDatabase())
     return;
 
-  DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::MANIFEST, hosts);
+  manifest_table_->DeleteData(hosts);
 }
 
 void ResourcePrefetchPredictorTables::DeleteOriginData(
@@ -312,7 +288,7 @@
   if (CantAccessDatabase())
     return;
 
-  DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::ORIGIN, hosts);
+  origin_table_->DeleteData(hosts);
 }
 
 void ResourcePrefetchPredictorTables::DeleteAllData() {
@@ -320,117 +296,17 @@
   if (CantAccessDatabase())
     return;
 
-  sql::Statement deleter;
-  for (const char* table_name :
-       {kUrlResourceTableName, kUrlRedirectTableName, kHostResourceTableName,
-        kHostRedirectTableName, kManifestTableName}) {
-    deleter.Assign(DB()->GetUniqueStatement(
-        base::StringPrintf("DELETE FROM %s", table_name).c_str()));
-    deleter.Run();
-  }
+  url_resource_table_->DeleteAllData();
+  url_redirect_table_->DeleteAllData();
+  host_resource_table_->DeleteAllData();
+  host_redirect_table_->DeleteAllData();
+  manifest_table_->DeleteAllData();
+  origin_table_->DeleteAllData();
 }
 
-ResourcePrefetchPredictorTables::ResourcePrefetchPredictorTables() {}
+ResourcePrefetchPredictorTables::ResourcePrefetchPredictorTables() = default;
 
-ResourcePrefetchPredictorTables::~ResourcePrefetchPredictorTables() {}
-
-void ResourcePrefetchPredictorTables::GetAllResourceDataHelper(
-    PrefetchKeyType key_type,
-    PrefetchDataMap* data_map) {
-  // Read the resources table and organize it per primary key.
-  const char* table_name = GetTableName(key_type, PrefetchDataType::RESOURCE);
-  sql::Statement resource_reader(DB()->GetUniqueStatement(
-      base::StringPrintf(kSelectAllStatementTemplate, table_name).c_str()));
-
-  PrefetchData data;
-  std::string key;
-  while (StepAndInitializeProtoData(&resource_reader, &key, &data)) {
-    data_map->insert({key, data});
-    DCHECK_EQ(data.primary_key(), key);
-  }
-}
-
-void ResourcePrefetchPredictorTables::GetAllRedirectDataHelper(
-    PrefetchKeyType key_type,
-    RedirectDataMap* data_map) {
-  // Read the redirects table and organize it per primary key.
-  const char* table_name = GetTableName(key_type, PrefetchDataType::REDIRECT);
-  sql::Statement redirect_reader(DB()->GetUniqueStatement(
-      base::StringPrintf(kSelectAllStatementTemplate, table_name).c_str()));
-
-  RedirectData data;
-  std::string key;
-  while (StepAndInitializeProtoData(&redirect_reader, &key, &data)) {
-    data_map->insert({key, data});
-    DCHECK_EQ(data.primary_key(), key);
-  }
-}
-
-void ResourcePrefetchPredictorTables::GetAllManifestDataHelper(
-    ManifestDataMap* manifest_map) {
-  sql::Statement manifest_reader(DB()->GetUniqueStatement(
-      base::StringPrintf(kSelectAllStatementTemplate, kManifestTableName)
-          .c_str()));
-
-  precache::PrecacheManifest data;
-  std::string key;
-  while (StepAndInitializeProtoData(&manifest_reader, &key, &data)) {
-    manifest_map->insert({key, data});
-  }
-}
-
-void ResourcePrefetchPredictorTables::GetAllOriginDataHelper(
-    OriginDataMap* origin_map) {
-  sql::Statement reader(DB()->GetUniqueStatement(
-      base::StringPrintf(kSelectAllStatementTemplate, kOriginTableName)
-          .c_str()));
-
-  OriginData data;
-  std::string key;
-  while (StepAndInitializeProtoData(&reader, &key, &data)) {
-    origin_map->insert({key, data});
-    DCHECK_EQ(data.host(), key);
-  }
-}
-
-void ResourcePrefetchPredictorTables::UpdateDataHelper(
-    PrefetchKeyType key_type,
-    PrefetchDataType data_type,
-    const std::string& key,
-    const MessageLite& data) {
-  DB()->BeginTransaction();
-
-  // Delete the older data from the table.
-  std::unique_ptr<sql::Statement> deleter(
-      GetTableUpdateStatement(key_type, data_type, TableOperationType::REMOVE));
-  deleter->BindString(0, key);
-  bool success = deleter->Run();
-
-  if (success) {
-    // Add the new data to the table.
-    std::unique_ptr<sql::Statement> inserter(GetTableUpdateStatement(
-        key_type, data_type, TableOperationType::INSERT));
-    BindProtoDataToStatement(key, data, inserter.get());
-    success = inserter->Run();
-  }
-
-  if (!success)
-    DB()->RollbackTransaction();
-  else
-    DB()->CommitTransaction();
-}
-
-void ResourcePrefetchPredictorTables::DeleteDataHelper(
-    PrefetchKeyType key_type,
-    PrefetchDataType data_type,
-    const std::vector<std::string>& keys) {
-  for (const std::string& key : keys) {
-    std::unique_ptr<sql::Statement> deleter(GetTableUpdateStatement(
-        key_type, data_type, TableOperationType::REMOVE));
-    deleter->BindString(0, key);
-    deleter->Run();
-  }
-}
+ResourcePrefetchPredictorTables::~ResourcePrefetchPredictorTables() = default;
 
 // static
 float ResourcePrefetchPredictorTables::ComputeResourceScore(
@@ -586,6 +462,24 @@
 
   if (!success)
     ResetDB();
+
+  if (success) {
+    url_resource_table_ = base::MakeUnique<GlowplugKeyValueTable<PrefetchData>>(
+        kUrlResourceTableName, db);
+    url_redirect_table_ = base::MakeUnique<GlowplugKeyValueTable<RedirectData>>(
+        kUrlRedirectTableName, db);
+    host_resource_table_ =
+        base::MakeUnique<GlowplugKeyValueTable<PrefetchData>>(
+            kHostResourceTableName, db);
+    host_redirect_table_ =
+        base::MakeUnique<GlowplugKeyValueTable<RedirectData>>(
+            kHostRedirectTableName, db);
+    manifest_table_ =
+        base::MakeUnique<GlowplugKeyValueTable<precache::PrecacheManifest>>(
+            kManifestTableName, db);
+    origin_table_ = base::MakeUnique<GlowplugKeyValueTable<OriginData>>(
+        kOriginTableName, db);
+  }
 }
 
 void ResourcePrefetchPredictorTables::LogDatabaseStats() {
@@ -608,39 +502,4 @@
                          statement.ColumnInt(0));
 }
 
-std::unique_ptr<sql::Statement>
-ResourcePrefetchPredictorTables::GetTableUpdateStatement(
-    PrefetchKeyType key_type,
-    PrefetchDataType data_type,
-    TableOperationType op_type) {
-  sql::StatementID id(__FILE__, key_type | (static_cast<int>(data_type) << 1) |
-                                    (static_cast<int>(op_type) << 3));
-  const char* statement_template =
-      (op_type == TableOperationType::REMOVE ? kDeleteProtoStatementTemplate
-                                             : kInsertProtoStatementTemplate);
-  const char* table_name = GetTableName(key_type, data_type);
-  return base::MakeUnique<sql::Statement>(DB()->GetCachedStatement(
-      id, base::StringPrintf(statement_template, table_name).c_str()));
-}
-
-// static
-const char* ResourcePrefetchPredictorTables::GetTableName(
-    PrefetchKeyType key_type,
-    PrefetchDataType data_type) {
-  bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
-  switch (data_type) {
-    case PrefetchDataType::RESOURCE:
-      return is_host ? kHostResourceTableName : kUrlResourceTableName;
-    case PrefetchDataType::REDIRECT:
-      return is_host ? kHostRedirectTableName : kUrlRedirectTableName;
-    case PrefetchDataType::MANIFEST:
-      return kManifestTableName;
-    case PrefetchDataType::ORIGIN:
-      return kOriginTableName;
-  }
-
-  NOTREACHED();
-  return nullptr;
-}
-
 }  // namespace predictors
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.h b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
index 2e2f273..aee6e41 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
@@ -13,15 +13,12 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "chrome/browser/predictors/glowplug_key_value_table.h"
 #include "chrome/browser/predictors/predictor_table_base.h"
 #include "chrome/browser/predictors/resource_prefetch_common.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor.pb.h"
 #include "components/precache/core/proto/precache.pb.h"
 
-namespace sql {
-class Statement;
-}
-
 namespace predictors {
 
 // Interface for database tables used by the ResourcePrefetchPredictor.
@@ -29,10 +26,13 @@
 // thread.
 //
 // Currently manages:
-//  - UrlResourceTable - resources per Urls.
-//  - UrlRedirectTable - redirects per Urls.
-//  - HostResourceTable - resources per host.
-//  - HostRedirectTable - redirects per host.
+//  - UrlResourceTable - key: url, value: PrefetchData
+//  - UrlRedirectTable - key: url, value: RedirectData
+//  - HostResourceTable - key: host, value: PrefetchData
+//  - HostRedirectTable - key: host, value: RedirectData
+//  - ManifestTable - key: host with stripped "www." prefix,
+//                    value: precache::PrecacheManifest
+//  - OriginTable - key: host, value: OriginData
 class ResourcePrefetchPredictorTables : public PredictorTableBase {
  public:
   typedef std::map<std::string, PrefetchData> PrefetchDataMap;
@@ -131,11 +131,6 @@
   ~ResourcePrefetchPredictorTables() override;
 
  private:
-  // Represents the type of information that is stored in prefetch database.
-  enum class PrefetchDataType { RESOURCE, REDIRECT, MANIFEST, ORIGIN };
-
-  enum class TableOperationType { INSERT, REMOVE };
-
   friend class PredictorDatabaseInternal;
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTablesTest,
                            DatabaseVersionIsSet);
@@ -146,23 +141,6 @@
   // schema (including the .proto).
   static constexpr int kDatabaseVersion = 8;
 
-  // Helper functions below help perform functions on the Url and host table
-  // using the same code.
-  void GetAllResourceDataHelper(PrefetchKeyType key_type,
-                                PrefetchDataMap* data_map);
-  void GetAllRedirectDataHelper(PrefetchKeyType key_type,
-                                RedirectDataMap* redirect_map);
-  void GetAllManifestDataHelper(ManifestDataMap* manifest_map);
-  void GetAllOriginDataHelper(OriginDataMap* manifest_map);
-
-  void UpdateDataHelper(PrefetchKeyType key_type,
-                        PrefetchDataType data_type,
-                        const std::string& key,
-                        const google::protobuf::MessageLite& data);
-  void DeleteDataHelper(PrefetchKeyType key_type,
-                        PrefetchDataType data_type,
-                        const std::vector<std::string>& keys);
-
   // PredictorTableBase:
   void CreateTableIfNonExistent() override;
   void LogDatabaseStats() override;
@@ -171,14 +149,13 @@
   static int GetDatabaseVersion(sql::Connection* db);
   static bool SetDatabaseVersion(sql::Connection* db, int version);
 
-  // Helper to return cached Statements.
-  std::unique_ptr<sql::Statement> GetTableUpdateStatement(
-      PrefetchKeyType key_type,
-      PrefetchDataType data_type,
-      TableOperationType op_type);
-
-  static const char* GetTableName(PrefetchKeyType key_type,
-                                  PrefetchDataType data_type);
+  std::unique_ptr<GlowplugKeyValueTable<PrefetchData>> url_resource_table_;
+  std::unique_ptr<GlowplugKeyValueTable<RedirectData>> url_redirect_table_;
+  std::unique_ptr<GlowplugKeyValueTable<PrefetchData>> host_resource_table_;
+  std::unique_ptr<GlowplugKeyValueTable<RedirectData>> host_redirect_table_;
+  std::unique_ptr<GlowplugKeyValueTable<precache::PrecacheManifest>>
+      manifest_table_;
+  std::unique_ptr<GlowplugKeyValueTable<OriginData>> origin_table_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourcePrefetchPredictorTables);
 };
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index 20b97e6..d4915f6 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task_scheduler/task_scheduler.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "base/version.h"
@@ -48,6 +49,7 @@
 #include "extensions/common/value_builder.h"
 #include "net/base/net_errors.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/reporting/reporting_feature.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"
@@ -550,11 +552,15 @@
       main_context_getter->GetURLRequestContext();
 
   // Check that the URLRequestContexts are different and that their
-  // ChannelIDServices and CookieStores are different.
+  // ChannelIDServices, CookieStores, and ReportingServices are different.
   EXPECT_NE(extension_context, main_context);
   EXPECT_NE(extension_context->channel_id_service(),
             main_context->channel_id_service());
   EXPECT_NE(extension_context->cookie_store(), main_context->cookie_store());
+  if (extension_context->reporting_service()) {
+    EXPECT_NE(extension_context->reporting_service(),
+              main_context->reporting_service());
+  }
 
   // Check that the ChannelIDService in the HttpNetworkSession is the same as
   // the one directly on the URLRequestContext.
@@ -577,6 +583,9 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kReporting);
+
   MockProfileDelegate delegate;
   EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
 
@@ -613,6 +622,9 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kReporting);
+
   MockProfileDelegate delegate;
   EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
 
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index c4fe90c..ae46c2b 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -65,6 +65,9 @@
 #include "net/http/http_cache.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_server_properties_manager.h"
+#include "net/reporting/reporting_feature.h"
+#include "net/reporting/reporting_policy.h"
+#include "net/reporting/reporting_service.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/url_request/url_request_context_storage.h"
 #include "net/url_request/url_request_intercepting_job_factory.h"
@@ -552,6 +555,9 @@
   InitializeExtensionsRequestContext(profile_params);
 #endif
 
+  main_context_storage->set_reporting_service(
+      MaybeCreateReportingService(main_context));
+
   // Create a media request context based on the main context, but using a
   // media cache.  It shares the same job factory as the main context.
   StoragePartitionDescriptor details(profile_path_, false);
@@ -696,6 +702,8 @@
           context->host_resolver()));
   context->SetJobFactory(std::move(top_job_factory));
 
+  context->SetReportingService(MaybeCreateReportingService(context));
+
   return context;
 }
 
@@ -784,6 +792,16 @@
   return predictor_.get();
 }
 
+std::unique_ptr<net::ReportingService>
+ProfileImplIOData::MaybeCreateReportingService(
+    net::URLRequestContext* url_request_context) const {
+  if (!base::FeatureList::IsEnabled(features::kReporting))
+    return std::unique_ptr<net::ReportingService>();
+
+  return net::ReportingService::Create(net::ReportingPolicy(),
+                                       url_request_context);
+}
+
 void ProfileImplIOData::ClearNetworkingHistorySinceOnIOThread(
     base::Time time,
     const base::Closure& completion) {
diff --git a/chrome/browser/profiles/profile_impl_io_data.h b/chrome/browser/profiles/profile_impl_io_data.h
index 68a95265..70a9565 100644
--- a/chrome/browser/profiles/profile_impl_io_data.h
+++ b/chrome/browser/profiles/profile_impl_io_data.h
@@ -190,6 +190,9 @@
       const StoragePartitionDescriptor& partition_descriptor) const override;
   chrome_browser_net::Predictor* GetPredictor() override;
 
+  std::unique_ptr<net::ReportingService> MaybeCreateReportingService(
+      net::URLRequestContext* url_request_context) const;
+
   // Deletes all network related data since |time|. It deletes transport
   // security state since |time| and also deletes HttpServerProperties data.
   // Works asynchronously, however if the |completion| callback is non-null,
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index e0821fb..72d30e5 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -96,6 +96,7 @@
 #include "net/proxy/proxy_config_service_fixed.h"
 #include "net/proxy/proxy_script_fetcher_impl.h"
 #include "net/proxy/proxy_service.h"
+#include "net/reporting/reporting_service.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/client_cert_store.h"
 #include "net/url_request/data_protocol_handler.h"
@@ -578,7 +579,14 @@
   set_job_factory(job_factory_.get());
 }
 
+void ProfileIOData::AppRequestContext::SetReportingService(
+    std::unique_ptr<net::ReportingService> reporting_service) {
+  reporting_service_ = std::move(reporting_service);
+  set_reporting_service(reporting_service_.get());
+}
+
 ProfileIOData::AppRequestContext::~AppRequestContext() {
+  SetReportingService(std::unique_ptr<net::ReportingService>());
   AssertNoURLRequests();
 }
 
@@ -662,6 +670,10 @@
   if (transport_security_state_)
     transport_security_state_->SetRequireCTDelegate(nullptr);
 
+  // And the same for the ReportingService.
+  main_request_context_storage()->set_reporting_service(
+      std::unique_ptr<net::ReportingService>());
+
   // TODO(ajwong): These AssertNoURLRequests() calls are unnecessary since they
   // are already done in the URLRequestContext destructor.
   if (main_request_context_)
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 9f3ea25..3422079 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -81,6 +81,7 @@
 class HttpTransactionFactory;
 class ProxyConfigService;
 class ProxyService;
+class ReportingService;
 class ReportSender;
 class SSLConfigService;
 class TransportSecurityPersister;
@@ -283,6 +284,8 @@
     void SetHttpTransactionFactory(
         std::unique_ptr<net::HttpTransactionFactory> http_factory);
     void SetJobFactory(std::unique_ptr<net::URLRequestJobFactory> job_factory);
+    void SetReportingService(
+        std::unique_ptr<net::ReportingService> reporting_service);
 
    private:
     ~AppRequestContext() override;
@@ -292,6 +295,7 @@
     std::unique_ptr<net::HttpNetworkSession> http_network_session_;
     std::unique_ptr<net::HttpTransactionFactory> http_factory_;
     std::unique_ptr<net::URLRequestJobFactory> job_factory_;
+    std::unique_ptr<net::ReportingService> reporting_service_;
   };
 
   // Created on the UI thread, read on the IO thread during ProfileIOData lazy
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index a8c8bff..340f264 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -610,8 +610,8 @@
     EXPECT_EQ(HIDDEN, GetVisibility("extended-reporting-opt-in"));
     EXPECT_EQ(HIDDEN, GetVisibility("opt-in-checkbox"));
     EXPECT_EQ(HIDDEN, GetVisibility("proceed-link"));
-    EXPECT_TRUE(Click("details-button"));
     EXPECT_EQ(VISIBLE, GetVisibility("learn-more-link"));
+    EXPECT_TRUE(Click("details-button"));
     EXPECT_EQ(VISIBLE, GetVisibility("proceed-link"));
 
     EXPECT_TRUE(ClickAndWaitForDetach("primary-button"));
diff --git a/chrome/browser/safe_browsing/srt_chrome_prompt_impl.cc b/chrome/browser/safe_browsing/srt_chrome_prompt_impl.cc
index 38bb601..dae99a6 100644
--- a/chrome/browser/safe_browsing/srt_chrome_prompt_impl.cc
+++ b/chrome/browser/safe_browsing/srt_chrome_prompt_impl.cc
@@ -14,8 +14,11 @@
 using chrome_cleaner::mojom::PromptAcceptance;
 using chrome_cleaner::mojom::UwSPtr;
 
-ChromePromptImpl::ChromePromptImpl(ChromePromptRequest request)
-    : binding_(this, std::move(request)) {}
+ChromePromptImpl::ChromePromptImpl(ChromePromptRequest request,
+                                   base::Closure on_connection_closed)
+    : binding_(this, std::move(request)) {
+  binding_.set_connection_error_handler(std::move(on_connection_closed));
+}
 
 ChromePromptImpl::~ChromePromptImpl() {}
 
diff --git a/chrome/browser/safe_browsing/srt_chrome_prompt_impl.h b/chrome/browser/safe_browsing/srt_chrome_prompt_impl.h
index bf14b30..6027044b 100644
--- a/chrome/browser/safe_browsing/srt_chrome_prompt_impl.h
+++ b/chrome/browser/safe_browsing/srt_chrome_prompt_impl.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_SAFE_BROWSING_SRT_CHROME_PROMPT_IMPL_H_
 #define CHROME_BROWSER_SAFE_BROWSING_SRT_CHROME_PROMPT_IMPL_H_
 
+#include "base/callback.h"
+#include "base/macros.h"
 #include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
@@ -13,7 +15,8 @@
 // Implementation of the ChromePrompt Mojo interface.
 class ChromePromptImpl : public chrome_cleaner::mojom::ChromePrompt {
  public:
-  explicit ChromePromptImpl(chrome_cleaner::mojom::ChromePromptRequest request);
+  ChromePromptImpl(chrome_cleaner::mojom::ChromePromptRequest request,
+                   base::Closure on_connection_closed);
   ~ChromePromptImpl() override;
 
   void PromptUser(
@@ -24,6 +27,8 @@
 
  private:
   mojo::Binding<chrome_cleaner::mojom::ChromePrompt> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromePromptImpl);
 };
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc b/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc
index 328c9be..adcde7569 100644
--- a/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc
+++ b/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc
@@ -15,6 +15,7 @@
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/files/file_path.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
@@ -30,6 +31,7 @@
 #include "chrome/browser/lifetime/keep_alive_types.h"
 #include "chrome/browser/lifetime/scoped_keep_alive.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/safe_browsing/srt_chrome_prompt_impl.h"
 #include "chrome/browser/safe_browsing/srt_client_info_win.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -37,7 +39,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/chrome_cleaner/public/constants/constants.h"
-#include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h"
 #include "components/component_updater/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing_db/safe_browsing_prefs.h"
@@ -59,6 +60,7 @@
 constexpr char kReportUwSFoundSwitch[] = "report-uws-found";
 constexpr char kReportElevationRequiredSwitch[] = "report-elevation-required";
 constexpr char kExpectedPromptAcceptanceSwitch[] = "expected-prompt-acceptance";
+constexpr char kExpectedReporterFailureSwitch[] = "expected-reporter-crash";
 
 // The exit code to be returned in case of failure in the child process.
 // This should never be passed as the expected exit code to be reported by
@@ -95,6 +97,38 @@
 // object must be created, deleted, and accessed on the IPC thread only.
 chrome_cleaner::mojom::ChromePromptPtr* g_chrome_prompt_ptr = nullptr;
 
+// Potential failures in the reporter process that should be handled by the
+// parent process.
+enum class MockedReporterFailure {
+  kNone = 0,
+  // Crashes at specific moments in the reporter when connected to the IPC.
+  kCrashOnStartup = 1,
+  kCrashAfterConnectedToParentProcess = 2,
+  kCrashWhileWaitingForResponse = 3,
+  kCrashAfterReceivedResponse = 4,
+  // Once an IPC message is sent by the reporter, the parent process will
+  // report a bad message that will lead to an invocation of OnConnectionError.
+  kBadMessageReported = 5,
+};
+
+void AddExpectedCrashToCommandLine(MockedReporterFailure reporter_failure,
+                                   base::CommandLine* command_line) {
+  command_line->AppendSwitchASCII(
+      kExpectedReporterFailureSwitch,
+      base::IntToString(static_cast<int>(reporter_failure)));
+}
+
+void CrashIf(MockedReporterFailure reporter_failure) {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  const std::string& expected_str =
+      command_line->GetSwitchValueASCII(kExpectedReporterFailureSwitch);
+  int val = -1;
+  if (base::StringToInt(expected_str, &val) &&
+      static_cast<MockedReporterFailure>(val) == reporter_failure) {
+    exit(kFailureExitCode);
+  }
+}
+
 // The callback function to be passed to ChromePrompt::PromptUser to check if
 // the prompt accepted returned by the parent process is equal to
 // |expected_prompt_acceptance|. Will set |expected_value_received| with the
@@ -109,6 +143,7 @@
   // used anymore by the child process.
   delete g_chrome_prompt_ptr;
   g_chrome_prompt_ptr = nullptr;
+  CrashIf(MockedReporterFailure::kCrashAfterReceivedResponse);
   done.Run();
 }
 
@@ -145,6 +180,14 @@
   const PromptAcceptance expected_prompt_acceptance =
       PromptAcceptanceFromCommandLine(command_line);
 
+  // This task is posted to the IPC thread so that it will happen after the
+  // request is sent to the parent process and before the response gets
+  // handled on the IPC thread.
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&CrashIf,
+                 MockedReporterFailure::kCrashWhileWaitingForResponse));
+
   (*g_chrome_prompt_ptr)
       ->PromptUser(
           std::move(removable_uws_found), elevation_status,
@@ -169,6 +212,9 @@
       io_thread.task_runner(),
       mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
   mojo::edk::SetParentPipeHandleFromCommandLine();
+
+  CrashIf(MockedReporterFailure::kCrashAfterConnectedToParentProcess);
+
   base::MessageLoop message_loop;
   base::RunLoop run_loop;
   // After the response from the parent process is received, this will post a
@@ -185,6 +231,7 @@
   io_thread.task_runner()->PostTask(
       FROM_HERE, base::Bind(&SendScanResults, chrome_mojo_pipe_token,
                             command_line, done, &expected_value_received));
+
   run_loop.Run();
 
   return expected_value_received;
@@ -196,6 +243,7 @@
 // to the parent process using data passed as command line switches.
 MULTIPROCESS_TEST_MAIN(MockSwReporterProcess) {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  CrashIf(MockedReporterFailure::kCrashOnStartup);
   const std::string& str =
       command_line->GetSwitchValueASCII(kExitCodeToReturnSwitch);
   const std::string& chrome_mojo_pipe_token = command_line->GetSwitchValueASCII(
@@ -208,22 +256,59 @@
   return success ? exit_code_to_report : kFailureExitCode;
 }
 
+// Decorates a ChromePromptImpl object to simulate failures indentified by the
+// parent process and keeps track of errors handled. By default, delegates all
+// actions to the decorated object.
+class ReportBadMessageChromePromptImpl : public ChromePromptImpl {
+ public:
+  ReportBadMessageChromePromptImpl(
+      chrome_cleaner::mojom::ChromePromptRequest request,
+      bool bad_message_expected,
+      base::Closure on_connection_closed)
+      : ChromePromptImpl(std::move(request), std::move(on_connection_closed)),
+        bad_message_expected_(bad_message_expected) {}
+  ~ReportBadMessageChromePromptImpl() override = default;
+
+  void PromptUser(
+      std::vector<chrome_cleaner::mojom::UwSPtr> removable_uws_found,
+      chrome_cleaner::mojom::ElevationStatus elevation_status,
+      const chrome_cleaner::mojom::ChromePrompt::PromptUserCallback& callback)
+      override {
+    if (bad_message_expected_)
+      mojo::ReportBadMessage("bad message");
+
+    ChromePromptImpl::PromptUser(std::move(removable_uws_found),
+                                 elevation_status, callback);
+  }
+
+ private:
+  bool bad_message_expected_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(ReportBadMessageChromePromptImpl);
+};
+
 // Parameters for this test:
 //  - bool in_browser_cleaner_ui: indicates if InBrowserCleanerUI experiment
 //    is enabled; if so, the parent and the child processes will communicate
-//    via a Mojo IPC;
+//    via a Mojo IPC.
 //  - ElevationStatus elevation_status: indicates if the scan results sent by
 //    the child process should consider that elevation will be required for
 //    cleanup.
+//  - MockedReporterFailure expected_reporter_failure: indicates errors that
+//    should be simulated in the reporter process.
 class SRTFetcherTest
     : public InProcessBrowserTest,
       public SwReporterTestingDelegate,
-      public ::testing::WithParamInterface<std::tuple<bool, ElevationStatus>> {
+      public ::testing::WithParamInterface<
+          std::tuple<bool, ElevationStatus, MockedReporterFailure>> {
  public:
+  SRTFetcherTest() = default;
+
   void SetUpInProcessBrowserTestFixture() override {
     SetSwReporterTestingDelegate(this);
 
-    std::tie(in_browser_cleaner_ui_, elevation_status_) = GetParam();
+    std::tie(in_browser_cleaner_ui_, elevation_status_,
+             expected_reporter_failure_) = GetParam();
     // The config should only accept elevation_status_ if InBrowserCleanerUI
     // feature is enabled.
     ASSERT_TRUE(elevation_status_ == ElevationStatus::NOT_REQUIRED ||
@@ -280,12 +365,16 @@
     if (first_launch_callback_)
       std::move(first_launch_callback_).Run();
 
+    if (exit_code_to_report_ == kReporterNotLaunchedExitCode)
+      return base::Process();  // IsValid() will return false.
+
     base::CommandLine command_line(
         base::GetMultiProcessTestChildBaseCommandLine());
     command_line.AppendArguments(invocation.command_line,
                                  /*include_program=*/false);
     command_line.AppendSwitchASCII(kExitCodeToReturnSwitch,
                                    base::IntToString(exit_code_to_report_));
+
     if (in_browser_cleaner_ui_) {
       AddPromptAcceptanceToCommandLine(PromptAcceptance::DENIED, &command_line);
       if (exit_code_to_report_ == chrome_cleaner::kSwReporterCleanupNeeded) {
@@ -294,6 +383,14 @@
           command_line.AppendSwitch(kReportElevationRequiredSwitch);
       }
     }
+
+    if (expected_reporter_failure_ != MockedReporterFailure::kNone)
+      AddExpectedCrashToCommandLine(expected_reporter_failure_, &command_line);
+
+    bad_message_expected_ = expected_reporter_failure_ ==
+                            MockedReporterFailure::kBadMessageReported;
+    bad_message_reported_ = false;
+
     base::SpawnChildResult result = base::SpawnMultiProcessTestChild(
         "MockSwReporterProcess", command_line, launch_options);
     return std::move(result.process);
@@ -312,6 +409,20 @@
     return mock_time_task_runner_.get();
   }
 
+  std::unique_ptr<ChromePromptImpl> CreateChromePromptImpl(
+      chrome_cleaner::mojom::ChromePromptRequest request) override {
+    return base::MakeUnique<ReportBadMessageChromePromptImpl>(
+        std::move(request), bad_message_expected_,
+        base::Bind(&SRTFetcherTest::OnConnectionClosed,
+                   base::Unretained(this)));
+  }
+
+  void OnConnectionClosed() override {}
+
+  void OnConnectionError(const std::string& message) override {
+    bad_message_reported_ = true;
+  }
+
   // Schedules a single reporter to run.
   void RunReporter(int exit_code_to_report,
                    const base::FilePath& exe_path = base::FilePath()) {
@@ -400,7 +511,16 @@
         base::TimeDelta::FromDays(days_until_launch));
 
     EXPECT_EQ(expected_launch_count, reporter_launch_count_);
-    EXPECT_EQ(expect_prompt, prompt_trigger_called_);
+    // Note: a bad message error will not prevent the prompt that is shown to
+    // the user today. Once we hook the new prompt here, we will need to review
+    // this expectation.
+    EXPECT_EQ(expect_prompt &&
+                  (expected_reporter_failure_ == MockedReporterFailure::kNone ||
+                   expected_reporter_failure_ ==
+                       MockedReporterFailure::kBadMessageReported),
+              prompt_trigger_called_);
+
+    EXPECT_EQ(bad_message_expected_, bad_message_reported_);
   }
 
   // Expects that after |days_until_launched| days, the reporter will be
@@ -467,11 +587,19 @@
 
   bool in_browser_cleaner_ui_;
   ElevationStatus elevation_status_;
+  MockedReporterFailure expected_reporter_failure_;
+
+  // Indicates if a bad message error should be simulated by the parent
+  // process.
+  bool bad_message_expected_ = false;
+
+  // Set by ReportBadMessageChromePromptImpl if a bad message error is reported.
+  bool bad_message_reported_ = false;
 
   bool prompt_trigger_called_ = false;
   int reporter_launch_count_ = 0;
   std::vector<SwReporterInvocation> reporter_launch_parameters_;
-  int exit_code_to_report_ = kReporterFailureExitCode;
+  int exit_code_to_report_ = kReporterNotLaunchedExitCode;
 
   // A callback to invoke when the first reporter of a queue is launched. This
   // can be used to perform actions in the middle of a queue of reporters which
@@ -479,6 +607,8 @@
   base::OnceClosure first_launch_callback_;
 
   base::test::ScopedFeatureList scoped_feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(SRTFetcherTest);
 };
 
 class SRTFetcherPromptTest : public DialogBrowserTest {
@@ -560,7 +690,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, Failure) {
-  RunReporter(kReporterFailureExitCode);
+  RunReporter(kReporterNotLaunchedExitCode);
   ExpectReporterLaunches(0, 1, false);
   ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns);
 }
@@ -703,7 +833,7 @@
   // Second launch should not occur after a failure.
   {
     SCOPED_TRACE("Launch multiple times with failure");
-    RunReporterQueue(kReporterFailureExitCode, invocations);
+    RunReporterQueue(kReporterNotLaunchedExitCode, invocations);
     ExpectReporterLaunches(kDaysBetweenSuccessfulSwReporterRuns, {path1},
                            false);
     ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns);
@@ -805,14 +935,24 @@
     NoInBrowserCleanerUI,
     SRTFetcherTest,
     testing::Combine(testing::Values(false),
-                     testing::Values(ElevationStatus::NOT_REQUIRED)));
+                     testing::Values(ElevationStatus::NOT_REQUIRED),
+                     testing::Values(MockedReporterFailure::kNone,
+                                     MockedReporterFailure::kCrashOnStartup)));
 
 INSTANTIATE_TEST_CASE_P(
     InBrowserCleanerUI,
     SRTFetcherTest,
-    testing::Combine(testing::Values(true),
-                     testing::Values(ElevationStatus::NOT_REQUIRED,
-                                     ElevationStatus::REQUIRED)));
+    testing::Combine(
+        testing::Values(true),
+        testing::Values(ElevationStatus::NOT_REQUIRED,
+                        ElevationStatus::REQUIRED),
+        testing::Values(
+            MockedReporterFailure::kNone,
+            MockedReporterFailure::kCrashOnStartup,
+            MockedReporterFailure::kCrashAfterConnectedToParentProcess,
+            MockedReporterFailure::kCrashWhileWaitingForResponse,
+            MockedReporterFailure::kCrashAfterReceivedResponse,
+            MockedReporterFailure::kBadMessageReported)));
 
 // This provide tests which allows explicit invocation of the SRT Prompt
 // useful for checking dialog layout or any other interactive functionality
diff --git a/chrome/browser/safe_browsing/srt_fetcher_win.cc b/chrome/browser/safe_browsing/srt_fetcher_win.cc
index 6f2ee0f..b786599 100644
--- a/chrome/browser/safe_browsing/srt_fetcher_win.cc
+++ b/chrome/browser/safe_browsing/srt_fetcher_win.cc
@@ -45,7 +45,6 @@
 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "components/chrome_cleaner/public/constants/constants.h"
-#include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h"
 #include "components/component_updater/pref_names.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "components/prefs/pref_service.h"
@@ -545,6 +544,20 @@
     global_error->ShowBubbleView(browser);
 }
 
+// Handles the case when the remote end has been closed, by performing the
+// necessary cleanups if the prompt dialog is being shown to the user.
+void OnConnectionClosed() {
+  // Placeholder. This should handle cases when the reporter process is
+  // disconnected (e.g. due to a crash) and the prompt dialog is being shown
+  // to the user.
+}
+
+// Handles the case when a mojo::ReportBadMessage has been explicitly reported.
+void OnConnectionError(const std::string& message) {
+  // Placeholder. This should handle cases when the reporter process sends
+  // a bad message and the prompt dialog is being shown to the user.
+}
+
 // Class responsible for launching the reporter process and waiting for its
 // completion. If feature InBrowserCleanerUI is enabled, this object will also
 // be responsible for starting the ChromePromptImpl object on the IO thread and
@@ -591,7 +604,8 @@
   base::Process LaunchConnectedReporterProcess();
 
   // Starts a new instance of ChromePromptImpl to receive requests from the
-  // reporter. Must be run on the IO thread.
+  // reporter and establishes the mojo connection to it.
+  // Must be run on the IO thread.
   void CreateChromePromptImpl(
       chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request);
 
@@ -620,7 +634,7 @@
 
   // This exit code is used to identify that a reporter run didn't happen, so
   // the result should be ignored and a rerun scheduled for the usual delay.
-  int exit_code = kReporterFailureExitCode;
+  int exit_code = kReporterNotLaunchedExitCode;
   UMAHistogramReporter uma(invocation_.suffix);
   if (reporter_process.IsValid()) {
     uma.RecordReporterStep(SW_REPORTER_START_EXECUTION);
@@ -668,10 +682,6 @@
   if (!reporter_process.IsValid())
     return reporter_process;
 
-  pending_process_connection.Connect(
-      reporter_process.Handle(),
-      mojo::edk::ConnectionParams(channel.PassServerHandle()));
-
   chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request;
   chrome_prompt_request.Bind(std::move(mojo_pipe));
 
@@ -684,6 +694,16 @@
                                 base::RetainedRef(this),
                                 std::move(chrome_prompt_request)));
 
+  mojo::edk::ProcessErrorCallback on_connection_error =
+      g_testing_delegate_
+          ? base::Bind(&SwReporterTestingDelegate::OnConnectionError,
+                       base::Unretained(g_testing_delegate_))
+          : base::Bind(&OnConnectionError);
+  pending_process_connection.Connect(
+      reporter_process.Handle(),
+      mojo::edk::ConnectionParams(channel.PassServerHandle()),
+      on_connection_error);
+
   return reporter_process;
 }
 
@@ -701,7 +721,11 @@
   DCHECK(base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature));
 
   chrome_prompt_impl_ =
-      base::MakeUnique<ChromePromptImpl>(std::move(chrome_prompt_request));
+      g_testing_delegate_
+          ? g_testing_delegate_->CreateChromePromptImpl(
+                std::move(chrome_prompt_request))
+          : base::MakeUnique<ChromePromptImpl>(std::move(chrome_prompt_request),
+                                               base::Bind(&OnConnectionClosed));
 }
 
 void SwReporterProcess::ReleaseChromePromptImpl() {
@@ -934,7 +958,7 @@
     base::TimeDelta reporter_running_time = now - reporter_start_time;
 
     // Don't continue the current queue of reporters if one failed to launch.
-    if (exit_code == kReporterFailureExitCode)
+    if (exit_code == kReporterNotLaunchedExitCode)
       current_invocations_ = SwReporterQueue();
 
     // As soon as we're not running this queue, schedule the next overall queue
@@ -954,7 +978,7 @@
     // code itself doesn't need to be logged in this case because
     // SW_REPORTER_FAILED_TO_START is logged in
     // |LaunchAndWaitForExitOnBackgroundThread|.)
-    if (exit_code == kReporterFailureExitCode)
+    if (exit_code == kReporterNotLaunchedExitCode)
       return;
 
     const auto& finished_invocation = sw_reporter_process->invocation();
diff --git a/chrome/browser/safe_browsing/srt_fetcher_win.h b/chrome/browser/safe_browsing/srt_fetcher_win.h
index 2d1ca85..26400ce 100644
--- a/chrome/browser/safe_browsing/srt_fetcher_win.h
+++ b/chrome/browser/safe_browsing/srt_fetcher_win.h
@@ -16,6 +16,7 @@
 #include "base/process/launch.h"
 #include "base/process/process.h"
 #include "base/time/time.h"
+#include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h"
 
 namespace base {
 class FilePath;
@@ -27,8 +28,10 @@
 
 namespace safe_browsing {
 
+class ChromePromptImpl;
+
 // A special exit code identifying a failure to run the reporter.
-const int kReporterFailureExitCode = INT_MAX;
+const int kReporterNotLaunchedExitCode = INT_MAX;
 
 // The number of days to wait before triggering another reporter run.
 const int kDaysBetweenSuccessfulSwReporterRuns = 7;
@@ -103,25 +106,45 @@
 // run the cleaner, rather than checking if they've run it at all.
 bool UserHasRunCleaner();
 
-// Mocks and callbacks for the unit tests.
+// A delegate used by tests to implement test doubles (e.g., stubs, fakes, or
+// mocks).
 class SwReporterTestingDelegate {
  public:
   virtual ~SwReporterTestingDelegate() {}
 
-  // Test mock for launching the reporter.
+  // Invoked by tests in places of base::LaunchProcess.
+  // See chrome_cleaner::mojom::ChromePromptRequest().
   virtual base::Process LaunchReporter(
       const SwReporterInvocation& invocation,
       const base::LaunchOptions& launch_options) = 0;
 
-  // Test mock for showing the prompt.
+  // Invoked by tests in place of the actual prompting logic.
+  // See MaybeFetchSRT().
   virtual void TriggerPrompt(Browser* browser,
                              const std::string& reporter_version) = 0;
 
-  // Returns the test's idea of the current time.
+  // Invoked by tests to override the current time.
+  // See Now() in srt_fetcher_win.cc.
   virtual base::Time Now() const = 0;
 
   // A task runner used to spawn the reporter process (which blocks).
+  // See ReporterRunner::ScheduleNextInvocation().
   virtual base::TaskRunner* BlockingTaskRunner() const = 0;
+
+  // Returns a ChromePromptImpl object that keeps track of specific
+  // actions during tests. Replaces the object returned by
+  // SwReporterProcess::CreateChromePromptImpl().
+  // See SwReporterProcess::LaunchConnectedReporterProcess().
+  virtual std::unique_ptr<ChromePromptImpl> CreateChromePromptImpl(
+      chrome_cleaner::mojom::ChromePromptRequest request) = 0;
+
+  // Connection closed callback defined by tests in place of the default
+  // error handler. See SRTFetcherTest::CreateChromePromptImpl().
+  virtual void OnConnectionClosed() = 0;
+
+  // Bad message handler callback defined by tests in place of the default
+  // error handler. See SwReporterProcess::LaunchConnectedReporterProcess().
+  virtual void OnConnectionError(const std::string& message) = 0;
 };
 
 // Set a delegate for testing. The implementation will not take ownership of
diff --git a/chrome/browser/task_manager/providers/web_contents/background_contents_tag.h b/chrome/browser/task_manager/providers/web_contents/background_contents_tag.h
index 33b3990..e05ad02a 100644
--- a/chrome/browser/task_manager/providers/web_contents/background_contents_tag.h
+++ b/chrome/browser/task_manager/providers/web_contents/background_contents_tag.h
@@ -17,6 +17,8 @@
 // service.
 class BackgroundContentsTag : public WebContentsTag {
  public:
+  ~BackgroundContentsTag() override;
+
   // task_manager::WebContentsTag:
   BackgroundContentsTask* CreateTask() const override;
 
@@ -25,7 +27,6 @@
 
   BackgroundContentsTag(content::WebContents* web_contents,
                         BackgroundContents* background_contents);
-  ~BackgroundContentsTag() override;
 
   // The owning BackgroundContents.
   BackgroundContents* background_contents_;
diff --git a/chrome/browser/task_manager/providers/web_contents/devtools_tag.h b/chrome/browser/task_manager/providers/web_contents/devtools_tag.h
index 4f0dd119..580a419 100644
--- a/chrome/browser/task_manager/providers/web_contents/devtools_tag.h
+++ b/chrome/browser/task_manager/providers/web_contents/devtools_tag.h
@@ -14,6 +14,8 @@
 // Defines a concrete UserData type for WebContents owned by DevToolsWindow.
 class DevToolsTag : public WebContentsTag {
  public:
+  ~DevToolsTag() override;
+
   // task_manager::WebContentsTag:
   DevToolsTask* CreateTask() const override;
 
@@ -21,7 +23,6 @@
   friend class WebContentsTags;
 
   explicit DevToolsTag(content::WebContents* web_contents);
-  ~DevToolsTag() override;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsTag);
 };
diff --git a/chrome/browser/task_manager/providers/web_contents/extension_tag.h b/chrome/browser/task_manager/providers/web_contents/extension_tag.h
index 9368f99..386a9ee 100644
--- a/chrome/browser/task_manager/providers/web_contents/extension_tag.h
+++ b/chrome/browser/task_manager/providers/web_contents/extension_tag.h
@@ -14,6 +14,8 @@
 // Defines a concrete UserData type for WebContents owned by extensions.
 class ExtensionTag : public WebContentsTag {
  public:
+  ~ExtensionTag() override;
+
   // task_manager::WebContentsTag:
   ExtensionTask* CreateTask() const override;
 
@@ -22,7 +24,6 @@
 
   ExtensionTag(content::WebContents* web_contents,
                const extensions::ViewType view_type);
-  ~ExtensionTag() override;
 
   // The ViewType of the extension WebContents this tag is attached to.
   const extensions::ViewType view_type_;
diff --git a/chrome/browser/task_manager/providers/web_contents/guest_tag.h b/chrome/browser/task_manager/providers/web_contents/guest_tag.h
index 725a327..14048de 100644
--- a/chrome/browser/task_manager/providers/web_contents/guest_tag.h
+++ b/chrome/browser/task_manager/providers/web_contents/guest_tag.h
@@ -15,6 +15,8 @@
 // which represents browser <*view> tag plugin guests.
 class GuestTag : public WebContentsTag {
  public:
+  ~GuestTag() override;
+
   // task_manager::WebContentsTag:
   GuestTask* CreateTask() const override;
 
@@ -22,7 +24,6 @@
   friend class WebContentsTags;
 
   explicit GuestTag(content::WebContents* web_contents);
-  ~GuestTag() override;
 
   DISALLOW_COPY_AND_ASSIGN(GuestTag);
 };
diff --git a/chrome/browser/task_manager/providers/web_contents/prerender_tag.h b/chrome/browser/task_manager/providers/web_contents/prerender_tag.h
index d637eff..d4c3e52 100644
--- a/chrome/browser/task_manager/providers/web_contents/prerender_tag.h
+++ b/chrome/browser/task_manager/providers/web_contents/prerender_tag.h
@@ -15,6 +15,8 @@
 // PrerenderManager.
 class PrerenderTag : public WebContentsTag {
  public:
+  ~PrerenderTag() override;
+
   // task_manager::WebContentsTag:
   PrerenderTask* CreateTask() const override;
 
@@ -22,7 +24,6 @@
   friend class WebContentsTags;
 
   explicit PrerenderTag(content::WebContents* web_contents);
-  ~PrerenderTag() override;
 
   DISALLOW_COPY_AND_ASSIGN(PrerenderTag);
 };
diff --git a/chrome/browser/task_manager/providers/web_contents/printing_tag.h b/chrome/browser/task_manager/providers/web_contents/printing_tag.h
index dfcd671..0d113db 100644
--- a/chrome/browser/task_manager/providers/web_contents/printing_tag.h
+++ b/chrome/browser/task_manager/providers/web_contents/printing_tag.h
@@ -15,6 +15,8 @@
 // and background printing.
 class PrintingTag : public WebContentsTag {
  public:
+  ~PrintingTag() override;
+
   // task_manager::WebContentsTag:
   PrintingTask* CreateTask() const override;
 
@@ -22,7 +24,6 @@
   friend class WebContentsTags;
 
   explicit PrintingTag(content::WebContents* web_contents);
-  ~PrintingTag() override;
 
   DISALLOW_COPY_AND_ASSIGN(PrintingTag);
 };
diff --git a/chrome/browser/task_manager/providers/web_contents/tab_contents_tag.h b/chrome/browser/task_manager/providers/web_contents/tab_contents_tag.h
index 5b0fd891..4de647e 100644
--- a/chrome/browser/task_manager/providers/web_contents/tab_contents_tag.h
+++ b/chrome/browser/task_manager/providers/web_contents/tab_contents_tag.h
@@ -14,6 +14,8 @@
 // Defines a concrete UserData type for WebContents owned by the TabStripModel.
 class TabContentsTag : public WebContentsTag {
  public:
+  ~TabContentsTag() override;
+
   // task_manager::WebContentsTag:
   TabContentsTask* CreateTask() const override;
 
@@ -21,7 +23,6 @@
   friend class WebContentsTags;
 
   explicit TabContentsTag(content::WebContents* web_contents);
-  ~TabContentsTag() override;
 
   DISALLOW_COPY_AND_ASSIGN(TabContentsTag);
 };
diff --git a/chrome/browser/task_manager/providers/web_contents/web_contents_tag.h b/chrome/browser/task_manager/providers/web_contents/web_contents_tag.h
index 713c201..eff58d04 100644
--- a/chrome/browser/task_manager/providers/web_contents/web_contents_tag.h
+++ b/chrome/browser/task_manager/providers/web_contents/web_contents_tag.h
@@ -25,6 +25,8 @@
 // |task_manager::WebContentsTags|.
 class WebContentsTag : public base::SupportsUserData::Data {
  public:
+  ~WebContentsTag() override;
+
   // Retrieves the instance of the WebContentsTag that was attached to the
   // specified WebContents and returns it. If no instance was attached, returns
   // nullptr.
@@ -45,7 +47,6 @@
   friend class WebContentsTags;
 
   explicit WebContentsTag(content::WebContents* contents);
-  ~WebContentsTag() override;
 
  private:
   // The user data key.
diff --git a/chrome/browser/task_manager/web_contents_tags.cc b/chrome/browser/task_manager/web_contents_tags.cc
index ce2f04b..a9c16fd 100644
--- a/chrome/browser/task_manager/web_contents_tags.cc
+++ b/chrome/browser/task_manager/web_contents_tags.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/task_manager/web_contents_tags.h"
 
+#include <memory>
+
 #include "build/build_config.h"
 #include "chrome/browser/task_manager/providers/web_contents/background_contents_tag.h"
 #include "chrome/browser/task_manager/providers/web_contents/devtools_tag.h"
@@ -32,13 +34,14 @@
 // |WebContentsTagsManager|.
 // Note: This will fail if |contents| is already tagged by |tag|.
 void TagWebContents(content::WebContents* contents,
-                    WebContentsTag* tag,
+                    std::unique_ptr<WebContentsTag> tag,
                     void* tag_key) {
   DCHECK(contents);
   DCHECK(tag);
   DCHECK(WebContentsTag::FromWebContents(contents) == nullptr);
-  contents->SetUserData(tag_key, tag);
-  WebContentsTagsManager::GetInstance()->AddTag(tag);
+  WebContentsTag* tag_ptr = tag.get();
+  contents->SetUserData(tag_key, std::move(tag));
+  WebContentsTagsManager::GetInstance()->AddTag(tag_ptr);
 }
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -67,10 +70,10 @@
     BackgroundContents* background_contents) {
 #if !defined(OS_ANDROID)
   if (!WebContentsTag::FromWebContents(web_contents)) {
-    TagWebContents(
-        web_contents,
-        new BackgroundContentsTag(web_contents, background_contents),
-        WebContentsTag::kTagKey);
+    TagWebContents(web_contents,
+                   base::WrapUnique(new BackgroundContentsTag(
+                       web_contents, background_contents)),
+                   WebContentsTag::kTagKey);
   }
 #endif  // !defined(OS_ANDROID)
 }
@@ -81,7 +84,7 @@
 #if !defined(OS_ANDROID)
   if (!WebContentsTag::FromWebContents(web_contents)) {
     TagWebContents(web_contents,
-                   new DevToolsTag(web_contents),
+                   base::WrapUnique(new DevToolsTag(web_contents)),
                    WebContentsTag::kTagKey);
   }
 #endif  // !defined(OS_ANDROID)
@@ -93,7 +96,7 @@
 #if !defined(OS_ANDROID)
   if (!WebContentsTag::FromWebContents(web_contents)) {
     TagWebContents(web_contents,
-                   new PrerenderTag(web_contents),
+                   base::WrapUnique(new PrerenderTag(web_contents)),
                    WebContentsTag::kTagKey);
   }
 #endif  // !defined(OS_ANDROID)
@@ -104,7 +107,7 @@
 #if !defined(OS_ANDROID)
   if (!WebContentsTag::FromWebContents(web_contents)) {
     TagWebContents(web_contents,
-                   new TabContentsTag(web_contents),
+                   base::WrapUnique(new TabContentsTag(web_contents)),
                    WebContentsTag::kTagKey);
   }
 #endif  // !defined(OS_ANDROID)
@@ -116,7 +119,7 @@
 #if !defined(OS_ANDROID) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
   if (!WebContentsTag::FromWebContents(web_contents)) {
     TagWebContents(web_contents,
-                   new PrintingTag(web_contents),
+                   base::WrapUnique(new PrintingTag(web_contents)),
                    WebContentsTag::kTagKey);
   }
 #endif  // !defined(OS_ANDROID) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -128,8 +131,7 @@
 #if !defined(OS_ANDROID)
   DCHECK(guest_view::GuestViewBase::IsGuest(web_contents));
   if (!WebContentsTag::FromWebContents(web_contents)) {
-    TagWebContents(web_contents,
-                   new GuestTag(web_contents),
+    TagWebContents(web_contents, base::WrapUnique(new GuestTag(web_contents)),
                    WebContentsTag::kTagKey);
   }
 #endif  // !defined(OS_ANDROID)
@@ -143,7 +145,7 @@
 
   if (!WebContentsTag::FromWebContents(web_contents)) {
     TagWebContents(web_contents,
-                   new ExtensionTag(web_contents, view_type),
+                   base::WrapUnique(new ExtensionTag(web_contents, view_type)),
                    WebContentsTag::kTagKey);
   }
 #endif  // !defined(OS_ANDROID) && BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 1339579..8d17f985 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -1794,7 +1794,7 @@
 
 // Drags from browser to a second display and releases input.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserInSeparateDisplayTabDragControllerTest,
-                       DISABLED_DragSingleTabToSeparateWindowInSecondDisplay) {
+                       DragSingleTabToSeparateWindowInSecondDisplay) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
   TabStrip* tab_strip = GetTabStripForBrowser(browser());
@@ -1822,16 +1822,12 @@
   TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
 
-  // This other browser should be on the second screen (with mouse drag)
-  // With the touch input the browser cannot be dragged from one screen
-  // to another and the window stays on the first screen.
-  if (input_source() == INPUT_SOURCE_MOUSE) {
-    aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
-    ASSERT_EQ(2u, roots.size());
-    aura::Window* second_root = roots[1];
-    EXPECT_EQ(second_root,
-              new_browser->window()->GetNativeWindow()->GetRootWindow());
-  }
+  // This other browser should be on the second screen with mouse drag.
+  aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
+  ASSERT_EQ(2u, roots.size());
+  aura::Window* second_root = roots[1];
+  EXPECT_EQ(second_root,
+            new_browser->window()->GetNativeWindow()->GetRootWindow());
 
   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
   EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
@@ -2453,9 +2449,11 @@
 #endif  // OS_CHROMEOS
 
 #if defined(USE_ASH)
+// There are no use case for touch drag to move across displays right now.
+// Removes touch input here until we have that case.
 INSTANTIATE_TEST_CASE_P(TabDragging,
                         DetachToBrowserInSeparateDisplayTabDragControllerTest,
-                        ::testing::Values("mouse", "touch"));
+                        ::testing::Values("mouse"));
 INSTANTIATE_TEST_CASE_P(TabDragging,
                         DifferentDeviceScaleFactorDisplayTabDragControllerTest,
                         ::testing::Values("mouse"));
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 78b04f4..357a0af 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -230,13 +230,6 @@
     {"newframe_replicated_origin", kSmallSize},
     {"newframe_oopifs_possible", kSmallSize},
 
-    // Temporary for https://crbug.com/630103.
-    {"origin_mismatch_url", crash_keys::kLargeSize},
-    {"origin_mismatch_origin", crash_keys::kMediumSize},
-    {"origin_mismatch_transition", crash_keys::kSmallSize},
-    {"origin_mismatch_redirects", crash_keys::kSmallSize},
-    {"origin_mismatch_same_page", crash_keys::kSmallSize},
-
     // Temporary for https://crbug.com/612711.
     {"aci_wrong_sp_extension_id", kSmallSize},
 
diff --git a/chrome/gpu/arc_gpu_video_decode_accelerator.cc b/chrome/gpu/arc_gpu_video_decode_accelerator.cc
index 32e7ad7f..d0212aef0 100644
--- a/chrome/gpu/arc_gpu_video_decode_accelerator.cc
+++ b/chrome/gpu/arc_gpu_video_decode_accelerator.cc
@@ -296,7 +296,8 @@
       }
       CreateInputRecord(bitstream_buffer_id, index, metadata.timestamp);
       vda_->Decode(media::BitstreamBuffer(
-          bitstream_buffer_id, base::SharedMemoryHandle(dup_fd, true),
+          bitstream_buffer_id,
+          base::SharedMemoryHandle(base::FileDescriptor(dup_fd, true)),
           metadata.bytes_used, input_info->offset));
       break;
     }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockStorageDelegate.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockStorageDelegate.java
index 7dadd18..ea864aa 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockStorageDelegate.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockStorageDelegate.java
@@ -52,8 +52,7 @@
     @Override
     public File getStateDirectory() {
         // This is a test class, allowing StrictMode violations.
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             if (!mStateDirectory.exists() && !mStateDirectory.mkdirs()) {
                 Assert.fail("Failed to create state directory.  Tests should fail.");
diff --git a/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js b/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js
index 5b33ab3f..e0b55aab 100644
--- a/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js
@@ -444,11 +444,28 @@
       clickRemoveButton();
     });
 
+    test('verifyFederatedPassword', function() {
+      var item = FakeDataMaker.passwordEntry('goo.gl', 'bart', 0);
+      item.federationText = 'with chromium.org';
+      var passwordDialog = createPasswordDialog(item);
+
+      Polymer.dom.flush();
+
+      assertEquals(item.federationText,
+                   passwordDialog.$.passwordInput.value);
+      // Text should be readable.
+      assertEquals('text',
+                   passwordDialog.$.passwordInput.type);
+      assertTrue(passwordDialog.$.showPasswordButton.hidden);
+    });
+
     test('showSavedPassword', function() {
       var PASSWORD = 'bAn@n@5';
       var item = FakeDataMaker.passwordEntry('goo.gl', 'bart', PASSWORD.length);
       var passwordDialog = createPasswordDialog(item);
 
+      assertFalse(passwordDialog.$.showPasswordButton.hidden);
+
       passwordDialog.password = PASSWORD;
       passwordDialog.showPassword = true;
 
@@ -459,6 +476,7 @@
       // Password should be visible.
       assertEquals('text',
                    passwordDialog.$.passwordInput.type);
+      assertFalse(passwordDialog.$.showPasswordButton.hidden);
     });
 
     // Test will timeout if event is not received.
diff --git a/chromecast/crash/cast_crash_keys.cc b/chromecast/crash/cast_crash_keys.cc
index 7953a3f..67ac15a 100644
--- a/chromecast/crash/cast_crash_keys.cc
+++ b/chromecast/crash/cast_crash_keys.cc
@@ -97,13 +97,6 @@
       {"newframe_replicated_origin", ::crash_keys::kSmallSize},
       {"newframe_oopifs_possible", ::crash_keys::kSmallSize},
 
-      // Temporary for https://crbug.com/630103.
-      {"origin_mismatch_url", ::crash_keys::kLargeSize},
-      {"origin_mismatch_origin", ::crash_keys::kMediumSize},
-      {"origin_mismatch_transition", ::crash_keys::kSmallSize},
-      {"origin_mismatch_redirects", ::crash_keys::kSmallSize},
-      {"origin_mismatch_same_page", ::crash_keys::kSmallSize},
-
       // Temporary for https://crbug.com/612711.
       {"aci_wrong_sp_extension_id", ::crash_keys::kSmallSize},
 
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 6af3c08..76ea445 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -14,10 +14,6 @@
 
 assert(!is_component_build, "Cronet requires static library build.")
 
-declare_args() {
-  cronet_enable_data_reduction_proxy_support = false
-}
-
 generate_jni("cronet_jni_headers") {
   sources = [
     "java/src/org/chromium/net/impl/CronetBidirectionalStream.java",
@@ -181,8 +177,6 @@
       "//components/cronet/android/cert/cert_verifier_cache_serializer.h",
       "//components/cronet/android/cronet_bidirectional_stream_adapter.cc",
       "//components/cronet/android/cronet_bidirectional_stream_adapter.h",
-      "//components/cronet/android/cronet_in_memory_pref_store.cc",
-      "//components/cronet/android/cronet_in_memory_pref_store.h",
       "//components/cronet/android/cronet_library_loader.cc",
       "//components/cronet/android/cronet_library_loader.h",
       "//components/cronet/android/cronet_upload_data_stream.cc",
@@ -219,14 +213,6 @@
       "log",
     ]
 
-    if (cronet_enable_data_reduction_proxy_support) {
-      defines += [ "DATA_REDUCTION_PROXY_SUPPORT" ]
-      sources += [
-        "//components/cronet/android/cronet_data_reduction_proxy.cc",
-        "//components/cronet/android/cronet_data_reduction_proxy.h",
-      ]
-    }
-
     if (defined(invoker.defines)) {
       defines += invoker.defines
     }
@@ -243,13 +229,6 @@
     "//url",
   ]
 
-  if (cronet_enable_data_reduction_proxy_support) {
-    deps += [
-      "//components/data_reduction_proxy/core/browser:browser_small",
-      "//components/data_reduction_proxy/core/common",
-    ]
-  }
-
   if (!use_platform_icu_alternatives) {
     deps += [ "//base:i18n" ]
   }
@@ -548,10 +527,6 @@
   ]
 
   include_dirs = [ _cronet_version_header_include_dir ]
-
-  if (cronet_enable_data_reduction_proxy_support) {
-    deps += [ "//components/data_reduction_proxy/core/browser:browser_small" ]
-  }
 }
 
 android_resources("cronet_test_apk_resources") {
@@ -631,8 +606,6 @@
     "test/assets/test/cacheable.txt.mock-http-headers",
     "test/assets/test/content_length_mismatch.html",
     "test/assets/test/content_length_mismatch.html.mock-http-headers",
-    "test/assets/test/datareductionproxysuccess.txt",
-    "test/assets/test/datareductionproxysuccess.txt.mock-http-headers",
     "test/assets/test/gzipped.html",
     "test/assets/test/gzipped.html.mock-http-headers",
     "test/assets/test/multiredirect.html",
diff --git a/components/cronet/android/DEPS b/components/cronet/android/DEPS
index 73d8aca..d6643eb6 100644
--- a/components/cronet/android/DEPS
+++ b/components/cronet/android/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+components/data_reduction_proxy",
   "+components/metrics",
   "+crypto",
   "+jni",
diff --git a/components/cronet/android/api.txt b/components/cronet/android/api.txt
index db30e54..7386916f 100644
--- a/components/cronet/android/api.txt
+++ b/components/cronet/android/api.txt
@@ -99,7 +99,6 @@
   public org.chromium.net.ICronetEngineBuilder();
   public abstract org.chromium.net.ICronetEngineBuilder addPublicKeyPins(java.lang.String, java.util.Set<byte[]>, boolean, java.util.Date);
   public abstract org.chromium.net.ICronetEngineBuilder addQuicHint(java.lang.String, int, int);
-  public abstract org.chromium.net.ICronetEngineBuilder enableDataReductionProxy(java.lang.String);
   public abstract org.chromium.net.ICronetEngineBuilder enableHttp2(boolean);
   public abstract org.chromium.net.ICronetEngineBuilder enableHttpCache(int, long);
   public abstract org.chromium.net.ICronetEngineBuilder enablePublicKeyPinningBypassForLocalTrustAnchors(boolean);
@@ -114,7 +113,6 @@
   public abstract org.chromium.net.ExperimentalCronetEngine build();
   public org.chromium.net.ICronetEngineBuilder enableNetworkQualityEstimator(boolean);
   public org.chromium.net.ICronetEngineBuilder setCertVerifierData(java.lang.String);
-  public org.chromium.net.ICronetEngineBuilder setDataReductionProxyOptions(java.lang.String, java.lang.String, java.lang.String);
 }
 public final class org.chromium.net.InlineExecutionProhibitedException extends java.util.concurrent.RejectedExecutionException {
   public org.chromium.net.InlineExecutionProhibitedException();
diff --git a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
index cdf54bc..0168249c 100644
--- a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
@@ -139,37 +139,6 @@
         }
 
         /**
-         * Overrides
-         * <a href="https://developer.chrome.com/multidevice/data-compression">
-         * Data Reduction Proxy</a> configuration parameters with a primary
-         * proxy name, fallback proxy name, and a secure proxy check URL. Proxies
-         * are specified as [scheme://]host[:port]. Used for testing.
-         * @param primaryProxy the primary data reduction proxy to use.
-         * @param fallbackProxy a fallback data reduction proxy to use.
-         * @param secureProxyCheckUrl a URL to fetch to determine if using a secure
-         * proxy is allowed.
-         * @return the builder to facilitate chaining.
-         */
-        public Builder setDataReductionProxyOptions(
-                String primaryProxy, String fallbackProxy, String secureProxyCheckUrl) {
-            mBuilderDelegate.setDataReductionProxyOptions(
-                    primaryProxy, fallbackProxy, secureProxyCheckUrl);
-            return this;
-        }
-
-        /**
-         * Enables
-         * <a href="https://developer.chrome.com/multidevice/data-compression">Data
-         * Reduction Proxy</a>. Defaults to disabled.
-         * @param key key to use when authenticating with the proxy.
-         * @return the builder to facilitate chaining.
-         */
-        public Builder enableDataReductionProxy(String key) {
-            mBuilderDelegate.enableDataReductionProxy(key);
-            return this;
-        }
-
-        /**
          * Sets experimental options to be used in Cronet.
          *
          * @param options JSON formatted experimental options.
diff --git a/components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java b/components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java
index 513b3e7..b75b73a 100644
--- a/components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java
+++ b/components/cronet/android/api/src/org/chromium/net/ICronetEngineBuilder.java
@@ -20,7 +20,6 @@
     public abstract ICronetEngineBuilder addPublicKeyPins(String hostName, Set<byte[]> pinsSha256,
             boolean includeSubdomains, Date expirationDate);
     public abstract ICronetEngineBuilder addQuicHint(String host, int port, int alternatePort);
-    public abstract ICronetEngineBuilder enableDataReductionProxy(String key);
     public abstract ICronetEngineBuilder enableHttp2(boolean value);
     public abstract ICronetEngineBuilder enableHttpCache(int cacheMode, long maxSize);
     public abstract ICronetEngineBuilder enablePublicKeyPinningBypassForLocalTrustAnchors(
@@ -53,8 +52,4 @@
         return this;
     }
 
-    public ICronetEngineBuilder setDataReductionProxyOptions(
-            String primaryProxy, String fallbackProxy, String secureProxyCheckUrl) {
-        return this;
-    }
 }
diff --git a/components/cronet/android/cronet_data_reduction_proxy.cc b/components/cronet/android/cronet_data_reduction_proxy.cc
deleted file mode 100644
index a0303e4..0000000
--- a/components/cronet/android/cronet_data_reduction_proxy.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/cronet/android/cronet_data_reduction_proxy.h"
-
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/single_thread_task_runner.h"
-#include "components/cronet/android/cronet_in_memory_pref_store.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "components/data_reduction_proxy/core/browser/data_store.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/pref_service_factory.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_interceptor.h"
-
-namespace cronet {
-namespace {
-
-// Name of the preference that governs enabling the Data Reduction Proxy.
-const char kDataReductionProxyEnabled[] = "data_reduction_proxy.enabled";
-
-std::unique_ptr<PrefService> CreatePrefService() {
-  scoped_refptr<PrefRegistrySimple> pref_registry(new PrefRegistrySimple());
-  pref_registry->RegisterBooleanPref(kDataReductionProxyEnabled, false);
-  data_reduction_proxy::RegisterSimpleProfilePrefs(pref_registry.get());
-  PrefServiceFactory pref_service_factory;
-  pref_service_factory.set_user_prefs(
-      make_scoped_refptr(new CronetInMemoryPrefStore()));
-  std::unique_ptr<PrefService> pref_service =
-      pref_service_factory.Create(pref_registry.get());
-  pref_registry = nullptr;
-  return pref_service;
-}
-
-// TODO(bengr): Apply test configurations directly, instead of via the
-// command line.
-void AddOptionsToCommandLine(const std::string& primary_proxy,
-                             const std::string& fallback_proxy,
-                             const std::string& secure_proxy_check_url,
-                             base::CommandLine* command_line) {
-  DCHECK((primary_proxy.empty() && fallback_proxy.empty() &&
-      secure_proxy_check_url.empty()) ||
-          (!primary_proxy.empty() && !fallback_proxy.empty() &&
-              !secure_proxy_check_url.empty()));
-  if (primary_proxy.empty())
-    return;
-  command_line->AppendSwitchASCII(
-      data_reduction_proxy::switches::kDataReductionProxy, primary_proxy);
-  command_line->AppendSwitchASCII(
-      data_reduction_proxy::switches::kDataReductionProxyFallback,
-      fallback_proxy);
-  command_line->AppendSwitchASCII(
-      data_reduction_proxy::switches::kDataReductionProxySecureProxyCheckURL,
-      secure_proxy_check_url);
-}
-
-}  // namespace
-
-CronetDataReductionProxy::CronetDataReductionProxy(
-    const std::string& key,
-    const std::string& primary_proxy,
-    const std::string& fallback_proxy,
-    const std::string& secure_proxy_check_url,
-    const std::string& user_agent,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    net::NetLog* net_log)
-    : task_runner_(task_runner) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
-  AddOptionsToCommandLine(primary_proxy, fallback_proxy, secure_proxy_check_url,
-                          base::CommandLine::ForCurrentProcess());
-  prefs_ = CreatePrefService();
-  // In Cronet, the Data Reduction Proxy's UI classes are Created on Cronet's
-  // network thread.
-  settings_.reset(
-      new data_reduction_proxy::DataReductionProxySettings());
-  io_data_.reset(new data_reduction_proxy::DataReductionProxyIOData(
-      data_reduction_proxy::Client::CRONET_ANDROID, 0, net_log, task_runner,
-      task_runner, false, user_agent, std::string()));
-  io_data_->request_options()->SetKeyOnIO(key);
-}
-
-CronetDataReductionProxy::~CronetDataReductionProxy() {
-  io_data_->ShutdownOnUIThread();
-}
-
-std::unique_ptr<net::NetworkDelegate>
-CronetDataReductionProxy::CreateNetworkDelegate(
-    std::unique_ptr<net::NetworkDelegate> wrapped_network_delegate) {
-  return io_data_->CreateNetworkDelegate(std::move(wrapped_network_delegate),
-                                         false /* No bypass UMA */);
-}
-
-std::unique_ptr<net::ProxyDelegate>
-CronetDataReductionProxy::CreateProxyDelegate() {
-  return io_data_->CreateProxyDelegate();
-}
-
-std::unique_ptr<net::URLRequestInterceptor>
-CronetDataReductionProxy::CreateInterceptor() {
-  return io_data_->CreateInterceptor();
-}
-
-void CronetDataReductionProxy::Init(bool enable,
-                                    net::URLRequestContext* context) {
-  url_request_context_getter_ =
-      new net::TrivialURLRequestContextGetter(
-          context, task_runner_);
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyService>
-      data_reduction_proxy_service(
-          new data_reduction_proxy::DataReductionProxyService(
-              settings_.get(), prefs_.get(), url_request_context_getter_.get(),
-              base::MakeUnique<data_reduction_proxy::DataStore>(), task_runner_,
-              task_runner_, task_runner_, base::TimeDelta()));
-  io_data_->SetDataReductionProxyService(
-      data_reduction_proxy_service->GetWeakPtr());
-  settings_->InitDataReductionProxySettings(
-      kDataReductionProxyEnabled, prefs_.get(), io_data_.get(),
-      std::move(data_reduction_proxy_service));
-  settings_->SetDataReductionProxyEnabled(enable);
-  settings_->MaybeActivateDataReductionProxy(true);
-}
-
-}  // namespace cronet
diff --git a/components/cronet/android/cronet_data_reduction_proxy.h b/components/cronet/android/cronet_data_reduction_proxy.h
deleted file mode 100644
index 0d80ca3..0000000
--- a/components/cronet/android/cronet_data_reduction_proxy.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CRONET_ANDROID_CRONET_DATA_REDUCTION_PROXY_H_
-#define COMPONENTS_CRONET_ANDROID_CRONET_DATA_REDUCTION_PROXY_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-
-class PrefService;
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace data_reduction_proxy {
-class DataReductionProxyIOData;
-class DataReductionProxySettings;
-}
-
-namespace net {
-class NetLog;
-class NetworkDelegate;
-class ProxyDelegate;
-class URLRequestContext;
-class URLRequestContextGetter;
-class URLRequestInterceptor;
-}
-
-namespace cronet {
-
-// Wrapper and configurator of Data Reduction Proxy objects for Cronet. It
-// configures the Data Reduction Proxy to run both its UI and IO classes on
-// Cronet's network thread.
-class CronetDataReductionProxy {
- public:
-  // Construct Data Reduction Proxy Settings and IOData objects and set
-  // the authentication key. The |task_runner| should be suitable for running
-  // tasks on the network thread. The primary proxy, fallback proxy, and secure
-  // proxy check url can override defaults. All or none must be specified.
-  CronetDataReductionProxy(
-      const std::string& key,
-      const std::string& primary_proxy,
-      const std::string& fallback_proxy,
-      const std::string& secure_proxy_check_url,
-      const std::string& user_agent,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-      net::NetLog* net_log);
-
-  ~CronetDataReductionProxy();
-
-  // Constructs a network delegate suitable for adding Data Reduction Proxy
-  // request headers.
-  std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate(
-      std::unique_ptr<net::NetworkDelegate> wrapped_network_delegate);
-
-  // Constructs a proxy delegate suitable for adding Data Reduction Proxy
-  // proxy resolution.
-  std::unique_ptr<net::ProxyDelegate> CreateProxyDelegate();
-
-  // Constructs a URLRequestInterceptor suitable for carrying out the Data
-  // Reduction Proxy's bypass protocol.
-  std::unique_ptr<net::URLRequestInterceptor> CreateInterceptor();
-
-  // Constructs a bridge between the Settings and IOData objects, sets up a
-  // context for secure proxy check requests, and enables the proxy, if
-  // |enable| is true.
-  void Init(bool enable, net::URLRequestContext* context);
-
- private:
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  std::unique_ptr<PrefService> prefs_;
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
-  std::unique_ptr<data_reduction_proxy::DataReductionProxySettings> settings_;
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyIOData> io_data_;
-
-  DISALLOW_COPY_AND_ASSIGN(CronetDataReductionProxy);
-};
-
-}  // namespace cronet
-
-#endif  // COMPONENTS_CRONET_ANDROID_CRONET_DATA_REDUCTION_PROXY_H_
diff --git a/components/cronet/android/cronet_in_memory_pref_store.cc b/components/cronet/android/cronet_in_memory_pref_store.cc
deleted file mode 100644
index c057e5b..0000000
--- a/components/cronet/android/cronet_in_memory_pref_store.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/cronet/android/cronet_in_memory_pref_store.h"
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/values.h"
-
-CronetInMemoryPrefStore::CronetInMemoryPrefStore() {}
-
-CronetInMemoryPrefStore::~CronetInMemoryPrefStore() {}
-
-bool CronetInMemoryPrefStore::GetValue(const std::string& key,
-                                       const base::Value** value) const {
-  return prefs_.GetValue(key, value);
-}
-
-std::unique_ptr<base::DictionaryValue> CronetInMemoryPrefStore::GetValues()
-    const {
-  return prefs_.AsDictionaryValue();
-}
-
-bool CronetInMemoryPrefStore::GetMutableValue(const std::string& key,
-                                              base::Value** value) {
-  return prefs_.GetValue(key, value);
-}
-
-void CronetInMemoryPrefStore::AddObserver(PrefStore::Observer* observer) {
-  observers_.AddObserver(observer);
-}
-
-void CronetInMemoryPrefStore::RemoveObserver(PrefStore::Observer* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-bool CronetInMemoryPrefStore::HasObservers() const {
-  return observers_.might_have_observers();
-}
-
-bool CronetInMemoryPrefStore::IsInitializationComplete() const {
-  return true;
-}
-
-void CronetInMemoryPrefStore::SetValue(const std::string& key,
-                                       std::unique_ptr<base::Value> value,
-                                       uint32_t flags) {
-  DCHECK(value);
-  if (prefs_.SetValue(key, std::move(value)))
-    ReportValueChanged(key, flags);
-}
-
-void CronetInMemoryPrefStore::SetValueSilently(
-    const std::string& key,
-    std::unique_ptr<base::Value> value,
-    uint32_t flags) {
-  prefs_.SetValue(key, std::move(value));
-}
-
-void CronetInMemoryPrefStore::RemoveValue(const std::string& key,
-                                          uint32_t flags) {
-  if (prefs_.RemoveValue(key))
-    ReportValueChanged(key, flags);
-}
-
-bool CronetInMemoryPrefStore::ReadOnly() const {
-  return false;
-}
-
-PersistentPrefStore::PrefReadError
-CronetInMemoryPrefStore::GetReadError() const {
-  return PersistentPrefStore::PREF_READ_ERROR_NONE;
-}
-
-PersistentPrefStore::PrefReadError CronetInMemoryPrefStore::ReadPrefs() {
-  return PersistentPrefStore::PREF_READ_ERROR_NONE;
-}
-
-void CronetInMemoryPrefStore::ReadPrefsAsync(
-    ReadErrorDelegate* error_delegate_raw) {
-}
-
-void CronetInMemoryPrefStore::ReportValueChanged(const std::string& key,
-                                                 uint32_t flags) {
-  for (Observer& observer : observers_)
-    observer.OnPrefValueChanged(key);
-}
diff --git a/components/cronet/android/cronet_in_memory_pref_store.h b/components/cronet/android/cronet_in_memory_pref_store.h
deleted file mode 100644
index 20c1689..0000000
--- a/components/cronet/android/cronet_in_memory_pref_store.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CRONET_ANDROID_CRONET_IN_MEMORY_PREF_STORE_H_
-#define COMPONENTS_CRONET_ANDROID_CRONET_IN_MEMORY_PREF_STORE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/prefs/persistent_pref_store.h"
-#include "components/prefs/pref_value_map.h"
-
-namespace base {
-class DictionaryValue;
-class Value;
-}
-
-// A light-weight prefstore implementation that keeps preferences
-// in a memory backed store. This is not a persistent prefstore.
-// TODO(bengr): Move to components/prefs or some other shared location.
-class CronetInMemoryPrefStore : public PersistentPrefStore {
- public:
-  CronetInMemoryPrefStore();
-
-  // PrefStore overrides:
-  bool GetValue(const std::string& key,
-                const base::Value** result) const override;
-  std::unique_ptr<base::DictionaryValue> GetValues() const override;
-  void AddObserver(PrefStore::Observer* observer) override;
-  void RemoveObserver(PrefStore::Observer* observer) override;
-  bool HasObservers() const override;
-  bool IsInitializationComplete() const override;
-
-  // PersistentPrefStore overrides:
-  bool GetMutableValue(const std::string& key, base::Value** result) override;
-  void ReportValueChanged(const std::string& key, uint32_t flags) override;
-  void SetValue(const std::string& key,
-                std::unique_ptr<base::Value> value,
-                uint32_t flags) override;
-  void SetValueSilently(const std::string& key,
-                        std::unique_ptr<base::Value> value,
-                        uint32_t flags) override;
-  void RemoveValue(const std::string& key, uint32_t flags) override;
-  bool ReadOnly() const override;
-  PrefReadError GetReadError() const override;
-  PersistentPrefStore::PrefReadError ReadPrefs() override;
-  void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
-  void CommitPendingWrite() override {}
-  void SchedulePendingLossyWrites() override {}
-  void ClearMutableValues() override {}
-
- private:
-  ~CronetInMemoryPrefStore() override;
-
-  // Stores the preference values.
-  PrefValueMap prefs_;
-
-  base::ObserverList<PrefStore::Observer, true> observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(CronetInMemoryPrefStore);
-};
-
-#endif  // COMPONENTS_CRONET_ANDROID_CRONET_IN_MEMORY_PREF_STORE_H_
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index 66e4cc3..2a252b43 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -68,10 +68,6 @@
 #include "net/url_request/url_request_context_builder.h"
 #include "net/url_request/url_request_interceptor.h"
 
-#if defined(DATA_REDUCTION_PROXY_SUPPORT)
-#include "components/cronet/android/cronet_data_reduction_proxy.h"
-#endif
-
 using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
@@ -615,25 +611,6 @@
 
   std::unique_ptr<net::NetworkDelegate> network_delegate(
       new BasicNetworkDelegate());
-#if defined(DATA_REDUCTION_PROXY_SUPPORT)
-  DCHECK(!data_reduction_proxy_);
-  // For now, the choice to enable the data reduction proxy happens once,
-  // at initialization. It cannot be disabled thereafter.
-  if (!config->data_reduction_proxy_key.empty()) {
-    data_reduction_proxy_.reset(new CronetDataReductionProxy(
-        config->data_reduction_proxy_key, config->data_reduction_primary_proxy,
-        config->data_reduction_fallback_proxy,
-        config->data_reduction_secure_proxy_check_url, config->user_agent,
-        GetNetworkTaskRunner(), g_net_log.Get().net_log()));
-    network_delegate = data_reduction_proxy_->CreateNetworkDelegate(
-        std::move(network_delegate));
-    context_builder.set_proxy_delegate(
-        data_reduction_proxy_->CreateProxyDelegate());
-    std::vector<std::unique_ptr<net::URLRequestInterceptor>> interceptors;
-    interceptors.push_back(data_reduction_proxy_->CreateInterceptor());
-    context_builder.SetInterceptors(std::move(interceptors));
-  }
-#endif  // defined(DATA_REDUCTION_PROXY_SUPPORT)
   context_builder.set_network_delegate(std::move(network_delegate));
   context_builder.set_net_log(g_net_log.Get().net_log());
 
@@ -819,10 +796,6 @@
   Java_CronetUrlRequestContext_initNetworkThread(env,
                                                  jcronet_url_request_context);
 
-#if defined(DATA_REDUCTION_PROXY_SUPPORT)
-  if (data_reduction_proxy_)
-    data_reduction_proxy_->Init(true, GetURLRequestContext());
-#endif
   is_context_initialized_ = true;
   while (!tasks_waiting_for_context_.empty()) {
     tasks_waiting_for_context_.front().Run();
@@ -1092,10 +1065,6 @@
     jboolean jhttp2_enabled,
     jboolean jsdch_enabled,
     jboolean jbrotli_enabled,
-    const JavaParamRef<jstring>& jdata_reduction_proxy_key,
-    const JavaParamRef<jstring>& jdata_reduction_proxy_primary_proxy,
-    const JavaParamRef<jstring>& jdata_reduction_proxy_fallback_proxy,
-    const JavaParamRef<jstring>& jdata_reduction_proxy_secure_proxy_check_url,
     jboolean jdisable_cache,
     jint jhttp_cache_mode,
     jlong jhttp_cache_max_size,
@@ -1114,12 +1083,6 @@
       ConvertNullableJavaStringToUTF8(env, juser_agent),
       ConvertNullableJavaStringToUTF8(env,
                                       jexperimental_quic_connection_options),
-      ConvertNullableJavaStringToUTF8(env, jdata_reduction_proxy_key),
-      ConvertNullableJavaStringToUTF8(env, jdata_reduction_proxy_primary_proxy),
-      ConvertNullableJavaStringToUTF8(env,
-                                      jdata_reduction_proxy_fallback_proxy),
-      ConvertNullableJavaStringToUTF8(
-          env, jdata_reduction_proxy_secure_proxy_check_url),
       base::WrapUnique(
           reinterpret_cast<net::CertVerifier*>(jmock_cert_verifier)),
       jenable_network_quality_estimator,
diff --git a/components/cronet/android/cronet_url_request_context_adapter.h b/components/cronet/android/cronet_url_request_context_adapter.h
index 664c8f3..666af1a7e 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.h
+++ b/components/cronet/android/cronet_url_request_context_adapter.h
@@ -42,10 +42,6 @@
 namespace cronet {
 class TestUtil;
 
-#if defined(DATA_REDUCTION_PROXY_SUPPORT)
-class CronetDataReductionProxy;
-#endif
-
 struct URLRequestContextConfig;
 
 bool CronetUrlRequestContextAdapterRegisterJni(JNIEnv* env);
@@ -255,10 +251,6 @@
   // Java object that owns this CronetURLRequestContextAdapter.
   base::android::ScopedJavaGlobalRef<jobject> jcronet_url_request_context_;
 
-#if defined(DATA_REDUCTION_PROXY_SUPPORT)
-  std::unique_ptr<CronetDataReductionProxy> data_reduction_proxy_;
-#endif
-
   DISALLOW_COPY_AND_ASSIGN(CronetURLRequestContextAdapter);
 };
 
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java
index 842d11c..813db69 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetEngineBuilderImpl.java
@@ -84,10 +84,6 @@
     private boolean mHttp2Enabled;
     private boolean mSdchEnabled;
     private boolean mBrotiEnabled;
-    private String mDataReductionProxyKey;
-    private String mDataReductionProxyPrimaryProxy;
-    private String mDataReductionProxyFallbackProxy;
-    private String mDataReductionProxySecureProxyCheckUrl;
     private boolean mDisableCache;
     private int mHttpCacheMode;
     private long mHttpCacheMaxSize;
@@ -199,41 +195,6 @@
         return mBrotiEnabled;
     }
 
-    @Override
-    public CronetEngineBuilderImpl enableDataReductionProxy(String key) {
-        mDataReductionProxyKey = key;
-        return this;
-    }
-
-    String dataReductionProxyKey() {
-        return mDataReductionProxyKey;
-    }
-
-    @Override
-    public CronetEngineBuilderImpl setDataReductionProxyOptions(
-            String primaryProxy, String fallbackProxy, String secureProxyCheckUrl) {
-        if (primaryProxy.isEmpty() || fallbackProxy.isEmpty() || secureProxyCheckUrl.isEmpty()) {
-            throw new IllegalArgumentException(
-                    "Primary and fallback proxies and check url must be set");
-        }
-        mDataReductionProxyPrimaryProxy = primaryProxy;
-        mDataReductionProxyFallbackProxy = fallbackProxy;
-        mDataReductionProxySecureProxyCheckUrl = secureProxyCheckUrl;
-        return this;
-    }
-
-    String dataReductionProxyPrimaryProxy() {
-        return mDataReductionProxyPrimaryProxy;
-    }
-
-    String dataReductionProxyFallbackProxy() {
-        return mDataReductionProxyFallbackProxy;
-    }
-
-    String dataReductionProxySecureProxyCheckUrl() {
-        return mDataReductionProxySecureProxyCheckUrl;
-    }
-
     @IntDef({
             HTTP_CACHE_DISABLED, HTTP_CACHE_IN_MEMORY, HTTP_CACHE_DISK_NO_HTTP, HTTP_CACHE_DISK,
     })
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
index f3c95b69..4de86f0 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
@@ -140,7 +140,7 @@
     /** Holds CertVerifier data. */
     private String mCertVerifierData;
 
-    private ConditionVariable mStopNetLogCompleted;
+    private volatile ConditionVariable mStopNetLogCompleted;
 
     /**
      * True if a NetLog observer is active.
@@ -187,10 +187,8 @@
         final long urlRequestContextConfig = nativeCreateRequestContextConfig(
                 builder.getUserAgent(), builder.storagePath(), builder.quicEnabled(),
                 builder.getDefaultQuicUserAgentId(), builder.http2Enabled(), builder.sdchEnabled(),
-                builder.brotliEnabled(), builder.dataReductionProxyKey(),
-                builder.dataReductionProxyPrimaryProxy(), builder.dataReductionProxyFallbackProxy(),
-                builder.dataReductionProxySecureProxyCheckUrl(), builder.cacheDisabled(),
-                builder.httpCacheMode(), builder.httpCacheMaxSize(), builder.experimentalOptions(),
+                builder.brotliEnabled(), builder.cacheDisabled(), builder.httpCacheMode(),
+                builder.httpCacheMaxSize(), builder.experimentalOptions(),
                 builder.mockCertVerifier(), builder.networkQualityEstimatorEnabled(),
                 builder.publicKeyPinningBypassForLocalTrustAnchorsEnabled(),
                 builder.certVerifierData());
@@ -297,9 +295,9 @@
                 return;
             }
             checkHaveAdapter();
+            mStopNetLogCompleted = new ConditionVariable();
             nativeStopNetLog(mUrlRequestContextAdapter);
             mIsLogging = false;
-            mStopNetLogCompleted = new ConditionVariable();
         }
         mStopNetLogCompleted.block();
     }
@@ -679,9 +677,7 @@
     // Native methods are implemented in cronet_url_request_context_adapter.cc.
     private static native long nativeCreateRequestContextConfig(String userAgent,
             String storagePath, boolean quicEnabled, String quicUserAgentId, boolean http2Enabled,
-            boolean sdchEnabled, boolean brotliEnabled, String dataReductionProxyKey,
-            String dataReductionProxyPrimaryProxy, String dataReductionProxyFallbackProxy,
-            String dataReductionProxySecureProxyCheckUrl, boolean disableCache, int httpCacheMode,
+            boolean sdchEnabled, boolean brotliEnabled, boolean disableCache, int httpCacheMode,
             long httpCacheMaxSize, String experimentalOptions, long mockCertVerifier,
             boolean enableNetworkQualityEstimator,
             boolean bypassPublicKeyPinningForLocalTrustAnchors, String certVerifierData);
diff --git a/components/cronet/android/test/assets/test/datareductionproxysuccess.txt b/components/cronet/android/test/assets/test/datareductionproxysuccess.txt
deleted file mode 100644
index e9ea42a..0000000
--- a/components/cronet/android/test/assets/test/datareductionproxysuccess.txt
+++ /dev/null
@@ -1 +0,0 @@
-this is a text file
diff --git a/components/cronet/android/test/assets/test/datareductionproxysuccess.txt.mock-http-headers b/components/cronet/android/test/assets/test/datareductionproxysuccess.txt.mock-http-headers
deleted file mode 100644
index 856b4ba..0000000
--- a/components/cronet/android/test/assets/test/datareductionproxysuccess.txt.mock-http-headers
+++ /dev/null
@@ -1,5 +0,0 @@
-HTTP/1.1 200 OK
-Content-Type: text/plain
-Content-Length: 19
-header-name: header-value
-Via: 1.1 Chrome-Compression-Proxy
diff --git a/components/cronet/android/test/cronet_url_request_context_config_test.cc b/components/cronet/android/test/cronet_url_request_context_config_test.cc
index c804345..ad522b7 100644
--- a/components/cronet/android/test/cronet_url_request_context_config_test.cc
+++ b/components/cronet/android/test/cronet_url_request_context_config_test.cc
@@ -42,12 +42,8 @@
   CHECK_EQ(config->cert_verifier_data, "test_cert_verifier_data");
   CHECK_EQ(config->http_cache, URLRequestContextConfig::HttpCacheType::MEMORY);
   CHECK_EQ(config->http_cache_max_size, 54321);
-  CHECK_EQ(config->data_reduction_proxy_key, "abcd");
   CHECK_EQ(config->user_agent, "efgh");
   CHECK_EQ(config->experimental_options, "ijkl");
-  CHECK_EQ(config->data_reduction_primary_proxy, "mnop");
-  CHECK_EQ(config->data_reduction_fallback_proxy, "qrst");
-  CHECK_EQ(config->data_reduction_secure_proxy_check_url, "uvwx");
   CHECK_EQ(config->storage_path,
            base::android::ConvertJavaStringToUTF8(env, jstorage_path));
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index b9cc1cd..afaf8993 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -190,49 +190,6 @@
 
     @SmallTest
     @Feature({"Cronet"})
-    @OnlyRunNativeCronet
-    public void testDataReductionProxyEnabled() throws Exception {
-        final CronetTestFramework testFramework = startCronetTestFrameworkAndSkipLibraryInit();
-
-        // Ensure native code is loaded before trying to start test server.
-        new ExperimentalCronetEngine.Builder(getContext()).build().shutdown();
-
-        assertTrue(NativeTestServer.startNativeTestServer(getContext()));
-        if (!NativeTestServer.isDataReductionProxySupported()) {
-            return;
-        }
-        String serverHostPort = NativeTestServer.getHostPort();
-
-        // Enable the Data Reduction Proxy and configure it to use the test
-        // server as its primary proxy, and to check successfully that this
-        // proxy is OK to use.
-        ExperimentalCronetEngine.Builder cronetEngineBuilder =
-                new ExperimentalCronetEngine.Builder(getContext());
-        cronetEngineBuilder.enableDataReductionProxy("test-key");
-        cronetEngineBuilder.setDataReductionProxyOptions(serverHostPort, "unused.net:9999",
-                NativeTestServer.getFileURL("/secureproxychecksuccess.txt"));
-        testFramework.mCronetEngine = (CronetEngineBase) cronetEngineBuilder.build();
-        TestUrlRequestCallback callback = new TestUrlRequestCallback();
-
-        // Construct and start a request that can only be returned by the test
-        // server. This request will fail if the configuration logic for the
-        // Data Reduction Proxy is not used.
-        UrlRequest.Builder urlRequestBuilder = testFramework.mCronetEngine.newUrlRequestBuilder(
-                "http://DomainThatDoesnt.Resolve/datareductionproxysuccess.txt", callback,
-                callback.getExecutor());
-        urlRequestBuilder.build().start();
-        callback.blockForDone();
-
-        // Verify that the request is successful and that the Data Reduction
-        // Proxy logic configured to use the test server as its proxy.
-        assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
-        assertEquals(serverHostPort, callback.mResponseInfo.getProxyServer());
-        assertEquals("http://DomainThatDoesnt.Resolve/datareductionproxysuccess.txt",
-                callback.mResponseInfo.getUrl());
-    }
-
-    @SmallTest
-    @Feature({"Cronet"})
     @DisabledTest(message = "Disabled due to flaky assert. See crbug.com/710626")
     public void testRealTimeNetworkQualityObservationsNotEnabled() throws Exception {
         ExperimentalCronetEngine.Builder mCronetEngineBuilder =
@@ -1414,10 +1371,8 @@
         builder.addQuicHint("example.com", 12, 34);
         builder.setCertVerifierData("test_cert_verifier_data");
         builder.enableHttpCache(HTTP_CACHE_IN_MEMORY, 54321);
-        builder.enableDataReductionProxy("abcd");
         builder.setUserAgent("efgh");
         builder.setExperimentalOptions("ijkl");
-        builder.setDataReductionProxyOptions("mnop", "qrst", "uvwx");
         builder.setStoragePath(CronetTestFramework.getTestStorage(getContext()));
         builder.enablePublicKeyPinningBypassForLocalTrustAnchors(false);
         nativeVerifyUrlRequestContextConfig(
diff --git a/components/cronet/android/test/native_test_server.cc b/components/cronet/android/test/native_test_server.cc
index 6f4a21e..54f32ab 100644
--- a/components/cronet/android/test/native_test_server.cc
+++ b/components/cronet/android/test/native_test_server.cc
@@ -313,15 +313,6 @@
   return base::android::ConvertUTF8ToJavaString(env, host_port);
 }
 
-jboolean IsDataReductionProxySupported(JNIEnv* env,
-                                       const JavaParamRef<jclass>& jcaller) {
-#if defined(DATA_REDUCTION_PROXY_SUPPORT)
-  return JNI_TRUE;
-#else
-  return JNI_FALSE;
-#endif
-}
-
 bool RegisterNativeTestServer(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/components/cronet/android/test/src/org/chromium/net/NativeTestServer.java b/components/cronet/android/test/src/org/chromium/net/NativeTestServer.java
index 37f8032e..325cfcc7 100644
--- a/components/cronet/android/test/src/org/chromium/net/NativeTestServer.java
+++ b/components/cronet/android/test/src/org/chromium/net/NativeTestServer.java
@@ -91,10 +91,6 @@
         return nativeGetHostPort();
     }
 
-    public static boolean isDataReductionProxySupported() {
-        return nativeIsDataReductionProxySupported();
-    }
-
     private static native boolean nativeStartNativeTestServer(String filePath, String testDataDir);
     private static native void nativeShutdownNativeTestServer();
     private static native String nativeGetEchoBodyURL();
@@ -106,5 +102,4 @@
     private static native String nativeGetExabyteResponseURL();
     private static native String nativeGetHostPort();
     private static native int nativeGetPort();
-    private static native boolean nativeIsDataReductionProxySupported();
 }
diff --git a/components/cronet/ios/BUILD.gn b/components/cronet/ios/BUILD.gn
index ac1dfe0..a78296e9 100644
--- a/components/cronet/ios/BUILD.gn
+++ b/components/cronet/ios/BUILD.gn
@@ -14,10 +14,6 @@
 
 assert(!is_component_build, "Cronet requires static library build.")
 
-declare_args() {
-  cronet_enable_data_reduction_proxy_support = false
-}
-
 process_version("cronet_version_header") {
   template_file = "//components/cronet/version.h.in"
   sources = [
diff --git a/components/cronet/stale_host_resolver_unittest.cc b/components/cronet/stale_host_resolver_unittest.cc
index 9e6e6554..0bff86e8 100644
--- a/components/cronet/stale_host_resolver_unittest.cc
+++ b/components/cronet/stale_host_resolver_unittest.cc
@@ -470,14 +470,6 @@
       "\"delay_ms\":0,"
       "\"max_expired_time_ms\":0,"
       "\"max_stale_uses\":0}}",
-      // Data reduction proxy key.
-      "",
-      // Data reduction proxy.
-      "",
-      // Fallback data reduction proxy.
-      "",
-      // Data reduction proxy secure proxy check URL.
-      "",
       // MockCertVerifier to use for testing purposes.
       std::unique_ptr<net::CertVerifier>(),
       // Enable network quality estimator.
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc
index 6a2f8c3..16bd87f 100644
--- a/components/cronet/url_request_context_config.cc
+++ b/components/cronet/url_request_context_config.cc
@@ -339,10 +339,6 @@
     const std::string& storage_path,
     const std::string& user_agent,
     const std::string& experimental_options,
-    const std::string& data_reduction_proxy_key,
-    const std::string& data_reduction_primary_proxy,
-    const std::string& data_reduction_fallback_proxy,
-    const std::string& data_reduction_secure_proxy_check_url,
     std::unique_ptr<net::CertVerifier> mock_cert_verifier,
     bool enable_network_quality_estimator,
     bool bypass_public_key_pinning_for_local_trust_anchors,
@@ -358,11 +354,6 @@
       storage_path(storage_path),
       user_agent(user_agent),
       experimental_options(experimental_options),
-      data_reduction_proxy_key(data_reduction_proxy_key),
-      data_reduction_primary_proxy(data_reduction_primary_proxy),
-      data_reduction_fallback_proxy(data_reduction_fallback_proxy),
-      data_reduction_secure_proxy_check_url(
-          data_reduction_secure_proxy_check_url),
       mock_cert_verifier(std::move(mock_cert_verifier)),
       enable_network_quality_estimator(enable_network_quality_estimator),
       bypass_public_key_pinning_for_local_trust_anchors(
@@ -425,9 +416,7 @@
   return base::MakeUnique<URLRequestContextConfig>(
       enable_quic, quic_user_agent_id, enable_spdy, enable_sdch, enable_brotli,
       http_cache, http_cache_max_size, load_disable_cache, storage_path,
-      user_agent, experimental_options, data_reduction_proxy_key,
-      data_reduction_primary_proxy, data_reduction_fallback_proxy,
-      data_reduction_secure_proxy_check_url, std::move(mock_cert_verifier),
+      user_agent, experimental_options, std::move(mock_cert_verifier),
       enable_network_quality_estimator,
       bypass_public_key_pinning_for_local_trust_anchors, cert_verifier_data);
 }
diff --git a/components/cronet/url_request_context_config.h b/components/cronet/url_request_context_config.h
index ce398236..6e55a92a 100644
--- a/components/cronet/url_request_context_config.h
+++ b/components/cronet/url_request_context_config.h
@@ -102,14 +102,6 @@
       const std::string& user_agent,
       // JSON encoded experimental options.
       const std::string& experimental_options,
-      // Data reduction proxy key.
-      const std::string& data_reduction_proxy_key,
-      // Data reduction proxy.
-      const std::string& data_reduction_primary_proxy,
-      // Fallback data reduction proxy.
-      const std::string& data_reduction_fallback_proxy,
-      // Data reduction proxy secure proxy check URL.
-      const std::string& data_reduction_secure_proxy_check_url,
       // MockCertVerifier to use for testing purposes.
       std::unique_ptr<net::CertVerifier> mock_cert_verifier,
       // Enable network quality estimator.
@@ -154,11 +146,6 @@
   //   {"experiment1": {"option1": "option_value1", "option2": "option_value2",
   //    ...}, "experiment2: {"option3", "option_value3", ...}, ...}
   const std::string experimental_options;
-  // Enable Data Reduction Proxy with authentication key.
-  const std::string data_reduction_proxy_key;
-  const std::string data_reduction_primary_proxy;
-  const std::string data_reduction_fallback_proxy;
-  const std::string data_reduction_secure_proxy_check_url;
 
   // Certificate verifier for testing.
   std::unique_ptr<net::CertVerifier> mock_cert_verifier;
@@ -226,11 +213,6 @@
   //   {"experiment1": {"option1": "option_value1", "option2": "option_value2",
   //    ...}, "experiment2: {"option3", "option_value3", ...}, ...}
   std::string experimental_options = "{}";
-  // Enable Data Reduction Proxy with authentication key.
-  std::string data_reduction_proxy_key = "";
-  std::string data_reduction_primary_proxy = "";
-  std::string data_reduction_fallback_proxy = "";
-  std::string data_reduction_secure_proxy_check_url = "";
 
   // Certificate verifier for testing.
   std::unique_ptr<net::CertVerifier> mock_cert_verifier = nullptr;
diff --git a/components/cronet/url_request_context_config_unittest.cc b/components/cronet/url_request_context_config_unittest.cc
index 1e6711e..1ee203b 100644
--- a/components/cronet/url_request_context_config_unittest.cc
+++ b/components/cronet/url_request_context_config_unittest.cc
@@ -55,14 +55,6 @@
       "\"MAP * 127.0.0.1\"},"
       // See http://crbug.com/696569.
       "\"disable_ipv6_on_wifi\":true}",
-      // Data reduction proxy key.
-      "",
-      // Data reduction proxy.
-      "",
-      // Fallback data reduction proxy.
-      "",
-      // Data reduction proxy secure proxy check URL.
-      "",
       // MockCertVerifier to use for testing purposes.
       std::unique_ptr<net::CertVerifier>(),
       // Enable network quality estimator.
@@ -144,14 +136,6 @@
       // JSON encoded experimental options.
       "{\"QUIC\":{\"migrate_sessions_on_network_change\":true,"
       "\"migrate_sessions_early\":true}}",
-      // Data reduction proxy key.
-      "",
-      // Data reduction proxy.
-      "",
-      // Fallback data reduction proxy.
-      "",
-      // Data reduction proxy secure proxy check URL.
-      "",
       // MockCertVerifier to use for testing purposes.
       std::unique_ptr<net::CertVerifier>(),
       // Enable network quality estimator.
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index 8c17ba5..e6043678 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -450,9 +450,9 @@
   size_t stride = width_ * kBytesPerPixel;
   buffer->shared_memory.reset(new base::SharedMemory());
   buffer->shared_memory->CreateAndMapAnonymous(stride * height_);
-  buffer->shm_pool.reset(
-      wl_shm_create_pool(globals_.shm.get(), buffer->shared_memory->handle().fd,
-                         buffer->shared_memory->requested_size()));
+  buffer->shm_pool.reset(wl_shm_create_pool(
+      globals_.shm.get(), buffer->shared_memory->handle().GetHandle(),
+      buffer->shared_memory->requested_size()));
 
   buffer->buffer.reset(static_cast<wl_buffer*>(wl_shm_pool_create_buffer(
       buffer->shm_pool.get(), 0, width_, height_, stride, kShmFormat)));
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index 0d27ff60..5b718c3 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -443,7 +443,7 @@
                      int32_t size) {
   std::unique_ptr<SharedMemory> shared_memory =
       GetUserDataAs<Display>(resource)->CreateSharedMemory(
-          base::FileDescriptor(fd, true), size);
+          base::SharedMemoryHandle::ImportHandle(fd), size);
   if (!shared_memory) {
     wl_resource_post_no_memory(resource);
     return;
@@ -2749,7 +2749,7 @@
     memcpy(shared_keymap.memory(), keymap_string.get(), keymap_size);
     wl_keyboard_send_keymap(keyboard_resource_,
                             WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
-                            shared_keymap.handle().fd, keymap_size);
+                            shared_keymap.handle().GetHandle(), keymap_size);
   }
 
   // Overridden from KeyboardDelegate:
diff --git a/components/guest_view/browser/guest_view_message_filter.cc b/components/guest_view/browser/guest_view_message_filter.cc
index 03aefe80..c2124ed 100644
--- a/components/guest_view/browser/guest_view_message_filter.cc
+++ b/components/guest_view/browser/guest_view_message_filter.cc
@@ -144,7 +144,8 @@
 
   guest->WillAttach(
       owner_web_contents, element_instance_id, false,
-      base::Bind(&GuestViewMessageFilter::WillAttachCallback, this, guest));
+      base::Bind(&GuestViewBase::DidAttach,
+                 guest->weak_ptr_factory_.GetWeakPtr(), MSG_ROUTING_NONE));
 
   // Attach this inner WebContents |guest_web_contents| to the outer
   // WebContents |owner_web_contents|. The outer WebContents's
@@ -155,8 +156,4 @@
                                                     embedder_frame);
 }
 
-void GuestViewMessageFilter::WillAttachCallback(GuestViewBase* guest) {
-  guest->DidAttach(MSG_ROUTING_NONE);
-}
-
 }  // namespace guest_view
diff --git a/components/guest_view/browser/guest_view_message_filter.h b/components/guest_view/browser/guest_view_message_filter.h
index 7c271d8..1a24bf2c 100644
--- a/components/guest_view/browser/guest_view_message_filter.h
+++ b/components/guest_view/browser/guest_view_message_filter.h
@@ -23,7 +23,6 @@
 }
 
 namespace guest_view {
-class GuestViewBase;
 class GuestViewManager;
 
 // This class filters out incoming GuestView-specific IPC messages from the
@@ -75,8 +74,6 @@
   void OnViewCreated(int view_instance_id, const std::string& view_type);
   void OnViewGarbageCollected(int view_instance_id);
 
-  void WillAttachCallback(GuestViewBase* guest);
-
   DISALLOW_COPY_AND_ASSIGN(GuestViewMessageFilter);
 };
 
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index 01c55c5..fb51172 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -159,10 +159,6 @@
 
 namespace {
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-content::ZygoteHandle g_nacl_zygote;
-#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
-
 // NOTE: changes to this class need to be reviewed by the security team.
 class NaClSandboxedProcessLauncherDelegate
     : public content::SandboxedProcessLauncherDelegate {
@@ -333,14 +329,6 @@
   NaClBrowser::GetDelegate()->SetDebugPatterns(nacl_debug_mask);
 }
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-// static
-void NaClProcessHost::EarlyZygoteLaunch() {
-  DCHECK(!g_nacl_zygote);
-  g_nacl_zygote = content::CreateZygote();
-}
-#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
-
 void NaClProcessHost::Launch(
     NaClHostMessageFilter* nacl_host_message_filter,
     IPC::Message* reply_msg,
diff --git a/components/nacl/browser/nacl_process_host.h b/components/nacl/browser/nacl_process_host.h
index d3fd57a..5d85183ef 100644
--- a/components/nacl/browser/nacl_process_host.h
+++ b/components/nacl/browser/nacl_process_host.h
@@ -93,11 +93,6 @@
   // Do any minimal work that must be done at browser startup.
   static void EarlyStartup();
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-  // Launch the NaCl zygote early in the browser startup.
-  static void EarlyZygoteLaunch();
-#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
-
   // Specifies throttling time in milliseconds for PpapiHostMsg_Keepalive IPCs.
   static void SetPpapiKeepAliveThrottleForTesting(unsigned milliseconds);
 
diff --git a/components/printing/renderer/print_web_view_helper_linux.cc b/components/printing/renderer/print_web_view_helper_linux.cc
index dac616a6..ffa0752 100644
--- a/components/printing/renderer/print_web_view_helper_linux.cc
+++ b/components/printing/renderer/print_web_view_helper_linux.cc
@@ -94,7 +94,7 @@
     printed_page_params.page_number = printed_pages[i];
     Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params));
     // Send the rest of the pages with an invalid metafile handle.
-    printed_page_params.metafile_data_handle.fd = -1;
+    printed_page_params.metafile_data_handle.Release();
   }
   return true;
 #endif  // defined(OS_ANDROID)
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerHelper.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerHelper.java
index 3ec989d..761a728 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerHelper.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerHelper.java
@@ -32,13 +32,9 @@
  */
 public class AccountManagerHelper {
     private static final String TAG = "Sync_Signin";
-
     private static final Pattern AT_SYMBOL = Pattern.compile("@");
-
     private static final String GMAIL_COM = "gmail.com";
-
     private static final String GOOGLEMAIL_COM = "googlemail.com";
-
     public static final String GOOGLE_ACCOUNT_TYPE = "com.google";
 
     /**
@@ -50,7 +46,7 @@
 
     private static final AtomicReference<AccountManagerHelper> sInstance = new AtomicReference<>();
 
-    private final AccountManagerDelegate mAccountManager;
+    private final AccountManagerDelegate mDelegate;
 
     /**
      * A simple callback for getAuthToken.
@@ -73,10 +69,10 @@
     }
 
     /**
-     * @param accountManager the account manager to use as a backend service
+     * @param delegate the account manager to use as a backend service
      */
-    private AccountManagerHelper(AccountManagerDelegate accountManager) {
-        mAccountManager = accountManager;
+    private AccountManagerHelper(AccountManagerDelegate delegate) {
+        mDelegate = delegate;
     }
 
     /**
@@ -169,7 +165,7 @@
      * See http://crbug.com/517697 for details.
      */
     public Account[] getGoogleAccounts() {
-        return mAccountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE);
+        return mDelegate.getAccountsByType(GOOGLE_ACCOUNT_TYPE);
     }
 
     /**
@@ -286,7 +282,7 @@
      * @return Whether or not there is an account authenticator for Google accounts.
      */
     public boolean hasGoogleAccountAuthenticator() {
-        AuthenticatorDescription[] descs = mAccountManager.getAuthenticatorTypes();
+        AuthenticatorDescription[] descs = mDelegate.getAuthenticatorTypes();
         for (AuthenticatorDescription desc : descs) {
             if (GOOGLE_ACCOUNT_TYPE.equals(desc.type)) return true;
         }
@@ -305,7 +301,7 @@
         ConnectionRetry.runAuthTask(new AuthTask<String>() {
             @Override
             public String run() throws AuthException {
-                return mAccountManager.getAuthToken(account, authTokenType);
+                return mDelegate.getAuthToken(account, authTokenType);
             }
             @Override
             public void onSuccess(String token) {
@@ -339,7 +335,7 @@
         ConnectionRetry.runAuthTask(new AuthTask<Boolean>() {
             @Override
             public Boolean run() throws AuthException {
-                mAccountManager.invalidateAuthToken(authToken);
+                mDelegate.invalidateAuthToken(authToken);
                 return true;
             }
             @Override
@@ -356,7 +352,7 @@
     }
 
     private boolean hasFeatures(Account account, String[] features) {
-        return mAccountManager.hasFeatures(account, features);
+        return mDelegate.hasFeatures(account, features);
     }
 
     private void hasFeatures(
@@ -380,7 +376,7 @@
      */
     public void updateCredentials(
             Account account, Activity activity, @Nullable Callback<Boolean> callback) {
-        mAccountManager.updateCredentials(account, activity, callback);
+        mDelegate.updateCredentials(account, activity, callback);
     }
 
     private interface AuthTask<T> {
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index b024d9f..bd97520f 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -177,6 +177,7 @@
 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
 
 #if !defined(OS_ANDROID)
+#include "content/browser/zygote_host/zygote_communication_linux.h"
 #include "content/public/browser/zygote_handle_linux.h"
 #endif  // !defined(OS_ANDROID)
 #endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
@@ -229,7 +230,11 @@
   // Tickle the zygote host so it forks now.
   ZygoteHostImpl::GetInstance()->Init(parsed_command_line);
   *GetGenericZygote() = CreateZygote();
-  RenderProcessHostImpl::EarlyZygoteLaunch();
+  // TODO(kerrnel): Investigate doing this without the ZygoteHostImpl as a
+  // proxy. It is currently done this way due to concerns about race
+  // conditions.
+  ZygoteHostImpl::GetInstance()->SetRendererSandboxStatus(
+      (*GetGenericZygote())->GetSandboxStatus());
 }
 #endif
 
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index e4f6850a..0b5e04d 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -316,6 +316,10 @@
       associated_site_instance_type_(AssociatedSiteInstanceType::NONE),
       may_transfer_(may_transfer) {
   DCHECK(!browser_initiated || (entry != nullptr && frame_entry != nullptr));
+  TRACE_EVENT_ASYNC_BEGIN2("navigation", "NavigationRequest", this,
+                           "frame_tree_node",
+                           frame_tree_node_->frame_tree_node_id(), "url",
+                           common_params_.url.possibly_invalid_spec());
 
   // Sanitize the referrer.
   common_params_.referrer =
@@ -360,11 +364,14 @@
 }
 
 NavigationRequest::~NavigationRequest() {
+  TRACE_EVENT_ASYNC_END0("navigation", "NavigationRequest", this);
 }
 
 void NavigationRequest::BeginNavigation() {
   DCHECK(!loader_);
   DCHECK(state_ == NOT_STARTED || state_ == WAITING_FOR_RENDERER_RESPONSE);
+  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this,
+                               "BeginNavigation");
   state_ = STARTED;
   RenderFrameDevToolsAgentHost::OnBeforeNavigation(navigation_handle_.get());
 
@@ -390,6 +397,8 @@
 
   // There is no need to make a network request for this navigation, so commit
   // it immediately.
+  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this,
+                               "ResponseStarted");
   state_ = RESPONSE_STARTED;
 
   // Select an appropriate RenderFrameHost.
@@ -404,6 +413,13 @@
   CommitNavigation();
 }
 
+void NavigationRequest::SetWaitingForRendererResponse() {
+  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this,
+                               "WaitingForRendererResponse");
+  DCHECK(state_ == NOT_STARTED);
+  state_ = WAITING_FOR_RENDERER_RESPONSE;
+}
+
 void NavigationRequest::CreateNavigationHandle(int pending_nav_entry_id) {
   DCHECK_EQ(frame_tree_node_->navigation_request(), this);
   FrameTreeNode* frame_tree_node = frame_tree_node_;
@@ -516,6 +532,8 @@
     bool is_stream) {
   DCHECK(state_ == STARTED);
   DCHECK(response);
+  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this,
+                               "OnResponseStarted");
   state_ = RESPONSE_STARTED;
 
   // Check if the response should be sent to a renderer.
@@ -596,6 +614,8 @@
 void NavigationRequest::OnRequestFailed(bool has_stale_copy_in_cache,
                                         int net_error) {
   DCHECK(state_ == STARTED || state_ == RESPONSE_STARTED);
+  TRACE_EVENT_ASYNC_STEP_INTO1("navigation", "NavigationRequest", this,
+                               "OnRequestFailed", "error", net_error);
   state_ = FAILED;
   navigation_handle_->set_net_error_code(static_cast<net::Error>(net_error));
 
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 095b77f5..851fcfb 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -134,11 +134,6 @@
 
   bool may_transfer() const { return may_transfer_; }
 
-  void SetWaitingForRendererResponse() {
-    DCHECK(state_ == NOT_STARTED);
-    state_ = WAITING_FOR_RENDERER_RESPONSE;
-  }
-
   AssociatedSiteInstanceType associated_site_instance_type() const {
     return associated_site_instance_type_;
   }
@@ -150,6 +145,8 @@
     return navigation_handle_.get();
   }
 
+  void SetWaitingForRendererResponse();
+
   // Creates a NavigationHandle. This should be called after any previous
   // NavigationRequest for the FrameTreeNode has been destroyed.
   void CreateNavigationHandle(int pending_nav_entry_id);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 486d206..f579450b 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1207,12 +1207,21 @@
   // active.
   if (!is_active())
     return;
+
+  TRACE_EVENT2("navigation", "RenderFrameHostImpl::OnDidStartProvisionalLoad",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(), "url",
+               url.possibly_invalid_spec());
+
   frame_tree_node_->navigator()->DidStartProvisionalLoad(
       this, url, redirect_chain, navigation_start);
 }
 
 void RenderFrameHostImpl::OnDidFailProvisionalLoadWithError(
     const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) {
+  TRACE_EVENT2("navigation",
+               "RenderFrameHostImpl::OnDidFailProvisionalLoadWithError",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(),
+               "error", params.error_code);
   // TODO(clamy): Kill the renderer with RFH_FAIL_PROVISIONAL_LOAD_NO_HANDLE and
   // return early if navigation_handle_ is null, once we prevent that case from
   // happening in practice.
@@ -1231,6 +1240,11 @@
     int error_code,
     const base::string16& error_description,
     bool was_ignored_by_handler) {
+  TRACE_EVENT2("navigation",
+               "RenderFrameHostImpl::OnDidFailProvisionalLoadWithError",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(),
+               "error", error_code);
+
   GURL validated_url(url);
   GetProcess()->FilterURL(false, &validated_url);
 
@@ -1255,8 +1269,9 @@
         process, bad_message::RFH_COMMIT_DESERIALIZATION_FAILED);
     return;
   }
-  TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnDidCommitProvisionalLoad",
-               "url", validated_params.url.possibly_invalid_spec());
+  TRACE_EVENT2("navigation", "RenderFrameHostImpl::OnDidCommitProvisionalLoad",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(), "url",
+               validated_params.url.possibly_invalid_spec());
 
   // Sanity-check the page transition for frame type.
   DCHECK_EQ(ui::PageTransitionIsMainFrame(validated_params.transition),
@@ -1450,7 +1465,9 @@
   // the operation and sends back an IPC message.
   // The trace event may not end properly if the ACK times out.  We expect this
   // to be fixed when RenderViewHostImpl::OnSwapOut moves to RenderFrameHost.
-  TRACE_EVENT_ASYNC_BEGIN0("navigation", "RenderFrameHostImpl::SwapOut", this);
+  TRACE_EVENT_ASYNC_BEGIN1("navigation", "RenderFrameHostImpl::SwapOut", this,
+                           "frame_tree_node",
+                           frame_tree_node_->frame_tree_node_id());
 
   // If this RenderFrameHost is already pending deletion, it must have already
   // gone through this, therefore just return.
@@ -1783,6 +1800,14 @@
     const GURL& frame_url,
     bool is_reload,
     IPC::Message* reply_msg) {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnRunBeforeUnloadConfirm",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
+
+  // TODO(nasko): It is strange to accept the frame URL as a parameter from
+  // the renderer. Investigate and remove parameter, but for now let's
+  // double check.
+  DCHECK_EQ(frame_url, last_committed_url_);
+
   // While a JS beforeunload dialog is showing, tabs in the same process
   // shouldn't process input events.
   GetProcess()->SetIgnoreInputEvents(true);
@@ -1843,6 +1868,9 @@
     NOTREACHED() << "Never grant bindings to a guest process.";
     return;
   }
+  TRACE_EVENT2("navigation", "RenderFrameHostImpl::AllowBindings",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(),
+               "bindings flags", bindings_flags);
 
   // Ensure we aren't granting WebUI bindings to a process that has already
   // been used for non-privileged views.
@@ -1927,6 +1955,9 @@
     // TODO(lukasza): Call ReceivedBadMessage when |unique_name| is empty.
     DCHECK(!unique_name.empty());
   }
+  TRACE_EVENT2("navigation", "RenderFrameHostImpl::OnDidChangeName",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(),
+               "name length", name.length());
 
   std::string old_name = frame_tree_node()->frame_name();
   frame_tree_node()->SetFrameName(name, unique_name);
@@ -1944,6 +1975,10 @@
 
 void RenderFrameHostImpl::OnDidAddContentSecurityPolicies(
     const std::vector<ContentSecurityPolicy>& policies) {
+  TRACE_EVENT1("navigation",
+               "RenderFrameHostImpl::OnDidAddContentSecurityPolicies",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
+
   std::vector<ContentSecurityPolicyHeader> headers;
   for (const ContentSecurityPolicy& policy : policies) {
     AddContentSecurityPolicy(policy);
@@ -1959,6 +1994,9 @@
 
 void RenderFrameHostImpl::OnUpdateToUniqueOrigin(
     bool is_potentially_trustworthy_unique_origin) {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnUpdateToUniqueOrigin",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
+
   url::Origin origin;
   DCHECK(origin.unique());
   frame_tree_node()->SetCurrentOrigin(origin,
@@ -2048,6 +2086,11 @@
   CHECK(IsBrowserSideNavigationEnabled());
   if (!is_active())
     return;
+
+  TRACE_EVENT2("navigation", "RenderFrameHostImpl::OnBeforeNavigation",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(), "url",
+               common_params.url.possibly_invalid_spec());
+
   CommonNavigationParams validated_params = common_params;
   GetProcess()->FilterURL(false, &validated_params.url);
 
@@ -2065,6 +2108,8 @@
 }
 
 void RenderFrameHostImpl::OnAbortNavigation() {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnAbortNavigation",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
   if (!IsBrowserSideNavigationEnabled()) {
     NOTREACHED();
     return;
@@ -2075,6 +2120,8 @@
 }
 
 void RenderFrameHostImpl::OnDispatchLoad() {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnDispatchLoad",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
   CHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible());
 
   // Don't forward the load event if this RFH is pending deletion.  This can
@@ -2318,6 +2365,10 @@
 }
 
 void RenderFrameHostImpl::OnDidStartLoading(bool to_different_document) {
+  TRACE_EVENT2("navigation", "RenderFrameHostImpl::OnDidStartLoading",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(),
+               "to different document", to_different_document);
+
   if (IsBrowserSideNavigationEnabled() && to_different_document) {
     bad_message::ReceivedBadMessage(GetProcess(),
                                     bad_message::RFH_UNEXPECTED_LOAD_START);
@@ -2335,6 +2386,9 @@
 }
 
 void RenderFrameHostImpl::OnDidStopLoading() {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnDidStopLoading",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
+
   // This method should never be called when the frame is not loading.
   // Unfortunately, it can happen if a history navigation happens during a
   // BeforeUnload or Unload event.
@@ -2441,6 +2495,9 @@
     mojom::CreateNewWindowParamsPtr params,
     CreateNewWindowCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  TRACE_EVENT2("navigation", "RenderFrameHostImpl::CreateNewWindow",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(), "url",
+               params->target_url.possibly_invalid_spec());
 
   bool no_javascript_access = false;
 
@@ -2716,7 +2773,8 @@
     const CommonNavigationParams& common_params,
     const StartNavigationParams& start_params,
     const RequestNavigationParams& request_params) {
-  TRACE_EVENT0("navigation", "RenderFrameHostImpl::Navigate");
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::Navigate", "frame_tree_node",
+               frame_tree_node_->frame_tree_node_id());
   DCHECK(!IsBrowserSideNavigationEnabled());
 
   UpdatePermissionsForNavigation(common_params, request_params);
@@ -2753,6 +2811,8 @@
 }
 
 void RenderFrameHostImpl::NavigateToInterstitialURL(const GURL& data_url) {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::NavigateToInterstitialURL",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
   DCHECK(data_url.SchemeIs(url::kDataScheme));
   CommonNavigationParams common_params(
       data_url, Referrer(), ui::PAGE_TRANSITION_LINK,
@@ -2770,6 +2830,8 @@
 }
 
 void RenderFrameHostImpl::Stop() {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::Stop", "frame_tree_node",
+               frame_tree_node_->frame_tree_node_id());
   Send(new FrameMsg_Stop(routing_id_));
 }
 
@@ -2838,6 +2900,9 @@
 }
 
 void RenderFrameHostImpl::UpdateOpener() {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::UpdateOpener",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
+
   // This frame (the frame whose opener is being updated) might not have had
   // proxies for the new opener chain in its SiteInstance.  Make sure they
   // exist.
@@ -2926,6 +2991,9 @@
     const CommonNavigationParams& common_params,
     const RequestNavigationParams& request_params,
     bool is_view_source) {
+  TRACE_EVENT2("navigation", "RenderFrameHostImpl::CommitNavigation",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(), "url",
+               common_params.url.possibly_invalid_spec());
   DCHECK(
       (response && (body.get() || handle.is_valid())) ||
       common_params.url.SchemeIs(url::kDataScheme) ||
@@ -2979,6 +3047,10 @@
     const RequestNavigationParams& request_params,
     bool has_stale_copy_in_cache,
     int error_code) {
+  TRACE_EVENT2("navigation", "RenderFrameHostImpl::FailedNavigation",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(),
+               "error", error_code);
+
   // Update renderer permissions even for failed commits, so that for example
   // the URL bar correctly displays privileged URLs instead of filtering them.
   UpdatePermissionsForNavigation(common_params, request_params);
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index f6f5ba88..11e104a 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/frame_host/navigation_request_info.h"
@@ -27,6 +28,11 @@
 
 namespace content {
 
+namespace {
+static base::LazyInstance<mojom::URLLoaderFactoryPtr>::Leaky
+    g_url_loader_factory = LAZY_INSTANCE_INITIALIZER;
+}
+
 // This function is called on the IO thread for POST/PUT requests for
 // attaching blob information to the request body.
 void HandleRequestsWithBody(
@@ -57,8 +63,12 @@
 
   // TODO(scottmg): Maybe some of this setup should be done only once, instead
   // of every time.
-  ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface(
-      mojom::kNetworkServiceName, &url_loader_factory_);
+  if (g_url_loader_factory.Get().get()) {
+    url_loader_factory_ = std::move(g_url_loader_factory.Get());
+  } else {
+    ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface(
+        mojom::kNetworkServiceName, &url_loader_factory_);
+  }
 
   // TODO(scottmg): Port over stuff from RDHI::BeginNavigationRequest() here.
   auto new_request = base::MakeUnique<ResourceRequest>();
@@ -106,6 +116,11 @@
 
 NavigationURLLoaderNetworkService::~NavigationURLLoaderNetworkService() {}
 
+void NavigationURLLoaderNetworkService::OverrideURLLoaderFactoryForTesting(
+    mojom::URLLoaderFactoryPtr url_loader_factory) {
+  g_url_loader_factory.Get() = std::move(url_loader_factory);
+}
+
 void NavigationURLLoaderNetworkService::FollowRedirect() {
   url_loader_associated_ptr_->FollowRedirect();
 }
diff --git a/content/browser/loader/navigation_url_loader_network_service.h b/content/browser/loader/navigation_url_loader_network_service.h
index 8223c83a..f284a57 100644
--- a/content/browser/loader/navigation_url_loader_network_service.h
+++ b/content/browser/loader/navigation_url_loader_network_service.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "content/browser/loader/navigation_url_loader.h"
+#include "content/common/content_export.h"
 #include "content/common/url_loader.mojom.h"
 #include "content/common/url_loader_factory.mojom.h"
 #include "content/public/browser/ssl_status.h"
@@ -39,6 +40,10 @@
       NavigationURLLoaderDelegate* delegate);
   ~NavigationURLLoaderNetworkService() override;
 
+  // Overrides the URLLoaderFactory for the next request.
+  static CONTENT_EXPORT void OverrideURLLoaderFactoryForTesting(
+      mojom::URLLoaderFactoryPtr url_loader_factory);
+
   // NavigationURLLoader implementation:
   void FollowRedirect() override;
   void ProceedWithResponse() override;
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index 7b541e7..b067102 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -54,10 +54,6 @@
 
 namespace content {
 
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-ZygoteHandle g_ppapi_zygote;
-#endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-
 // NOTE: changes to this class need to be reviewed by the security team.
 class PpapiPluginSandboxedProcessLauncherDelegate
     : public content::SandboxedProcessLauncherDelegate {
@@ -204,14 +200,6 @@
   return NULL;
 }
 
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-// static
-void PpapiPluginProcessHost::EarlyZygoteLaunch() {
-  DCHECK(!g_ppapi_zygote);
-  g_ppapi_zygote = CreateZygote();
-}
-#endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-
 // static
 void PpapiPluginProcessHost::DidCreateOutOfProcessInstance(
     int plugin_process_id,
diff --git a/content/browser/ppapi_plugin_process_host.h b/content/browser/ppapi_plugin_process_host.h
index b769e4f..61ed6d3 100644
--- a/content/browser/ppapi_plugin_process_host.h
+++ b/content/browser/ppapi_plugin_process_host.h
@@ -119,11 +119,6 @@
     return profile_data_directory_;
   }
 
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-  // Launch the zygote early in the browser startup.
-  static void EarlyZygoteLaunch();
-#endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-
   // The client pointer must remain valid until its callback is issued.
 
  private:
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index fbd191b..db3e90d 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -224,8 +224,6 @@
 #endif
 
 #if defined(OS_POSIX)
-#include "content/browser/zygote_host/zygote_communication_linux.h"
-#include "content/browser/zygote_host/zygote_host_impl_linux.h"
 #include "content/public/browser/zygote_handle_linux.h"
 #endif  // defined(OS_POSIX)
 
@@ -383,12 +381,6 @@
   return map;
 }
 
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-// This static member variable holds the zygote communication information for
-// the renderer.
-ZygoteHandle g_render_zygote;
-#endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-
 // NOTE: changes to this class need to be reviewed by the security team.
 class RendererSandboxedProcessLauncherDelegate
     : public SandboxedProcessLauncherDelegate {
@@ -695,18 +687,6 @@
   g_max_renderer_count_override = count;
 }
 
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-// static
-void RenderProcessHostImpl::EarlyZygoteLaunch() {
-  DCHECK(!g_render_zygote);
-  // TODO(kerrnel): Investigate doing this without the ZygoteHostImpl as a
-  // proxy. It is currently done this way due to concerns about race
-  // conditions.
-  ZygoteHostImpl::GetInstance()->SetRendererSandboxStatus(
-      (*GetGenericZygote())->GetSandboxStatus());
-}
-#endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-
 RenderProcessHostImpl::RenderProcessHostImpl(
     BrowserContext* browser_context,
     StoragePartitionImpl* storage_partition_impl,
diff --git a/content/browser/renderer_host/sandbox_ipc_linux.cc b/content/browser/renderer_host/sandbox_ipc_linux.cc
index 37445f0..dad523f 100644
--- a/content/browser/renderer_host/sandbox_ipc_linux.cc
+++ b/content/browser/renderer_host/sandbox_ipc_linux.cc
@@ -341,7 +341,7 @@
   int shm_fd = -1;
   base::SharedMemory shm;
   if (shm.Create(options))
-    shm_fd = shm.handle().fd;
+    shm_fd = shm.handle().GetHandle();
   base::Pickle reply;
   SendRendererReply(fds, reply, shm_fd);
 }
diff --git a/content/browser/screen_orientation/screen_orientation_browsertest.cc b/content/browser/screen_orientation/screen_orientation_browsertest.cc
index aeb3d4d..253f167 100644
--- a/content/browser/screen_orientation/screen_orientation_browsertest.cc
+++ b/content/browser/screen_orientation/screen_orientation_browsertest.cc
@@ -7,7 +7,11 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/page_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
@@ -20,7 +24,9 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "content/shell/common/shell_switches.h"
+#include "net/dns/mock_host_resolver.h"
 #include "ui/compositor/compositor_switches.h"
+#include "ui/display/screen.h"
 
 namespace content {
 
@@ -29,12 +35,16 @@
   ScreenOrientationBrowserTest() {
   }
 
+  WebContentsImpl* web_contents() {
+    return static_cast<WebContentsImpl*>(shell()->web_contents());
+  }
+
  protected:
   void SendFakeScreenOrientation(unsigned angle, const std::string& strType) {
-    RenderWidgetHost* rwh = shell()->web_contents()->GetRenderWidgetHostView()
-        ->GetRenderWidgetHost();
+    RenderWidgetHost* main_frame_rwh =
+        web_contents()->GetMainFrame()->GetRenderWidgetHost();
     ScreenInfo screen_info;
-    rwh->GetScreenInfo(&screen_info);
+    main_frame_rwh->GetScreenInfo(&screen_info);
     screen_info.orientation_angle = angle;
 
     ScreenOrientationValues type = SCREEN_ORIENTATION_VALUES_DEFAULT;
@@ -57,7 +67,36 @@
     params.top_controls_height = 0.f;
     params.browser_controls_shrink_blink_size = false;
     params.is_fullscreen_granted = false;
-    rwh->Send(new ViewMsg_Resize(rwh->GetRoutingID(), params));
+
+    std::set<RenderWidgetHost*> rwhs;
+    for (RenderFrameHost* rfh : web_contents()->GetAllFrames()) {
+      if (rfh == web_contents()->GetMainFrame())
+        continue;
+
+      rwhs.insert(static_cast<RenderFrameHostImpl*>(rfh)
+                      ->frame_tree_node()
+                      ->render_manager()
+                      ->GetRenderWidgetHostView()
+                      ->GetRenderWidgetHost());
+    }
+
+    // This simulates what the browser process does when the screen orientation
+    // is changed:
+    // 1. The top-level frame is resized and a ViweMsg_Resize is sent to the
+    // top-level frame.
+    main_frame_rwh->Send(
+        new ViewMsg_Resize(main_frame_rwh->GetRoutingID(), params));
+
+    // 2. The WebContents sends a PageMsg_UpdateScreenInfo to all the renderers
+    // involved in the FrameTree.
+    web_contents()->GetFrameTree()->root()->render_manager()->SendPageMessage(
+        new PageMsg_UpdateScreenInfo(MSG_ROUTING_NONE, screen_info), nullptr);
+
+    // 3. When the top-level frame gets the ViewMsg_Resize, it'll dispatch a
+    // FrameHostMsg_FrameRectsChanged IPC that causes the remote subframes to
+    // receive the ViewMsg_Resize from the browser.
+    for (auto* rwh : rwhs)
+      rwh->Send(new ViewMsg_Resize(rwh->GetRoutingID(), params));
   }
 
   int GetOrientationAngle() {
@@ -99,6 +138,24 @@
   DISALLOW_COPY_AND_ASSIGN(ScreenOrientationBrowserTest);
 };
 
+class ScreenOrientationOOPIFBrowserTest : public ScreenOrientationBrowserTest {
+ public:
+  ScreenOrientationOOPIFBrowserTest() {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    IsolateAllSitesForTesting(command_line);
+  }
+
+  void SetUpOnMainThread() override {
+    host_resolver()->AddRule("*", "127.0.0.1");
+    SetupCrossSiteRedirector(embedded_test_server());
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScreenOrientationOOPIFBrowserTest);
+};
+
 // This test doesn't work on MacOS X but the reason is mostly because it is not
 // used Aura. It could be set as !defined(OS_MACOSX) but the rule below will
 // actually support MacOS X if and when it switches to Aura.
@@ -245,4 +302,57 @@
 }
 #endif // defined(OS_ANDROID)
 
+IN_PROC_BROWSER_TEST_F(ScreenOrientationOOPIFBrowserTest, ScreenOrientation) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+#if USE_AURA || defined(OS_ANDROID)
+  WaitForResizeComplete(shell()->web_contents());
+#endif  // USE_AURA || defined(OS_ANDROID)
+
+  std::string types[] = {"portrait-primary", "portrait-secondary",
+                         "landscape-primary", "landscape-secondary"};
+
+  int angle = GetOrientationAngle();
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  FrameTreeNode* child = root->child_at(0);
+  MainThreadFrameObserver root_observer(
+      root->current_frame_host()->GetRenderWidgetHost());
+  MainThreadFrameObserver child_observer(
+      child->current_frame_host()->GetRenderWidgetHost());
+  for (int i = 0; i < 4; ++i) {
+    angle = (angle + 90) % 360;
+    SendFakeScreenOrientation(angle, types[i]);
+
+    root_observer.Wait();
+    child_observer.Wait();
+
+    int orientation_angle;
+    std::string orientation_type;
+
+    EXPECT_TRUE(ExecuteScriptAndExtractInt(
+        root->current_frame_host(),
+        "window.domAutomationController.send(screen.orientation.angle)",
+        &orientation_angle));
+    EXPECT_EQ(angle, orientation_angle);
+    EXPECT_TRUE(ExecuteScriptAndExtractInt(
+        child->current_frame_host(),
+        "window.domAutomationController.send(screen.orientation.angle)",
+        &orientation_angle));
+    EXPECT_EQ(angle, orientation_angle);
+
+    EXPECT_TRUE(ExecuteScriptAndExtractString(
+        root->current_frame_host(),
+        "window.domAutomationController.send(screen.orientation.type)",
+        &orientation_type));
+    EXPECT_EQ(types[i], orientation_type);
+    EXPECT_TRUE(ExecuteScriptAndExtractString(
+        child->current_frame_host(),
+        "window.domAutomationController.send(screen.orientation.type)",
+        &orientation_type));
+    EXPECT_EQ(types[i], orientation_type);
+  }
+}
+
 } // namespace content
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index fdf7ab5..d8caf50f 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -38,6 +38,7 @@
 #include "content/browser/frame_host/render_frame_proxy_host.h"
 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
 #include "content/browser/gpu/compositor_util.h"
+#include "content/browser/loader/navigation_url_loader_network_service.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/renderer_host/input/input_router_impl.h"
 #include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
@@ -71,6 +72,7 @@
 #include "content/test/content_browser_test_utils_internal.h"
 #include "ipc/ipc.mojom.h"
 #include "ipc/ipc_security_test_util.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
@@ -2395,6 +2397,40 @@
   }
 }
 
+namespace {
+class FailingURLLoaderImpl : public mojom::URLLoader {
+ public:
+  explicit FailingURLLoaderImpl(mojom::URLLoaderClientPtr client) {
+    ResourceRequestCompletionStatus status;
+    status.error_code = net::ERR_NOT_IMPLEMENTED;
+    client->OnComplete(status);
+  }
+
+  void FollowRedirect() override {}
+  void SetPriority(net::RequestPriority priority,
+                   int32_t intra_priority_value) override {}
+};
+
+class FailingLoadFactory : public mojom::URLLoaderFactory {
+ public:
+  FailingLoadFactory() {}
+  ~FailingLoadFactory() override {}
+
+  void CreateLoaderAndStart(mojom::URLLoaderAssociatedRequest loader,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const ResourceRequest& request,
+                            mojom::URLLoaderClientPtr client) override {
+    new FailingURLLoaderImpl(std::move(client));
+  }
+  void SyncLoad(int32_t routing_id,
+                int32_t request_id,
+                const ResourceRequest& request,
+                SyncLoadCallback callback) override {}
+};
+}
+
 // Ensure that a cross-site page ends up in the correct process when it
 // successfully loads after earlier encountering a network error for it.
 // See https://crbug.com/560511.
@@ -2413,7 +2449,18 @@
   // Disable host resolution in the test server and try to navigate the subframe
   // cross-site, which will lead to a committed net error.
   GURL url_b = embedded_test_server()->GetURL("b.com", "/title3.html");
-  host_resolver()->ClearRules();
+  bool network_service = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableNetworkService);
+  mojom::URLLoaderFactoryPtr failing_factory;
+  mojo::MakeStrongBinding(base::MakeUnique<FailingLoadFactory>(),
+                          mojo::MakeRequest(&failing_factory));
+  if (network_service) {
+    NavigationURLLoaderNetworkService::OverrideURLLoaderFactoryForTesting(
+        std::move(failing_factory));
+  } else {
+    host_resolver()->ClearRules();
+  }
+
   TestNavigationObserver observer(shell()->web_contents());
   NavigateIframeToURL(shell()->web_contents(), "child-0", url_b);
   EXPECT_FALSE(observer.last_navigation_succeeded());
@@ -2446,7 +2493,9 @@
   EXPECT_EQ("null", child->current_origin().Serialize());
 
   // Try again after re-enabling host resolution.
-  host_resolver()->AddRule("*", "127.0.0.1");
+  if (!network_service)
+    host_resolver()->AddRule("*", "127.0.0.1");
+
   NavigateIframeToURL(shell()->web_contents(), "child-0", url_b);
   EXPECT_TRUE(observer.last_navigation_succeeded());
   EXPECT_EQ(url_b, observer.last_navigation_url());
@@ -9654,7 +9703,6 @@
 
   // Must be called after any calls to SetDelayedRequestsForPath.
   void SetUpEmbeddedTestServer() {
-    host_resolver()->AddRule("*", "127.0.0.1");
     SetupCrossSiteRedirector(test_server_.get());
     test_server_->RegisterRequestHandler(base::Bind(
         &RequestDelayingSitePerProcessBrowserTest::HandleMockResource,
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc
index a2c181a..d8f11f6 100644
--- a/content/browser/utility_process_host_impl.cc
+++ b/content/browser/utility_process_host_impl.cc
@@ -54,12 +54,6 @@
 
 namespace content {
 
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-namespace {
-ZygoteHandle g_utility_zygote;
-}  // namespace
-#endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-
 // NOTE: changes to this class need to be reviewed by the security team.
 class UtilitySandboxedProcessLauncherDelegate
     : public SandboxedProcessLauncherDelegate {
@@ -237,14 +231,6 @@
   name_ = name;
 }
 
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-// static
-void UtilityProcessHostImpl::EarlyZygoteLaunch() {
-  DCHECK(!g_utility_zygote);
-  g_utility_zygote = CreateZygote();
-}
-#endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-
 bool UtilityProcessHostImpl::StartProcess() {
   if (started_)
     return true;
diff --git a/content/browser/utility_process_host_impl.h b/content/browser/utility_process_host_impl.h
index 23da5be..76dc35507 100644
--- a/content/browser/utility_process_host_impl.h
+++ b/content/browser/utility_process_host_impl.h
@@ -63,11 +63,6 @@
 
   void set_child_flags(int flags) { child_flags_ = flags; }
 
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-  // Launch the zygote early in the browser startup.
-  static void EarlyZygoteLaunch();
-#endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
-
  private:
   // Starts a process if necessary.  Returns true if it succeeded or a process
   // has already been started via StartBatchMode().
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 7bda23f..2888777 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1846,6 +1846,10 @@
   if (!rfh || render_widget_host != rfh->GetRenderWidgetHost())
     return;
 
+  ScreenInfo screen_info;
+  GetScreenInfo(&screen_info);
+  SendPageMessage(new PageMsg_UpdateScreenInfo(MSG_ROUTING_NONE, screen_info));
+
   for (auto& observer : observers_)
     observer.MainFrameWasResized(width_changed);
 }
diff --git a/content/child/blob_storage/blob_transport_controller_unittest.cc b/content/child/blob_storage/blob_transport_controller_unittest.cc
index c016777..82b599c 100644
--- a/content/child/blob_storage/blob_transport_controller_unittest.cc
+++ b/content/child/blob_storage/blob_transport_controller_unittest.cc
@@ -300,7 +300,7 @@
   memory.CreateAnonymous(11 + 6);
   base::SharedMemoryHandle handle =
       base::SharedMemory::DuplicateHandle(memory.handle());
-  CHECK(base::SharedMemory::NULLHandle() != handle);
+  CHECK(handle.IsValid());
   memory_handles.push_back(handle);
 
   OnMemoryRequest(holder, kBlobUUID, requests, &memory_handles, file_handles);
diff --git a/content/common/page_messages.h b/content/common/page_messages.h
index 6d81f3f96..4fa9f056 100644
--- a/content/common/page_messages.h
+++ b/content/common/page_messages.h
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/common/page_message_enums.h"
+#include "content/public/common/screen_info.h"
 #include "ipc/ipc_message_macros.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -45,6 +46,10 @@
 
 IPC_MESSAGE_ROUTED1(PageMsg_AudioStateChanged, bool /* is_audio_playing */)
 
+// Sent to OOPIF renderers when the main frame's ScreenInfo changes.
+IPC_MESSAGE_ROUTED1(PageMsg_UpdateScreenInfo,
+                    content::ScreenInfo /* screen_info */)
+
 // -----------------------------------------------------------------------------
 // Messages sent from the renderer to the browser.
 
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index c424c6ec..1892182 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -373,8 +373,20 @@
 }
 
 void BrowserTestBase::InitializeNetworkProcess() {
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableNetworkService))
+  const testing::TestInfo* const test_info =
+      testing::UnitTest::GetInstance()->current_test_info();
+  bool network_service = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableNetworkService);
+  // ProcessTransferAfterError is the only browser test which needs to modify
+  // the host rules (when not using the network service).
+  if (network_service ||
+      std::string(test_info->name()) != "ProcessTransferAfterError") {
+    // TODO(jam): enable this once all access to host_resolver() is in
+    // SetUpOnMainThread or before. http://crbug.com/713847
+    // host_resolver()->DisableModifications();
+  }
+
+  if (!network_service)
     return;
 
   net::RuleBasedHostResolverProc::RuleList rules = host_resolver()->GetRules();
@@ -401,10 +413,6 @@
   ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface(
       mojom::kNetworkServiceName, &network_service_test);
   network_service_test->AddRules(std::move(mojo_rules));
-
-  // TODO(jam): enable this once all access to host_resolver() is in
-  // SetUpOnMainThread or before. http://crbug.com/713847
-  // host_resolver()->DisableModifications();
 }
 
 }  // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index f0e42e8..6c8ad23 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5111,16 +5111,6 @@
     if (params.origin.scheme() != url::kFileScheme ||
         !render_view_->GetWebkitPreferences()
              .allow_universal_access_from_file_urls) {
-      base::debug::SetCrashKeyValue("origin_mismatch_url", params.url.spec());
-      base::debug::SetCrashKeyValue("origin_mismatch_origin",
-                                    params.origin.Serialize());
-      base::debug::SetCrashKeyValue("origin_mismatch_transition",
-                                    base::IntToString(params.transition));
-      base::debug::SetCrashKeyValue("origin_mismatch_redirects",
-                                    base::IntToString(params.redirects.size()));
-      base::debug::SetCrashKeyValue(
-          "origin_mismatch_same_page",
-          base::IntToString(params.was_within_same_document));
       CHECK(params.origin.IsSamePhysicalOriginWith(url::Origin(params.url)))
           << " url:" << params.url << " origin:" << params.origin;
     }
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 3f21403..42953f4e 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1252,6 +1252,7 @@
     IPC_MESSAGE_HANDLER(PageMsg_SetHistoryOffsetAndLength,
                         OnSetHistoryOffsetAndLength)
     IPC_MESSAGE_HANDLER(PageMsg_AudioStateChanged, OnAudioStateChanged)
+    IPC_MESSAGE_HANDLER(PageMsg_UpdateScreenInfo, OnUpdateScreenInfo)
 
 #if defined(OS_ANDROID)
     IPC_MESSAGE_HANDLER(ViewMsg_UpdateBrowserControlsState,
@@ -2133,11 +2134,6 @@
     webview()->PerformMediaPlayerAction(action, location);
 }
 
-void RenderViewImpl::OnOrientationChange() {
-  if (webview() && webview()->MainFrame()->IsWebLocalFrame())
-    webview()->MainFrame()->ToWebLocalFrame()->SendOrientationChangeEvent();
-}
-
 void RenderViewImpl::OnPluginActionAt(const gfx::Point& location,
                                       const WebPluginAction& action) {
   if (webview())
@@ -2278,6 +2274,14 @@
   }
 }
 
+void RenderViewImpl::OnUpdateScreenInfo(const ScreenInfo& screen_info) {
+  // This IPC only updates the screen info on RenderViews that have a remote
+  // main frame. For local main frames, the ScreenInfo is updated in
+  // ViewMsg_Resize.
+  if (!main_render_frame_)
+    screen_info_ = screen_info;
+}
+
 GURL RenderViewImpl::GetURLForGraphicsContext3D() {
   DCHECK(webview());
   if (webview()->MainFrame()->IsWebLocalFrame())
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index ed261d1a..6b27bfb 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -395,7 +395,6 @@
   void OnResize(const ResizeParams& params) override;
   void OnSetFocus(bool enable) override;
   GURL GetURLForGraphicsContext3D() override;
-  void OnOrientationChange() override;
   void DidCommitCompositorFrame() override;
   void DidCompletePageScaleAnimation() override;
   void OnDeviceScaleFactorChanged() override;
@@ -567,6 +566,7 @@
   void OnSetZoomLevel(PageMsg_SetZoomLevel_Command command, double zoom_level);
   void OnPageWasHidden();
   void OnPageWasShown();
+  void OnUpdateScreenInfo(const ScreenInfo& screen_info);
 
   // Adding a new message handler? Please add it in alphabetical order above
   // and put it in the same position in the .cc file.
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index f7fec29..1f4539dc 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1912,6 +1912,11 @@
 }
 
 void RenderWidget::OnOrientationChange() {
+  WebWidget* web_widget = GetWebWidget();
+  if (web_widget && web_widget->IsWebFrameWidget()) {
+    WebFrameWidget* web_frame_widget = static_cast<WebFrameWidget*>(web_widget);
+    web_frame_widget->LocalRoot()->SendOrientationChangeEvent();
+  }
 }
 
 void RenderWidget::SetHidden(bool hidden) {
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index ed16377e..0aa91b2 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -573,7 +573,7 @@
 
   virtual void OnSetDeviceScaleFactor(float device_scale_factor);
 
-  virtual void OnOrientationChange();
+  void OnOrientationChange();
 
   // Override points to notify derived classes that a paint has happened.
   // DidInitiatePaint happens when that has completed, and subsequent rendering
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 4313af0..e370326 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -43,6 +43,7 @@
     # All platforms.
     self.Flaky('conformance2/query/occlusion-query.html', bug=603168)
     self.Fail('conformance2/glsl3/tricky-loop-conditions.html', bug=483282)
+    self.Fail('conformance2/textures/misc/tex-srgb-mipmap.html', bug=712096)
 
     # canvas.commit() promise synchronization isn't fully reliable yet.
     self.Fail('conformance/offscreencanvas/offscreencanvas-resize.html',
@@ -108,8 +109,6 @@
         ['win', 'nvidia', 'opengl'], bug=693090)
     self.Fail('conformance2/glsl3/vector-dynamic-indexing-nv-driver-bug.html',
         ['win', 'nvidia', 'opengl'], bug=693090)
-    self.Fail('conformance2/textures/misc/tex-srgb-mipmap.html',
-        ['win', 'nvidia', 'opengl'], bug=693090)
     self.Fail('conformance2/glsl3/' +
         'vector-dynamic-indexing-swizzled-lvalue.html',
         ['win', 'nvidia', 'opengl'], bug=709874)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 44d999d80..cf37c6c 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -623,6 +623,9 @@
     self.Skip('conformance/glsl/misc/shader-with-non-reserved-words.html',
         ['android', ('qualcomm', 'Adreno (TM) 418'), 'no_passthrough'],
         bug=609883)
+    self.Flaky('conformance/textures/image_bitmap_from_video/' +
+        'tex-2d-rgb-rgb-unsigned_byte.html',
+        ['android', ('qualcomm', 'Adreno (TM) 418')], bug=716496)
     self.Fail('conformance/uniforms/uniform-samplers-test.html',
         ['android', ('qualcomm', 'Adreno (TM) 418'), 'no_passthrough'],
         bug=610951)
@@ -694,16 +697,6 @@
         ['android', 'android-chromium',
          ('nvidia', 'NVIDIA Tegra')], bug=624621)
 
-    # NVIDIA Shield
-    self.Flaky('conformance/context/' +
-        'context-eviction-with-garbage-collection.html',
-        ['android', ('nvidia', 'NVIDIA Tegra')], bug=701929)
-    self.Flaky('conformance/glsl/misc/glsl-long-variable-names.html',
-        ['android', ('nvidia', 'NVIDIA Tegra')], bug=701929)
-    self.Flaky('conformance/textures/image_bitmap_from_video/' +
-        'tex-2d-rgb-rgb-unsigned_byte.html',
-        ['android', ('nvidia', 'NVIDIA Tegra')], bug=701929)
-
     ############
     # ChromeOS #
     ############
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
index d9345de..b1779e3 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
+++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@
 # AUTOGENERATED FILE - DO NOT EDIT
 # SEE roll_webgl_conformance.py
-Current webgl revision f7157c2751220a8f0def9f3f7f6ff37392ac83f0
+Current webgl revision 239528772a1362d0e0c2d1cb2f256f19d6e0c1c1
diff --git a/content/zygote/zygote_main_linux.cc b/content/zygote/zygote_main_linux.cc
index b6f7089..78636ee 100644
--- a/content/zygote/zygote_main_linux.cc
+++ b/content/zygote/zygote_main_linux.cc
@@ -617,10 +617,15 @@
 
   if (using_layer1_sandbox) {
     // Let the ZygoteHost know we're booting up.
-    CHECK(base::UnixDomainSocket::SendMsg(kZygoteSocketPairFd,
-                                          kZygoteBootMessage,
-                                          sizeof(kZygoteBootMessage),
-                                          std::vector<int>()));
+    if (!base::UnixDomainSocket::SendMsg(
+            kZygoteSocketPairFd, kZygoteBootMessage, sizeof(kZygoteBootMessage),
+            std::vector<int>())) {
+      // This is not a CHECK failure because the browser process could either
+      // crash or quickly exit while the zygote is starting. In either case a
+      // zygote crash is not useful. http://crbug.com/692227
+      PLOG(ERROR) << "Failed sending zygote boot message";
+      _exit(1);
+    }
   }
 
   VLOG(1) << "ZygoteMain: initializing " << fork_delegates.size()
diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc
index fb9cecb..2002b29 100644
--- a/extensions/common/permissions/permissions_data.cc
+++ b/extensions/common/permissions/permissions_data.cc
@@ -297,6 +297,19 @@
           *active_permissions_unsafe_, manifest_type_));
 }
 
+PermissionMessages PermissionsData::GetNewPermissionMessages(
+    const PermissionSet& granted_permissions) const {
+  base::AutoLock auto_lock(runtime_lock_);
+
+  std::unique_ptr<const PermissionSet> new_permissions =
+      PermissionSet::CreateDifference(*active_permissions_unsafe_,
+                                      granted_permissions);
+
+  return PermissionMessageProvider::Get()->GetPermissionMessages(
+      PermissionMessageProvider::Get()->GetAllPermissionIDs(*new_permissions,
+                                                            manifest_type_));
+}
+
 bool PermissionsData::HasWithheldImpliedAllHosts() const {
   base::AutoLock auto_lock(runtime_lock_);
   // Since we currently only withhold all_hosts, it's sufficient to check
diff --git a/extensions/common/permissions/permissions_data.h b/extensions/common/permissions/permissions_data.h
index 6997403..a619590a 100644
--- a/extensions/common/permissions/permissions_data.h
+++ b/extensions/common/permissions/permissions_data.h
@@ -165,6 +165,12 @@
   // display at install time, in a nested format ready for display.
   PermissionMessages GetPermissionMessages() const;
 
+  // Returns the list of permission details for permissions that are included in
+  // active_permissions(), but not present in |granted_permissions|.  These are
+  // returned in a nested format, ready for display.
+  PermissionMessages GetNewPermissionMessages(
+      const PermissionSet& granted_permissions) const;
+
   // Returns true if the extension has requested all-hosts permissions (or
   // something close to it), but has had it withheld.
   bool HasWithheldImpliedAllHosts() const;
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index c7e2e16d..4bea377 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -316,9 +316,12 @@
     "api_invocation_errors_unittest.cc",
     "api_last_error_unittest.cc",
     "api_request_handler_unittest.cc",
+    "api_signature_unittest.cc",
     "api_test_base.cc",
     "api_test_base.h",
     "api_test_base_unittest.cc",
+    "argument_spec_builder.cc",
+    "argument_spec_builder.h",
     "argument_spec_unittest.cc",
     "declarative_event_unittest.cc",
     "event_unittest.cc",
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/api_binding_unittest.cc
index fc82ff4..682c0ed 100644
--- a/extensions/renderer/api_binding_unittest.cc
+++ b/extensions/renderer/api_binding_unittest.cc
@@ -46,19 +46,6 @@
     "     'name': 'int'"
     "   }]"
     "}, {"
-    "  'name': 'stringOptionalIntAndBool',"
-    "  'parameters': [{"
-    "    'type': 'string',"
-    "    'name': 'str'"
-    "   }, {"
-    "     'type': 'integer',"
-    "     'name': 'optionalint',"
-    "     'optional': true"
-    "   }, {"
-    "     'type': 'boolean',"
-    "     'name': 'bool'"
-    "   }]"
-    "}, {"
     "  'name': 'oneObject',"
     "  'parameters': [{"
     "    'type': 'object',"
@@ -69,9 +56,6 @@
     "    }"
     "  }]"
     "}, {"
-    "  'name': 'noArgs',"
-    "  'parameters': []"
-    "}, {"
     "  'name': 'intAndCallback',"
     "  'parameters': [{"
     "    'name': 'int',"
@@ -80,39 +64,6 @@
     "    'name': 'callback',"
     "    'type': 'function'"
     "  }]"
-    "}, {"
-    "  'name': 'optionalIntAndCallback',"
-    "  'parameters': [{"
-    "    'name': 'int',"
-    "    'type': 'integer',"
-    "    'optional': true"
-    "  }, {"
-    "    'name': 'callback',"
-    "    'type': 'function'"
-    "  }]"
-    "}, {"
-    "  'name': 'optionalCallback',"
-    "  'parameters': [{"
-    "    'name': 'callback',"
-    "    'type': 'function',"
-    "    'optional': true"
-    "  }]"
-    "}, {"
-    "  'name': 'intAnyOptionalObjectOptionalCallback',"
-    "  'parameters': [{"
-    "    'type': 'integer', 'name': 'tabId', 'minimum': 0"
-    "  }, {"
-    "    'type': 'any', 'name': 'message'"
-    "  }, {"
-    "    'type': 'object',"
-    "    'name': 'options',"
-    "    'properties': {"
-    "      'frameId': {'type': 'integer', 'optional': true, 'minimum': 0}"
-    "    },"
-    "    'optional': true"
-    "  }, {"
-    "    'type': 'function', 'name': 'responseCallback', 'optional': true"
-    "  }]"
     "}]";
 
 const char kError[] = "Uncaught TypeError: Invalid invocation";
@@ -319,9 +270,9 @@
       binding_object->GetOwnPropertyNames(context).ToLocalChecked()->Length());
 }
 
-TEST_F(APIBindingUnittest, Test) {
-  // TODO(devlin): Move this test to an api_signature_unittest file? It really
-  // only tests parsing.
+// Tests the basic call -> request flow of the API binding (ensuring that
+// functions are set up correctly and correctly enforced).
+TEST_F(APIBindingUnittest, TestBasicAPICalls) {
   SetFunctions(kFunctions);
   InitializeBinding();
 
@@ -331,75 +282,21 @@
   v8::Local<v8::Object> binding_object =
       binding()->CreateInstance(context, base::Bind(&AllowAllAPIs));
 
+  // Argument parsing is tested primarily in APISignature and ArgumentSpec
+  // tests, so do a few quick sanity checks...
   ExpectPass(binding_object, "obj.oneString('foo');", "['foo']", false);
-  ExpectPass(binding_object, "obj.oneString('');", "['']", false);
   ExpectFailure(binding_object, "obj.oneString(1);", kError);
-  ExpectFailure(binding_object, "obj.oneString();", kError);
-  ExpectFailure(binding_object, "obj.oneString({});", kError);
-  ExpectFailure(binding_object, "obj.oneString('foo', 'bar');", kError);
+  ExpectPass(binding_object, "obj.stringAndInt('foo', 1)", "['foo',1]", false);
+  ExpectFailure(binding_object, "obj.stringAndInt(1)", kError);
+  ExpectPass(binding_object, "obj.intAndCallback(1, function() {})", "[1]",
+             true);
+  ExpectFailure(binding_object, "obj.intAndCallback(function() {})", kError);
 
-  ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]",
-             false);
-  ExpectPass(binding_object, "obj.stringAndInt('foo', -1);", "['foo',-1]",
-             false);
-  ExpectFailure(binding_object, "obj.stringAndInt(1);", kError);
-  ExpectFailure(binding_object, "obj.stringAndInt('foo');", kError);
-  ExpectFailure(binding_object, "obj.stringAndInt(1, 'foo');", kError);
-  ExpectFailure(binding_object, "obj.stringAndInt('foo', 'foo');", kError);
-  ExpectFailure(binding_object, "obj.stringAndInt('foo', '1');", kError);
-  ExpectFailure(binding_object, "obj.stringAndInt('foo', 2.3);", kError);
-
-  ExpectPass(binding_object, "obj.stringOptionalIntAndBool('foo', 42, true);",
-             "['foo',42,true]", false);
-  ExpectPass(binding_object, "obj.stringOptionalIntAndBool('foo', true);",
-             "['foo',null,true]", false);
-  ExpectFailure(binding_object,
-                "obj.stringOptionalIntAndBool('foo', 'bar', true);", kError);
-
-  ExpectPass(binding_object, "obj.oneObject({prop1: 'foo'});",
-             "[{'prop1':'foo'}]", false);
+  // ...And an interesting case (throwing an error during parsing).
   ExpectFailure(
       binding_object,
       "obj.oneObject({ get prop1() { throw new Error('Badness'); } });",
       "Uncaught Error: Badness");
-
-  ExpectPass(binding_object, "obj.noArgs()", "[]", false);
-  ExpectFailure(binding_object, "obj.noArgs(0)", kError);
-  ExpectFailure(binding_object, "obj.noArgs('')", kError);
-  ExpectFailure(binding_object, "obj.noArgs(null)", kError);
-  ExpectFailure(binding_object, "obj.noArgs(undefined)", kError);
-
-  ExpectPass(binding_object, "obj.intAndCallback(1, function() {})", "[1]",
-             true);
-  ExpectFailure(binding_object, "obj.intAndCallback(function() {})", kError);
-  ExpectFailure(binding_object, "obj.intAndCallback(1)", kError);
-
-  ExpectPass(binding_object, "obj.optionalIntAndCallback(1, function() {})",
-             "[1]", true);
-  ExpectPass(binding_object, "obj.optionalIntAndCallback(function() {})",
-             "[null]", true);
-  ExpectFailure(binding_object, "obj.optionalIntAndCallback(1)", kError);
-
-  ExpectPass(binding_object, "obj.optionalCallback(function() {})", "[]", true);
-  ExpectPass(binding_object, "obj.optionalCallback()", "[]", false);
-  ExpectPass(binding_object, "obj.optionalCallback(undefined)", "[]", false);
-  ExpectFailure(binding_object, "obj.optionalCallback(0)", kError);
-
-  ExpectPass(binding_object,
-             "obj.intAnyOptionalObjectOptionalCallback(4, {foo: 'bar'}, "
-             "function() {})",
-             "[4,{'foo':'bar'},null]", true);
-  ExpectPass(binding_object,
-             "obj.intAnyOptionalObjectOptionalCallback(4, {foo: 'bar'})",
-             "[4,{'foo':'bar'},null]", false);
-  ExpectPass(binding_object,
-             "obj.intAnyOptionalObjectOptionalCallback(4, {foo: 'bar'}, {})",
-             "[4,{'foo':'bar'},{}]", false);
-  ExpectFailure(binding_object,
-                "obj.intAnyOptionalObjectOptionalCallback(4, function() {})",
-                kError);
-  ExpectFailure(binding_object, "obj.intAnyOptionalObjectOptionalCallback(4)",
-                kError);
 }
 
 // Test that enum values are properly exposed on the binding object.
@@ -457,6 +354,7 @@
       GetStringPropertyFromObject(binding_object, context, "enumWithEmpty"));
 }
 
+// Test that type references are correctly set up in the API.
 TEST_F(APIBindingUnittest, TypeRefsTest) {
   const char kTypes[] =
       "[{"
@@ -499,14 +397,14 @@
   v8::Local<v8::Object> binding_object =
       binding()->CreateInstance(context, base::Bind(&AllowAllAPIs));
 
+  // Parsing in general is tested in APISignature and ArgumentSpec tests, but
+  // we test that the binding a) correctly finds the definitions, and b) accepts
+  // properties from the API object.
   ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo'})",
              "[{'prop1':'foo'}]", false);
-  ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 2})",
-             "[{'prop1':'foo','prop2':2}]", false);
   ExpectFailure(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 'a'})",
                 kError);
   ExpectPass(binding_object, "obj.takesRefEnum('alpha')", "['alpha']", false);
-  ExpectPass(binding_object, "obj.takesRefEnum('beta')", "['beta']", false);
   ExpectPass(binding_object, "obj.takesRefEnum(obj.refEnum.BETA)", "['beta']",
              false);
   ExpectFailure(binding_object, "obj.takesRefEnum('gamma')", kError);
diff --git a/extensions/renderer/api_signature_unittest.cc b/extensions/renderer/api_signature_unittest.cc
new file mode 100644
index 0000000..3477f98
--- /dev/null
+++ b/extensions/renderer/api_signature_unittest.cc
@@ -0,0 +1,289 @@
+// 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/renderer/api_signature.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "extensions/renderer/api_binding_test.h"
+#include "extensions/renderer/api_binding_test_util.h"
+#include "extensions/renderer/api_type_reference_map.h"
+#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/argument_spec_builder.h"
+#include "gin/converter.h"
+
+namespace extensions {
+namespace {
+
+using SpecVector = std::vector<std::unique_ptr<ArgumentSpec>>;
+
+std::unique_ptr<APISignature> OneString() {
+  SpecVector specs;
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string").Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+std::unique_ptr<APISignature> StringAndInt() {
+  SpecVector specs;
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string").Build());
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+std::unique_ptr<APISignature> StringOptionalIntAndBool() {
+  SpecVector specs;
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string").Build());
+  specs.push_back(
+      ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional().Build());
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::BOOLEAN, "bool").Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+std::unique_ptr<APISignature> OneObject() {
+  SpecVector specs;
+  specs.push_back(
+      ArgumentSpecBuilder(ArgumentType::OBJECT, "obj")
+          .AddProperty("prop1",
+                       ArgumentSpecBuilder(ArgumentType::STRING).Build())
+          .AddProperty(
+              "prop2",
+              ArgumentSpecBuilder(ArgumentType::STRING).MakeOptional().Build())
+          .Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+std::unique_ptr<APISignature> NoArgs() {
+  return base::MakeUnique<APISignature>(SpecVector());
+}
+
+std::unique_ptr<APISignature> IntAndCallback() {
+  SpecVector specs;
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build());
+  specs.push_back(
+      ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+std::unique_ptr<APISignature> OptionalIntAndCallback() {
+  SpecVector specs;
+  specs.push_back(
+      ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional().Build());
+  specs.push_back(
+      ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+std::unique_ptr<APISignature> OptionalCallback() {
+  SpecVector specs;
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")
+                      .MakeOptional()
+                      .Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+std::unique_ptr<APISignature> IntAnyOptionalObjectOptionalCallback() {
+  SpecVector specs;
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build());
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::ANY, "any").Build());
+  specs.push_back(
+      ArgumentSpecBuilder(ArgumentType::OBJECT, "obj")
+          .AddProperty(
+              "prop",
+              ArgumentSpecBuilder(ArgumentType::INTEGER).MakeOptional().Build())
+          .MakeOptional()
+          .Build());
+  specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")
+                      .MakeOptional()
+                      .Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+std::unique_ptr<APISignature> RefObj() {
+  SpecVector specs;
+  specs.push_back(
+      ArgumentSpecBuilder(ArgumentType::REF, "obj").SetRef("refObj").Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+std::unique_ptr<APISignature> RefEnum() {
+  SpecVector specs;
+  specs.push_back(
+      ArgumentSpecBuilder(ArgumentType::REF, "enum").SetRef("refEnum").Build());
+  return base::MakeUnique<APISignature>(std::move(specs));
+}
+
+}  // namespace
+
+class APISignatureTest : public APIBindingTest {
+ public:
+  APISignatureTest()
+      : type_refs_(APITypeReferenceMap::InitializeTypeCallback()) {}
+  ~APISignatureTest() override = default;
+
+  void SetUp() override {
+    APIBindingTest::SetUp();
+
+    std::unique_ptr<ArgumentSpec> ref_obj_spec =
+        ArgumentSpecBuilder(ArgumentType::OBJECT)
+            .AddProperty("prop1",
+                         ArgumentSpecBuilder(ArgumentType::STRING).Build())
+            .AddProperty("prop2", ArgumentSpecBuilder(ArgumentType::INTEGER)
+                                      .MakeOptional()
+                                      .Build())
+            .Build();
+    type_refs_.AddSpec("refObj", std::move(ref_obj_spec));
+
+    type_refs_.AddSpec("refEnum", ArgumentSpecBuilder(ArgumentType::STRING)
+                                      .SetEnums({"alpha", "beta"})
+                                      .Build());
+  }
+
+  void ExpectPass(const APISignature& signature,
+                  base::StringPiece arg_values,
+                  base::StringPiece expected_parsed_args,
+                  bool expect_callback) {
+    RunTest(signature, arg_values, expected_parsed_args, expect_callback, true);
+  }
+
+  void ExpectFailure(const APISignature& signature,
+                     base::StringPiece arg_values) {
+    RunTest(signature, arg_values, base::StringPiece(), false, false);
+  }
+
+ private:
+  void RunTest(const APISignature& signature,
+               base::StringPiece arg_values,
+               base::StringPiece expected_parsed_args,
+               bool expect_callback,
+               bool should_succeed) {
+    SCOPED_TRACE(arg_values);
+    v8::Local<v8::Context> context = MainContext();
+    v8::Local<v8::Value> v8_args = V8ValueFromScriptSource(context, arg_values);
+    ASSERT_FALSE(v8_args.IsEmpty());
+    ASSERT_TRUE(v8_args->IsArray());
+    std::vector<v8::Local<v8::Value>> vector_args;
+    ASSERT_TRUE(gin::ConvertFromV8(isolate(), v8_args, &vector_args));
+
+    std::unique_ptr<base::ListValue> result;
+    v8::Local<v8::Function> callback;
+    std::string error;
+    bool success = signature.ParseArgumentsToJSON(
+        context, vector_args, type_refs_, &result, &callback, &error);
+    EXPECT_EQ(should_succeed, success);
+    ASSERT_EQ(should_succeed, !!result);
+    EXPECT_EQ(expect_callback, !callback.IsEmpty());
+    if (should_succeed) {
+      EXPECT_EQ(ReplaceSingleQuotes(expected_parsed_args),
+                ValueToString(*result));
+    }
+  }
+
+  APITypeReferenceMap type_refs_;
+
+  DISALLOW_COPY_AND_ASSIGN(APISignatureTest);
+};
+
+TEST_F(APISignatureTest, BasicSignatureParsing) {
+  v8::HandleScope handle_scope(isolate());
+
+  {
+    auto signature = OneString();
+    ExpectPass(*signature, "['foo']", "['foo']", false);
+    ExpectPass(*signature, "['']", "['']", false);
+    ExpectFailure(*signature, "[1]");
+    ExpectFailure(*signature, "[]");
+    ExpectFailure(*signature, "[{}]");
+    ExpectFailure(*signature, "['foo', 'bar']");
+  }
+
+  {
+    auto signature = StringAndInt();
+    ExpectPass(*signature, "['foo', 42]", "['foo',42]", false);
+    ExpectPass(*signature, "['foo', -1]", "['foo',-1]", false);
+    ExpectFailure(*signature, "[1]");
+    ExpectFailure(*signature, "['foo'];");
+    ExpectFailure(*signature, "[1, 'foo']");
+    ExpectFailure(*signature, "['foo', 'foo']");
+    ExpectFailure(*signature, "['foo', '1']");
+    ExpectFailure(*signature, "['foo', 2.3]");
+  }
+
+  {
+    auto signature = StringOptionalIntAndBool();
+    ExpectPass(*signature, "['foo', 42, true]", "['foo',42,true]", false);
+    ExpectPass(*signature, "['foo', true]", "['foo',null,true]", false);
+    ExpectFailure(*signature, "['foo', 'bar', true]");
+  }
+
+  {
+    auto signature = OneObject();
+    ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]", false);
+    ExpectFailure(*signature,
+                  "[{ get prop1() { throw new Error('Badness'); } }]");
+  }
+
+  {
+    auto signature = NoArgs();
+    ExpectPass(*signature, "[]", "[]", false);
+    ExpectFailure(*signature, "[0]");
+    ExpectFailure(*signature, "['']");
+    ExpectFailure(*signature, "[null]");
+    ExpectFailure(*signature, "[undefined]");
+  }
+
+  {
+    auto signature = IntAndCallback();
+    ExpectPass(*signature, "[1, function() {}]", "[1]", true);
+    ExpectFailure(*signature, "[function() {}]");
+    ExpectFailure(*signature, "[1]");
+  }
+
+  {
+    auto signature = OptionalIntAndCallback();
+    ExpectPass(*signature, "[1, function() {}]", "[1]", true);
+    ExpectPass(*signature, "[function() {}]", "[null]", true);
+    ExpectFailure(*signature, "[1]");
+  }
+
+  {
+    auto signature = OptionalCallback();
+    ExpectPass(*signature, "[function() {}]", "[]", true);
+    ExpectPass(*signature, "[]", "[]", false);
+    ExpectPass(*signature, "[undefined]", "[]", false);
+    ExpectFailure(*signature, "[0]");
+  }
+
+  {
+    auto signature = IntAnyOptionalObjectOptionalCallback();
+    ExpectPass(*signature, "[4, {foo: 'bar'}, function() {}]",
+               "[4,{'foo':'bar'},null]", true);
+    ExpectPass(*signature, "[4, {foo: 'bar'}]", "[4,{'foo':'bar'},null]",
+               false);
+    ExpectPass(*signature, "[4, {foo: 'bar'}, {}]", "[4,{'foo':'bar'},{}]",
+               false);
+    ExpectFailure(*signature, "[4, function() {}]");
+    ExpectFailure(*signature, "[4]");
+  }
+}
+
+TEST_F(APISignatureTest, TypeRefsTest) {
+  v8::HandleScope handle_scope(isolate());
+
+  {
+    auto signature = RefObj();
+    ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]", false);
+    ExpectPass(*signature, "[{prop1: 'foo', prop2: 2}]",
+               "[{'prop1':'foo','prop2':2}]", false);
+    ExpectFailure(*signature, "[{prop1: 'foo', prop2: 'a'}]");
+  }
+
+  {
+    auto signature = RefEnum();
+    ExpectPass(*signature, "['alpha']", "['alpha']", false);
+    ExpectPass(*signature, "['beta']", "['beta']", false);
+    ExpectFailure(*signature, "['gamma']");
+  }
+}
+
+}  // namespace extensions
diff --git a/extensions/renderer/argument_spec_builder.cc b/extensions/renderer/argument_spec_builder.cc
new file mode 100644
index 0000000..1805a0b
--- /dev/null
+++ b/extensions/renderer/argument_spec_builder.cc
@@ -0,0 +1,74 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/renderer/argument_spec_builder.h"
+
+#include "base/memory/ptr_util.h"
+
+namespace extensions {
+
+ArgumentSpecBuilder::ArgumentSpecBuilder(ArgumentType type)
+    : ArgumentSpecBuilder(type, base::StringPiece()) {}
+
+ArgumentSpecBuilder::ArgumentSpecBuilder(ArgumentType type,
+                                         base::StringPiece name)
+    : spec_(base::MakeUnique<ArgumentSpec>(type)) {
+  if (!name.empty())
+    spec_->set_name(name);
+}
+
+ArgumentSpecBuilder::~ArgumentSpecBuilder() {}
+
+ArgumentSpecBuilder& ArgumentSpecBuilder::MakeOptional() {
+  spec_->set_optional(true);
+  return *this;
+}
+
+ArgumentSpecBuilder& ArgumentSpecBuilder::AddProperty(
+    base::StringPiece property_name,
+    std::unique_ptr<ArgumentSpec> property_spec) {
+  properties_[property_name.as_string()] = std::move(property_spec);
+  return *this;
+}
+
+ArgumentSpecBuilder& ArgumentSpecBuilder::SetMinimum(int minimum) {
+  spec_->set_minimum(minimum);
+  return *this;
+}
+
+ArgumentSpecBuilder& ArgumentSpecBuilder::SetListType(
+    std::unique_ptr<ArgumentSpec> list_type) {
+  spec_->set_list_element_type(std::move(list_type));
+  return *this;
+}
+
+ArgumentSpecBuilder& ArgumentSpecBuilder::SetRef(base::StringPiece ref) {
+  spec_->set_ref(ref);
+  return *this;
+}
+
+ArgumentSpecBuilder& ArgumentSpecBuilder::SetChoices(
+    std::vector<std::unique_ptr<ArgumentSpec>> choices) {
+  spec_->set_choices(std::move(choices));
+  return *this;
+}
+
+ArgumentSpecBuilder& ArgumentSpecBuilder::SetEnums(
+    std::set<std::string> enum_values) {
+  spec_->set_enum_values(std::move(enum_values));
+  return *this;
+}
+
+ArgumentSpecBuilder& ArgumentSpecBuilder::SetAdditionalProperties(
+    std::unique_ptr<ArgumentSpec> additional_properties) {
+  spec_->set_additional_properties(std::move(additional_properties));
+  return *this;
+}
+
+std::unique_ptr<ArgumentSpec> ArgumentSpecBuilder::Build() {
+  spec_->set_properties(std::move(properties_));
+  return std::move(spec_);
+}
+
+}  // namespace extensions
diff --git a/extensions/renderer/argument_spec_builder.h b/extensions/renderer/argument_spec_builder.h
new file mode 100644
index 0000000..0f0b8760
--- /dev/null
+++ b/extensions/renderer/argument_spec_builder.h
@@ -0,0 +1,50 @@
+// 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_RENDERER_ARGUMENT_SPEC_BUILDER_H_
+#define EXTENSIONS_RENDERER_ARGUMENT_SPEC_BUILDER_H_
+
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "extensions/renderer/argument_spec.h"
+
+namespace extensions {
+
+// A utility class for helping construct ArgumentSpecs in tests.
+// NOTE: This is designed to be test-only. It's not worth adding to production
+// code because it's a) only a bit of syntactic sugar and b) rife with footguns.
+class ArgumentSpecBuilder {
+ public:
+  explicit ArgumentSpecBuilder(ArgumentType type);
+  ArgumentSpecBuilder(ArgumentType type, base::StringPiece name);
+
+  ~ArgumentSpecBuilder();
+
+  ArgumentSpecBuilder& MakeOptional();
+  ArgumentSpecBuilder& AddProperty(base::StringPiece property_name,
+                                   std::unique_ptr<ArgumentSpec> property_spec);
+  ArgumentSpecBuilder& SetMinimum(int minimum);
+  ArgumentSpecBuilder& SetListType(std::unique_ptr<ArgumentSpec> list_type);
+  ArgumentSpecBuilder& SetRef(base::StringPiece ref);
+  ArgumentSpecBuilder& SetChoices(
+      std::vector<std::unique_ptr<ArgumentSpec>> choices);
+  ArgumentSpecBuilder& SetEnums(std::set<std::string> enum_values);
+  ArgumentSpecBuilder& SetAdditionalProperties(
+      std::unique_ptr<ArgumentSpec> additional_properties);
+  std::unique_ptr<ArgumentSpec> Build();
+
+ private:
+  std::unique_ptr<ArgumentSpec> spec_;
+  ArgumentSpec::PropertiesMap properties_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArgumentSpecBuilder);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_RENDERER_ARGUMENT_SPEC_BUILDER_H_
diff --git a/ios/chrome/app/spotlight/topsites_spotlight_manager.h b/ios/chrome/app/spotlight/topsites_spotlight_manager.h
index 02f010e0..1a1d3b09c 100644
--- a/ios/chrome/app/spotlight/topsites_spotlight_manager.h
+++ b/ios/chrome/app/spotlight/topsites_spotlight_manager.h
@@ -13,9 +13,9 @@
 
 // This spotlight manager handles indexing of sites shown on the NTP. Because of
 // privacy concerns, only sites shown on the NTP are indexed; therefore, this
-// manager mirrors the functionality seen in google_landing_controller. It uses
-// suggestions (most likely) as a data source if the user is logged in and top
-// sites otherwise.
+// manager mirrors the functionality seen in google_landing_view_controller. It
+// uses suggestions (most likely) as a data source if the user is logged in and
+// top sites otherwise.
 
 @interface TopSitesSpotlightManager : BaseSpotlightManager
 
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 030f6f1..419fce24 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -431,6 +431,7 @@
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/ui",
     "//ios/public/provider/chrome/browser/voice",
+    "//ios/shared/chrome/browser/ui/commands",
     "//ios/shared/chrome/browser/ui/tools_menu",
     "//ios/third_party/material_components_ios",
     "//ios/web",
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 1c37fbc..f9c0d98 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -169,6 +169,7 @@
 #include "ios/public/provider/chrome/browser/voice/voice_search_controller.h"
 #include "ios/public/provider/chrome/browser/voice/voice_search_controller_delegate.h"
 #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
+#import "ios/shared/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/shared/chrome/browser/ui/tools_menu/tools_menu_configuration.h"
 #include "ios/web/public/active_state_manager.h"
 #include "ios/web/public/navigation_item.h"
@@ -400,6 +401,9 @@
   // Handles presentation of JavaScript dialogs.
   std::unique_ptr<JavaScriptDialogPresenterImpl> _javaScriptDialogPresenter;
 
+  // Handles command dispatching.
+  CommandDispatcher* _dispatcher;
+
   // Keyboard commands provider.  It offloads most of the keyboard commands
   // management off of the BVC.
   KeyCommandsProvider* _keyCommandsProvider;
@@ -948,6 +952,14 @@
     _nativeControllersForTabIDs = [NSMapTable strongToWeakObjectsMapTable];
     _dialogPresenter = [[DialogPresenter alloc] initWithDelegate:self
                                         presentingViewController:self];
+    _dispatcher = [[CommandDispatcher alloc] init];
+    [_dispatcher startDispatchingToTarget:self
+                              forProtocol:@protocol(UrlLoader)];
+    [_dispatcher startDispatchingToTarget:self
+                              forProtocol:@protocol(WebToolbarDelegate)];
+    [_dispatcher startDispatchingToTarget:self
+                              forSelector:@selector(chromeExecuteCommand:)];
+
     _javaScriptDialogPresenter.reset(
         new JavaScriptDialogPresenterImpl(_dialogPresenter));
     _webStateDelegate.reset(new web::WebStateDelegateBridge(self));
@@ -1716,6 +1728,8 @@
   // The file remover needs the browser state, so needs to be destroyed now.
   _externalFileRemover = nil;
   _browserState = nullptr;
+  [_dispatcher stopDispatchingToTarget:self];
+  _dispatcher = nil;
 }
 
 - (void)installFakeStatusBar {
@@ -1762,6 +1776,8 @@
       newWebToolbarControllerWithDelegate:self
                                 urlLoader:self
                           preloadProvider:_preloadController];
+  [_dispatcher startDispatchingToTarget:_toolbarController
+                            forProtocol:@protocol(OmniboxFocuser)];
   [_toolbarController setTabCount:[_model count]];
   if (_voiceSearchController)
     _voiceSearchController->SetDelegate(_toolbarController);
@@ -3028,7 +3044,8 @@
                                        colorCache:_dominantColorCache
                                webToolbarDelegate:self
                                          tabModel:_model
-                             parentViewController:self];
+                             parentViewController:self
+                                       dispatcher:_dispatcher];
     pageController.swipeRecognizerProvider = self.sideSwipeController;
 
     // Panel is always NTP for iPhone.
diff --git a/ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h b/ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h
index 50c31f2..67e6b1c 100644
--- a/ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h
+++ b/ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h
@@ -20,4 +20,11 @@
 - (void)chromeExecuteCommand:(id)sender;
 @end
 
+@protocol ChromeExecuteCommand
+// Executes a Chrome command.  |sender| must implement the |-tag| method and
+// return the id of the command to execute.  The default implementation of this
+// method simply forwards the call to the next responder.
+- (IBAction)chromeExecuteCommand:(id)sender;
+@end
+
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_UIKIT_CHROMEEXECUTECOMMAND_H_
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn
index 2bc28e6..0fa5f8a 100644
--- a/ios/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -114,11 +114,11 @@
     "centering_scrollview.h",
     "centering_scrollview.mm",
     "google_landing_consumer.h",
-    "google_landing_controller.h",
-    "google_landing_controller.mm",
     "google_landing_data_source.h",
     "google_landing_mediator.h",
     "google_landing_mediator.mm",
+    "google_landing_view_controller.h",
+    "google_landing_view_controller.mm",
     "incognito_panel_controller.h",
     "incognito_panel_controller.mm",
     "most_visited_cell.h",
@@ -193,6 +193,7 @@
     "//ios/public/provider/chrome/browser/images",
     "//ios/public/provider/chrome/browser/ui",
     "//ios/public/provider/chrome/browser/voice",
+    "//ios/shared/chrome/browser/ui/commands",
     "//ios/third_party/material_components_ios",
     "//ios/third_party/material_roboto_font_loader_ios",
     "//ios/web",
@@ -214,7 +215,7 @@
   testonly = true
   sources = [
     "centering_scrollview_unittest.mm",
-    "google_landing_controller_unittest.mm",
+    "google_landing_view_controller_unittest.mm",
     "most_visited_cell_unittest.mm",
     "new_tab_page_bar_unittest.mm",
     "new_tab_page_controller_unittest.mm",
diff --git a/ios/chrome/browser/ui/ntp/google_landing_consumer.h b/ios/chrome/browser/ui/ntp/google_landing_consumer.h
index b91d33e1..311f8c09 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_consumer.h
+++ b/ios/chrome/browser/ui/ntp/google_landing_consumer.h
@@ -65,11 +65,6 @@
 // Tell location bar has taken focus.
 - (void)locationBarBecomesFirstResponder;
 
-// TODO(crbug.com/694750): This call will be removed once dispatching is
-// available.
-// Asks the consumer to execute a chrome command.
-- (void)chromeExecuteCommand:(id)sender;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_GOOGLE_LANDING_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/ntp/google_landing_data_source.h b/ios/chrome/browser/ui/ntp/google_landing_data_source.h
index aa3d3ed..1ef2068 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_data_source.h
+++ b/ios/chrome/browser/ui/ntp/google_landing_data_source.h
@@ -9,8 +9,6 @@
 
 #include "components/ntp_tiles/ntp_tile.h"
 #include "components/ntp_tiles/tile_visual_type.h"
-#import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
-#import "ios/chrome/browser/ui/url_loader.h"
 #include "url/gurl.h"
 
 class ReadingListModel;
@@ -18,12 +16,10 @@
 namespace favicon {
 class LargeIconService;
 }
-@class TabModel;
-@protocol WebToolbarDelegate;
 
 // DataSource for the google landing controller.
 // TODO(crbug.com/694750): Most everything here can be moved to dispatcher.
-@protocol GoogleLandingDataSource<OmniboxFocuser, UrlLoader>
+@protocol GoogleLandingDataSource
 
 // Removes a blacklisted URL in both |_mostVisitedData|.
 - (void)removeBlacklistedURL:(const GURL&)url;
@@ -41,10 +37,6 @@
 // Called when a what's new promo is tapped.
 - (void)promoTapped;
 
-// TODO(crbug.com/694750): This should move to a dispatcher.
-// Called before the fake tab switcher icon is tapped to save snapshots.
-- (void)prepareToEnterTabSwitcher:(id)sender;
-
 // TODO(crbug.com/694750): The following two methods should be moved to the
 // consumer, and converted into types more suitable for a consumer.
 // Gets an a most visited NTP tile at |index|.
@@ -66,8 +58,6 @@
 // Gets the large icon service.
 - (favicon::LargeIconService*)largeIconService;
 
-
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_GOOGLE_LANDING_DATA_SOURCE_H_
diff --git a/ios/chrome/browser/ui/ntp/google_landing_mediator.h b/ios/chrome/browser/ui/ntp/google_landing_mediator.h
index 8275eed..63babf9 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_mediator.h
+++ b/ios/chrome/browser/ui/ntp/google_landing_mediator.h
@@ -8,7 +8,9 @@
 #import <Foundation/Foundation.h>
 
 #import "ios/chrome/browser/ui/ntp/google_landing_data_source.h"
+#import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
 
+@protocol ChromeExecuteCommand;
 @protocol GoogleLandingConsumer;
 @protocol OmniboxFocuser;
 @protocol UrlLoader;
@@ -23,9 +25,7 @@
 
 - (instancetype)initWithConsumer:(id<GoogleLandingConsumer>)consumer
                     browserState:(ios::ChromeBrowserState*)browserState
-                          loader:(id<UrlLoader>)loader
-                         focuser:(id<OmniboxFocuser>)focuser
-              webToolbarDelegate:(id<WebToolbarDelegate>)webToolbarDelegate
+                      dispatcher:(id<ChromeExecuteCommand, UrlLoader>)dispatcher
                     webStateList:(WebStateList*)webStateList
     NS_DESIGNATED_INITIALIZER;
 - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/ntp/google_landing_mediator.mm b/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
index 5dfa2c379..d93c60f 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
+++ b/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
@@ -35,6 +35,7 @@
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
+#import "ios/shared/chrome/browser/ui/commands/command_dispatcher.h"
 #include "ios/web/public/web_state/web_state.h"
 
 using base::UserMetricsAction;
@@ -82,7 +83,8 @@
 
 }  // namespace google_landing
 
-@interface GoogleLandingMediator ()<MostVisitedSitesObserving,
+@interface GoogleLandingMediator ()<GoogleLandingDataSource,
+                                    MostVisitedSitesObserving,
                                     WebStateListObserving> {
   // The ChromeBrowserState associated with this mediator.
   ios::ChromeBrowserState* _browserState;  // Weak.
@@ -90,12 +92,6 @@
   // |YES| if impressions were logged already and shouldn't be logged again.
   BOOL _recordedPageImpression;
 
-  // The designated url loader.
-  id<UrlLoader> _loader;  // Weak.
-
-  // Delegate to focus and blur the omnibox.
-  base::WeakNSProtocol<id<OmniboxFocuser>> _focuser;
-
   // Controller to fetch and show doodles or a default Google logo.
   base::scoped_nsprotocol<id<LogoVendor>> _doodleController;
 
@@ -114,8 +110,6 @@
   // the callback).
   ntp_tiles::NTPTilesVector _mostVisitedData;
 
-  base::WeakNSProtocol<id<WebToolbarDelegate>> _webToolbarDelegate;
-
   // Observes the WebStateList so that this mediator can update the UI when the
   // active WebState changes.
   std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
@@ -130,6 +124,9 @@
 // The WebStateList that is being observed by this mediator.
 @property(nonatomic, assign) WebStateList* webStateList;
 
+// The dispatcher for this mediator.
+@property(nonatomic, assign) id<ChromeExecuteCommand, UrlLoader> dispatcher;
+
 // Perform initial setup.
 - (void)setUp;
 
@@ -138,21 +135,18 @@
 @implementation GoogleLandingMediator
 
 @synthesize consumer = _consumer;
+@synthesize dispatcher = _dispatcher;
 @synthesize webStateList = _webStateList;
 
 - (instancetype)initWithConsumer:(id<GoogleLandingConsumer>)consumer
                     browserState:(ios::ChromeBrowserState*)browserState
-                          loader:(id<UrlLoader>)loader
-                         focuser:(id<OmniboxFocuser>)focuser
-              webToolbarDelegate:(id<WebToolbarDelegate>)webToolbarDelegate
+                      dispatcher:(id<ChromeExecuteCommand, UrlLoader>)dispatcher
                     webStateList:(WebStateList*)webStateList {
   self = [super init];
   if (self) {
     _consumer = consumer;
     _browserState = browserState;
-    _loader = loader;
-    _focuser.reset(focuser);
-    _webToolbarDelegate.reset(webToolbarDelegate);
+    _dispatcher = dispatcher;
     _webStateList = webStateList;
 
     _webStateListObserver = base::MakeUnique<WebStateListObserverBridge>(self);
@@ -190,7 +184,7 @@
       new google_landing::SearchEngineObserver(self, _templateURLService));
   _templateURLService->Load();
   _doodleController.reset(ios::GetChromeBrowserProvider()->CreateLogoVendor(
-      _browserState, _loader));
+      _browserState, self.dispatcher));
   [_consumer setLogoVendor:_doodleController];
   [self updateShowLogo];
 
@@ -352,10 +346,10 @@
   [self.consumer setPromoCanShow:_notification_promo->CanShow()];
 
   if (_notification_promo->IsURLPromo()) {
-    [_loader webPageOrderedOpen:_notification_promo->url()
-                       referrer:web::Referrer()
-                   inBackground:NO
-                       appendTo:kCurrentTab];
+    [self.dispatcher webPageOrderedOpen:_notification_promo->url()
+                               referrer:web::Referrer()
+                           inBackground:NO
+                               appendTo:kCurrentTab];
     return;
   }
 
@@ -363,78 +357,10 @@
     base::scoped_nsobject<GenericChromeCommand> command(
         [[GenericChromeCommand alloc]
             initWithTag:_notification_promo->command_id()]);
-    [self.consumer chromeExecuteCommand:command];
+    [self.dispatcher chromeExecuteCommand:command];
     return;
   }
   NOTREACHED();
 }
 
-- (void)prepareToEnterTabSwitcher:(id)sender {
-  [_webToolbarDelegate prepareToEnterTabSwitcher:sender];
-}
-
-#pragma mark - UrlLoader
-
-- (void)loadURL:(const GURL&)url
-             referrer:(const web::Referrer&)referrer
-           transition:(ui::PageTransition)transition
-    rendererInitiated:(BOOL)rendererInitiated {
-  [_loader loadURL:url
-               referrer:referrer
-             transition:transition
-      rendererInitiated:rendererInitiated];
-}
-
-- (void)webPageOrderedOpen:(const GURL&)url
-                  referrer:(const web::Referrer&)referrer
-              inBackground:(BOOL)inBackground
-                  appendTo:(OpenPosition)appendTo {
-  [_loader webPageOrderedOpen:url
-                     referrer:referrer
-                 inBackground:inBackground
-                     appendTo:appendTo];
-}
-
-- (void)webPageOrderedOpen:(const GURL&)url
-                  referrer:(const web::Referrer&)referrer
-               inIncognito:(BOOL)inIncognito
-              inBackground:(BOOL)inBackground
-                  appendTo:(OpenPosition)appendTo {
-  [_loader webPageOrderedOpen:url
-                     referrer:referrer
-                  inIncognito:inIncognito
-                 inBackground:inBackground
-                     appendTo:appendTo];
-}
-
-- (void)loadSessionTab:(const sessions::SessionTab*)sessionTab {
-  NOTREACHED();
-}
-
-- (void)loadJavaScriptFromLocationBar:(NSString*)script {
-  NOTREACHED();
-}
-
-#pragma mark - OmniboxFocuser
-
-- (void)focusOmnibox {
-  [_focuser focusOmnibox];
-}
-
-- (void)cancelOmniboxEdit {
-  [_focuser cancelOmniboxEdit];
-}
-
-- (void)focusFakebox {
-  [_focuser focusFakebox];
-}
-
-- (void)onFakeboxBlur {
-  [_focuser onFakeboxBlur];
-}
-
-- (void)onFakeboxAnimationComplete {
-  [_focuser onFakeboxAnimationComplete];
-}
-
 @end
diff --git a/ios/chrome/browser/ui/ntp/google_landing_controller.h b/ios/chrome/browser/ui/ntp/google_landing_view_controller.h
similarity index 68%
rename from ios/chrome/browser/ui/ntp/google_landing_controller.h
rename to ios/chrome/browser/ui/ntp/google_landing_view_controller.h
index af2352d..01859bf 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_controller.h
+++ b/ios/chrome/browser/ui/ntp/google_landing_view_controller.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 IOS_CHROME_BROWSER_UI_NTP_GOOGLE_LANDING_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_NTP_GOOGLE_LANDING_CONTROLLER_H_
+#ifndef IOS_CHROME_BROWSER_UI_NTP_GOOGLE_LANDING_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_UI_NTP_GOOGLE_LANDING_VIEW_CONTROLLER_H_
 
 #import <UIKit/UIKit.h>
 
@@ -15,9 +15,11 @@
 #import "ios/public/provider/chrome/browser/voice/logo_animation_controller.h"
 
 @protocol GoogleLandingDataSource;
+@protocol OmniboxFocuser;
+@protocol UrlLoader;
 
 // Google centric new tab page.
-@interface GoogleLandingController
+@interface GoogleLandingViewController
     : UIViewController<GoogleLandingConsumer,
                        LogoAnimationControllerOwnerOwner,
                        NewTabPagePanelProtocol,
@@ -25,6 +27,8 @@
 
 @property(nonatomic, assign) id<GoogleLandingDataSource> dataSource;
 
+@property(nonatomic, assign) id<UrlLoader, OmniboxFocuser> dispatcher;
+
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_NTP_GOOGLE_LANDING_CONTROLLER_H_
+#endif  // IOS_CHROME_BROWSER_UI_NTP_GOOGLE_LANDING_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/ntp/google_landing_controller.mm b/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
similarity index 96%
rename from ios/chrome/browser/ui/ntp/google_landing_controller.mm
rename to ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
index 70306b6..6897491 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_controller.mm
+++ b/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
@@ -2,7 +2,7 @@
 // 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/ntp/google_landing_controller.h"
+#import "ios/chrome/browser/ui/ntp/google_landing_view_controller.h"
 
 #include <algorithm>
 
@@ -21,8 +21,10 @@
 #import "ios/chrome/browser/ui/ntp/new_tab_page_header_view.h"
 #import "ios/chrome/browser/ui/ntp/whats_new_header_view.h"
 #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
+#import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
+#import "ios/chrome/browser/ui/url_loader.h"
 #include "ios/chrome/common/string_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
@@ -30,6 +32,7 @@
 #import "ios/web/public/web_state/context_menu_params.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/page_transition_types.h"
 
 using base::UserMetricsAction;
 
@@ -69,7 +72,7 @@
 
 }  // namespace
 
-@interface GoogleLandingController (UsedByGoogleLandingView)
+@interface GoogleLandingViewController (UsedByGoogleLandingView)
 // Update frames for subviews depending on the interface orientation.
 - (void)updateSubviewFrames;
 // Resets the collection view's inset to 0.
@@ -79,16 +82,16 @@
 
 // Subclassing the main UIScrollView allows calls for setFrame.
 @interface GoogleLandingView : UIView {
-  GoogleLandingController* _googleLanding;
+  GoogleLandingViewController* _googleLanding;
 }
 
-- (void)setFrameDelegate:(GoogleLandingController*)delegate;
+- (void)setFrameDelegate:(GoogleLandingViewController*)delegate;
 
 @end
 
 @implementation GoogleLandingView
 
-- (void)setFrameDelegate:(GoogleLandingController*)delegate {
+- (void)setFrameDelegate:(GoogleLandingViewController*)delegate {
   _googleLanding = delegate;
 }
 
@@ -107,12 +110,12 @@
 
 @end
 
-@interface GoogleLandingController ()<OverscrollActionsControllerDelegate,
-                                      UICollectionViewDataSource,
-                                      UICollectionViewDelegate,
-                                      UICollectionViewDelegateFlowLayout,
-                                      UIGestureRecognizerDelegate,
-                                      WhatsNewHeaderViewDelegate> {
+@interface GoogleLandingViewController ()<OverscrollActionsControllerDelegate,
+                                          UICollectionViewDataSource,
+                                          UICollectionViewDelegate,
+                                          UICollectionViewDelegateFlowLayout,
+                                          UIGestureRecognizerDelegate,
+                                          WhatsNewHeaderViewDelegate> {
   // Fake omnibox.
   base::scoped_nsobject<UIButton> _searchTapTarget;
 
@@ -257,13 +260,14 @@
 
 @end
 
-@implementation GoogleLandingController
+@implementation GoogleLandingViewController
 
 @dynamic view;
 @synthesize logoVendor = _logoVendor;
 @synthesize dataSource = _dataSource;
 // Property declared in NewTabPagePanelProtocol.
 @synthesize delegate = _delegate;
+@synthesize dispatcher = _dispatcher;
 @synthesize isOffTheRecord = _isOffTheRecord;
 @synthesize logoIsShowing = _logoIsShowing;
 @synthesize promoText = _promoText;
@@ -792,7 +796,7 @@
         if (_scrolledToTop) {
           _animateHeader = NO;
           if (!IsIPadIdiom()) {
-            [self.dataSource onFakeboxAnimationComplete];
+            [self.dispatcher onFakeboxAnimationComplete];
             [_headerView fadeOutShadow];
             [_searchTapTarget setHidden:YES];
           }
@@ -801,12 +805,12 @@
 }
 
 - (void)searchFieldTapped:(id)sender {
-  [self.dataSource focusFakebox];
+  [self.dispatcher focusFakebox];
 }
 
 - (void)blurOmnibox {
   if (_omniboxFocused) {
-    [self.dataSource cancelOmniboxEdit];
+    [self.dispatcher cancelOmniboxEdit];
   } else {
     [self locationBarResignsFirstResponder];
   }
@@ -829,7 +833,7 @@
   _scrolledToTop = NO;
   if (!IsIPadIdiom()) {
     [_searchTapTarget setHidden:NO];
-    [self.dataSource onFakeboxBlur];
+    [self.dispatcher onFakeboxBlur];
   }
 
   // Reload most visited sites in case the number of placeholder cells needs to
@@ -978,7 +982,7 @@
   [self blurOmnibox];
   DCHECK(visitedIndex < [self numberOfItems]);
   [self.dataSource logMostVisitedClick:visitedIndex tileType:cell.tileType];
-  [self.dataSource loadURL:[self urlForIndex:visitedIndex]
+  [self.dispatcher loadURL:[self urlForIndex:visitedIndex]
                   referrer:web::Referrer()
                 transition:ui::PAGE_TRANSITION_AUTO_BOOKMARK
          rendererInitiated:NO];
@@ -1008,7 +1012,8 @@
       if (!IsIPadIdiom()) {
         // iPhone header also contains a toolbar since the normal toolbar is
         // hidden.
-        [_headerView addToolbarWithDataSource:self.dataSource];
+        [_headerView addToolbarWithDataSource:self.dataSource
+                                   dispatcher:self.dispatcher];
         [_headerView setToolbarTabCount:self.tabCount];
         [_headerView setCanGoForward:self.canGoForward];
         [_headerView setCanGoBack:self.canGoBack];
@@ -1132,16 +1137,16 @@
 
     // Open In New Tab.
     GURL url = [self urlForIndex:index];
-    base::WeakNSObject<GoogleLandingController> weakSelf(self);
+    base::WeakNSObject<GoogleLandingViewController> weakSelf(self);
     action = ^{
-      base::scoped_nsobject<GoogleLandingController> strongSelf(
+      base::scoped_nsobject<GoogleLandingViewController> strongSelf(
           [weakSelf retain]);
       if (!strongSelf)
         return;
       MostVisitedCell* cell = (MostVisitedCell*)sender.view;
       [[strongSelf dataSource] logMostVisitedClick:index
                                           tileType:cell.tileType];
-      [[strongSelf dataSource] webPageOrderedOpen:url
+      [[strongSelf dispatcher] webPageOrderedOpen:url
                                          referrer:web::Referrer()
                                      inBackground:YES
                                          appendTo:kCurrentTab];
@@ -1154,14 +1159,14 @@
     if (!self.isOffTheRecord) {
       // Open in Incognito Tab.
       action = ^{
-        base::scoped_nsobject<GoogleLandingController> strongSelf(
+        base::scoped_nsobject<GoogleLandingViewController> strongSelf(
             [weakSelf retain]);
         if (!strongSelf)
           return;
         MostVisitedCell* cell = (MostVisitedCell*)sender.view;
         [[strongSelf dataSource] logMostVisitedClick:index
                                             tileType:cell.tileType];
-        [[strongSelf dataSource] webPageOrderedOpen:url
+        [[strongSelf dispatcher] webPageOrderedOpen:url
                                            referrer:web::Referrer()
                                         inIncognito:YES
                                        inBackground:NO
@@ -1177,7 +1182,7 @@
     NSString* title =
         l10n_util::GetNSStringWithFixup(IDS_BOOKMARK_BUBBLE_REMOVE_BOOKMARK);
     action = ^{
-      base::scoped_nsobject<GoogleLandingController> strongSelf(
+      base::scoped_nsobject<GoogleLandingViewController> strongSelf(
           [weakSelf retain]);
       // Early return if the controller has been deallocated.
       if (!strongSelf)
@@ -1200,9 +1205,9 @@
 
   MDCSnackbarMessageAction* action =
       [[[MDCSnackbarMessageAction alloc] init] autorelease];
-  base::WeakNSObject<GoogleLandingController> weakSelf(self);
+  base::WeakNSObject<GoogleLandingViewController> weakSelf(self);
   action.handler = ^{
-    base::scoped_nsobject<GoogleLandingController> strongSelf(
+    base::scoped_nsobject<GoogleLandingViewController> strongSelf(
         [weakSelf retain]);
     if (!strongSelf)
       return;
@@ -1222,7 +1227,7 @@
 }
 
 - (void)onPromoLabelTapped {
-  [self.dataSource cancelOmniboxEdit];
+  [self.dispatcher cancelOmniboxEdit];
   [_promoHeaderView setHidden:YES];
   [self.view setNeedsLayout];
   [self.dataSource promoTapped];
@@ -1319,7 +1324,7 @@
   CGFloat pinnedOffsetY = [self pinnedOffsetY];
   if (_omniboxFocused && scrollView.dragging &&
       scrollView.contentOffset.y < pinnedOffsetY) {
-    [self.dataSource cancelOmniboxEdit];
+    [self.dispatcher cancelOmniboxEdit];
   }
 
   if (IsIPadIdiom()) {
@@ -1408,7 +1413,7 @@
   return [self.dataSource mostVisitedAtIndex:index].url;
 }
 
-#pragma mark - GoogleLandingController (ExposedForTesting) methods.
+#pragma mark - GoogleLandingViewController (ExposedForTesting) methods.
 
 - (BOOL)scrolledToTop {
   return _scrolledToTop;
diff --git a/ios/chrome/browser/ui/ntp/google_landing_controller_unittest.mm b/ios/chrome/browser/ui/ntp/google_landing_view_controller_unittest.mm
similarity index 82%
rename from ios/chrome/browser/ui/ntp/google_landing_controller_unittest.mm
rename to ios/chrome/browser/ui/ntp/google_landing_view_controller_unittest.mm
index f8773537..16f4199 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_controller_unittest.mm
+++ b/ios/chrome/browser/ui/ntp/google_landing_view_controller_unittest.mm
@@ -10,8 +10,8 @@
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
-#import "ios/chrome/browser/ui/ntp/google_landing_controller.h"
 #import "ios/chrome/browser/ui/ntp/google_landing_mediator.h"
+#import "ios/chrome/browser/ui/ntp/google_landing_view_controller.h"
 #include "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
 #include "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/chrome/test/block_cleanup_test.h"
@@ -27,9 +27,9 @@
 
 namespace {
 
-class GoogleLandingControllerTest : public BlockCleanupTest {
+class GoogleLandingViewControllerTest : public BlockCleanupTest {
  public:
-  GoogleLandingControllerTest()
+  GoogleLandingViewControllerTest()
       : ui_thread_(web::WebThread::UI, &message_loop_),
         io_thread_(web::WebThread::IO, &message_loop_) {}
 
@@ -56,15 +56,13 @@
 
     // Set up stub UrlLoader.
     mockUrlLoader_ = [OCMockObject mockForProtocol:@protocol(UrlLoader)];
-    controller_ = [[GoogleLandingController alloc] init];
+    controller_ = [[GoogleLandingViewController alloc] init];
     webStateList_ = base::MakeUnique<WebStateList>(&webStateListDelegate_);
     mediator_ = [[GoogleLandingMediator alloc]
-          initWithConsumer:controller_
-              browserState:chrome_browser_state_.get()
-                    loader:(id<UrlLoader>)mockUrlLoader_
-                   focuser:nil
-        webToolbarDelegate:nil
-              webStateList:webStateList_.get()];
+        initWithConsumer:controller_
+            browserState:chrome_browser_state_.get()
+              dispatcher:nil
+            webStateList:webStateList_.get()];
   };
 
   void TearDown() override { [mediator_ shutdown]; }
@@ -78,10 +76,10 @@
   std::unique_ptr<WebStateList> webStateList_;
   OCMockObject* mockUrlLoader_;
   GoogleLandingMediator* mediator_;
-  GoogleLandingController* controller_;
+  GoogleLandingViewController* controller_;
 };
 
-TEST_F(GoogleLandingControllerTest, TestConstructorDestructor) {
+TEST_F(GoogleLandingViewControllerTest, TestConstructorDestructor) {
   EXPECT_TRUE(controller_);
 }
 
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_bar.h b/ios/chrome/browser/ui/ntp/new_tab_page_bar.h
index 4258681..e0e4fd4 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_bar.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_bar.h
@@ -7,7 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-#import "ios/chrome/browser/ui/ntp/google_landing_controller.h"
+#import "ios/chrome/browser/ui/ntp/google_landing_view_controller.h"
 
 @class NewTabPageBarItem;
 
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.h b/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
index 164f203..b4bc70c 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
@@ -38,7 +38,7 @@
 
 @class BookmarkHomeTabletNTPController;
 @protocol CRWSwipeRecognizerProvider;
-@class GoogleLandingController;
+@class GoogleLandingViewController;
 @protocol NewTabPagePanelProtocol;
 @protocol OmniboxFocuser;
 @class TabModel;
@@ -77,7 +77,7 @@
                               UIScrollViewDelegate> {
  @private
   base::scoped_nsobject<BookmarkHomeTabletNTPController> bookmarkController_;
-  base::scoped_nsobject<GoogleLandingController> googleLandingController_;
+  base::scoped_nsobject<GoogleLandingViewController> googleLandingController_;
   base::scoped_nsprotocol<id<NewTabPagePanelProtocol>> incognitoController_;
   // The currently visible controller, one of the above.
   id<NewTabPagePanelProtocol> currentController_;  // weak
@@ -98,7 +98,8 @@
               colorCache:(NSMutableDictionary*)colorCache
       webToolbarDelegate:(id<WebToolbarDelegate>)webToolbarDelegate
                 tabModel:(TabModel*)tabModel
-    parentViewController:(UIViewController*)parentViewController;
+    parentViewController:(UIViewController*)parentViewController
+              dispatcher:(id)dispatcher;
 
 // Select a panel based on the given |panelType|.
 - (void)selectPanel:(NewTabPage::PanelIdentifier)panelType;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
index 72b1007f..60b9af7 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
@@ -26,8 +26,8 @@
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/ntp/google_landing_controller.h"
 #import "ios/chrome/browser/ui/ntp/google_landing_mediator.h"
+#import "ios/chrome/browser/ui/ntp/google_landing_view_controller.h"
 #import "ios/chrome/browser/ui/ntp/incognito_panel_controller.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_view.h"
@@ -172,6 +172,10 @@
 // is initiated, and when WebController calls -willBeDismissed.
 @property(nonatomic, assign) UIViewController* parentViewController;
 
+// To ease modernizing the NTP a non-descript CommandDispatcher is passed thru
+// to be used by the reuabled NTP panels.
+@property(nonatomic, assign) id dispatcher;
+
 @end
 
 @implementation NewTabPageController
@@ -179,6 +183,7 @@
 @synthesize ntpView = newTabPageView_;
 @synthesize swipeRecognizerProvider = swipeRecognizerProvider_;
 @synthesize parentViewController = parentViewController_;
+@synthesize dispatcher = dispatcher_;
 
 - (id)initWithUrl:(const GURL&)url
                   loader:(id<UrlLoader>)loader
@@ -188,7 +193,8 @@
               colorCache:(NSMutableDictionary*)colorCache
       webToolbarDelegate:(id<WebToolbarDelegate>)webToolbarDelegate
                 tabModel:(TabModel*)tabModel
-    parentViewController:(UIViewController*)parentViewController {
+    parentViewController:(UIViewController*)parentViewController
+              dispatcher:(id)dispatcher {
   self = [super initWithNibName:nil url:url];
   if (self) {
     DCHECK(browserState);
@@ -198,6 +204,7 @@
     loader_ = loader;
     newTabPageObserver_ = ntpObserver;
     parentViewController_ = parentViewController;
+    dispatcher_ = dispatcher;
     focuser_.reset(focuser);
     webToolbarDelegate_.reset(webToolbarDelegate);
     tabModel_.reset([tabModel retain]);
@@ -538,14 +545,14 @@
     [bookmarkController_ setDelegate:self];
   } else if (item.identifier == NewTabPage::kMostVisitedPanel) {
     if (!googleLandingController_) {
-      googleLandingController_.reset([[GoogleLandingController alloc] init]);
+      googleLandingController_.reset(
+          [[GoogleLandingViewController alloc] init]);
+      [googleLandingController_ setDispatcher:self.dispatcher];
       googleLandingMediator_.reset([[GoogleLandingMediator alloc]
-            initWithConsumer:googleLandingController_
-                browserState:browserState_
-                      loader:loader_
-                     focuser:focuser_
-          webToolbarDelegate:webToolbarDelegate_
-                webStateList:[tabModel_ webStateList]]);
+          initWithConsumer:googleLandingController_
+              browserState:browserState_
+                dispatcher:self.dispatcher
+              webStateList:[tabModel_ webStateList]]);
       [googleLandingController_ setDataSource:googleLandingMediator_];
     }
     panelController = googleLandingController_;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller_unittest.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller_unittest.mm
index 0c54bfe5..2314916 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller_unittest.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller_unittest.mm
@@ -102,7 +102,8 @@
                                        colorCache:nil
                                webToolbarDelegate:nil
                                          tabModel:tabModel_
-                             parentViewController:parentViewController_];
+                             parentViewController:parentViewController_
+                                       dispatcher:nil];
 
     incognitoController_ = [[NewTabPageController alloc]
                  initWithUrl:url
@@ -114,7 +115,8 @@
                   colorCache:nil
           webToolbarDelegate:nil
                     tabModel:nil
-        parentViewController:parentViewController_];
+        parentViewController:parentViewController_
+                  dispatcher:nil];
   };
 
   void TearDown() override {
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_egtest.mm b/ios/chrome/browser/ui/ntp/new_tab_page_egtest.mm
index 4cb8d2d..5076e4f 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_egtest.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_egtest.mm
@@ -24,12 +24,12 @@
 #endif
 
 @implementation NewTabPageController (ExposedForTesting)
-- (GoogleLandingController*)googleLandingController {
+- (GoogleLandingViewController*)googleLandingController {
   return googleLandingController_;
 }
 @end
 
-@interface GoogleLandingController (ExposedForTesting)
+@interface GoogleLandingViewController (ExposedForTesting)
 - (BOOL)scrolledToTop;
 - (BOOL)animateHeader;
 @end
@@ -88,15 +88,16 @@
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
   NewTabPageController* ntp_controller =
       chrome_test_util::GetCurrentNewTabPageController();
-  GoogleLandingController* google_landing_controller =
+  GoogleLandingViewController* google_landing_view_controller =
       [ntp_controller googleLandingController];
   [[GREYCondition
       conditionWithName:@"Wait for end of animation."
                   block:^BOOL {
-                    return ![google_landing_controller animateHeader];
+                    return ![google_landing_view_controller animateHeader];
                   }] waitWithTimeout:testing::kWaitForUIElementTimeout];
-  GREYAssertTrue([google_landing_controller scrolledToTop] == scrolledToTop,
-                 @"scrolledToTop_ does not match expected value");
+  GREYAssertTrue(
+      [google_landing_view_controller scrolledToTop] == scrolledToTop,
+      @"scrolledToTop_ does not match expected value");
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.h b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.h
index 911b7b08..64ea947 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.h
@@ -21,7 +21,8 @@
 
 // Creates a NewTabPageToolbarController using the given |toolbarDelegate|,
 // |focuser| and |readingListModel|, and adds the toolbar view to self.
-- (void)addToolbarWithDataSource:(id<GoogleLandingDataSource>)dataSource;
+- (void)addToolbarWithDataSource:(id<GoogleLandingDataSource>)dataSource
+                      dispatcher:(id)dispatcher;
 
 // Changes the frame of |searchField| based on its |initialFrame| and the scroll
 // view's y |offset|. Also adjust the alpha values for |_searchBoxBorder| and
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
index 4fe3ce9e..805d5a1 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
@@ -64,12 +64,13 @@
   [self addSubview:[_toolbarController view]];
 }
 
-- (void)addToolbarWithDataSource:(id<GoogleLandingDataSource>)dataSource {
+- (void)addToolbarWithDataSource:(id<GoogleLandingDataSource>)dataSource
+                      dispatcher:(id)dispatcher {
   DCHECK(!_toolbarController);
   DCHECK(dataSource);
 
-  _toolbarController.reset([[NewTabPageToolbarController alloc]
-      initWithToolbarDataSource:dataSource]);
+  _toolbarController.reset([[NewTabPageToolbarController alloc] init]);
+  [_toolbarController setDispatcher:dispatcher];
   _toolbarController.get().readingListModel = [dataSource readingListModel];
 
   UIView* toolbarView = [_toolbarController view];
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.h b/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.h
index 0f497a7..6cb49b3 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.h
@@ -8,6 +8,9 @@
 #import "ios/chrome/browser/ui/toolbar/toolbar_controller.h"
 
 @protocol GoogleLandingDataSource;
+@protocol UrlLoader;
+@protocol OmniboxFocuser;
+@protocol WebToolbarDelegate;
 
 // New tab page specific toolbar. The background view is hidden and the
 // navigation buttons are also hidden if there is no forward history. Does not
@@ -17,8 +20,10 @@
 
 // Designated initializer. The underlying ToolbarController is initialized with
 // ToolbarControllerStyleLightMode.
-- (instancetype)initWithToolbarDataSource:
-    (id<GoogleLandingDataSource>)dataSource;
+- (instancetype)init;
+
+@property(nonatomic, assign) id<UrlLoader, OmniboxFocuser, WebToolbarDelegate>
+    dispatcher;
 
 // |YES| if the toolbar can show the forward arrow.
 - (void)setCanGoForward:(BOOL)canGoForward;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.mm
index bb5bf3c..57c3eb3 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.mm
@@ -16,6 +16,7 @@
 #import "ios/chrome/browser/ui/ntp/google_landing_data_source.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
 #include "ios/chrome/browser/ui/toolbar/toolbar_resource_macros.h"
+#import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -43,8 +44,6 @@
   base::scoped_nsobject<UIButton> _backButton;
   base::scoped_nsobject<UIButton> _forwardButton;
   base::scoped_nsobject<UIButton> _omniboxFocuser;
-
-  base::WeakNSProtocol<id<GoogleLandingDataSource>> _dataSource;
 }
 
 // |YES| if the google landing toolbar can show the forward arrow.
@@ -57,14 +56,13 @@
 
 @implementation NewTabPageToolbarController
 
+@synthesize dispatcher = _dispatcher;
 @synthesize canGoForward = _canGoForward;
 @synthesize canGoBack = _canGoBack;
 
-- (instancetype)initWithToolbarDataSource:
-    (id<GoogleLandingDataSource>)dataSource {
+- (instancetype)init {
   self = [super initWithStyle:ToolbarControllerStyleLightMode];
   if (self) {
-    _dataSource.reset(dataSource);
     [self.backgroundView setHidden:YES];
 
     CGFloat boundingWidth = self.view.bounds.size.width;
@@ -217,11 +215,11 @@
 }
 
 - (void)focusOmnibox:(id)sender {
-  [_dataSource focusFakebox];
+  [self.dispatcher focusFakebox];
 }
 
 - (IBAction)stackButtonTouchDown:(id)sender {
-  [_dataSource prepareToEnterTabSwitcher:self];
+  [self.dispatcher prepareToEnterTabSwitcher:self];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h
index 62d66196..2b06653 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h
@@ -46,9 +46,6 @@
 - (IBAction)locationBarBeganEdit:(id)sender;
 // Called when the stack view controller is about to be shown.
 - (IBAction)prepareToEnterTabSwitcher:(id)sender;
-// Loads the text entered in the location bar as javascript.
-// Note: The JavaScript is executed asynchronously.
-- (void)loadJavaScriptFromLocationBar:(NSString*)script;
 // Returns the WebState.
 - (web::WebState*)currentWebState;
 // Called when the toolbar height changes. Other elements, such as the web view,
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index 645a9651e..59bbe17 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -1249,7 +1249,7 @@
     // Evaluate the URL as JavaScript if its scheme is JavaScript.
     NSString* jsToEval = [base::SysUTF8ToNSString(url.GetContent())
         stringByRemovingPercentEncoding];
-    [self.delegate loadJavaScriptFromLocationBar:jsToEval];
+    [self.urlLoader loadJavaScriptFromLocationBar:jsToEval];
   } else {
     // When opening a URL, force the omnibox to resign first responder.  This
     // will also close the popup.
diff --git a/ios/clean/chrome/browser/ui/ntp/ntp_home_coordinator.mm b/ios/clean/chrome/browser/ui/ntp/ntp_home_coordinator.mm
index dd8932a..92484b3 100644
--- a/ios/clean/chrome/browser/ui/ntp/ntp_home_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/ntp/ntp_home_coordinator.mm
@@ -4,10 +4,11 @@
 
 #import "ios/clean/chrome/browser/ui/ntp/ntp_home_coordinator.h"
 
-#import "ios/chrome/browser/ui/ntp/google_landing_controller.h"
 #import "ios/chrome/browser/ui/ntp/google_landing_mediator.h"
+#import "ios/chrome/browser/ui/ntp/google_landing_view_controller.h"
 #import "ios/clean/chrome/browser/ui/ntp/ntp_home_mediator.h"
 #import "ios/shared/chrome/browser/ui/browser_list/browser.h"
+#import "ios/shared/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -17,7 +18,7 @@
 @interface NTPHomeCoordinator ()
 @property(nonatomic, strong) NTPHomeMediator* mediator;
 @property(nonatomic, strong) GoogleLandingMediator* googleLandingMediator;
-@property(nonatomic, strong) GoogleLandingController* viewController;
+@property(nonatomic, strong) GoogleLandingViewController* viewController;
 @end
 
 @implementation NTPHomeCoordinator
@@ -29,14 +30,20 @@
   // PLACEHOLDER: self.mediator and self.oldMediator should be merged together.
   self.mediator = [[NTPHomeMediator alloc] init];
   self.mediator.dispatcher = static_cast<id>(self.browser->dispatcher());
-  self.viewController = [[GoogleLandingController alloc] init];
+
+  // PLACEHOLDER: These will go elsewhere.
+  [self.browser->dispatcher() startDispatchingToTarget:self.mediator
+                                           forProtocol:@protocol(UrlLoader)];
+  [self.browser->dispatcher()
+      startDispatchingToTarget:self.mediator
+                   forProtocol:@protocol(OmniboxFocuser)];
+  self.viewController = [[GoogleLandingViewController alloc] init];
+  self.viewController.dispatcher = static_cast<id>(self.browser->dispatcher());
   self.googleLandingMediator = [[GoogleLandingMediator alloc]
-        initWithConsumer:self.viewController
-            browserState:self.browser->browser_state()
-                  loader:self.mediator
-                 focuser:self.mediator
-      webToolbarDelegate:nil
-            webStateList:&self.browser->web_state_list()];
+      initWithConsumer:self.viewController
+          browserState:self.browser->browser_state()
+            dispatcher:static_cast<id>(self.browser->dispatcher())
+          webStateList:&self.browser->web_state_list()];
   self.viewController.dataSource = self.googleLandingMediator;
   [super start];
 }
@@ -44,6 +51,10 @@
 - (void)stop {
   [super stop];
   [self.googleLandingMediator shutdown];
+
+  [self.browser->dispatcher() stopDispatchingForProtocol:@protocol(UrlLoader)];
+  [self.browser->dispatcher()
+      stopDispatchingForProtocol:@protocol(OmniboxFocuser)];
 }
 
 @end
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
index 80533181..db36c0f 100644
--- a/ipc/ipc_message_utils.cc
+++ b/ipc/ipc_message_utils.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/shared_memory_handle.h"
 #include "base/strings/nullable_string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -27,10 +28,6 @@
 #include "ipc/ipc_platform_file_attachment_posix.h"
 #endif
 
-#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
-#include "base/memory/shared_memory_handle.h"
-#endif  // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
-
 #if defined(OS_MACOSX) && !defined(OS_IOS)
 #include "ipc/mach_port_mac.h"
 #endif
@@ -647,7 +644,6 @@
   if (!ReadParam(m, iter, &valid))
     return false;
 
-  // TODO(morrita): Seems like this should return false.
   if (!valid)
     return true;
 
@@ -781,6 +777,69 @@
   l->append(" needs brokering: ");
   LogParam(p.NeedsBrokering(), l);
 }
+#elif defined(OS_POSIX)
+void ParamTraits<base::SharedMemoryHandle>::GetSize(base::PickleSizer* sizer,
+                                                    const param_type& p) {
+  GetParamSize(sizer, p.IsValid());
+  if (p.IsValid())
+    sizer->AddAttachment();
+}
+
+void ParamTraits<base::SharedMemoryHandle>::Write(base::Pickle* m,
+                                                  const param_type& p) {
+  const bool valid = p.IsValid();
+  WriteParam(m, valid);
+
+  if (!valid)
+    return;
+
+  if (p.OwnershipPassesToIPC()) {
+    if (!m->WriteAttachment(new internal::PlatformFileAttachment(
+            base::ScopedFD(p.GetHandle()))))
+      NOTREACHED();
+  } else {
+    if (!m->WriteAttachment(
+            new internal::PlatformFileAttachment(p.GetHandle())))
+      NOTREACHED();
+  }
+}
+
+bool ParamTraits<base::SharedMemoryHandle>::Read(const base::Pickle* m,
+                                                 base::PickleIterator* iter,
+                                                 param_type* r) {
+  *r = base::SharedMemoryHandle();
+
+  bool valid;
+  if (!ReadParam(m, iter, &valid))
+    return false;
+
+  if (!valid)
+    return true;
+
+  scoped_refptr<base::Pickle::Attachment> attachment;
+  if (!m->ReadAttachment(iter, &attachment))
+    return false;
+
+  if (static_cast<MessageAttachment*>(attachment.get())->GetType() !=
+      MessageAttachment::Type::PLATFORM_FILE) {
+    return false;
+  }
+
+  *r = base::SharedMemoryHandle(base::FileDescriptor(
+      static_cast<internal::PlatformFileAttachment*>(attachment.get())
+          ->TakePlatformFile(),
+      true));
+  return true;
+}
+
+void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p,
+                                                std::string* l) {
+  if (p.OwnershipPassesToIPC()) {
+    l->append(base::StringPrintf("FD(%d auto-close)", p.GetHandle()));
+  } else {
+    l->append(base::StringPrintf("FD(%d)", p.GetHandle()));
+  }
+}
 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 
 void ParamTraits<base::FilePath>::GetSize(base::PickleSizer* sizer,
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index 5f036068..847a617 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -37,15 +37,12 @@
 class FilePath;
 class ListValue;
 class NullableString16;
+class SharedMemoryHandle;
 class Time;
 class TimeDelta;
 class TimeTicks;
 class UnguessableToken;
 struct FileDescriptor;
-
-#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
-class SharedMemoryHandle;
-#endif  // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
 }
 
 namespace IPC {
@@ -585,7 +582,6 @@
 };
 #endif  // defined(OS_POSIX)
 
-#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
 template <>
 struct IPC_EXPORT ParamTraits<base::SharedMemoryHandle> {
   typedef base::SharedMemoryHandle param_type;
@@ -596,7 +592,6 @@
                    param_type* r);
   static void Log(const param_type& p, std::string* l);
 };
-#endif  // (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
 
 template <>
 struct IPC_EXPORT ParamTraits<base::FilePath> {
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 5148d00..500842c5 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -712,13 +712,13 @@
 
 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
   DCHECK_EQ(storage_type_, STORAGE_SHMEM);
-  DCHECK(shared_memory_handle_ != base::SharedMemory::NULLHandle());
+  DCHECK(shared_memory_handle_.IsValid());
   return shared_memory_handle_;
 }
 
 size_t VideoFrame::shared_memory_offset() const {
   DCHECK_EQ(storage_type_, STORAGE_SHMEM);
-  DCHECK(shared_memory_handle_ != base::SharedMemory::NULLHandle());
+  DCHECK(shared_memory_handle_.IsValid());
   return shared_memory_offset_;
 }
 
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn
index a48ceee7..e220cba7 100644
--- a/media/capture/BUILD.gn
+++ b/media/capture/BUILD.gn
@@ -76,6 +76,8 @@
     "video/mac/video_capture_device_mac.h",
     "video/mac/video_capture_device_mac.mm",
     "video/scoped_result_callback.h",
+    "video/shared_memory_buffer_handle.cc",
+    "video/shared_memory_buffer_handle.h",
     "video/shared_memory_buffer_tracker.cc",
     "video/shared_memory_buffer_tracker.h",
     "video/video_capture_buffer_handle.h",
diff --git a/media/capture/video/fake_video_capture_device_unittest.cc b/media/capture/video/fake_video_capture_device_unittest.cc
index 927845c..2af74e7a 100644
--- a/media/capture/video/fake_video_capture_device_unittest.cc
+++ b/media/capture/video/fake_video_capture_device_unittest.cc
@@ -40,8 +40,8 @@
       : mapped_size_(mapped_size), data_(data) {}
 
   size_t mapped_size() const override { return mapped_size_; }
-  uint8_t* data() override { return data_; }
-  const uint8_t* data() const override { return data_; }
+  uint8_t* data() const override { return data_; }
+  const uint8_t* const_data() const override { return data_; }
 
  private:
   const size_t mapped_size_;
diff --git a/media/capture/video/shared_memory_buffer_handle.cc b/media/capture/video/shared_memory_buffer_handle.cc
new file mode 100644
index 0000000..8814697
--- /dev/null
+++ b/media/capture/video/shared_memory_buffer_handle.cc
@@ -0,0 +1,31 @@
+// 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 "media/capture/video/shared_memory_buffer_handle.h"
+
+#include "base/memory/ptr_util.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace media {
+
+SharedMemoryBufferHandle::SharedMemoryBufferHandle(
+    base::SharedMemory* shared_memory,
+    size_t mapped_size)
+    : shared_memory_(shared_memory), mapped_size_(mapped_size) {}
+
+SharedMemoryBufferHandle::~SharedMemoryBufferHandle() = default;
+
+size_t SharedMemoryBufferHandle::mapped_size() const {
+  return mapped_size_;
+}
+
+uint8_t* SharedMemoryBufferHandle::data() const {
+  return static_cast<uint8_t*>(shared_memory_->memory());
+}
+
+const uint8_t* SharedMemoryBufferHandle::const_data() const {
+  return static_cast<const uint8_t*>(shared_memory_->memory());
+}
+
+}  // namespace media
diff --git a/media/capture/video/shared_memory_buffer_handle.h b/media/capture/video/shared_memory_buffer_handle.h
new file mode 100644
index 0000000..839457e
--- /dev/null
+++ b/media/capture/video/shared_memory_buffer_handle.h
@@ -0,0 +1,37 @@
+// 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 MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_HANDLE_H_
+#define MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_HANDLE_H_
+
+#include "media/capture/capture_export.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
+
+namespace media {
+
+// Provides access to memory-mapped shared memory without participating in the
+// lifetime management of the memory. Instances are typically handed out by
+// an instance of VideoCaptureDevice::Client as part of a
+// VideoCaptureDevice::Client::Buffer, which contains a separate
+// |access_permission| that guarantees that the memory stays alive. The buffers
+// are typically managed by an instance of VideoCaptureBufferPool.
+class CAPTURE_EXPORT SharedMemoryBufferHandle
+    : public VideoCaptureBufferHandle {
+ public:
+  explicit SharedMemoryBufferHandle(base::SharedMemory* shared_memory,
+                                    size_t mapped_size);
+  ~SharedMemoryBufferHandle() override;
+
+  size_t mapped_size() const override;
+  uint8_t* data() const override;
+  const uint8_t* const_data() const override;
+
+ private:
+  base::SharedMemory* const shared_memory_;
+  const size_t mapped_size_;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_HANDLE_H_
diff --git a/media/capture/video/shared_memory_buffer_tracker.cc b/media/capture/video/shared_memory_buffer_tracker.cc
index dfdae676..c64ed384 100644
--- a/media/capture/video/shared_memory_buffer_tracker.cc
+++ b/media/capture/video/shared_memory_buffer_tracker.cc
@@ -5,6 +5,7 @@
 #include "media/capture/video/shared_memory_buffer_tracker.h"
 
 #include "base/memory/ptr_util.h"
+#include "media/capture/video/shared_memory_buffer_handle.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 
 namespace media {
@@ -31,7 +32,8 @@
 
 std::unique_ptr<VideoCaptureBufferHandle>
 SharedMemoryBufferTracker::GetMemoryMappedAccess() {
-  return base::MakeUnique<SharedMemoryBufferHandle>(this);
+  return base::MakeUnique<SharedMemoryBufferHandle>(&shared_memory_,
+                                                    mapped_size_);
 }
 
 mojo::ScopedSharedBufferHandle
@@ -46,22 +48,4 @@
   return shared_memory_.handle();
 }
 
-SharedMemoryBufferHandle::SharedMemoryBufferHandle(
-    SharedMemoryBufferTracker* tracker)
-    : tracker_(tracker) {}
-
-SharedMemoryBufferHandle::~SharedMemoryBufferHandle() = default;
-
-size_t SharedMemoryBufferHandle::mapped_size() const {
-  return tracker_->mapped_size_;
-}
-
-uint8_t* SharedMemoryBufferHandle::data() {
-  return static_cast<uint8_t*>(tracker_->shared_memory_.memory());
-}
-
-const uint8_t* SharedMemoryBufferHandle::data() const {
-  return static_cast<const uint8_t*>(tracker_->shared_memory_.memory());
-}
-
 }  // namespace media
diff --git a/media/capture/video/shared_memory_buffer_tracker.h b/media/capture/video/shared_memory_buffer_tracker.h
index bbca851..1d107272 100644
--- a/media/capture/video/shared_memory_buffer_tracker.h
+++ b/media/capture/video/shared_memory_buffer_tracker.h
@@ -5,12 +5,11 @@
 #ifndef MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_TRACKER_H_
 #define MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_TRACKER_H_
 
+#include "media/capture/video/shared_memory_buffer_handle.h"
 #include "media/capture/video/video_capture_buffer_tracker.h"
 
 namespace media {
 
-class SharedMemoryBufferHandle;
-
 // Tracker specifics for SharedMemory.
 class SharedMemoryBufferTracker final : public VideoCaptureBufferTracker {
  public:
@@ -33,24 +32,6 @@
   size_t mapped_size_;
 };
 
-// A simple proxy that implements the BufferHandle interface, providing
-// accessors to SharedMemTracker's memory and properties.
-class SharedMemoryBufferHandle : public VideoCaptureBufferHandle {
- public:
-  // |tracker| must outlive SimpleBufferHandle. This is ensured since a
-  // tracker is pinned until ownership of this SimpleBufferHandle is returned
-  // to VideoCaptureBufferPool.
-  explicit SharedMemoryBufferHandle(SharedMemoryBufferTracker* tracker);
-  ~SharedMemoryBufferHandle() override;
-
-  size_t mapped_size() const override;
-  uint8_t* data() override;
-  const uint8_t* data() const override;
-
- private:
-  SharedMemoryBufferTracker* const tracker_;
-};
-
 }  // namespace media
 
 #endif  // MEDIA_CAPTURE_VIDEO_SHARED_MEMORY_BUFFER_TRACKER_H_
diff --git a/media/capture/video/video_capture_buffer_handle.h b/media/capture/video/video_capture_buffer_handle.h
index 5dd15ebd..657ebc92 100644
--- a/media/capture/video/video_capture_buffer_handle.h
+++ b/media/capture/video/video_capture_buffer_handle.h
@@ -18,8 +18,8 @@
  public:
   virtual ~VideoCaptureBufferHandle() {}
   virtual size_t mapped_size() const = 0;
-  virtual uint8_t* data() = 0;
-  virtual const uint8_t* data() const = 0;
+  virtual uint8_t* data() const = 0;
+  virtual const uint8_t* const_data() const = 0;
 };
 
 }  // namespace media
diff --git a/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.cc b/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.cc
index ec2a433..70ab1306 100644
--- a/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.cc
+++ b/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.cc
@@ -178,9 +178,8 @@
   if (!base::SharedMemory::IsHandleValid(output_handle)) {
     DLOG(ERROR) << "Failed to duplicate handle of VideoFrame";
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
-    if (input_handle.auto_close) {
-      // Defer closing task to the ScopedFD.
-      base::ScopedFD(input_handle.fd);
+    if (input_handle.OwnershipPassesToIPC()) {
+      input_handle.Close();
     }
 #else
 // TODO(kcwu) fix the handle leak after crbug.com/493414 resolved.
diff --git a/mojo/edk/embedder/platform_shared_buffer.cc b/mojo/edk/embedder/platform_shared_buffer.cc
index 623e6539..514cbeb 100644
--- a/mojo/edk/embedder/platform_shared_buffer.cc
+++ b/mojo/edk/embedder/platform_shared_buffer.cc
@@ -29,12 +29,10 @@
 // Takes ownership of |memory_handle|.
 ScopedPlatformHandle SharedMemoryToPlatformHandle(
     base::SharedMemoryHandle memory_handle) {
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
-  return ScopedPlatformHandle(PlatformHandle(memory_handle.fd));
-#elif defined(OS_WIN)
-  return ScopedPlatformHandle(PlatformHandle(memory_handle.GetHandle()));
-#else
+#if defined(OS_MACOSX) && !defined(OS_IOS)
   return ScopedPlatformHandle(PlatformHandle(memory_handle.GetMemoryObject()));
+#else
+  return ScopedPlatformHandle(PlatformHandle(memory_handle.GetHandle()));
 #endif
 }
 
@@ -148,9 +146,9 @@
   }
 
   // TODO(crbug.com/706689): Remove this when the bug is sorted out.
-  CHECK(handle != base::SharedMemory::NULLHandle());
+  CHECK(handle.IsValid());
 
-  if (handle == base::SharedMemory::NULLHandle())
+  if (!handle.IsValid())
     return nullptr;
 
   std::unique_ptr<PlatformSharedBufferMapping> mapping(
@@ -168,7 +166,7 @@
     base::AutoLock locker(lock_);
     handle = base::SharedMemory::DuplicateHandle(shared_memory_->handle());
   }
-  if (handle == base::SharedMemory::NULLHandle())
+  if (!handle.IsValid())
     return ScopedPlatformHandle();
 
   return SharedMemoryToPlatformHandle(handle);
@@ -200,7 +198,7 @@
     base::AutoLock locker(lock_);
     base::SharedMemoryHandle handle;
     handle = base::SharedMemory::DuplicateHandle(ro_shared_memory_->handle());
-    if (handle == base::SharedMemory::NULLHandle())
+    if (!handle.IsValid())
       return nullptr;
     return CreateFromSharedMemoryHandle(num_bytes_, true, handle);
   }
@@ -212,8 +210,8 @@
     success = shared_memory_->ShareReadOnlyToProcess(
         base::GetCurrentProcessHandle(), &handle);
   }
-  if (!success || handle == base::SharedMemory::NULLHandle())
-      return nullptr;
+  if (!success || !handle.IsValid())
+    return nullptr;
 
   return CreateFromSharedMemoryHandle(num_bytes_, true, handle);
 }
@@ -248,7 +246,8 @@
   handle = base::SharedMemoryHandle(platform_handle.release().port, num_bytes_,
                                     base::GetCurrentProcId());
 #else
-  base::SharedMemoryHandle handle(platform_handle.release().handle, false);
+  base::SharedMemoryHandle handle(
+      base::FileDescriptor(platform_handle.release().handle, false));
 #endif
 
   shared_memory_.reset(new base::SharedMemory(handle, read_only_));
@@ -269,9 +268,10 @@
   base::SharedMemoryHandle ro_handle(ro_platform_handle.release().handle,
                                      base::GetCurrentProcId());
 #else  // defined(OS_WIN)
-  base::SharedMemoryHandle handle(rw_platform_handle.release().handle, false);
-  base::SharedMemoryHandle ro_handle(ro_platform_handle.release().handle,
-                                     false);
+  base::SharedMemoryHandle handle(
+      base::FileDescriptor(rw_platform_handle.release().handle, false));
+  base::SharedMemoryHandle ro_handle(
+      base::FileDescriptor(ro_platform_handle.release().handle, false));
 #endif  // defined(OS_WIN)
 
   DCHECK(!shared_memory_);
diff --git a/mojo/edk/system/platform_wrapper_unittest.cc b/mojo/edk/system/platform_wrapper_unittest.cc
index f29d62b..a6d4be3 100644
--- a/mojo/edk/system/platform_wrapper_unittest.cc
+++ b/mojo/edk/system/platform_wrapper_unittest.cc
@@ -125,7 +125,7 @@
 #if defined(OS_MACOSX) && !defined(OS_IOS)
     os_buffer.value = static_cast<uint64_t>(memory_handle.GetMemoryObject());
 #elif defined(OS_POSIX)
-    os_buffer.value = static_cast<uint64_t>(memory_handle.fd);
+    os_buffer.value = static_cast<uint64_t>(memory_handle.GetHandle());
 #elif defined(OS_WIN)
     os_buffer.value = reinterpret_cast<uint64_t>(memory_handle.GetHandle());
 #endif
@@ -168,8 +168,8 @@
       base::GetCurrentProcId());
 #elif defined(OS_POSIX)
   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR, os_buffer.type);
-  base::SharedMemoryHandle memory_handle(static_cast<int>(os_buffer.value),
-                                         false);
+  base::SharedMemoryHandle memory_handle(
+      base::FileDescriptor(static_cast<int>(os_buffer.value), false));
 #elif defined(OS_WIN)
   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE, os_buffer.type);
   base::SharedMemoryHandle memory_handle(
diff --git a/mojo/public/cpp/system/platform_handle.cc b/mojo/public/cpp/system/platform_handle.cc
index 42e4abac..63c8c14 100644
--- a/mojo/public/cpp/system/platform_handle.cc
+++ b/mojo/public/cpp/system/platform_handle.cc
@@ -66,22 +66,15 @@
     const base::SharedMemoryHandle& memory_handle,
     size_t size,
     bool read_only) {
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
-  if (memory_handle.fd == base::kInvalidPlatformFile)
-    return ScopedSharedBufferHandle();
-#else
   if (!memory_handle.IsValid())
     return ScopedSharedBufferHandle();
-#endif
   MojoPlatformHandle platform_handle;
   platform_handle.struct_size = sizeof(MojoPlatformHandle);
   platform_handle.type = kPlatformSharedBufferHandleType;
 #if defined(OS_MACOSX) && !defined(OS_IOS)
   platform_handle.value =
       static_cast<uint64_t>(memory_handle.GetMemoryObject());
-#elif defined(OS_POSIX)
-  platform_handle.value = PlatformHandleValueFromPlatformFile(memory_handle.fd);
-#elif defined(OS_WIN)
+#else
   platform_handle.value =
       PlatformHandleValueFromPlatformFile(memory_handle.GetHandle());
 #endif
@@ -129,7 +122,7 @@
 #elif defined(OS_POSIX)
   CHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR);
   *memory_handle = base::SharedMemoryHandle(
-      static_cast<int>(platform_handle.value), false);
+      base::FileDescriptor(static_cast<int>(platform_handle.value), false));
 #elif defined(OS_WIN)
   CHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE);
   *memory_handle = base::SharedMemoryHandle(
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 66ba36e9..769184d 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1428,6 +1428,8 @@
       "reporting/reporting_delivery_agent.h",
       "reporting/reporting_endpoint_manager.cc",
       "reporting/reporting_endpoint_manager.h",
+      "reporting/reporting_feature.cc",
+      "reporting/reporting_feature.h",
       "reporting/reporting_garbage_collector.cc",
       "reporting/reporting_garbage_collector.h",
       "reporting/reporting_header_parser.cc",
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index fbdf5cef..2db34f1 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1801,6 +1801,7 @@
   if (allowed_encodings.find("*") != allowed_encodings.end())
     return true;
 
+  bool result = true;
   for (auto const& encoding : used_encodings) {
     SourceStream::SourceType source_type =
         FilterSourceStream::ParseEncodingType(encoding);
@@ -1808,11 +1809,21 @@
     if (source_type == SourceStream::TYPE_UNKNOWN)
       continue;
     if (allowed_encodings.find(encoding) == allowed_encodings.end()) {
-      FilterSourceStream::ReportContentDecodingFailed(source_type);
-      return false;
+      FilterSourceStream::ReportContentDecodingFailed(
+          SourceStream::TYPE_REJECTED);
+      result = false;
+      break;
     }
   }
-  return true;
+
+  // Temporary workaround for http://crbug.com/714514
+  if (headers->IsRedirect(nullptr)) {
+    UMA_HISTOGRAM_BOOLEAN("Net.RedirectWithUnadvertisedContentEncoding",
+                          !result);
+    return true;
+  }
+
+  return result;
 }
 
 }  // namespace net
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 967939cf..e3c33c2 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -16679,6 +16679,7 @@
 void CheckContentEncodingMatching(SpdySessionDependencies* session_deps,
                                   const std::string& accept_encoding,
                                   const std::string& content_encoding,
+                                  const std::string& location,
                                   bool should_match) {
   HttpRequestInfo request;
   request.method = "GET";
@@ -16697,9 +16698,19 @@
       MockWrite(accept_encoding.data()), MockWrite("\r\n\r\n"),
   };
 
+  std::string response_code = "200 OK";
+  std::string extra;
+  if (!location.empty()) {
+    response_code = "301 Redirect\r\nLocation: ";
+    response_code.append(location);
+  }
+
   MockRead data_reads[] = {
-      MockRead("HTTP/1.0 200 OK\r\n"),   MockRead("Content-Encoding: "),
-      MockRead(content_encoding.data()), MockRead("\r\n\r\n"),
+      MockRead("HTTP/1.0 "),
+      MockRead(response_code.data()),
+      MockRead("\r\nContent-Encoding: "),
+      MockRead(content_encoding.data()),
+      MockRead("\r\n\r\n"),
       MockRead(SYNCHRONOUS, OK),
   };
   StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes,
@@ -16720,16 +16731,22 @@
 }
 
 TEST_F(HttpNetworkTransactionTest, MatchContentEncoding1) {
-  CheckContentEncodingMatching(&session_deps_, "gzip,sdch", "br", false);
+  CheckContentEncodingMatching(&session_deps_, "gzip,sdch", "br", "", false);
 }
 
 TEST_F(HttpNetworkTransactionTest, MatchContentEncoding2) {
-  CheckContentEncodingMatching(&session_deps_, "identity;q=1, *;q=0", "", true);
+  CheckContentEncodingMatching(&session_deps_, "identity;q=1, *;q=0", "", "",
+                               true);
 }
 
 TEST_F(HttpNetworkTransactionTest, MatchContentEncoding3) {
   CheckContentEncodingMatching(&session_deps_, "identity;q=1, *;q=0", "gzip",
-                               false);
+                               "", false);
+}
+
+TEST_F(HttpNetworkTransactionTest, MatchContentEncoding4) {
+  CheckContentEncodingMatching(&session_deps_, "identity;q=1, *;q=0", "gzip",
+                               "www.foo.com/other", true);
 }
 
 }  // namespace net
diff --git a/net/reporting/reporting_feature.cc b/net/reporting/reporting_feature.cc
new file mode 100644
index 0000000..9f4e28e
--- /dev/null
+++ b/net/reporting/reporting_feature.cc
@@ -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.
+
+#include "net/reporting/reporting_feature.h"
+
+namespace features {
+
+const base::Feature kReporting{"Reporting", base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace features
diff --git a/net/reporting/reporting_feature.h b/net/reporting/reporting_feature.h
new file mode 100644
index 0000000..eae3cfb
--- /dev/null
+++ b/net/reporting/reporting_feature.h
@@ -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.
+
+#ifndef NET_REPORTING_REPORTING_FEATURE_H_
+#define NET_REPORTING_REPORTING_FEATURE_H_
+
+#include "base/feature_list.h"
+#include "net/base/net_export.h"
+
+namespace features {
+
+extern const base::Feature NET_EXPORT kReporting;
+
+}  // namespace features
+
+#endif
diff --git a/net/reporting/reporting_garbage_collector.cc b/net/reporting/reporting_garbage_collector.cc
index b6486b4..a8cabe1 100644
--- a/net/reporting/reporting_garbage_collector.cc
+++ b/net/reporting/reporting_garbage_collector.cc
@@ -40,17 +40,15 @@
 
   // ReportingObserver implementation:
   void OnCacheUpdated() override {
-    if (!timer_->IsRunning())
-      StartTimer();
-  }
+    if (timer_->IsRunning())
+      return;
 
- private:
-  void StartTimer() {
     timer_->Start(FROM_HERE, context_->policy().garbage_collection_interval,
                   base::Bind(&ReportingGarbageCollectorImpl::CollectGarbage,
                              base::Unretained(this)));
   }
 
+ private:
   void CollectGarbage() {
     base::TimeTicks now = context_->tick_clock()->NowTicks();
     const ReportingPolicy& policy = context_->policy();
diff --git a/net/reporting/reporting_persister.h b/net/reporting/reporting_persister.h
index c6b52f87..40414f0 100644
--- a/net/reporting/reporting_persister.h
+++ b/net/reporting/reporting_persister.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/callback.h"
 #include "net/base/net_export.h"
 
 namespace net {
diff --git a/net/reporting/reporting_persister_unittest.cc b/net/reporting/reporting_persister_unittest.cc
index c0bda9f..1ac54c0 100644
--- a/net/reporting/reporting_persister_unittest.cc
+++ b/net/reporting/reporting_persister_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/time/time.h"
 #include "base/timer/mock_timer.h"
 #include "base/values.h"
+#include "net/base/test_completion_callback.h"
 #include "net/reporting/reporting_cache.h"
 #include "net/reporting/reporting_client.h"
 #include "net/reporting/reporting_policy.h"
@@ -50,11 +51,13 @@
                      kGroup_,
                      tick_clock()->NowTicks() + base::TimeDelta::FromDays(1));
 
-  // TODO: Actually trigger persistence, once it's possible.
+  // TODO: Actually save data, once it's possible.
 
   SimulateRestart(/* delta= */ base::TimeDelta::FromHours(1),
                   /* delta_ticks= */ base::TimeDelta::FromHours(-3));
 
+  // TODO: Actually load data, once it's possible.
+
   std::vector<const ReportingReport*> reports;
   cache()->GetReports(&reports);
   ASSERT_EQ(1u, reports.size());
@@ -76,5 +79,7 @@
             client->expires);
 }
 
+// TODO(juliatuttle): Test asynchronous behavior.
+
 }  // namespace
 }  // namespace net
diff --git a/net/reporting/reporting_service.cc b/net/reporting/reporting_service.cc
index 4dcee9da..0ba05c0 100644
--- a/net/reporting/reporting_service.cc
+++ b/net/reporting/reporting_service.cc
@@ -6,7 +6,7 @@
 
 #include <memory>
 
-#include "base/callback.h"
+#include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/time/tick_clock.h"
@@ -15,6 +15,7 @@
 #include "net/reporting/reporting_cache.h"
 #include "net/reporting/reporting_context.h"
 #include "net/reporting/reporting_header_parser.h"
+#include "net/reporting/reporting_persister.h"
 #include "url/gurl.h"
 
 namespace net {
diff --git a/net/spdy/core/spdy_framer.cc b/net/spdy/core/spdy_framer.cc
index ce6cfef..0dc97c4d 100644
--- a/net/spdy/core/spdy_framer.cc
+++ b/net/spdy/core/spdy_framer.cc
@@ -1674,7 +1674,7 @@
 
 SpdyFramer::SpdyFrameIterator::~SpdyFrameIterator() {}
 
-bool SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) {
+size_t SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) {
   SpdyFrameWithHeaderBlockIR* frame_ir = GetIR();
   if (frame_ir == nullptr) {
     LOG(WARNING) << "frame_ir doesn't exist.";
@@ -1712,7 +1712,9 @@
   if (is_first_frame_) {
     is_first_frame_ = false;
     frame_ir->set_end_headers(!has_next_frame_);
-    return SerializeGivenEncoding(*encoding, output);
+    size_t free_bytes_before = output->BytesFree();
+    bool ok = SerializeGivenEncoding(*encoding, output);
+    return ok ? free_bytes_before - output->BytesFree() : 0;
   } else {
     SpdyContinuationIR continuation_ir(frame_ir->stream_id());
     continuation_ir.set_end_headers(!has_next_frame_);
@@ -1774,6 +1776,55 @@
                                                         encoding, output);
 }
 
+SpdyFramer::SpdyControlFrameIterator::SpdyControlFrameIterator(
+    SpdyFramer* framer,
+    std::unique_ptr<SpdyFrameIR> frame_ir)
+    : framer_(framer), frame_ir_(std::move(frame_ir)) {}
+
+SpdyFramer::SpdyControlFrameIterator::~SpdyControlFrameIterator() {}
+
+size_t SpdyFramer::SpdyControlFrameIterator::NextFrame(
+    ZeroCopyOutputBuffer* output) {
+  size_t size_written = framer_->SerializeFrame(*frame_ir_, output);
+  frame_ir_.reset();
+  return size_written;
+}
+
+bool SpdyFramer::SpdyControlFrameIterator::HasNextFrame() const {
+  return frame_ir_ != nullptr;
+}
+
+// TODO(yasong): remove all the down_casts.
+std::unique_ptr<SpdyFrameSequence> SpdyFramer::CreateIterator(
+    SpdyFramer* framer,
+    std::unique_ptr<SpdyFrameIR> frame_ir) {
+  std::unique_ptr<SpdyFrameSequence> result = nullptr;
+  switch (frame_ir->frame_type()) {
+    case SpdyFrameType::DATA: {
+      DLOG(ERROR) << "Data should use a different path to write";
+      result = nullptr;
+      break;
+    }
+    case SpdyFrameType::HEADERS: {
+      result = base::MakeUnique<SpdyHeaderFrameIterator>(
+          framer,
+          base::WrapUnique(static_cast<SpdyHeadersIR*>(frame_ir.get())));
+      break;
+    }
+    case SpdyFrameType::PUSH_PROMISE: {
+      result = base::MakeUnique<SpdyPushPromiseFrameIterator>(
+          framer,
+          base::WrapUnique(static_cast<SpdyPushPromiseIR*>(frame_ir.get())));
+      break;
+    }
+    default: {
+      result = base::MakeUnique<SpdyControlFrameIterator>(framer,
+                                                          std::move(frame_ir));
+    }
+  }
+  return result;
+}
+
 void SpdyFramer::SerializeDataBuilderHelper(const SpdyDataIR& data_ir,
                                             uint8_t* flags,
                                             int* num_padding_fields,
@@ -2706,7 +2757,7 @@
       : framer_(framer), output_(output), result_(false) {}
   ~FrameSerializationVisitorWithOutput() override {}
 
-  bool Result() { return result_; }
+  size_t Result() { return result_; }
 
   void VisitData(const SpdyDataIR& data) override {
     result_ = framer_->SerializeData(data, output_);
@@ -2750,11 +2801,12 @@
 
 }  // namespace
 
-bool SpdyFramer::SerializeFrame(const SpdyFrameIR& frame,
-                                ZeroCopyOutputBuffer* output) {
+size_t SpdyFramer::SerializeFrame(const SpdyFrameIR& frame,
+                                  ZeroCopyOutputBuffer* output) {
   FrameSerializationVisitorWithOutput visitor(this, output);
+  size_t free_bytes_before = output->BytesFree();
   frame.Visit(&visitor);
-  return visitor.Result();
+  return visitor.Result() ? free_bytes_before - output->BytesFree() : 0;
 }
 
 size_t SpdyFramer::GetNumberRequiredContinuationFrames(size_t size) {
diff --git a/net/spdy/core/spdy_framer.h b/net/spdy/core/spdy_framer.h
index 555a2de..74079140 100644
--- a/net/spdy/core/spdy_framer.h
+++ b/net/spdy/core/spdy_framer.h
@@ -45,6 +45,8 @@
 
 class TestSpdyVisitor;
 class SpdyFramerPeer;
+class SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
+class SpdyFramerTest_PushPromiseFramesWithIterator_Test;
 
 }  // namespace test
 
@@ -210,7 +212,7 @@
   virtual bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) = 0;
 };
 
-class SpdyFrameSequence {
+class SPDY_EXPORT_PRIVATE SpdyFrameSequence {
  public:
   virtual ~SpdyFrameSequence() {}
 
@@ -391,90 +393,10 @@
                                 size_t header_length,
                                 SpdyHeaderBlock* block) const;
 
-  // Iteratively converts a SpdyFrameWithHeaderBlockIR into an appropriate
-  // sequence of SpdySerializedFrames.
-  class SPDY_EXPORT_PRIVATE SpdyFrameIterator {
-   public:
-    // Creates an iterator with the provided framer.
-    // Does not take ownership of |framer|.
-    // |framer| must outlive this instance.
-    explicit SpdyFrameIterator(SpdyFramer* framer);
-    virtual ~SpdyFrameIterator();
-
-    // Serializes the next frame in the sequence to |output|. Returns the number
-    // of bytes written to |output|.
-    virtual bool NextFrame(ZeroCopyOutputBuffer* output);
-
-    // Returns true iff there is at least one more frame in the sequence.
-    virtual bool HasNextFrame() const;
-
-    // SpdyFrameIterator is neither copyable nor movable.
-    SpdyFrameIterator(const SpdyFrameIterator&) = delete;
-    SpdyFrameIterator& operator=(const SpdyFrameIterator&) = delete;
-
-   protected:
-    virtual SpdyFrameWithHeaderBlockIR* GetIR() const = 0;
-    virtual size_t GetFrameSizeSansBlock() const = 0;
-    virtual bool SerializeGivenEncoding(const SpdyString& encoding,
-                                        ZeroCopyOutputBuffer* output) const = 0;
-
-    SpdyFramer* GetFramer() const { return framer_; }
-    void SetEncoder(SpdyFrameWithHeaderBlockIR* ir) {
-      encoder_ =
-          framer_->GetHpackEncoder()->EncodeHeaderSet(ir->header_block());
-    }
-
-   private:
-    SpdyFramer* const framer_;
-    std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoder_;
-    bool is_first_frame_;
-    bool has_next_frame_;
-
-    // Field for debug reporting.
-    size_t debug_total_size_;
-  };
-
-  // Iteratively converts a SpdyHeadersIR (with a possibly huge
-  // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
-  // write to the output.
-  class SPDY_EXPORT_PRIVATE SpdyHeaderFrameIterator : public SpdyFrameIterator {
-   public:
-    // Does not take ownership of |framer|. Take ownership of |headers_ir|.
-    SpdyHeaderFrameIterator(SpdyFramer* framer,
-                            std::unique_ptr<SpdyHeadersIR> headers_ir);
-
-    ~SpdyHeaderFrameIterator() override;
-
-   private:
-    SpdyFrameWithHeaderBlockIR* GetIR() const override;
-    size_t GetFrameSizeSansBlock() const override;
-    bool SerializeGivenEncoding(const SpdyString& encoding,
-                                ZeroCopyOutputBuffer* output) const override;
-
-    const std::unique_ptr<SpdyHeadersIR> headers_ir_;
-  };
-
-  // Iteratively converts a SpdyPushPromiseIR (with a possibly huge
-  // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
-  // write to the output.
-  class SPDY_EXPORT_PRIVATE SpdyPushPromiseFrameIterator
-      : public SpdyFrameIterator {
-   public:
-    // Does not take ownership of |framer|. Take ownership of |push_promise_ir|.
-    SpdyPushPromiseFrameIterator(
-        SpdyFramer* framer,
-        std::unique_ptr<SpdyPushPromiseIR> push_promise_ir);
-
-    ~SpdyPushPromiseFrameIterator() override;
-
-   private:
-    SpdyFrameWithHeaderBlockIR* GetIR() const override;
-    size_t GetFrameSizeSansBlock() const override;
-    bool SerializeGivenEncoding(const SpdyString& encoding,
-                                ZeroCopyOutputBuffer* output) const override;
-
-    const std::unique_ptr<SpdyPushPromiseIR> push_promise_ir_;
-  };
+  // Create a SpdyFrameSequence to serialize |frame_ir|.
+  static std::unique_ptr<SpdyFrameSequence> CreateIterator(
+      SpdyFramer* framer,
+      std::unique_ptr<SpdyFrameIR> frame_ir);
 
   // Serialize a data frame.
   SpdySerializedFrame SerializeData(const SpdyDataIR& data) const;
@@ -595,7 +517,7 @@
                          ZeroCopyOutputBuffer* output) const;
 
   // Serialize a frame of unknown type.
-  bool SerializeFrame(const SpdyFrameIR& frame, ZeroCopyOutputBuffer* output);
+  size_t SerializeFrame(const SpdyFrameIR& frame, ZeroCopyOutputBuffer* output);
 
   // Returns whether this SpdyFramer will compress header blocks using HPACK.
   bool compression_enabled() const {
@@ -692,6 +614,116 @@
   friend class SpdyStreamTest;
   friend class test::TestSpdyVisitor;
   friend class test::SpdyFramerPeer;
+  friend class test::SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
+  friend class test::SpdyFramerTest_PushPromiseFramesWithIterator_Test;
+
+  // Iteratively converts a SpdyFrameIR into an appropriate sequence of Spdy
+  // frames.
+  // Example usage:
+  // std::unique_ptr<SpdyFrameSequence> it = CreateIterator(framer, frame_ir);
+  // while (it->HasNextFrame()) {
+  //   if(it->NextFrame(output) == 0) {
+  //     // Write failed;
+  //   }
+  // }
+  class SPDY_EXPORT_PRIVATE SpdyFrameIterator : public SpdyFrameSequence {
+   public:
+    // Creates an iterator with the provided framer. Does not take ownership of
+    // |framer|, |framer| must outlive this instance.
+    explicit SpdyFrameIterator(SpdyFramer* framer);
+    ~SpdyFrameIterator() override;
+
+    // Serializes the next frame in the sequence to |output|. Returns the number
+    // of bytes written to |output|.
+    size_t NextFrame(ZeroCopyOutputBuffer* output) override;
+
+    // Returns true iff there is at least one more frame in the sequence.
+    bool HasNextFrame() const override;
+
+    // SpdyFrameIterator is neither copyable nor movable.
+    SpdyFrameIterator(const SpdyFrameIterator&) = delete;
+    SpdyFrameIterator& operator=(const SpdyFrameIterator&) = delete;
+
+   protected:
+    virtual SpdyFrameWithHeaderBlockIR* GetIR() const = 0;
+    virtual size_t GetFrameSizeSansBlock() const = 0;
+    virtual bool SerializeGivenEncoding(const SpdyString& encoding,
+                                        ZeroCopyOutputBuffer* output) const = 0;
+
+    SpdyFramer* GetFramer() const { return framer_; }
+    void SetEncoder(SpdyFrameWithHeaderBlockIR* ir) {
+      encoder_ =
+          framer_->GetHpackEncoder()->EncodeHeaderSet(ir->header_block());
+    }
+
+   private:
+    SpdyFramer* const framer_;
+    std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoder_;
+    bool is_first_frame_;
+    bool has_next_frame_;
+
+    // Field for debug reporting.
+    size_t debug_total_size_;
+  };
+
+  // Iteratively converts a SpdyHeadersIR (with a possibly huge
+  // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
+  // write to the output.
+  class SPDY_EXPORT_PRIVATE SpdyHeaderFrameIterator : public SpdyFrameIterator {
+   public:
+    // Does not take ownership of |framer|. Take ownership of |headers_ir|.
+    SpdyHeaderFrameIterator(SpdyFramer* framer,
+                            std::unique_ptr<SpdyHeadersIR> headers_ir);
+
+    ~SpdyHeaderFrameIterator() override;
+
+   private:
+    SpdyFrameWithHeaderBlockIR* GetIR() const override;
+    size_t GetFrameSizeSansBlock() const override;
+    bool SerializeGivenEncoding(const SpdyString& encoding,
+                                ZeroCopyOutputBuffer* output) const override;
+
+    const std::unique_ptr<SpdyHeadersIR> headers_ir_;
+  };
+
+  // Iteratively converts a SpdyPushPromiseIR (with a possibly huge
+  // SpdyHeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
+  // write to the output.
+  class SPDY_EXPORT_PRIVATE SpdyPushPromiseFrameIterator
+      : public SpdyFrameIterator {
+   public:
+    // Does not take ownership of |framer|. Take ownership of |push_promise_ir|.
+    SpdyPushPromiseFrameIterator(
+        SpdyFramer* framer,
+        std::unique_ptr<SpdyPushPromiseIR> push_promise_ir);
+
+    ~SpdyPushPromiseFrameIterator() override;
+
+   private:
+    SpdyFrameWithHeaderBlockIR* GetIR() const override;
+    size_t GetFrameSizeSansBlock() const override;
+    bool SerializeGivenEncoding(const SpdyString& encoding,
+                                ZeroCopyOutputBuffer* output) const override;
+
+    const std::unique_ptr<SpdyPushPromiseIR> push_promise_ir_;
+  };
+
+  // Converts a SpdyFrameIR into one Spdy frame (a sequence of length 1), and
+  // write it to the output.
+  class SpdyControlFrameIterator : public SpdyFrameSequence {
+   public:
+    SpdyControlFrameIterator(SpdyFramer* framer,
+                             std::unique_ptr<SpdyFrameIR> frame_ir);
+    ~SpdyControlFrameIterator() override;
+
+    size_t NextFrame(ZeroCopyOutputBuffer* output) override;
+
+    bool HasNextFrame() const override;
+
+   private:
+    SpdyFramer* const framer_;
+    std::unique_ptr<SpdyFrameIR> frame_ir_;
+  };
 
  private:
   class CharBuffer {
diff --git a/net/spdy/core/spdy_framer_test.cc b/net/spdy/core/spdy_framer_test.cc
index 66a53545..dc978900 100644
--- a/net/spdy/core/spdy_framer_test.cc
+++ b/net/spdy/core/spdy_framer_test.cc
@@ -262,7 +262,7 @@
     SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers));
     while (it.HasNextFrame()) {
       size_t size_before = frame_list_buffer.Size();
-      it.NextFrame(&frame_list_buffer);
+      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
           SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
                               frame_list_buffer.Size() - size_before, false));
@@ -292,7 +292,7 @@
     SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers));
     while (it.HasNextFrame()) {
       size_t size_before = frame_list_buffer.Size();
-      it.NextFrame(&frame_list_buffer);
+      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
           SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
                               frame_list_buffer.Size() - size_before, false));
@@ -332,7 +332,7 @@
         framer, CloneSpdyPushPromiseIR(push_promise));
     while (it.HasNextFrame()) {
       size_t size_before = frame_list_buffer.Size();
-      it.NextFrame(&frame_list_buffer);
+      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
           SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
                               frame_list_buffer.Size() - size_before, false));
@@ -365,7 +365,7 @@
         framer, CloneSpdyPushPromiseIR(push_promise));
     while (it.HasNextFrame()) {
       size_t size_before = frame_list_buffer.Size();
-      it.NextFrame(&frame_list_buffer);
+      EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
           SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
                               frame_list_buffer.Size() - size_before, false));
@@ -396,7 +396,6 @@
         continuation_count_(0),
         altsvc_count_(0),
         priority_count_(0),
-        test_altsvc_ir_(0),
         on_unknown_frame_result_(false),
         last_window_update_stream_(0),
         last_window_update_delta_(0),
@@ -551,12 +550,12 @@
                     altsvc_vector) override {
     VLOG(1) << "OnAltSvc(" << stream_id << ", \"" << origin
             << "\", altsvc_vector)";
-    test_altsvc_ir_.set_stream_id(stream_id);
+    test_altsvc_ir_ = SpdyMakeUnique<SpdyAltSvcIR>(stream_id);
     if (origin.length() > 0) {
-      test_altsvc_ir_.set_origin(SpdyString(origin));
+      test_altsvc_ir_->set_origin(SpdyString(origin));
     }
     for (const auto& altsvc : altsvc_vector) {
-      test_altsvc_ir_.add_altsvc(altsvc);
+      test_altsvc_ir_->add_altsvc(altsvc);
     }
     ++altsvc_count_;
   }
@@ -664,7 +663,7 @@
   int continuation_count_;
   int altsvc_count_;
   int priority_count_;
-  SpdyAltSvcIR test_altsvc_ir_;
+  std::unique_ptr<SpdyAltSvcIR> test_altsvc_ir_;
   bool on_unknown_frame_result_;
   SpdyStreamId last_window_update_stream_;
   int last_window_update_delta_;
@@ -1155,7 +1154,7 @@
   SpdyPriorityIR priority_ir(0, 1, 16, true);
   SpdySerializedFrame frame(framer.SerializeFrame(priority_ir));
   if (use_output_) {
-    ASSERT_TRUE(framer.SerializeFrame(priority_ir, &output_));
+    EXPECT_EQ(framer.SerializeFrame(priority_ir, &output_), frame.size());
     frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
   }
 
@@ -2704,7 +2703,7 @@
       SpdyAltSvcWireFormat::VersionVector{24}));
   SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir));
   if (use_output_) {
-    ASSERT_TRUE(framer.SerializeFrame(altsvc_ir, &output_));
+    EXPECT_EQ(framer.SerializeFrame(altsvc_ir, &output_), frame.size());
     frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
   }
   CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
@@ -2725,7 +2724,7 @@
   SpdyPriorityIR priority_ir(2, 1, 17, true);
   SpdySerializedFrame frame(framer.SerializeFrame(priority_ir));
   if (use_output_) {
-    ASSERT_TRUE(framer.SerializeFrame(priority_ir, &output_));
+    EXPECT_EQ(framer.SerializeFrame(priority_ir, &output_), frame.size());
     frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
   }
   CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
@@ -2810,7 +2809,7 @@
   SpdyFramer::SpdyHeaderFrameIterator frame_it(&framer, std::move(headers));
 
   EXPECT_TRUE(frame_it.HasNextFrame());
-  EXPECT_TRUE(frame_it.NextFrame(&output_));
+  EXPECT_GT(frame_it.NextFrame(&output_), 0u);
   SpdySerializedFrame headers_frame(output_.Begin(), output_.Size(), false);
   EXPECT_EQ(headers_frame.size(),
             TestSpdyVisitor::sent_control_frame_max_size());
@@ -2827,7 +2826,7 @@
 
   output_.Reset();
   EXPECT_TRUE(frame_it.HasNextFrame());
-  EXPECT_TRUE(frame_it.NextFrame(&output_));
+  EXPECT_GT(frame_it.NextFrame(&output_), 0u);
   SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false);
   EXPECT_EQ(first_cont_frame.size(),
             TestSpdyVisitor::sent_control_frame_max_size());
@@ -2843,7 +2842,7 @@
 
   output_.Reset();
   EXPECT_TRUE(frame_it.HasNextFrame());
-  EXPECT_TRUE(frame_it.NextFrame(&output_));
+  EXPECT_GT(frame_it.NextFrame(&output_), 0u);
   SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false);
   EXPECT_LT(second_cont_frame.size(),
             TestSpdyVisitor::sent_control_frame_max_size());
@@ -2879,7 +2878,7 @@
                                                     std::move(push_promise));
 
   EXPECT_TRUE(frame_it.HasNextFrame());
-  EXPECT_TRUE(frame_it.NextFrame(&output_));
+  EXPECT_GT(frame_it.NextFrame(&output_), 0u);
   SpdySerializedFrame push_promise_frame(output_.Begin(), output_.Size(),
                                          false);
   EXPECT_EQ(push_promise_frame.size(),
@@ -2897,7 +2896,7 @@
 
   EXPECT_TRUE(frame_it.HasNextFrame());
   output_.Reset();
-  EXPECT_TRUE(frame_it.NextFrame(&output_));
+  EXPECT_GT(frame_it.NextFrame(&output_), 0u);
   SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false);
 
   EXPECT_EQ(first_cont_frame.size(),
@@ -2913,7 +2912,7 @@
 
   EXPECT_TRUE(frame_it.HasNextFrame());
   output_.Reset();
-  EXPECT_TRUE(frame_it.NextFrame(&output_));
+  EXPECT_GT(frame_it.NextFrame(&output_), 0u);
   SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false);
   EXPECT_LT(second_cont_frame.size(),
             TestSpdyVisitor::sent_control_frame_max_size());
@@ -2930,6 +2929,69 @@
   EXPECT_FALSE(frame_it.HasNextFrame());
 }
 
+class SpdyControlFrameIteratorTest : public ::testing::Test {
+ public:
+  SpdyControlFrameIteratorTest() : output_(output_buffer, kSize) {}
+
+  void RunTest(std::unique_ptr<SpdyFrameIR> ir) {
+    SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
+    SpdySerializedFrame frame(framer.SerializeFrame(*ir));
+    std::unique_ptr<SpdyFrameSequence> it =
+        SpdyFramer::CreateIterator(&framer, std::move(ir));
+    EXPECT_TRUE(it->HasNextFrame());
+    EXPECT_EQ(it->NextFrame(&output_), frame.size());
+    EXPECT_FALSE(it->HasNextFrame());
+  }
+
+ private:
+  ArrayOutputBuffer output_;
+};
+
+TEST_F(SpdyControlFrameIteratorTest, RstStreamFrameWithIterator) {
+  auto ir = base::MakeUnique<SpdyRstStreamIR>(0, ERROR_CODE_PROTOCOL_ERROR);
+  RunTest(std::move(ir));
+}
+
+TEST_F(SpdyControlFrameIteratorTest, SettingsFrameWithIterator) {
+  auto ir = base::MakeUnique<SpdySettingsIR>();
+  uint32_t kValue = 0x0a0b0c0d;
+  SpdySettingsIds kId = SETTINGS_INITIAL_WINDOW_SIZE;
+  ir->AddSetting(kId, kValue);
+  RunTest(std::move(ir));
+}
+
+TEST_F(SpdyControlFrameIteratorTest, PingFrameWithIterator) {
+  const SpdyPingId kPingId = 0x123456789abcdeffULL;
+  auto ir = base::MakeUnique<SpdyPingIR>(kPingId);
+  RunTest(std::move(ir));
+}
+
+TEST_F(SpdyControlFrameIteratorTest, GoAwayFrameWithIterator) {
+  auto ir = base::MakeUnique<SpdyGoAwayIR>(0, ERROR_CODE_NO_ERROR, "GA");
+  RunTest(std::move(ir));
+}
+
+TEST_F(SpdyControlFrameIteratorTest, WindowUpdateFrameWithIterator) {
+  auto ir = base::MakeUnique<SpdyWindowUpdateIR>(1, 1);
+  RunTest(std::move(ir));
+}
+
+TEST_F(SpdyControlFrameIteratorTest, AtlSvcFrameWithIterator) {
+  auto ir = base::MakeUnique<SpdyAltSvcIR>(3);
+  ir->set_origin("origin");
+  ir->add_altsvc(SpdyAltSvcWireFormat::AlternativeService(
+      "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()));
+  ir->add_altsvc(SpdyAltSvcWireFormat::AlternativeService(
+      "p\"=i:d", "h_\\o\"st", 123, 42,
+      SpdyAltSvcWireFormat::VersionVector{24}));
+  RunTest(std::move(ir));
+}
+
+TEST_F(SpdyControlFrameIteratorTest, PriorityFrameWithIterator) {
+  auto ir = base::MakeUnique<SpdyPriorityIR>(2, 1, 17, true);
+  RunTest(std::move(ir));
+}
+
 TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) {
   SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION);
   SpdyPushPromiseIR push_promise(1, 2);
@@ -4382,7 +4444,7 @@
   SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir));
   if (use_output_) {
     output_.Reset();
-    ASSERT_TRUE(framer.SerializeFrame(altsvc_ir, &output_));
+    EXPECT_GT(framer.SerializeFrame(altsvc_ir, &output_), 0u);
     frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
   }
   framer.ProcessInput(frame.data(), frame.size());
@@ -4437,7 +4499,7 @@
   SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir));
   if (use_output_) {
     output_.Reset();
-    ASSERT_TRUE(framer.SerializeFrame(altsvc_ir, &output_));
+    EXPECT_GT(framer.SerializeFrame(altsvc_ir, &output_), 0u);
     frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
   }
   framer.ProcessInput(frame.data(), frame.size());
@@ -4493,9 +4555,10 @@
   }
   EXPECT_EQ(0, visitor.error_count_);
   EXPECT_EQ(1, visitor.altsvc_count_);
-  ASSERT_EQ(2u, visitor.test_altsvc_ir_.altsvc_vector().size());
-  EXPECT_TRUE(visitor.test_altsvc_ir_.altsvc_vector()[0] == altsvc1);
-  EXPECT_TRUE(visitor.test_altsvc_ir_.altsvc_vector()[1] == altsvc2);
+  ASSERT_NE(nullptr, visitor.test_altsvc_ir_);
+  ASSERT_EQ(2u, visitor.test_altsvc_ir_->altsvc_vector().size());
+  EXPECT_TRUE(visitor.test_altsvc_ir_->altsvc_vector()[0] == altsvc1);
+  EXPECT_TRUE(visitor.test_altsvc_ir_->altsvc_vector()[1] == altsvc2);
 }
 
 // While RFC7838 Section 4 says that an ALTSVC frame on stream 0 with empty
diff --git a/net/spdy/core/spdy_protocol.cc b/net/spdy/core/spdy_protocol.cc
index 2ae97a9b..9a0f52b 100644
--- a/net/spdy/core/spdy_protocol.cc
+++ b/net/spdy/core/spdy_protocol.cc
@@ -255,7 +255,7 @@
 
 SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id,
                                  SpdyErrorCode error_code)
-    : SpdyFrameWithStreamIdIR(stream_id) {
+    : SpdyFrameIR(stream_id) {
   set_error_code(error_code);
 }
 
@@ -324,7 +324,7 @@
 }
 
 SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id)
-    : SpdyFrameWithStreamIdIR(stream_id), end_headers_(false) {
+    : SpdyFrameIR(stream_id), end_headers_(false) {
   encoding_ = SpdyMakeUnique<SpdyString>();
 }
 
@@ -362,9 +362,7 @@
   return SpdyFrameType::PUSH_PROMISE;
 }
 
-SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id)
-    : SpdyFrameWithStreamIdIR(stream_id) {
-}
+SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id) : SpdyFrameIR(stream_id) {}
 
 SpdyAltSvcIR::~SpdyAltSvcIR() {
 }
diff --git a/net/spdy/core/spdy_protocol.h b/net/spdy/core/spdy_protocol.h
index 9c3458a..8670405 100644
--- a/net/spdy/core/spdy_protocol.h
+++ b/net/spdy/core/spdy_protocol.h
@@ -381,39 +381,21 @@
 
   virtual void Visit(SpdyFrameVisitor* visitor) const = 0;
   virtual SpdyFrameType frame_type() const = 0;
-
- protected:
-  SpdyFrameIR() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SpdyFrameIR);
-};
-
-// Abstract class intended to be inherited by IRs that have a stream associated
-// to them.
-class SPDY_EXPORT_PRIVATE SpdyFrameWithStreamIdIR : public SpdyFrameIR {
- public:
-  ~SpdyFrameWithStreamIdIR() override {}
   SpdyStreamId stream_id() const { return stream_id_; }
-  void set_stream_id(SpdyStreamId stream_id) {
-    DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
-    stream_id_ = stream_id;
-  }
 
  protected:
-  explicit SpdyFrameWithStreamIdIR(SpdyStreamId stream_id) {
-    set_stream_id(stream_id);
-  }
+  SpdyFrameIR() : stream_id_(0) {}
+  explicit SpdyFrameIR(SpdyStreamId stream_id) : stream_id_(stream_id) {}
 
  private:
   SpdyStreamId stream_id_;
 
-  DISALLOW_COPY_AND_ASSIGN(SpdyFrameWithStreamIdIR);
+  DISALLOW_COPY_AND_ASSIGN(SpdyFrameIR);
 };
 
 // Abstract class intended to be inherited by IRs that have the option of a FIN
-// flag. Implies SpdyFrameWithStreamIdIR.
-class SPDY_EXPORT_PRIVATE SpdyFrameWithFinIR : public SpdyFrameWithStreamIdIR {
+// flag.
+class SPDY_EXPORT_PRIVATE SpdyFrameWithFinIR : public SpdyFrameIR {
  public:
   ~SpdyFrameWithFinIR() override {}
   bool fin() const { return fin_; }
@@ -421,8 +403,7 @@
 
  protected:
   explicit SpdyFrameWithFinIR(SpdyStreamId stream_id)
-      : SpdyFrameWithStreamIdIR(stream_id),
-        fin_(false) {}
+      : SpdyFrameIR(stream_id), fin_(false) {}
 
  private:
   bool fin_;
@@ -530,7 +511,7 @@
   DISALLOW_COPY_AND_ASSIGN(SpdyDataIR);
 };
 
-class SPDY_EXPORT_PRIVATE SpdyRstStreamIR : public SpdyFrameWithStreamIdIR {
+class SPDY_EXPORT_PRIVATE SpdyRstStreamIR : public SpdyFrameIR {
  public:
   SpdyRstStreamIR(SpdyStreamId stream_id, SpdyErrorCode error_code);
 
@@ -680,10 +661,10 @@
   DISALLOW_COPY_AND_ASSIGN(SpdyHeadersIR);
 };
 
-class SPDY_EXPORT_PRIVATE SpdyWindowUpdateIR : public SpdyFrameWithStreamIdIR {
+class SPDY_EXPORT_PRIVATE SpdyWindowUpdateIR : public SpdyFrameIR {
  public:
   SpdyWindowUpdateIR(SpdyStreamId stream_id, int32_t delta)
-      : SpdyFrameWithStreamIdIR(stream_id) {
+      : SpdyFrameIR(stream_id) {
     set_delta(delta);
   }
   int32_t delta() const { return delta_; }
@@ -740,7 +721,7 @@
   DISALLOW_COPY_AND_ASSIGN(SpdyPushPromiseIR);
 };
 
-class SPDY_EXPORT_PRIVATE SpdyContinuationIR : public SpdyFrameWithStreamIdIR {
+class SPDY_EXPORT_PRIVATE SpdyContinuationIR : public SpdyFrameIR {
  public:
   explicit SpdyContinuationIR(SpdyStreamId stream_id);
   ~SpdyContinuationIR() override;
@@ -762,7 +743,7 @@
   DISALLOW_COPY_AND_ASSIGN(SpdyContinuationIR);
 };
 
-class SPDY_EXPORT_PRIVATE SpdyAltSvcIR : public SpdyFrameWithStreamIdIR {
+class SPDY_EXPORT_PRIVATE SpdyAltSvcIR : public SpdyFrameIR {
  public:
   explicit SpdyAltSvcIR(SpdyStreamId stream_id);
   ~SpdyAltSvcIR() override;
@@ -787,13 +768,13 @@
   DISALLOW_COPY_AND_ASSIGN(SpdyAltSvcIR);
 };
 
-class SPDY_EXPORT_PRIVATE SpdyPriorityIR : public SpdyFrameWithStreamIdIR {
+class SPDY_EXPORT_PRIVATE SpdyPriorityIR : public SpdyFrameIR {
  public:
   SpdyPriorityIR(SpdyStreamId stream_id,
                  SpdyStreamId parent_stream_id,
                  int weight,
                  bool exclusive)
-      : SpdyFrameWithStreamIdIR(stream_id),
+      : SpdyFrameIR(stream_id),
         parent_stream_id_(parent_stream_id),
         weight_(weight),
         exclusive_(exclusive) {}
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index e2a6a5d..f2f6441 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -6639,10 +6639,12 @@
     std::string header_value;
   };
 
-  ~TestReportingService() override {}
-
   const std::vector<Header>& headers() { return headers_; }
 
+  // ReportingService implementation:
+
+  ~TestReportingService() override {}
+
   void QueueReport(const GURL& url,
                    const std::string& group,
                    const std::string& type,
diff --git a/pdf/pdfium/fuzzers/BUILD.gn b/pdf/pdfium/fuzzers/BUILD.gn
index c5aaf3a..224bc11 100644
--- a/pdf/pdfium/fuzzers/BUILD.gn
+++ b/pdf/pdfium/fuzzers/BUILD.gn
@@ -177,6 +177,13 @@
     dict = "dicts/pdf_xml.dict"
   }
 
+  fuzzer_test("pdf_cfx_barcode_fuzzer") {
+    sources = []
+    deps = [
+      "//third_party/pdfium/testing/libfuzzer:pdf_cfx_barcode_fuzzer",
+    ]
+  }
+
   fuzzer_test("pdf_cfx_saxreader_fuzzer") {
     sources = []
     deps = [
diff --git a/remoting/test/BUILD.gn b/remoting/test/BUILD.gn
index 18dc5f1..ef0deaf 100644
--- a/remoting/test/BUILD.gn
+++ b/remoting/test/BUILD.gn
@@ -173,6 +173,7 @@
 
     deps = [
       ":fake_connection_event_logger",
+      "//base/test:test_support",
       "//third_party/webrtc/modules/desktop_capture",
     ]
 
diff --git a/remoting/test/it2me_standalone_host.cc b/remoting/test/it2me_standalone_host.cc
index e6b74de..eed5c913 100644
--- a/remoting/test/it2me_standalone_host.cc
+++ b/remoting/test/it2me_standalone_host.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "remoting/base/auto_thread_task_runner.h"
 #include "remoting/host/chromoting_host_context.h"
@@ -36,24 +37,26 @@
 using ::remoting::protocol::MockSession;
 
 It2MeStandaloneHost::It2MeStandaloneHost()
-  : context_(ChromotingHostContext::Create(
-        new AutoThreadTaskRunner(
-        message_loop_.task_runner(), run_loop_.QuitClosure()))),
-    main_task_runner_(context_->file_task_runner()),
-    factory_(main_task_runner_,
-             context_->video_capture_task_runner(),
-             context_->input_task_runner(),
-             context_->ui_task_runner()),
-    connection_(base::WrapUnique(new testing::NiceMock<MockSession>())),
-    session_jid_(kSessionJid),
+    : scoped_task_environment_(
+          base::test::ScopedTaskEnvironment::MainThreadType::UI),
+      context_(ChromotingHostContext::Create(
+          new AutoThreadTaskRunner(base::ThreadTaskRunnerHandle::Get(),
+                                   run_loop_.QuitClosure()))),
+      main_task_runner_(context_->file_task_runner()),
+      factory_(main_task_runner_,
+               context_->video_capture_task_runner(),
+               context_->input_task_runner(),
+               context_->ui_task_runner()),
+      connection_(base::WrapUnique(new testing::NiceMock<MockSession>())),
+      session_jid_(kSessionJid),
 #if defined(OS_LINUX)
-    // We cannot support audio capturing for linux, since a pipe name is
-    // needed to initialize AudioCapturerLinux.
-    config_(protocol::SessionConfig::ForTest()),
+      // We cannot support audio capturing for linux, since a pipe name is
+      // needed to initialize AudioCapturerLinux.
+      config_(protocol::SessionConfig::ForTest()),
 #else
-    config_(protocol::SessionConfig::ForTestWithAudio()),
+      config_(protocol::SessionConfig::ForTestWithAudio()),
 #endif
-    event_logger_(&connection_) {
+      event_logger_(&connection_) {
   EXPECT_CALL(*static_cast<MockSession*>(connection_.session()), jid())
       .WillRepeatedly(testing::ReturnRef(session_jid_));
   EXPECT_CALL(*static_cast<MockSession*>(connection_.session()), config())
diff --git a/remoting/test/it2me_standalone_host.h b/remoting/test/it2me_standalone_host.h
index c705537..5d1f643 100644
--- a/remoting/test/it2me_standalone_host.h
+++ b/remoting/test/it2me_standalone_host.h
@@ -9,8 +9,8 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/timer/timer.h"
 #include "remoting/host/host_mock_objects.h"
 #include "remoting/host/it2me_desktop_environment.h"
@@ -43,7 +43,7 @@
  private:
   void Connect();
 
-  base::MessageLoopForUI message_loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   base::RunLoop run_loop_;
   std::unique_ptr<ChromotingHostContext> context_;
   scoped_refptr<AutoThreadTaskRunner> main_task_runner_;
diff --git a/services/resource_coordinator/BUILD.gn b/services/resource_coordinator/BUILD.gn
index a669876..ef9bf45 100644
--- a/services/resource_coordinator/BUILD.gn
+++ b/services/resource_coordinator/BUILD.gn
@@ -2,24 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# There should be only one resource coordinator. It is currently
+# There should be only one memory instrumentaiton coordinator. It is currently
 # in the browser process. So, only //content/browser should link to this target.
 # Others modules should only need the public targets.
-import("//services/catalog/public/tools/catalog.gni")
-import("//services/service_manager/public/cpp/service.gni")
-import("//services/service_manager/public/service_manifest.gni")
-import("//services/service_manager/public/tools/test/service_test.gni")
-
 source_set("lib") {
   sources = [
-    "coordination_unit/coordination_unit_impl.cc",
-    "coordination_unit/coordination_unit_impl.h",
-    "coordination_unit/coordination_unit_provider_impl.cc",
-    "coordination_unit/coordination_unit_provider_impl.h",
     "memory/coordinator/coordinator_impl.cc",
     "memory/coordinator/coordinator_impl.h",
-    "resource_coordinator_service.cc",
-    "resource_coordinator_service.h",
   ]
 
   public_deps = [
@@ -27,33 +16,12 @@
     "//mojo/public/cpp/bindings",
     "//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
   ]
-
-  data_deps = [
-    ":manifest",
-  ]
-}
-
-service_manifest("manifest") {
-  name = "resource_coordinator"
-  source = "manifest.json"
-}
-
-service("resource_coordinator") {
-  sources = [
-    "service_main.cc",
-  ]
-
-  deps = [
-    ":lib",
-    "//mojo/public/cpp/system",
-  ]
 }
 
 source_set("tests") {
   testonly = true
 
   sources = [
-    "coordination_unit/coordination_unit_impl_unittest.cc",
     "memory/coordinator/coordinator_impl_unittest.cc",
     "public/cpp/memory/process_local_dump_manager_impl_unittest.cc",
   ]
@@ -66,31 +34,3 @@
     "//testing/gtest",
   ]
 }
-
-service_test("resource_coordinator_unittests") {
-  sources = [
-    "resource_coordinator_service_unittest.cc",
-  ]
-
-  catalog = ":resource_coordinator_unittests_catalog"
-
-  deps = [
-    "//base",
-    "//mojo/public/cpp/bindings",
-    "//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
-    "//services/service_manager/public/cpp",
-    "//services/service_manager/public/cpp:service_test_support",
-    "//services/service_manager/public/interfaces",
-    "//testing/gtest",
-  ]
-}
-
-service_manifest("unittest_manifest") {
-  name = "resource_coordinator_unittests"
-  source = "unittest_manifest.json"
-}
-
-catalog("resource_coordinator_unittests_catalog") {
-  embedded_services = [ ":unittest_manifest" ]
-  standalone_services = [ ":manifest" ]
-}
diff --git a/services/resource_coordinator/DEPS b/services/resource_coordinator/DEPS
deleted file mode 100644
index aa579c4..0000000
--- a/services/resource_coordinator/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+third_party/smhasher",
-]
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc
deleted file mode 100644
index 4743989..0000000
--- a/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc
+++ /dev/null
@@ -1,220 +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/resource_coordinator/coordination_unit/coordination_unit_impl.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/process/process_handle.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/unguessable_token.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
-
-namespace resource_coordinator {
-
-namespace {
-
-using CUIDMap = std::unordered_map<CoordinationUnitID, CoordinationUnitImpl*>;
-
-CUIDMap& g_cu_map() {
-  static CUIDMap* instance = new CUIDMap();
-  return *instance;
-}
-
-}  // namespace
-
-CoordinationUnitImpl::CoordinationUnitImpl(
-    const CoordinationUnitID& id,
-    std::unique_ptr<service_manager::ServiceContextRef> service_ref) {
-  if (!id.id) {
-    id_ = CoordinationUnitID(id.type,
-                             base::UnguessableToken().Create().ToString());
-  } else {
-    id_ = id;
-  }
-
-  auto it = g_cu_map().insert(std::make_pair(id_, this));
-  DCHECK(it.second);  // Inserted successfully
-
-  service_ref_ = std::move(service_ref);
-}
-
-CoordinationUnitImpl::~CoordinationUnitImpl() {
-  g_cu_map().erase(id_);
-
-  for (CoordinationUnitImpl* child : children_) {
-    child->RemoveParent(this);
-  }
-
-  for (CoordinationUnitImpl* parent : parents_) {
-    parent->RemoveChild(this);
-  }
-}
-
-bool CoordinationUnitImpl::SelfOrParentHasFlagSet(StateFlags state) {
-  const base::Optional<bool>& state_flag = state_flags_[state];
-  if (state_flag && *state_flag) {
-    return true;
-  }
-
-  for (CoordinationUnitImpl* parent : parents_) {
-    if (parent->SelfOrParentHasFlagSet(state)) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-void CoordinationUnitImpl::RecalcCoordinationPolicy() {
-  for (CoordinationUnitImpl* child : children_) {
-    child->RecalcCoordinationPolicy();
-  }
-
-  if (!policy_callback_) {
-    return;
-  }
-
-  bool background_priority = !SelfOrParentHasFlagSet(kTabVisible) &&
-                             !SelfOrParentHasFlagSet(kAudioPlaying);
-
-  // Send the priority to the client if it's new or changed.
-  if (!current_policy_) {
-    current_policy_ = mojom::CoordinationPolicy::New();
-  } else if ((current_policy_->use_background_priority ==
-              background_priority) &&
-             !SelfOrParentHasFlagSet(StateFlags::kTestState)) {
-    return;
-  }
-
-  // current_policy_ should be kept in sync with the policy we
-  // send to the client, to avoid redundant updates.
-  // TODO(oysteine): Once this object becomes more complex, make
-  // copying more robust.
-  mojom::CoordinationPolicyPtr policy = mojom::CoordinationPolicy::New();
-  policy->use_background_priority = background_priority;
-  current_policy_->use_background_priority = background_priority;
-
-  policy_callback_->SetCoordinationPolicy(std::move(policy));
-}
-
-void CoordinationUnitImpl::SendEvent(mojom::EventPtr event) {
-  switch (event->type) {
-    case mojom::EventType::kOnWebContentsShown:
-      state_flags_[kTabVisible] = true;
-      break;
-    case mojom::EventType::kOnWebContentsHidden:
-      state_flags_[kTabVisible] = false;
-      break;
-    case mojom::EventType::kOnProcessAudioStarted:
-      state_flags_[kAudioPlaying] = true;
-      break;
-    case mojom::EventType::kOnProcessAudioStopped:
-      state_flags_[kAudioPlaying] = false;
-      break;
-    case mojom::EventType::kTestEvent:
-      state_flags_[kTestState] = true;
-      break;
-    default:
-      return;
-  }
-
-  RecalcCoordinationPolicy();
-}
-
-void CoordinationUnitImpl::GetID(const GetIDCallback& callback) {
-  callback.Run(id_);
-}
-
-void CoordinationUnitImpl::Duplicate(mojom::CoordinationUnitRequest request) {
-  bindings_.AddBinding(this, std::move(request));
-}
-
-void CoordinationUnitImpl::AddChild(const CoordinationUnitID& child_id) {
-  if (child_id == id_) {
-    return;
-  }
-
-  auto child_iter = g_cu_map().find(child_id);
-  if (child_iter != g_cu_map().end()) {
-    CoordinationUnitImpl* child = child_iter->second;
-    if (HasParent(child) || HasChild(child)) {
-      return;
-    }
-
-    DCHECK(child->id_ == child_id);
-    DCHECK(child != this);
-
-    if (AddChild(child)) {
-      child->AddParent(this);
-    }
-  }
-}
-
-bool CoordinationUnitImpl::AddChild(CoordinationUnitImpl* child) {
-  // We don't recalculate the policy here as policies are only dependent
-  // on the current CU or its parents, not its children. In other words,
-  // policies only bubble down.
-  return children_.count(child) ? false : children_.insert(child).second;
-}
-
-void CoordinationUnitImpl::RemoveChild(CoordinationUnitImpl* child) {
-  size_t children_removed = children_.erase(child);
-  DCHECK_EQ(1u, children_removed);
-}
-
-void CoordinationUnitImpl::AddParent(CoordinationUnitImpl* parent) {
-  DCHECK_EQ(0u, parents_.count(parent));
-  parents_.insert(parent);
-
-  RecalcCoordinationPolicy();
-}
-
-void CoordinationUnitImpl::RemoveParent(CoordinationUnitImpl* parent) {
-  size_t parents_removed = parents_.erase(parent);
-  DCHECK_EQ(1u, parents_removed);
-
-  RecalcCoordinationPolicy();
-}
-
-bool CoordinationUnitImpl::HasParent(CoordinationUnitImpl* unit) {
-  for (CoordinationUnitImpl* parent : parents_) {
-    if (parent == unit || parent->HasParent(unit)) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-bool CoordinationUnitImpl::HasChild(CoordinationUnitImpl* unit) {
-  for (CoordinationUnitImpl* child : children_) {
-    if (child == unit || child->HasChild(unit)) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-void CoordinationUnitImpl::SetCoordinationPolicyCallback(
-    mojom::CoordinationPolicyCallbackPtr callback) {
-  callback.set_connection_error_handler(
-      base::Bind(&CoordinationUnitImpl::UnregisterCoordinationPolicyCallback,
-                 base::Unretained(this)));
-
-  policy_callback_ = std::move(callback);
-
-  RecalcCoordinationPolicy();
-}
-
-void CoordinationUnitImpl::UnregisterCoordinationPolicyCallback() {
-  policy_callback_.reset();
-  current_policy_.reset();
-}
-
-}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/coordination_unit_impl.h
deleted file mode 100644
index a5c47f5..0000000
--- a/services/resource_coordinator/coordination_unit/coordination_unit_impl.h
+++ /dev/null
@@ -1,72 +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_RESOURCE_COORDINATOR_COORDINATION_UNIT_COORDINATION_UNIT_IMPL_H_
-#define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_COORDINATION_UNIT_IMPL_H_
-
-#include <list>
-
-#include "base/optional.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom.h"
-#include "services/service_manager/public/cpp/service_context_ref.h"
-
-namespace resource_coordinator {
-
-class CoordinationUnitImpl : public mojom::CoordinationUnit {
- public:
-  CoordinationUnitImpl(
-      const CoordinationUnitID& id,
-      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
-  ~CoordinationUnitImpl() override;
-
-  // Overridden from mojom::CoordinationUnit:
-  void SendEvent(mojom::EventPtr event) override;
-  void GetID(const GetIDCallback& callback) override;
-  void Duplicate(mojom::CoordinationUnitRequest request) override;
-  void AddChild(const CoordinationUnitID& child_id) override;
-  void SetCoordinationPolicyCallback(
-      mojom::CoordinationPolicyCallbackPtr callback) override;
-
- private:
-  bool AddChild(CoordinationUnitImpl* child);
-  void RemoveChild(CoordinationUnitImpl* child);
-  void AddParent(CoordinationUnitImpl* parent);
-  void RemoveParent(CoordinationUnitImpl* parent);
-  bool HasParent(CoordinationUnitImpl* unit);
-  bool HasChild(CoordinationUnitImpl* unit);
-
-  void RecalcCoordinationPolicy();
-  void UnregisterCoordinationPolicyCallback();
-
-  enum StateFlags : uint8_t {
-    kTestState,
-    kTabVisible,
-    kAudioPlaying,
-    kNumStateFlags
-  };
-  bool SelfOrParentHasFlagSet(StateFlags state);
-
-  std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
-  mojo::BindingSet<mojom::CoordinationUnit> bindings_;
-  CoordinationUnitID id_;
-
-  std::set<CoordinationUnitImpl*> children_;
-  std::set<CoordinationUnitImpl*> parents_;
-
-  mojom::CoordinationPolicyCallbackPtr policy_callback_;
-  mojom::CoordinationPolicyPtr current_policy_;
-
-  base::Optional<bool> state_flags_[kNumStateFlags];
-
-  DISALLOW_COPY_AND_ASSIGN(CoordinationUnitImpl);
-};
-
-}  // namespace resource_coordinator
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_COORDINATION_UNIT_IMPL_H_
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_impl_unittest.cc b/services/resource_coordinator/coordination_unit/coordination_unit_impl_unittest.cc
deleted file mode 100644
index 4640865..0000000
--- a/services/resource_coordinator/coordination_unit/coordination_unit_impl_unittest.cc
+++ /dev/null
@@ -1,196 +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 <memory>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h"
-#include "services/service_manager/public/cpp/service_context_ref.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace resource_coordinator {
-
-namespace {
-
-void OnLastServiceRefDestroyed() {
-  // No-op. This is required by service_manager::ServiceContextRefFactory
-  // construction but not needed for the tests.
-}
-
-class CoordinationUnitImplTest : public testing::Test {
- public:
-  CoordinationUnitImplTest()
-      : service_ref_factory_(base::Bind(&OnLastServiceRefDestroyed)),
-        provider_(&service_ref_factory_) {}
-  ~CoordinationUnitImplTest() override {}
-
-  // testing::Test:
-  void TearDown() override { base::RunLoop().RunUntilIdle(); }
-
- protected:
-  CoordinationUnitProviderImpl* provider() { return &provider_; }
-
- private:
-  base::MessageLoop message_loop_;
-
-  service_manager::ServiceContextRefFactory service_ref_factory_;
-  CoordinationUnitProviderImpl provider_;
-};
-
-class TestCoordinationUnit : public mojom::CoordinationPolicyCallback {
- public:
-  TestCoordinationUnit(CoordinationUnitProviderImpl* provider,
-                       const CoordinationUnitType& type,
-                       const std::string& id)
-      : binding_(this) {
-    CHECK(provider);
-
-    CoordinationUnitID new_cu_id(type, id);
-    mojom::CoordinationUnitPtr coordination_unit;
-    provider->CreateCoordinationUnit(mojo::MakeRequest(&coordination_unit_),
-                                     new_cu_id);
-
-    base::RunLoop callback;
-    SetGetIDClosure(callback.QuitClosure());
-    coordination_unit_->SetCoordinationPolicyCallback(GetPolicyCallback());
-    // Forces us to wait for the creation of the CUID to finish.
-    coordination_unit_->GetID(base::Bind(&TestCoordinationUnit::GetIDCallback,
-                                         base::Unretained(this)));
-
-    callback.Run();
-  }
-
-  void GetIDCallback(const CoordinationUnitID& cu_id) {
-    id_ = cu_id;
-    get_id_closure_.Run();
-  }
-
-  void SetGetIDClosure(const base::Closure& get_id_closure) {
-    get_id_closure_ = get_id_closure;
-  }
-
-  void SetPolicyClosure(const base::Closure& policy_closure) {
-    policy_update_closure_ = policy_closure;
-  }
-
-  mojom::CoordinationPolicyCallbackPtr GetPolicyCallback() {
-    return binding_.CreateInterfacePtrAndBind();
-  }
-
-  // The CU will always send policy updates on events (including parent events)
-  void ForcePolicyUpdates() {
-    base::RunLoop callback;
-    SetPolicyClosure(callback.QuitClosure());
-    mojom::EventPtr event = mojom::Event::New();
-    event->type = mojom::EventType::kTestEvent;
-    coordination_unit_->SendEvent(std::move(event));
-    callback.Run();
-  }
-
-  const mojom::CoordinationUnitPtr& interface() const {
-    return coordination_unit_;
-  }
-
-  const CoordinationUnitID& id() const { return id_; }
-
-  // mojom::CoordinationPolicyCallback:
-  void SetCoordinationPolicy(
-      resource_coordinator::mojom::CoordinationPolicyPtr policy) override {
-    if (policy_update_closure_) {
-      policy_update_closure_.Run();
-    }
-  }
-
- private:
-  base::Closure policy_update_closure_;
-  base::Closure get_id_closure_;
-
-  mojo::Binding<mojom::CoordinationPolicyCallback> binding_;
-  mojom::CoordinationUnitPtr coordination_unit_;
-  CoordinationUnitID id_;
-};
-
-}  // namespace
-
-TEST_F(CoordinationUnitImplTest, BasicPolicyCallback) {
-  TestCoordinationUnit test_coordination_unit(
-      provider(), CoordinationUnitType::kWebContents, "test_id");
-  test_coordination_unit.ForcePolicyUpdates();
-}
-
-TEST_F(CoordinationUnitImplTest, AddChild) {
-  TestCoordinationUnit parent_unit(
-      provider(), CoordinationUnitType::kWebContents, "parent_unit");
-
-  TestCoordinationUnit child_unit(
-      provider(), CoordinationUnitType::kWebContents, "child_unit");
-
-  child_unit.ForcePolicyUpdates();
-  parent_unit.ForcePolicyUpdates();
-
-  {
-    base::RunLoop callback;
-    child_unit.SetPolicyClosure(callback.QuitClosure());
-    parent_unit.interface()->AddChild(child_unit.id());
-    callback.Run();
-  }
-
-  {
-    base::RunLoop parent_callback;
-    base::RunLoop child_callback;
-    parent_unit.SetPolicyClosure(parent_callback.QuitClosure());
-    child_unit.SetPolicyClosure(child_callback.QuitClosure());
-
-    // This event should force the policy to recalculated for all children.
-    mojom::EventPtr event = mojom::Event::New();
-    event->type = mojom::EventType::kTestEvent;
-    parent_unit.interface()->SendEvent(std::move(event));
-
-    parent_callback.Run();
-    child_callback.Run();
-  }
-}
-
-TEST_F(CoordinationUnitImplTest, CyclicGraphUnits) {
-  TestCoordinationUnit parent_unit(
-      provider(), CoordinationUnitType::kWebContents, std::string());
-
-  TestCoordinationUnit child_unit(
-      provider(), CoordinationUnitType::kWebContents, std::string());
-
-  child_unit.ForcePolicyUpdates();
-  parent_unit.ForcePolicyUpdates();
-
-  {
-    base::RunLoop callback;
-    child_unit.SetPolicyClosure(callback.QuitClosure());
-    parent_unit.interface()->AddChild(child_unit.id());
-    callback.Run();
-  }
-
-  // This should fail, due to the existing child-parent relationship.
-  // Otherwise we end up with infinite recursion and crash when recalculating
-  // policies below.
-  child_unit.interface()->AddChild(parent_unit.id());
-
-  {
-    base::RunLoop parent_callback;
-    base::RunLoop child_callback;
-    parent_unit.SetPolicyClosure(parent_callback.QuitClosure());
-    child_unit.SetPolicyClosure(child_callback.QuitClosure());
-
-    // This event should force the policy to recalculated for all children.
-    mojom::EventPtr event = mojom::Event::New();
-    event->type = mojom::EventType::kTestEvent;
-    parent_unit.interface()->SendEvent(std::move(event));
-
-    parent_callback.Run();
-    child_callback.Run();
-  }
-}
-
-}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.cc b/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.cc
deleted file mode 100644
index 831d1124..0000000
--- a/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.cc
+++ /dev/null
@@ -1,53 +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/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/logging.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/resource_coordinator/coordination_unit/coordination_unit_impl.h"
-#include "services/service_manager/public/cpp/service_context_ref.h"
-
-namespace resource_coordinator {
-
-CoordinationUnitProviderImpl::CoordinationUnitProviderImpl(
-    service_manager::ServiceContextRefFactory* service_ref_factory)
-    : service_ref_factory_(service_ref_factory) {
-  DCHECK(service_ref_factory);
-  service_ref_ = service_ref_factory->CreateRef();
-}
-
-CoordinationUnitProviderImpl::~CoordinationUnitProviderImpl() = default;
-
-void CoordinationUnitProviderImpl::CreateCoordinationUnit(
-    mojom::CoordinationUnitRequest request,
-    const CoordinationUnitID& id) {
-  // TODO(oysteine): A strong binding here means the first binding set up
-  // to a CoordinationUnit via CoordinationUnitProvider, i.e. the authoritative
-  // one in terms of setting the context, has to outlive all of the other
-  // connections (as the rest are just duplicated and held within
-  // CoordinationUnit). Make sure this assumption is correct, or refactor into
-  // some kind of refcounted thing.
-
-  // Once there's a need for custom code for various types of CUs (tabs,
-  // processes, etc) then this could become a factory function and instantiate
-  // different subclasses of CoordinationUnitImpl based on the id.type.
-  mojo::MakeStrongBinding(base::MakeUnique<CoordinationUnitImpl>(
-                              id, service_ref_factory_->CreateRef()),
-                          std::move(request));
-};
-
-// static
-void CoordinationUnitProviderImpl::Create(
-    service_manager::ServiceContextRefFactory* service_ref_factory,
-    resource_coordinator::mojom::CoordinationUnitProviderRequest request) {
-  mojo::MakeStrongBinding(
-      base::MakeUnique<CoordinationUnitProviderImpl>(service_ref_factory),
-      std::move(request));
-}
-
-}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h b/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h
deleted file mode 100644
index 79d193c..0000000
--- a/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h
+++ /dev/null
@@ -1,45 +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_RESOURCE_COORDINATOR_COORDINATION_UNIT_COORDINATION_UNIT_PROVIDER_IMPL_H_
-#define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_COORDINATION_UNIT_PROVIDER_IMPL_H_
-
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom.h"
-
-namespace service_manager {
-
-class ServiceContextRefFactory;
-class ServiceContextRef;
-
-}  // service_manager
-
-namespace resource_coordinator {
-
-class CoordinationUnitProviderImpl : public mojom::CoordinationUnitProvider {
- public:
-  CoordinationUnitProviderImpl(
-      service_manager::ServiceContextRefFactory* service_ref_factory);
-  ~CoordinationUnitProviderImpl() override;
-
-  static void Create(
-      service_manager::ServiceContextRefFactory* service_ref_factory,
-      resource_coordinator::mojom::CoordinationUnitProviderRequest request);
-
-  // Overridden from mojom::CoordinationUnitProvider:
-  void CreateCoordinationUnit(
-      resource_coordinator::mojom::CoordinationUnitRequest request,
-      const CoordinationUnitID& id) override;
-
- private:
-  service_manager::ServiceContextRefFactory* service_ref_factory_;
-  std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
-
-  DISALLOW_COPY_AND_ASSIGN(CoordinationUnitProviderImpl);
-};
-
-}  // namespace resource_coordinator
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_COORDINATION_UNIT_PROVIDER_IMPL_H_
diff --git a/services/resource_coordinator/manifest.json b/services/resource_coordinator/manifest.json
deleted file mode 100644
index 87ce583..0000000
--- a/services/resource_coordinator/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "name": "resource_coordinator",
-  "display_name": "Global Resource Coordinator",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "coordination_unit": [ "resource_coordinator::mojom::CoordinationUnitProvider"],
-        "tests": [ "*" ]
-      },
-      "requires": {
-        "service_manager": [ "service_manager:all_users" ]
-      }
-    }
-  }
-}
diff --git a/services/resource_coordinator/public/cpp/BUILD.gn b/services/resource_coordinator/public/cpp/BUILD.gn
index c6b2753..50912f2a 100644
--- a/services/resource_coordinator/public/cpp/BUILD.gn
+++ b/services/resource_coordinator/public/cpp/BUILD.gn
@@ -4,17 +4,12 @@
 
 component("resource_coordinator_cpp") {
   sources = [
-    "coordination_unit_id.cc",
-    "coordination_unit_id.h",
-    "coordination_unit_types.h",
     "memory/coordinator.h",
     "memory/process_local_dump_manager_impl.cc",
     "memory/process_local_dump_manager_impl.h",
-    "resource_coordinator_interface.cc",
-    "resource_coordinator_interface.h",
   ]
 
-  defines = [ "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_IMPLEMENTATION" ]
+  defines = [ "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_IMPLEMENTATION" ]
 
   deps = [
     ":struct_traits",
@@ -25,7 +20,6 @@
     "//mojo/public/cpp/bindings",
     "//services/resource_coordinator/public/interfaces:interfaces_internal",
     "//services/service_manager/public/cpp",
-    "//third_party/smhasher:murmurhash2",
   ]
 
   allow_circular_includes_from = [ "//services/resource_coordinator/public/interfaces:interfaces_internal" ]
@@ -33,13 +27,11 @@
 
 source_set("struct_traits") {
   sources = [
-    "coordination_unit_struct_traits.cc",
-    "coordination_unit_struct_traits.h",
     "memory/memory_instrumentation_struct_traits.cc",
     "memory/memory_instrumentation_struct_traits.h",
   ]
 
-  defines = [ "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_IMPLEMENTATION" ]
+  defines = [ "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_IMPLEMENTATION" ]
 
   public_deps = [
     "//base",
diff --git a/services/resource_coordinator/public/cpp/OWNERS b/services/resource_coordinator/public/cpp/OWNERS
deleted file mode 100644
index 6847a943..0000000
--- a/services/resource_coordinator/public/cpp/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
-
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/services/resource_coordinator/public/cpp/coordination_unit.typemap b/services/resource_coordinator/public/cpp/coordination_unit.typemap
deleted file mode 100644
index eadf9d2c..0000000
--- a/services/resource_coordinator/public/cpp/coordination_unit.typemap
+++ /dev/null
@@ -1,19 +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.
-
-mojom =
-    "//services/resource_coordinator/public/interfaces/coordination_unit.mojom"
-
-public_headers = [
-  "//services/resource_coordinator/public/cpp/coordination_unit_id.h",
-  "//services/resource_coordinator/public/cpp/coordination_unit_types.h",
-]
-traits_headers = [ "//services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h" ]
-
-deps = []
-
-type_mappings = [
-  "resource_coordinator.mojom.CoordinationUnitType=::resource_coordinator::CoordinationUnitType",
-  "resource_coordinator.mojom.CoordinationUnitID=::resource_coordinator::CoordinationUnitID",
-]
diff --git a/services/resource_coordinator/public/cpp/coordination_unit_id.cc b/services/resource_coordinator/public/cpp/coordination_unit_id.cc
deleted file mode 100644
index 7c1ade6..0000000
--- a/services/resource_coordinator/public/cpp/coordination_unit_id.cc
+++ /dev/null
@@ -1,27 +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/resource_coordinator/public/cpp/coordination_unit_id.h"
-
-#include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
-#include "third_party/smhasher/src/MurmurHash2.h"
-
-namespace resource_coordinator {
-
-// The seed to use when taking the murmur2 hash of the id.
-const uint64_t kMurmur2HashSeed = 0;
-
-CoordinationUnitID::CoordinationUnitID()
-    : id(0), type(CoordinationUnitType::kInvalidType) {}
-
-CoordinationUnitID::CoordinationUnitID(const CoordinationUnitType& type,
-                                       const std::string& new_id)
-    : type(type) {
-  DCHECK(base::IsValueInRangeForNumericType<int>(new_id.size()));
-  id = MurmurHash64A(&new_id.front(), static_cast<int>(new_id.size()),
-                     kMurmur2HashSeed);
-}
-
-}  // resource_coordinator
diff --git a/services/resource_coordinator/public/cpp/coordination_unit_id.h b/services/resource_coordinator/public/cpp/coordination_unit_id.h
deleted file mode 100644
index 71e9612..0000000
--- a/services/resource_coordinator/public/cpp/coordination_unit_id.h
+++ /dev/null
@@ -1,44 +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_RESOURCE_COORDINATOR_PUBLIC_CPP_ID_H_
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_ID_H_
-
-#include <string>
-
-#include "services/resource_coordinator/public/cpp/coordination_unit_types.h"
-#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
-
-namespace resource_coordinator {
-
-// This is a native struct rather than a mojom struct as we eventually want
-// to annotate base::TaskRunner with CUs for cost attribution purses and
-// would like to move it to base/ as easily as possible at that point.
-struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT CoordinationUnitID {
-  CoordinationUnitID();
-  CoordinationUnitID(const CoordinationUnitType& type,
-                     const std::string& new_id);
-
-  bool operator==(const CoordinationUnitID& b) const {
-    return id == b.id && type == b.type;
-  }
-
-  int64_t id;
-  CoordinationUnitType type;
-};
-
-}  // resource_coordinator
-
-namespace std {
-
-template <>
-struct hash<resource_coordinator::CoordinationUnitID> {
-  uint64_t operator()(
-      const resource_coordinator::CoordinationUnitID& id) const {
-    return ((static_cast<uint64_t>(id.type)) << 32) | id.id;
-  }
-};
-
-}  // namespace std
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_ID_H_
diff --git a/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.cc b/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.cc
deleted file mode 100644
index e30343a..0000000
--- a/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.cc
+++ /dev/null
@@ -1,66 +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/resource_coordinator/public/cpp/coordination_unit_struct_traits.h"
-
-namespace mojo {
-
-// static
-resource_coordinator::mojom::CoordinationUnitType
-EnumTraits<resource_coordinator::mojom::CoordinationUnitType,
-           resource_coordinator::CoordinationUnitType>::
-    ToMojom(resource_coordinator::CoordinationUnitType type) {
-  switch (type) {
-    case resource_coordinator::CoordinationUnitType::kWebContents:
-      return resource_coordinator::mojom::CoordinationUnitType::kWebContents;
-    case resource_coordinator::CoordinationUnitType::kFrame:
-      return resource_coordinator::mojom::CoordinationUnitType::kFrame;
-    case resource_coordinator::CoordinationUnitType::kNavigation:
-      return resource_coordinator::mojom::CoordinationUnitType::kNavigation;
-    case resource_coordinator::CoordinationUnitType::kProcess:
-      return resource_coordinator::mojom::CoordinationUnitType::kProcess;
-    default:
-      NOTREACHED() << "Invalid type: " << static_cast<uint8_t>(type);
-      // This should not be reached. Just return a random value.
-      return resource_coordinator::mojom::CoordinationUnitType::kWebContents;
-  }
-}
-
-// static
-bool EnumTraits<resource_coordinator::mojom::CoordinationUnitType,
-                resource_coordinator::CoordinationUnitType>::
-    FromMojom(resource_coordinator::mojom::CoordinationUnitType input,
-              resource_coordinator::CoordinationUnitType* out) {
-  switch (input) {
-    case resource_coordinator::mojom::CoordinationUnitType::kWebContents:
-      *out = resource_coordinator::CoordinationUnitType::kWebContents;
-      break;
-    case resource_coordinator::mojom::CoordinationUnitType::kFrame:
-      *out = resource_coordinator::CoordinationUnitType::kFrame;
-      break;
-    case resource_coordinator::mojom::CoordinationUnitType::kNavigation:
-      *out = resource_coordinator::CoordinationUnitType::kNavigation;
-      break;
-    case resource_coordinator::mojom::CoordinationUnitType::kProcess:
-      *out = resource_coordinator::CoordinationUnitType::kProcess;
-      break;
-    default:
-      NOTREACHED() << "Invalid type: " << static_cast<uint8_t>(input);
-      return false;
-  }
-  return true;
-}
-
-// static
-bool StructTraits<resource_coordinator::mojom::CoordinationUnitIDDataView,
-                  resource_coordinator::CoordinationUnitID>::
-    Read(resource_coordinator::mojom::CoordinationUnitIDDataView input,
-         resource_coordinator::CoordinationUnitID* out) {
-  out->id = input.id();
-  if (!input.ReadType(&out->type))
-    return false;
-  return true;
-}
-
-}  // namespace mojo
diff --git a/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h b/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h
deleted file mode 100644
index 79e7614..0000000
--- a/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h
+++ /dev/null
@@ -1,39 +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_RESOURCE_COORDINATOR_PUBLIC_CPP_COORDINATION_UNIT_STRUCT_TRAITS_H_
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_COORDINATION_UNIT_STRUCT_TRAITS_H_
-
-#include "services/resource_coordinator/public/cpp/coordination_unit_types.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
-
-namespace mojo {
-
-template <>
-struct EnumTraits<resource_coordinator::mojom::CoordinationUnitType,
-                  resource_coordinator::CoordinationUnitType> {
-  static resource_coordinator::mojom::CoordinationUnitType ToMojom(
-      resource_coordinator::CoordinationUnitType type);
-  static bool FromMojom(resource_coordinator::mojom::CoordinationUnitType input,
-                        resource_coordinator::CoordinationUnitType* out);
-};
-
-template <>
-struct StructTraits<resource_coordinator::mojom::CoordinationUnitIDDataView,
-                    resource_coordinator::CoordinationUnitID> {
-  static uint64_t id(const resource_coordinator::CoordinationUnitID& id) {
-    return id.id;
-  }
-  static resource_coordinator::CoordinationUnitType type(
-      const resource_coordinator::CoordinationUnitID& id) {
-    return id.type;
-  }
-  static bool Read(
-      resource_coordinator::mojom::CoordinationUnitIDDataView input,
-      resource_coordinator::CoordinationUnitID* out);
-};
-
-}  // namespace mojo
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_COORDINATION_UNIT_STRUCT_TRAITS_H_
diff --git a/services/resource_coordinator/public/cpp/coordination_unit_types.h b/services/resource_coordinator/public/cpp/coordination_unit_types.h
deleted file mode 100644
index 9e1255d3..0000000
--- a/services/resource_coordinator/public/cpp/coordination_unit_types.h
+++ /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.
-#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_TYPES_H_
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_TYPES_H_
-
-#include <stdint.h>
-
-namespace resource_coordinator {
-
-// Any new type here needs to be mirrored between coordination_unit_types.h and
-// coordination_unit.mojom, and have mappings between the two defined in
-// coordination_unit_struct_traits.h/.cc
-enum class CoordinationUnitType : uint8_t {
-  kInvalidType,
-  kWebContents,
-  kFrame,
-  kNavigation,
-  kProcess,
-};
-
-}  // resource_coordinator
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_TYPES_H_
diff --git a/services/resource_coordinator/public/cpp/memory/memory_export.h b/services/resource_coordinator/public/cpp/memory/memory_export.h
new file mode 100644
index 0000000..d674a861
--- /dev/null
+++ b/services/resource_coordinator/public/cpp/memory/memory_export.h
@@ -0,0 +1,32 @@
+// 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_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_EXPORT_H_
+#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_IMPLEMENTATION)
+#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT \
+  __declspec(dllexport)
+#else
+#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT \
+  __declspec(dllimport)
+#endif  // defined(SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_IMPLEMENTATION)
+#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT \
+  __attribute__((visibility("default")))
+#else
+#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT
+#endif
+
+#endif  // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_EXPORT_H_
diff --git a/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.h b/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.h
index fdd9c7d..55d916b9 100644
--- a/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.h
+++ b/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.h
@@ -8,13 +8,13 @@
 #include "base/process/process_handle.h"
 #include "base/trace_event/memory_dump_request_args.h"
 #include "mojo/common/common_custom_types_struct_traits.h"
-#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
+#include "services/resource_coordinator/public/cpp/memory/memory_export.h"
 #include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h"
 
 namespace mojo {
 
 template <>
-struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
+struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT
     EnumTraits<memory_instrumentation::mojom::DumpType,
                base::trace_event::MemoryDumpType> {
   static memory_instrumentation::mojom::DumpType ToMojom(
@@ -24,7 +24,7 @@
 };
 
 template <>
-struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
+struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT
     EnumTraits<memory_instrumentation::mojom::LevelOfDetail,
                base::trace_event::MemoryDumpLevelOfDetail> {
   static memory_instrumentation::mojom::LevelOfDetail ToMojom(
@@ -34,7 +34,7 @@
 };
 
 template <>
-struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
+struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT
     StructTraits<memory_instrumentation::mojom::RequestArgsDataView,
                  base::trace_event::MemoryDumpRequestArgs> {
   static uint64_t dump_guid(
@@ -54,7 +54,7 @@
 };
 
 template <>
-struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
+struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT
     StructTraits<memory_instrumentation::mojom::ChromeMemDumpDataView,
                  base::trace_event::MemoryDumpCallbackResult::ChromeMemDump> {
   static uint32_t malloc_total_kb(
@@ -79,7 +79,7 @@
 };
 
 template <>
-struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
+struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT
     StructTraits<memory_instrumentation::mojom::OSMemDumpDataView,
                  base::trace_event::MemoryDumpCallbackResult::OSMemDump> {
   static uint32_t resident_set_kb(
@@ -91,7 +91,7 @@
 };
 
 template <>
-struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT StructTraits<
+struct SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT StructTraits<
     memory_instrumentation::mojom::MemoryDumpCallbackResultDataView,
     base::trace_event::MemoryDumpCallbackResult> {
   static base::trace_event::MemoryDumpCallbackResult::OSMemDump os_dump(
diff --git a/services/resource_coordinator/public/cpp/memory/process_local_dump_manager_impl.h b/services/resource_coordinator/public/cpp/memory/process_local_dump_manager_impl.h
index 5647e454..8cd4f4f7b 100644
--- a/services/resource_coordinator/public/cpp/memory/process_local_dump_manager_impl.h
+++ b/services/resource_coordinator/public/cpp/memory/process_local_dump_manager_impl.h
@@ -12,7 +12,7 @@
 #include "base/trace_event/memory_dump_request_args.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/resource_coordinator/public/cpp/memory/coordinator.h"
-#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
+#include "services/resource_coordinator/public/cpp/memory/memory_export.h"
 #include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 
@@ -26,11 +26,11 @@
 // no Coordinator service in child processes. So, in a child process, the
 // local dump manager remotely connects to the Coordinator service. In the
 // browser process, it locally connects to the Coordinator service.
-class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
+class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT
     ProcessLocalDumpManagerImpl
     : public NON_EXPORTED_BASE(mojom::ProcessLocalDumpManager) {
  public:
-  class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT Config {
+  class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT Config {
    public:
     Config(service_manager::Connector* connector,
            const std::string& service_name)
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_export.h b/services/resource_coordinator/public/cpp/resource_coordinator_export.h
deleted file mode 100644
index c271f97..0000000
--- a/services/resource_coordinator/public/cpp/resource_coordinator_export.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_RESOURCE_COORDINATOR_EXPORT_H_
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_RESOURCE_COORDINATOR_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_IMPLEMENTATION)
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT __declspec(dllexport)
-#else
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT __declspec(dllimport)
-#endif  // defined(SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_IMPLEMENTATION)
-
-#else  // defined(WIN32)
-#if defined(SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_IMPLEMENTATION)
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT \
-  __attribute__((visibility("default")))
-#else
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
-#endif
-#endif
-
-#else  // defined(COMPONENT_BUILD)
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
-#endif
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_RESOURCE_COORDINATOR_EXPORT_H_
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_interface.cc b/services/resource_coordinator/public/cpp/resource_coordinator_interface.cc
deleted file mode 100644
index 7e25a5c..0000000
--- a/services/resource_coordinator/public/cpp/resource_coordinator_interface.cc
+++ /dev/null
@@ -1,80 +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/resource_coordinator/public/cpp/resource_coordinator_interface.h"
-
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom.h"
-#include "services/resource_coordinator/public/interfaces/service_constants.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
-
-namespace {
-
-void OnConnectionError() {
-  DCHECK(false);
-}
-
-}  // namespace
-
-namespace resource_coordinator {
-
-ResourceCoordinatorInterface::ResourceCoordinatorInterface(
-    service_manager::Connector* connector,
-    const CoordinationUnitType& type)
-    : weak_ptr_factory_(this) {
-  ConnectToService(connector, type, std::string());
-}
-
-ResourceCoordinatorInterface::ResourceCoordinatorInterface(
-    service_manager::Connector* connector,
-    const CoordinationUnitType& type,
-    const std::string& id)
-    : weak_ptr_factory_(this) {
-  ConnectToService(connector, type, id);
-}
-
-ResourceCoordinatorInterface::~ResourceCoordinatorInterface() = default;
-
-void ResourceCoordinatorInterface::ConnectToService(
-    service_manager::Connector* connector,
-    const CoordinationUnitType& type,
-    const std::string& id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(connector);
-  mojom::CoordinationUnitProviderPtr provider;
-  connector->BindInterface(mojom::kServiceName, mojo::MakeRequest(&provider));
-
-  CoordinationUnitID new_cu_id(type, id);
-
-  provider->CreateCoordinationUnit(mojo::MakeRequest(&service_), new_cu_id);
-
-  service_.set_connection_error_handler(base::Bind(&OnConnectionError));
-}
-
-void ResourceCoordinatorInterface::SendEvent(
-    const mojom::EventType& event_type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  mojom::EventPtr event = mojom::Event::New();
-  event->type = event_type;
-
-  service_->SendEvent(std::move(event));
-}
-
-void ResourceCoordinatorInterface::AddChild(
-    const ResourceCoordinatorInterface& child) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(service_);
-  // We could keep the ID around ourselves, but this hop ensures that the child
-  // has been created on the service-side.
-  child.service()->GetID(base::Bind(&ResourceCoordinatorInterface::AddChildByID,
-                                    weak_ptr_factory_.GetWeakPtr()));
-}
-
-void ResourceCoordinatorInterface::AddChildByID(
-    const CoordinationUnitID& child_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  service_->AddChild(child_id);
-}
-
-}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_interface.h b/services/resource_coordinator/public/cpp/resource_coordinator_interface.h
deleted file mode 100644
index 95d6748..0000000
--- a/services/resource_coordinator/public/cpp/resource_coordinator_interface.h
+++ /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.
-
-#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_RESOURCE_COORDINATOR_INTERFACE_H_
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_RESOURCE_COORDINATOR_INTERFACE_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
-
-namespace service_manager {
-class Connector;
-}
-
-namespace resource_coordinator {
-
-using EventType = mojom::EventType;
-
-class ResourceCoordinatorInterface {
- public:
-  ResourceCoordinatorInterface(service_manager::Connector* connector,
-                               const CoordinationUnitType& type);
-  ResourceCoordinatorInterface(service_manager::Connector* connector,
-                               const CoordinationUnitType& type,
-                               const std::string& id);
-  ~ResourceCoordinatorInterface();
-
-  const mojom::CoordinationUnitPtr& service() const { return service_; }
-
-  void SendEvent(const mojom::EventType& event_type);
-  void AddChild(const ResourceCoordinatorInterface& child);
-
- private:
-  void ConnectToService(service_manager::Connector* connector,
-                        const CoordinationUnitType& type,
-                        const std::string& id);
-  void AddChildByID(const CoordinationUnitID& child_id);
-
-  mojom::CoordinationUnitPtr service_;
-
-  base::ThreadChecker thread_checker_;
-
-  // The WeakPtrFactory should come last so the weak ptrs are invalidated
-  // before the rest of the member variables.
-  base::WeakPtrFactory<ResourceCoordinatorInterface> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ResourceCoordinatorInterface);
-};
-
-}  // namespace resource_coordinator
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_RESOURCE_COORDINATOR_INTERFACE_H_
diff --git a/services/resource_coordinator/public/cpp/typemaps.gni b/services/resource_coordinator/public/cpp/typemaps.gni
index 24b1483..a1a0793 100644
--- a/services/resource_coordinator/public/cpp/typemaps.gni
+++ b/services/resource_coordinator/public/cpp/typemaps.gni
@@ -2,7 +2,4 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-typemaps = [
-  "//services/resource_coordinator/public/cpp/memory/memory_instrumentation.typemap",
-  "//services/resource_coordinator/public/cpp/coordination_unit.typemap",
-]
+typemaps = [ "//services/resource_coordinator/public/cpp/memory/memory_instrumentation.typemap" ]
diff --git a/services/resource_coordinator/public/interfaces/BUILD.gn b/services/resource_coordinator/public/interfaces/BUILD.gn
index 7d20f8f..8560b05 100644
--- a/services/resource_coordinator/public/interfaces/BUILD.gn
+++ b/services/resource_coordinator/public/interfaces/BUILD.gn
@@ -8,12 +8,8 @@
   visibility = [ "//services/resource_coordinator/public/cpp:*" ]
 
   sources = [
-    "coordination_unit.mojom",
-    "coordination_unit_provider.mojom",
-    "events.mojom",
     "memory/constants.mojom",
     "memory/memory_instrumentation.mojom",
-    "service_constants.mojom",
     "tracing/tracing.mojom",
   ]
 
@@ -21,8 +17,10 @@
     "//mojo/common:common_custom_types",
   ]
 
-  export_class_attribute = "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT"
-  export_define = "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_IMPLEMENTATION=1"
+  export_class_attribute =
+      "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_EXPORT"
+  export_define =
+      "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_IMPLEMENTATION=1"
   export_header =
-      "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
+      "services/resource_coordinator/public/cpp/memory/memory_export.h"
 }
diff --git a/services/resource_coordinator/public/interfaces/coordination_unit.mojom b/services/resource_coordinator/public/interfaces/coordination_unit.mojom
deleted file mode 100644
index c8c35aa..0000000
--- a/services/resource_coordinator/public/interfaces/coordination_unit.mojom
+++ /dev/null
@@ -1,45 +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.
-
-module resource_coordinator.mojom;
-
-import "events.mojom";
-
-// Any new type here needs to be mirrored between coordination_unit_types.h and
-// coordination_unit.mojom, and have mappings between the two defined in
-// coordination_unit_struct_traits.h/.cc (see comment in coordination_unit_id.h).
-enum CoordinationUnitType {
-  kWebContents,
-  kFrame,
-  kNavigation,
-  kProcess,
-};
-
-struct CoordinationUnitID {
-  CoordinationUnitType type;
-  int64 id;
-};
-
-struct CoordinationPolicy {
-  bool use_background_priority;
-};
-
-interface CoordinationPolicyCallback {
-  SetCoordinationPolicy(CoordinationPolicy policy);
-};
-
-interface CoordinationUnit {
-  SendEvent(Event event);
-
-  // Mainly used to force a round-trip to the service over the pipe for
-  // a specific unit, so we don't have to deal with possibly-not-yet-created
-  // children in AddChild()
-  GetID() => (CoordinationUnitID id);
-
-  Duplicate(CoordinationUnit& request);
-  // child_id must represent a CU which already exists service-side,
-  // and can't be a direct ascendent or descendent of the current unit.
-  AddChild(CoordinationUnitID child_id);
-  SetCoordinationPolicyCallback(CoordinationPolicyCallback callback);
-};
diff --git a/services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom b/services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom
deleted file mode 100644
index 59c4451..0000000
--- a/services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom
+++ /dev/null
@@ -1,11 +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.
-
-module resource_coordinator.mojom;
-
-import "coordination_unit.mojom";
-
-interface CoordinationUnitProvider {
-  CreateCoordinationUnit(CoordinationUnit& request, CoordinationUnitID id);
-};
diff --git a/services/resource_coordinator/public/interfaces/events.mojom b/services/resource_coordinator/public/interfaces/events.mojom
deleted file mode 100644
index 9a0edd4..0000000
--- a/services/resource_coordinator/public/interfaces/events.mojom
+++ /dev/null
@@ -1,19 +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.
-
-module resource_coordinator.mojom;
-
-enum EventType {
-  kTestEvent,
-  kOnNavigationCommit,
-  kOnWebContentsShown,
-  kOnWebContentsHidden,
-  kOnRendererFrameCreated,
-  kOnProcessAudioStarted,
-  kOnProcessAudioStopped,
-};
-
-struct Event {
-  EventType type;
-};
diff --git a/services/resource_coordinator/public/interfaces/service_constants.mojom b/services/resource_coordinator/public/interfaces/service_constants.mojom
deleted file mode 100644
index 92df94e..0000000
--- a/services/resource_coordinator/public/interfaces/service_constants.mojom
+++ /dev/null
@@ -1,7 +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.
-
-module resource_coordinator.mojom;
-
-const string kServiceName = "resource_coordinator";
diff --git a/services/resource_coordinator/resource_coordinator_service.cc b/services/resource_coordinator/resource_coordinator_service.cc
deleted file mode 100644
index 5e93b33..0000000
--- a/services/resource_coordinator/resource_coordinator_service.cc
+++ /dev/null
@@ -1,39 +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/resource_coordinator/resource_coordinator_service.h"
-
-#include "base/macros.h"
-#include "services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h"
-#include "services/service_manager/public/cpp/service_context.h"
-
-namespace resource_coordinator {
-
-std::unique_ptr<service_manager::Service> ResourceCoordinatorService::Create() {
-  return base::MakeUnique<ResourceCoordinatorService>();
-}
-
-ResourceCoordinatorService::ResourceCoordinatorService()
-    : weak_factory_(this) {}
-
-ResourceCoordinatorService::~ResourceCoordinatorService() = default;
-
-void ResourceCoordinatorService::OnStart() {
-  ref_factory_.reset(new service_manager::ServiceContextRefFactory(
-      base::Bind(&service_manager::ServiceContext::RequestQuit,
-                 base::Unretained(context()))));
-
-  registry_.AddInterface(base::Bind(&CoordinationUnitProviderImpl::Create,
-                                    base::Unretained(ref_factory_.get())));
-}
-
-void ResourceCoordinatorService::OnBindInterface(
-    const service_manager::ServiceInfo& source_info,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  registry_.BindInterface(source_info.identity, interface_name,
-                          std::move(interface_pipe));
-}
-
-}  // namespace speed
diff --git a/services/resource_coordinator/resource_coordinator_service.h b/services/resource_coordinator/resource_coordinator_service.h
deleted file mode 100644
index 4750a68..0000000
--- a/services/resource_coordinator/resource_coordinator_service.h
+++ /dev/null
@@ -1,47 +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_SPEED_SPEED_SERVICE_H_
-#define SERVICES_SPEED_SPEED_SERVICE_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_context_ref.h"
-
-namespace resource_coordinator {
-
-class ResourceCoordinatorService : public service_manager::Service {
- public:
-  ResourceCoordinatorService();
-  ~ResourceCoordinatorService() override;
-
-  // service_manager::Service:
-  // Factory function for use as an embedded service.
-  static std::unique_ptr<service_manager::Service> Create();
-
-  // service_manager::Service:
-  void OnStart() override;
-  void OnBindInterface(const service_manager::ServiceInfo& source_info,
-                       const std::string& interface_name,
-                       mojo::ScopedMessagePipeHandle interface_pipe) override;
-
- private:
-  service_manager::BinderRegistry registry_;
-  std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
-
-  // WeakPtrFactory members should always come last so WeakPtrs are destructed
-  // before other members.
-  base::WeakPtrFactory<ResourceCoordinatorService> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ResourceCoordinatorService);
-};
-
-}  // namespace resource_coordinator
-
-#endif  // SERVICES_SPEED_SPEED_SERVICE_H_
diff --git a/services/resource_coordinator/resource_coordinator_service_unittest.cc b/services/resource_coordinator/resource_coordinator_service_unittest.cc
deleted file mode 100644
index fd17c20..0000000
--- a/services/resource_coordinator/resource_coordinator_service_unittest.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom.h"
-#include "services/resource_coordinator/public/interfaces/service_constants.mojom.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_test.h"
-
-namespace resource_coordinator {
-
-class ResourceCoordinatorTest : public service_manager::test::ServiceTest,
-                                public mojom::CoordinationPolicyCallback {
- public:
-  ResourceCoordinatorTest()
-      : service_manager::test::ServiceTest("resource_coordinator_unittests"),
-        binding_(this) {}
-  ~ResourceCoordinatorTest() override {}
-
- protected:
-  void SetUp() override {
-    service_manager::test::ServiceTest::SetUp();
-    connector()->StartService(mojom::kServiceName);
-  }
-
-  mojom::CoordinationPolicyCallbackPtr GetPolicyCallback() {
-    return binding_.CreateInterfacePtrAndBind();
-  }
-
-  void QuitOnPolicyCallback(base::RunLoop* loop) { loop_ = loop; }
-
- private:
-  // mojom::CoordinationPolicyCallback:
-  void SetCoordinationPolicy(
-      resource_coordinator::mojom::CoordinationPolicyPtr policy) override {
-    loop_->Quit();
-  }
-
-  mojo::Binding<mojom::CoordinationPolicyCallback> binding_;
-  base::RunLoop* loop_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(ResourceCoordinatorTest);
-};
-
-TEST_F(ResourceCoordinatorTest, ResourceCoordinatorInstantiate) {
-  mojom::CoordinationUnitProviderPtr provider;
-  connector()->BindInterface(mojom::kServiceName, mojo::MakeRequest(&provider));
-
-  CoordinationUnitID new_id(CoordinationUnitType::kWebContents, "test_id");
-  mojom::CoordinationUnitPtr coordination_unit;
-  provider->CreateCoordinationUnit(mojo::MakeRequest(&coordination_unit),
-                                   new_id);
-
-  coordination_unit->SetCoordinationPolicyCallback(GetPolicyCallback());
-
-  base::RunLoop loop;
-  QuitOnPolicyCallback(&loop);
-  loop.Run();
-}
-
-}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/service_main.cc b/services/resource_coordinator/service_main.cc
deleted file mode 100644
index 323eea8..0000000
--- a/services/resource_coordinator/service_main.cc
+++ /dev/null
@@ -1,13 +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/resource_coordinator/resource_coordinator_service.h"
-#include "services/service_manager/public/c/main.h"
-#include "services/service_manager/public/cpp/service_runner.h"
-
-MojoResult ServiceMain(MojoHandle service_request_handle) {
-  return service_manager::ServiceRunner(
-             new resource_coordinator::ResourceCoordinatorService())
-      .Run(service_request_handle);
-}
diff --git a/services/resource_coordinator/unittest_manifest.json b/services/resource_coordinator/unittest_manifest.json
deleted file mode 100644
index 281fa86..0000000
--- a/services/resource_coordinator/unittest_manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "name": "resource_coordinator_unittests",
-  "display_name": "Resource Coordinator Unittests",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "requires": {
-        "resource_coordinator": [ "tests" ]
-      }
-    }
-  }
-}
diff --git a/services/video_capture/BUILD.gn b/services/video_capture/BUILD.gn
index 1fc606e..02aa7f8 100644
--- a/services/video_capture/BUILD.gn
+++ b/services/video_capture/BUILD.gn
@@ -31,6 +31,10 @@
     "device_factory_media_to_mojo_adapter.h",
     "device_media_to_mojo_adapter.cc",
     "device_media_to_mojo_adapter.h",
+    "public/cpp/device_to_feedback_observer_adapter.cc",
+    "public/cpp/device_to_feedback_observer_adapter.h",
+    "public/cpp/receiver_media_to_mojo_adapter.cc",
+    "public/cpp/receiver_media_to_mojo_adapter.h",
     "receiver_mojo_to_media_adapter.cc",
     "receiver_mojo_to_media_adapter.h",
   ]
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.cc b/services/video_capture/device_factory_media_to_mojo_adapter.cc
index 07f6db53..12b3a00 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -15,6 +15,54 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/video_capture/device_media_to_mojo_adapter.h"
 
+namespace {
+
+// Translates a set of device infos reported by a VideoCaptureSystem to a set
+// of device infos that the video capture service exposes to its client.
+// The Video Capture Service instances of VideoCaptureDeviceClient to
+// convert the formats provided by the VideoCaptureDevice instances. Here, we
+// translate the set of supported formats as reported by the |device_factory_|
+// to what will be output by the VideoCaptureDeviceClient we connect to it.
+// TODO(chfremer): A cleaner design would be to have this translation
+// happen in VideoCaptureDeviceClient, and talk only to VideoCaptureDeviceClient
+// instead of VideoCaptureSystem.
+static void TranslateDeviceInfos(
+    const video_capture::mojom::DeviceFactory::GetDeviceInfosCallback& callback,
+    const std::vector<media::VideoCaptureDeviceInfo>& device_infos) {
+  std::vector<media::VideoCaptureDeviceInfo> translated_device_infos;
+  for (const auto& device_info : device_infos) {
+    media::VideoCaptureDeviceInfo translated_device_info;
+    translated_device_info.descriptor = device_info.descriptor;
+    for (const auto& format : device_info.supported_formats) {
+      media::VideoCaptureFormat translated_format;
+      switch (format.pixel_format) {
+        case media::PIXEL_FORMAT_I420:
+        case media::PIXEL_FORMAT_MJPEG:
+          translated_format.pixel_format = media::PIXEL_FORMAT_I420;
+          break;
+        case media::PIXEL_FORMAT_Y16:
+          translated_format.pixel_format = media::PIXEL_FORMAT_Y16;
+        default:
+          // Any other format cannot be consumed by VideoCaptureDeviceClient.
+          continue;
+      }
+      translated_format.frame_size = format.frame_size;
+      translated_format.frame_rate = format.frame_rate;
+      translated_format.pixel_storage = media::PIXEL_STORAGE_CPU;
+      if (base::ContainsValue(translated_device_info.supported_formats,
+                              translated_format))
+        continue;
+      translated_device_info.supported_formats.push_back(translated_format);
+    }
+    if (translated_device_info.supported_formats.empty())
+      continue;
+    translated_device_infos.push_back(translated_device_info);
+  }
+  callback.Run(translated_device_infos);
+}
+
+}  // anonymous namespace
+
 namespace video_capture {
 
 DeviceFactoryMediaToMojoAdapter::ActiveDeviceEntry::ActiveDeviceEntry() =
@@ -31,17 +79,18 @@
     DeviceFactoryMediaToMojoAdapter::ActiveDeviceEntry&& other) = default;
 
 DeviceFactoryMediaToMojoAdapter::DeviceFactoryMediaToMojoAdapter(
-    std::unique_ptr<media::VideoCaptureDeviceFactory> device_factory,
+    std::unique_ptr<media::VideoCaptureSystem> capture_system,
     const media::VideoCaptureJpegDecoderFactoryCB&
         jpeg_decoder_factory_callback)
-    : device_factory_(std::move(device_factory)),
+    : capture_system_(std::move(capture_system)),
       jpeg_decoder_factory_callback_(jpeg_decoder_factory_callback) {}
 
 DeviceFactoryMediaToMojoAdapter::~DeviceFactoryMediaToMojoAdapter() = default;
 
 void DeviceFactoryMediaToMojoAdapter::GetDeviceInfos(
     const GetDeviceInfosCallback& callback) {
-  NOTIMPLEMENTED();
+  capture_system_->GetDeviceInfosAsync(
+      base::Bind(&TranslateDeviceInfos, callback));
 }
 
 void DeviceFactoryMediaToMojoAdapter::CreateDevice(
@@ -63,14 +112,8 @@
     return;
   }
 
-  // Create device
-  media::VideoCaptureDeviceDescriptor descriptor;
-  if (LookupDescriptorFromId(device_id, &descriptor) == false) {
-    callback.Run(mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND);
-    return;
-  }
   std::unique_ptr<media::VideoCaptureDevice> media_device =
-      device_factory_->CreateDevice(descriptor);
+      capture_system_->CreateDevice(device_id);
   if (media_device == nullptr) {
     callback.Run(mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND);
     return;
@@ -96,20 +139,4 @@
   active_devices_by_id_.erase(device_id);
 }
 
-bool DeviceFactoryMediaToMojoAdapter::LookupDescriptorFromId(
-    const std::string& device_id,
-    media::VideoCaptureDeviceDescriptor* descriptor) {
-  media::VideoCaptureDeviceDescriptors descriptors;
-  device_factory_->GetDeviceDescriptors(&descriptors);
-  auto descriptor_iter = std::find_if(
-      descriptors.begin(), descriptors.end(),
-      [&device_id](const media::VideoCaptureDeviceDescriptor& descriptor) {
-        return descriptor.device_id == device_id;
-      });
-  if (descriptor_iter == descriptors.end())
-    return false;
-  *descriptor = *descriptor_iter;
-  return true;
-}
-
 }  // namespace video_capture
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.h b/services/video_capture/device_factory_media_to_mojo_adapter.h
index 1eb16054..6c10ff70 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.h
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -8,7 +8,7 @@
 #include <map>
 
 #include "media/capture/video/video_capture_device_client.h"
-#include "media/capture/video/video_capture_device_factory.h"
+#include "media/capture/video/video_capture_system.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/video_capture/public/interfaces/device_factory.mojom.h"
 
@@ -16,15 +16,14 @@
 
 class DeviceMediaToMojoAdapter;
 
-// Wraps a media::VideoCaptureDeviceFactory and exposes its functionality
-// through the mojom::DeviceFactory interface.
-// Keeps track of device instances that have been created to ensure that
-// it does not create more than one instance of the same
-// media::VideoCaptureDevice at the same time.
+// Wraps a media::VideoCaptureSystem and exposes its functionality through the
+// mojom::DeviceFactory interface. Keeps track of device instances that have
+// been created to ensure that it does not create more than one instance of the
+// same media::VideoCaptureDevice at the same time.
 class DeviceFactoryMediaToMojoAdapter : public mojom::DeviceFactory {
  public:
   DeviceFactoryMediaToMojoAdapter(
-      std::unique_ptr<media::VideoCaptureDeviceFactory> device_factory,
+      std::unique_ptr<media::VideoCaptureSystem> capture_system,
       const media::VideoCaptureJpegDecoderFactoryCB&
           jpeg_decoder_factory_callback);
   ~DeviceFactoryMediaToMojoAdapter() override;
@@ -51,11 +50,7 @@
 
   void OnClientConnectionErrorOrClose(const std::string& device_id);
 
-  // Returns false if no descriptor found.
-  bool LookupDescriptorFromId(const std::string& device_id,
-                              media::VideoCaptureDeviceDescriptor* descriptor);
-
-  const std::unique_ptr<media::VideoCaptureDeviceFactory> device_factory_;
+  const std::unique_ptr<media::VideoCaptureSystem> capture_system_;
   const media::VideoCaptureJpegDecoderFactoryCB jpeg_decoder_factory_callback_;
   std::map<std::string, ActiveDeviceEntry> active_devices_by_id_;
 };
diff --git a/services/video_capture/device_media_to_mojo_adapter.cc b/services/video_capture/device_media_to_mojo_adapter.cc
index a68c87f..ea7656a 100644
--- a/services/video_capture/device_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_media_to_mojo_adapter.cc
@@ -11,6 +11,14 @@
 #include "media/capture/video/video_capture_jpeg_decoder.h"
 #include "services/video_capture/receiver_mojo_to_media_adapter.h"
 
+namespace {
+
+// The maximum number of video frame buffers in-flight at any one time.
+// If all buffers are still in use by consumers when new frames are produced
+// those frames get dropped.
+static const int kMaxBufferCount = 3;
+}
+
 namespace video_capture {
 
 DeviceMediaToMojoAdapter::DeviceMediaToMojoAdapter(
@@ -22,7 +30,8 @@
       device_running_(false) {}
 
 DeviceMediaToMojoAdapter::~DeviceMediaToMojoAdapter() {
-  Stop();
+  if (device_running_)
+    device_->StopAndDeAllocate();
 }
 
 void DeviceMediaToMojoAdapter::Start(
@@ -36,12 +45,11 @@
       base::MakeUnique<ReceiverMojoToMediaAdapter>(std::move(receiver));
 
   // Create a dedicated buffer pool for the device usage session.
-  const int kMaxBufferCount = 2;
   auto buffer_tracker_factory =
       base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>();
   scoped_refptr<media::VideoCaptureBufferPool> buffer_pool(
       new media::VideoCaptureBufferPoolImpl(std::move(buffer_tracker_factory),
-                                            kMaxBufferCount));
+                                            max_buffer_pool_buffer_count()));
 
   auto device_client = base::MakeUnique<media::VideoCaptureDeviceClient>(
       std::move(media_receiver), buffer_pool, jpeg_decoder_factory_callback_);
@@ -50,15 +58,26 @@
   device_running_ = true;
 }
 
+void DeviceMediaToMojoAdapter::OnReceiverReportingUtilization(
+    int32_t frame_feedback_id,
+    double utilization) {
+  device_->OnUtilizationReport(frame_feedback_id, utilization);
+}
+
 void DeviceMediaToMojoAdapter::Stop() {
   if (device_running_ == false)
     return;
-  device_->StopAndDeAllocate();
   device_running_ = false;
+  device_->StopAndDeAllocate();
 }
 
 void DeviceMediaToMojoAdapter::OnClientConnectionErrorOrClose() {
   Stop();
 }
 
+// static
+int DeviceMediaToMojoAdapter::max_buffer_pool_buffer_count() {
+  return kMaxBufferCount;
+}
+
 }  // namespace video_capture
diff --git a/services/video_capture/device_media_to_mojo_adapter.h b/services/video_capture/device_media_to_mojo_adapter.h
index dd3a712..e09e9c0 100644
--- a/services/video_capture/device_media_to_mojo_adapter.h
+++ b/services/video_capture/device_media_to_mojo_adapter.h
@@ -24,11 +24,17 @@
   // mojom::Device:
   void Start(const media::VideoCaptureParams& requested_settings,
              mojom::ReceiverPtr receiver) override;
+  void OnReceiverReportingUtilization(int32_t frame_feedback_id,
+                                      double utilization) override;
 
   void Stop();
 
   void OnClientConnectionErrorOrClose();
 
+  // Returns the fixed maximum number of buffers passed to the constructor
+  // of VideoCaptureBufferPoolImpl.
+  static int max_buffer_pool_buffer_count();
+
  private:
   const std::unique_ptr<media::VideoCaptureDevice> device_;
   media::VideoCaptureJpegDecoderFactoryCB jpeg_decoder_factory_callback_;
diff --git a/services/video_capture/public/cpp/device_to_feedback_observer_adapter.cc b/services/video_capture/public/cpp/device_to_feedback_observer_adapter.cc
new file mode 100644
index 0000000..ad842a7
--- /dev/null
+++ b/services/video_capture/public/cpp/device_to_feedback_observer_adapter.cc
@@ -0,0 +1,20 @@
+// 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 "services/video_capture/public/cpp/device_to_feedback_observer_adapter.h"
+
+namespace video_capture {
+
+DeviceToFeedbackObserverAdapter::DeviceToFeedbackObserverAdapter(
+    mojom::DevicePtr device)
+    : device_(std::move(device)) {}
+
+DeviceToFeedbackObserverAdapter::~DeviceToFeedbackObserverAdapter() = default;
+
+void DeviceToFeedbackObserverAdapter::OnUtilizationReport(int frame_feedback_id,
+                                                          double utilization) {
+  device_->OnReceiverReportingUtilization(frame_feedback_id, utilization);
+}
+
+}  // namespace video_capture
diff --git a/services/video_capture/public/cpp/device_to_feedback_observer_adapter.h b/services/video_capture/public/cpp/device_to_feedback_observer_adapter.h
new file mode 100644
index 0000000..b35dab0
--- /dev/null
+++ b/services/video_capture/public/cpp/device_to_feedback_observer_adapter.h
@@ -0,0 +1,30 @@
+// 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 SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_DEVICE_TO_FEEDBACK_OBSERVER_ADAPTER_H_
+#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_DEVICE_TO_FEEDBACK_OBSERVER_ADAPTER_H_
+
+#include "media/capture/video/video_capture_device.h"
+#include "services/video_capture/public/interfaces/device.mojom.h"
+
+namespace video_capture {
+
+// Adapter that allows a video_capture::mojom::Device to be used in place of
+// a media::VideoFrameConsumerFeedbackObserver
+class DeviceToFeedbackObserverAdapter
+    : public media::VideoFrameConsumerFeedbackObserver {
+ public:
+  DeviceToFeedbackObserverAdapter(mojom::DevicePtr device);
+  ~DeviceToFeedbackObserverAdapter() override;
+
+  // media::VideoFrameConsumerFeedbackObserver:
+  void OnUtilizationReport(int frame_feedback_id, double utilization) override;
+
+ private:
+  mojom::DevicePtr device_;
+};
+
+}  // namespace video_capture
+
+#endif  // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_DEVICE_TO_FEEDBACK_OBSERVER_ADAPTER_H_
diff --git a/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.cc b/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.cc
new file mode 100644
index 0000000..7b65bd4
--- /dev/null
+++ b/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.cc
@@ -0,0 +1,112 @@
+// 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 "services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h"
+
+#include "media/capture/video/shared_memory_buffer_tracker.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace {
+
+class MojoBufferHandleProvider
+    : public media::VideoCaptureDevice::Client::Buffer::HandleProvider {
+ public:
+  MojoBufferHandleProvider(mojo::ScopedSharedBufferHandle buffer_handle)
+      : buffer_handle_(std::move(buffer_handle)) {}
+
+  // Implementation of Buffer::HandleProvider:
+  mojo::ScopedSharedBufferHandle GetHandleForInterProcessTransit() override {
+    return buffer_handle_->Clone();
+  }
+  base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC()
+      override {
+    LazyUnwrapHandleAndMapMemory();
+    return shared_memory_->handle();
+  }
+  std::unique_ptr<media::VideoCaptureBufferHandle> GetHandleForInProcessAccess()
+      override {
+    LazyUnwrapHandleAndMapMemory();
+    return base::MakeUnique<media::SharedMemoryBufferHandle>(
+        &shared_memory_.value(), memory_size_);
+  }
+
+ private:
+  void LazyUnwrapHandleAndMapMemory() {
+    if (shared_memory_.has_value())
+      return;  // already done before
+
+    base::SharedMemoryHandle memory_handle;
+    const MojoResult result =
+        mojo::UnwrapSharedMemoryHandle(buffer_handle_->Clone(), &memory_handle,
+                                       &memory_size_, &read_only_flag_);
+    DCHECK_EQ(MOJO_RESULT_OK, result);
+    DCHECK_GT(memory_size_, 0u);
+
+    shared_memory_.emplace(memory_handle, read_only_flag_);
+    if (!shared_memory_->Map(memory_size_)) {
+      DLOG(ERROR) << "LazyUnwrapHandleAndMapMemory: Map failed.";
+    }
+  }
+
+  mojo::ScopedSharedBufferHandle buffer_handle_;
+  base::Optional<base::SharedMemory> shared_memory_;
+  size_t memory_size_ = 0;
+  bool read_only_flag_ = false;
+};
+
+class ScopedAccessPermissionMojoToMediaAdapter
+    : public media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission {
+ public:
+  ScopedAccessPermissionMojoToMediaAdapter(
+      video_capture::mojom::ScopedAccessPermissionPtr access_permission)
+      : access_permission_(std::move(access_permission)) {}
+
+ private:
+  video_capture::mojom::ScopedAccessPermissionPtr access_permission_;
+};
+
+}  // anonymous namespace
+
+namespace video_capture {
+
+ReceiverMediaToMojoAdapter::ReceiverMediaToMojoAdapter(
+    std::unique_ptr<media::VideoFrameReceiver> receiver)
+    : receiver_(std::move(receiver)) {}
+
+ReceiverMediaToMojoAdapter::~ReceiverMediaToMojoAdapter() = default;
+
+void ReceiverMediaToMojoAdapter::OnNewBufferHandle(
+    int32_t buffer_id,
+    mojo::ScopedSharedBufferHandle buffer_handle) {
+  receiver_->OnNewBufferHandle(
+      buffer_id,
+      base::MakeUnique<MojoBufferHandleProvider>(std::move(buffer_handle)));
+}
+
+void ReceiverMediaToMojoAdapter::OnFrameReadyInBuffer(
+    int32_t buffer_id,
+    int32_t frame_feedback_id,
+    mojom::ScopedAccessPermissionPtr access_permission,
+    media::mojom::VideoFrameInfoPtr frame_info) {
+  receiver_->OnFrameReadyInBuffer(
+      buffer_id, frame_feedback_id,
+      base::MakeUnique<ScopedAccessPermissionMojoToMediaAdapter>(
+          std::move(access_permission)),
+      std::move(frame_info));
+}
+
+void ReceiverMediaToMojoAdapter::OnBufferRetired(int32_t buffer_id) {
+  receiver_->OnBufferRetired(buffer_id);
+}
+
+void ReceiverMediaToMojoAdapter::OnError() {
+  receiver_->OnError();
+}
+
+void ReceiverMediaToMojoAdapter::OnLog(const std::string& message) {
+  receiver_->OnLog(message);
+}
+
+}  // namespace video_capture
diff --git a/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h b/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h
new file mode 100644
index 0000000..98d073f
--- /dev/null
+++ b/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.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 SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MEDIA_TO_MOJO_ADAPTER_H_
+#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MEDIA_TO_MOJO_ADAPTER_H_
+
+#include "media/capture/video/video_frame_receiver.h"
+#include "services/video_capture/public/interfaces/receiver.mojom.h"
+
+namespace video_capture {
+
+// Adapter that allows a media::VideoFrameReceiver to be used in place of
+// a mojom::VideoFrameReceiver.
+class ReceiverMediaToMojoAdapter : public mojom::Receiver {
+ public:
+  ReceiverMediaToMojoAdapter(
+      std::unique_ptr<media::VideoFrameReceiver> receiver);
+  ~ReceiverMediaToMojoAdapter() override;
+
+  // video_capture::mojom::Receiver:
+  void OnNewBufferHandle(int32_t buffer_id,
+                         mojo::ScopedSharedBufferHandle buffer_handle) override;
+  void OnFrameReadyInBuffer(
+      int32_t buffer_id,
+      int32_t frame_feedback_id,
+      mojom::ScopedAccessPermissionPtr access_permission,
+      media::mojom::VideoFrameInfoPtr frame_info) override;
+  void OnBufferRetired(int32_t buffer_id) override;
+  void OnError() override;
+  void OnLog(const std::string& message) override;
+
+ private:
+  std::unique_ptr<media::VideoFrameReceiver> receiver_;
+};
+
+}  // namespace video_capture
+
+#endif  // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MEDIA_TO_MOJO_ADAPTER_H_
diff --git a/services/video_capture/public/interfaces/device.mojom b/services/video_capture/public/interfaces/device.mojom
index 66c740f..46707a97 100644
--- a/services/video_capture/public/interfaces/device.mojom
+++ b/services/video_capture/public/interfaces/device.mojom
@@ -13,4 +13,6 @@
 // Device or the given |receiver| is closed.
 interface Device {
   Start(media.mojom.VideoCaptureParams requested_settings, Receiver receiver);
+  OnReceiverReportingUtilization(int32 frame_feedback_id,
+                                 double utilization);
 };
diff --git a/services/video_capture/public/interfaces/receiver.mojom b/services/video_capture/public/interfaces/receiver.mojom
index 287c0579..6ec99df 100644
--- a/services/video_capture/public/interfaces/receiver.mojom
+++ b/services/video_capture/public/interfaces/receiver.mojom
@@ -4,14 +4,22 @@
 
 module video_capture.mojom;
 
+import "media/capture/mojo/video_capture_types.mojom";
 import "media/mojo/interfaces/media_types.mojom";
 
+// Empty interface for encapsulating scoped access permission to a Buffer.
+interface ScopedAccessPermission {};
+
 // Callback interface for receiving data and messages from a started
 // video_capture.mojom.Device.
 interface Receiver {
-  OnIncomingCapturedVideoFrame(media.mojom.VideoFrame frame);
+  OnNewBufferHandle(int32 buffer_id, handle<shared_buffer> buffer_handle);
+  OnFrameReadyInBuffer(int32 buffer_id, int32 frame_feedback_id,
+                       ScopedAccessPermission access_permission,
+                       media.mojom.VideoFrameInfo frame_info);
+  OnBufferRetired(int32 buffer_id);
   OnError();
   OnLog(string message);
   OnStarted();
-  OnBufferDestroyed(int32 buffer_id_to_drop);
+  OnStartedUsingGpuDecode();
 };
diff --git a/services/video_capture/receiver_mojo_to_media_adapter.cc b/services/video_capture/receiver_mojo_to_media_adapter.cc
index 70292d4..769c3f9 100644
--- a/services/video_capture/receiver_mojo_to_media_adapter.cc
+++ b/services/video_capture/receiver_mojo_to_media_adapter.cc
@@ -4,6 +4,27 @@
 
 #include "services/video_capture/receiver_mojo_to_media_adapter.h"
 
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace {
+
+class ScopedAccessPermissionMediaToMojoAdapter
+    : public video_capture::mojom::ScopedAccessPermission {
+ public:
+  ScopedAccessPermissionMediaToMojoAdapter(
+      std::unique_ptr<
+          media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
+          access_permission)
+      : access_permission_(std::move(access_permission)) {}
+
+ private:
+  std::unique_ptr<
+      media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
+      access_permission_;
+};
+
+}  // anonymous namespace
+
 namespace video_capture {
 
 ReceiverMojoToMediaAdapter::ReceiverMojoToMediaAdapter(
@@ -16,7 +37,8 @@
     int buffer_id,
     std::unique_ptr<media::VideoCaptureDevice::Client::Buffer::HandleProvider>
         handle_provider) {
-  NOTIMPLEMENTED();
+  receiver_->OnNewBufferHandle(
+      buffer_id, handle_provider->GetHandleForInterProcessTransit());
 }
 
 void ReceiverMojoToMediaAdapter::OnFrameReadyInBuffer(
@@ -24,9 +46,20 @@
     int frame_feedback_id,
     std::unique_ptr<
         media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
-        buffer_usage_reservation,
+        access_permission,
     media::mojom::VideoFrameInfoPtr frame_info) {
-  NOTIMPLEMENTED();
+  mojom::ScopedAccessPermissionPtr access_permission_proxy;
+  mojo::MakeStrongBinding<mojom::ScopedAccessPermission>(
+      base::MakeUnique<ScopedAccessPermissionMediaToMojoAdapter>(
+          std::move(access_permission)),
+      mojo::MakeRequest(&access_permission_proxy));
+  receiver_->OnFrameReadyInBuffer(buffer_id, frame_feedback_id,
+                                  std::move(access_permission_proxy),
+                                  std::move(frame_info));
+}
+
+void ReceiverMojoToMediaAdapter::OnBufferRetired(int buffer_id) {
+  receiver_->OnBufferRetired(buffer_id);
 }
 
 void ReceiverMojoToMediaAdapter::OnError() {
@@ -42,11 +75,7 @@
 }
 
 void ReceiverMojoToMediaAdapter::OnStartedUsingGpuDecode() {
-  NOTIMPLEMENTED();
-}
-
-void ReceiverMojoToMediaAdapter::OnBufferRetired(int buffer_id) {
-  NOTIMPLEMENTED();
+  receiver_->OnStartedUsingGpuDecode();
 }
 
 }  // namespace video_capture
diff --git a/services/video_capture/receiver_mojo_to_media_adapter.h b/services/video_capture/receiver_mojo_to_media_adapter.h
index e70358d..080d30a 100644
--- a/services/video_capture/receiver_mojo_to_media_adapter.h
+++ b/services/video_capture/receiver_mojo_to_media_adapter.h
@@ -27,7 +27,7 @@
       int frame_feedback_id,
       std::unique_ptr<
           media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
-          buffer_usage_reservation,
+          access_permission,
       media::mojom::VideoFrameInfoPtr frame_info) override;
   void OnBufferRetired(int buffer_id) override;
   void OnError() override;
diff --git a/services/video_capture/service_impl.cc b/services/video_capture/service_impl.cc
index bd3d050..cb1b98d9 100644
--- a/services/video_capture/service_impl.cc
+++ b/services/video_capture/service_impl.cc
@@ -10,6 +10,7 @@
 #include "media/capture/video/video_capture_buffer_pool.h"
 #include "media/capture/video/video_capture_buffer_tracker.h"
 #include "media/capture/video/video_capture_jpeg_decoder.h"
+#include "media/capture/video/video_capture_system_impl.h"
 #include "services/service_manager/public/cpp/service_info.h"
 #include "services/video_capture/device_factory_media_to_mojo_adapter.h"
 
@@ -65,18 +66,23 @@
   std::unique_ptr<media::VideoCaptureDeviceFactory> media_device_factory =
       media::VideoCaptureDeviceFactory::CreateFactory(
           base::MessageLoop::current()->task_runner());
+  auto video_capture_system = base::MakeUnique<media::VideoCaptureSystemImpl>(
+      std::move(media_device_factory));
 
   device_factory_ = base::MakeUnique<DeviceFactoryMediaToMojoAdapter>(
-      std::move(media_device_factory), base::Bind(CreateJpegDecoder));
+      std::move(video_capture_system), base::Bind(CreateJpegDecoder));
 }
 
 void ServiceImpl::LazyInitializeFakeDeviceFactory() {
   if (fake_device_factory_)
     return;
 
+  auto factory = base::MakeUnique<media::FakeVideoCaptureDeviceFactory>();
+  auto video_capture_system =
+      base::MakeUnique<media::VideoCaptureSystemImpl>(std::move(factory));
+
   fake_device_factory_ = base::MakeUnique<DeviceFactoryMediaToMojoAdapter>(
-      base::MakeUnique<media::FakeVideoCaptureDeviceFactory>(),
-      base::Bind(&CreateJpegDecoder));
+      std::move(video_capture_system), base::Bind(&CreateJpegDecoder));
 }
 
 }  // namespace video_capture
diff --git a/services/video_capture/test/fake_device_descriptor_unittest.cc b/services/video_capture/test/fake_device_descriptor_unittest.cc
index 4ef67ac..5565360 100644
--- a/services/video_capture/test/fake_device_descriptor_unittest.cc
+++ b/services/video_capture/test/fake_device_descriptor_unittest.cc
@@ -23,8 +23,8 @@
 // Tests that when requesting a second proxy for a device without closing the
 // first one, the service revokes access to the first one by closing the
 // connection.
-TEST_F(FakeVideoCaptureDeviceDescriptorTest,
-       DISABLED_AccessIsRevokedOnSecondAccess) {
+TEST_F(FakeVideoCaptureDeviceDescriptorTest, AccessIsRevokedOnSecondAccess) {
+  base::RunLoop wait_loop_1;
   mojom::DevicePtr device_proxy_1;
   bool device_access_1_revoked = false;
   MockCreateDeviceProxyCallback create_device_proxy_callback_1;
@@ -36,18 +36,21 @@
       mojo::MakeRequest(&device_proxy_1),
       base::Bind(&MockCreateDeviceProxyCallback::Run,
                  base::Unretained(&create_device_proxy_callback_1)));
-  device_proxy_1.set_connection_error_handler(
-      base::Bind([](bool* access_revoked) { *access_revoked = true; },
-                 &device_access_1_revoked));
+  device_proxy_1.set_connection_error_handler(base::Bind(
+      [](bool* access_revoked, base::RunLoop* wait_loop_1) {
+        *access_revoked = true;
+        wait_loop_1->Quit();
+      },
+      &device_access_1_revoked, &wait_loop_1));
 
-  base::RunLoop wait_loop;
+  base::RunLoop wait_loop_2;
   mojom::DevicePtr device_proxy_2;
   bool device_access_2_revoked = false;
   MockCreateDeviceProxyCallback create_device_proxy_callback_2;
   EXPECT_CALL(create_device_proxy_callback_2,
               Run(mojom::DeviceAccessResultCode::SUCCESS))
       .Times(1)
-      .WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
+      .WillOnce(InvokeWithoutArgs([&wait_loop_2]() { wait_loop_2.Quit(); }));
   factory_->CreateDevice(
       fake_device_info_.descriptor.device_id,
       mojo::MakeRequest(&device_proxy_2),
@@ -56,14 +59,14 @@
   device_proxy_2.set_connection_error_handler(
       base::Bind([](bool* access_revoked) { *access_revoked = true; },
                  &device_access_2_revoked));
-  wait_loop.Run();
+  wait_loop_1.Run();
+  wait_loop_2.Run();
   ASSERT_TRUE(device_access_1_revoked);
   ASSERT_FALSE(device_access_2_revoked);
 }
 
 // Tests that a second proxy requested for a device can be used successfully.
-TEST_F(FakeVideoCaptureDeviceDescriptorTest,
-       DISABLED_CanUseSecondRequestedProxy) {
+TEST_F(FakeVideoCaptureDeviceDescriptorTest, CanUseSecondRequestedProxy) {
   mojom::DevicePtr device_proxy_1;
   factory_->CreateDevice(
       fake_device_info_.descriptor.device_id,
@@ -92,7 +95,8 @@
   base::RunLoop wait_loop_2;
   mojom::ReceiverPtr receiver_proxy;
   MockReceiver receiver(mojo::MakeRequest(&receiver_proxy));
-  EXPECT_CALL(receiver, OnIncomingCapturedVideoFramePtr(_))
+  EXPECT_CALL(receiver, DoOnNewBufferHandle(_, _));
+  EXPECT_CALL(receiver, DoOnFrameReadyInBuffer(_, _, _, _))
       .WillRepeatedly(
           InvokeWithoutArgs([&wait_loop_2]() { wait_loop_2.Quit(); }));
 
diff --git a/services/video_capture/test/fake_device_unittest.cc b/services/video_capture/test/fake_device_unittest.cc
index 6550909..ee2d65183 100644
--- a/services/video_capture/test/fake_device_unittest.cc
+++ b/services/video_capture/test/fake_device_unittest.cc
@@ -12,6 +12,7 @@
 #include "services/video_capture/test/mock_receiver.h"
 
 using testing::_;
+using testing::AtLeast;
 using testing::Invoke;
 using testing::InvokeWithoutArgs;
 
@@ -20,7 +21,7 @@
 struct FrameInfo {
   gfx::Size size;
   media::VideoPixelFormat pixel_format;
-  media::VideoFrame::StorageType storage_type;
+  media::VideoPixelStorage storage_type;
   base::TimeDelta timestamp;
 };
 
@@ -32,23 +33,23 @@
 // TODO(rockot/chfremer): Consider just renaming the type.
 using FakeVideoCaptureDeviceTest = FakeDeviceTest;
 
-TEST_F(FakeVideoCaptureDeviceTest, DISABLED_FrameCallbacksArrive) {
+TEST_F(FakeVideoCaptureDeviceTest, FrameCallbacksArrive) {
   base::RunLoop wait_loop;
-  // These two constants must be static as a workaround
+  // Constants must be static as a workaround
   // for a MSVC++ bug about lambda captures, see the discussion at
   // https://social.msdn.microsoft.com/Forums/SqlServer/4abf18bd-4ae4-4c72-ba3e-3b13e7909d5f
   static const int kNumFramesToWaitFor = 3;
   int num_frames_arrived = 0;
   mojom::ReceiverPtr receiver_proxy;
   MockReceiver receiver(mojo::MakeRequest(&receiver_proxy));
-  EXPECT_CALL(receiver, OnIncomingCapturedVideoFramePtr(_))
-      .WillRepeatedly(InvokeWithoutArgs(
-          [&wait_loop, &num_frames_arrived]() {
-            num_frames_arrived += 1;
-            if (num_frames_arrived >= kNumFramesToWaitFor) {
-              wait_loop.Quit();
-            }
-          }));
+  EXPECT_CALL(receiver, DoOnNewBufferHandle(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(receiver, DoOnFrameReadyInBuffer(_, _, _, _))
+      .WillRepeatedly(InvokeWithoutArgs([&wait_loop, &num_frames_arrived]() {
+        num_frames_arrived += 1;
+        if (num_frames_arrived >= kNumFramesToWaitFor) {
+          wait_loop.Quit();
+        }
+      }));
 
   fake_device_proxy_->Start(requestable_settings_, std::move(receiver_proxy));
   wait_loop.Run();
@@ -56,29 +57,31 @@
 
 // Tests that frames received from a fake capture device match the requested
 // format and have increasing timestamps.
-TEST_F(FakeVideoCaptureDeviceTest,
-       DISABLED_ReceiveFramesFromFakeCaptureDevice) {
+TEST_F(FakeVideoCaptureDeviceTest, ReceiveFramesFromFakeCaptureDevice) {
   base::RunLoop wait_loop;
   mojom::ReceiverPtr receiver_proxy;
-  // These two constants must be static as a workaround
+  // Constants must be static as a workaround
   // for a MSVC++ bug about lambda captures, see the discussion at
   // https://social.msdn.microsoft.com/Forums/SqlServer/4abf18bd-4ae4-4c72-ba3e-3b13e7909d5f
   static const int num_frames_to_receive = 2;
   FrameInfo received_frame_infos[num_frames_to_receive];
   int received_frame_count = 0;
   MockReceiver receiver(mojo::MakeRequest(&receiver_proxy));
-  EXPECT_CALL(receiver, OnIncomingCapturedVideoFramePtr(_))
-      .WillRepeatedly(Invoke(
-          [&received_frame_infos, &received_frame_count, &wait_loop]
-          (const media::mojom::VideoFramePtr* frame) {
+  EXPECT_CALL(receiver, DoOnNewBufferHandle(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(receiver, DoOnFrameReadyInBuffer(_, _, _, _))
+      .WillRepeatedly(
+          Invoke([&received_frame_infos, &received_frame_count, &wait_loop](
+                     int32_t buffer_id, int32_t frame_feedback_id,
+                     mojom::ScopedAccessPermissionPtr* access_permission,
+                     media::mojom::VideoFrameInfoPtr* frame_info) {
             if (received_frame_count >= num_frames_to_receive)
               return;
-            auto video_frame = frame->To<scoped_refptr<media::VideoFrame>>();
-            auto& frame_info = received_frame_infos[received_frame_count];
-            frame_info.pixel_format = video_frame->format();
-            frame_info.storage_type = video_frame->storage_type();
-            frame_info.size = video_frame->natural_size();
-            frame_info.timestamp = video_frame->timestamp();
+            auto& received_frame_info =
+                received_frame_infos[received_frame_count];
+            received_frame_info.pixel_format = (*frame_info)->pixel_format;
+            received_frame_info.storage_type = (*frame_info)->storage_type;
+            received_frame_info.size = (*frame_info)->coded_size;
+            received_frame_info.timestamp = (*frame_info)->timestamp;
             received_frame_count += 1;
             if (received_frame_count == num_frames_to_receive)
               wait_loop.Quit();
@@ -93,9 +96,10 @@
     auto& frame_info = received_frame_infos[i];
     // Service is expected to always output I420
     EXPECT_EQ(media::PIXEL_FORMAT_I420, frame_info.pixel_format);
-    // Service is expected to always use STORAGE_MOJO_SHARED_BUFFER
-    EXPECT_EQ(media::VideoFrame::STORAGE_MOJO_SHARED_BUFFER,
-              frame_info.storage_type);
+    // Service is expected to always use PIXEL_STORAGE_CPU
+    EXPECT_EQ(media::PIXEL_STORAGE_CPU, frame_info.storage_type);
+    EXPECT_EQ(requestable_settings_.requested_format.frame_size,
+              frame_info.size);
     // Timestamps are expected to increase
     if (i > 0)
       EXPECT_GT(frame_info.timestamp, previous_timestamp);
@@ -103,4 +107,35 @@
   }
 }
 
+// Tests that buffers get reused when receiving more frames than the maximum
+// number of buffers in the pool.
+TEST_F(FakeVideoCaptureDeviceTest, BuffersGetReused) {
+  base::RunLoop wait_loop;
+  const int kMaxBufferPoolBuffers =
+      DeviceMediaToMojoAdapter::max_buffer_pool_buffer_count();
+  // Constants must be static as a workaround
+  // for a MSVC++ bug about lambda captures, see the discussion at
+  // https://social.msdn.microsoft.com/Forums/SqlServer/4abf18bd-4ae4-4c72-ba3e-3b13e7909d5f
+  static const int kNumFramesToWaitFor = kMaxBufferPoolBuffers + 3;
+  int num_buffers_created = 0;
+  int num_frames_arrived = 0;
+  mojom::ReceiverPtr receiver_proxy;
+  MockReceiver receiver(mojo::MakeRequest(&receiver_proxy));
+  EXPECT_CALL(receiver, DoOnNewBufferHandle(_, _))
+      .WillRepeatedly(InvokeWithoutArgs(
+          [&num_buffers_created]() { num_buffers_created++; }));
+  EXPECT_CALL(receiver, DoOnFrameReadyInBuffer(_, _, _, _))
+      .WillRepeatedly(InvokeWithoutArgs([&wait_loop, &num_frames_arrived]() {
+        if (++num_frames_arrived >= kNumFramesToWaitFor) {
+          wait_loop.Quit();
+        }
+      }));
+
+  fake_device_proxy_->Start(requestable_settings_, std::move(receiver_proxy));
+  wait_loop.Run();
+
+  ASSERT_LT(num_buffers_created, num_frames_arrived);
+  ASSERT_LE(num_buffers_created, kMaxBufferPoolBuffers);
+}
+
 }  // namespace video_capture
diff --git a/services/video_capture/test/mock_device_factory.cc b/services/video_capture/test/mock_device_factory.cc
index 8fe1077..dd9a7875 100644
--- a/services/video_capture/test/mock_device_factory.cc
+++ b/services/video_capture/test/mock_device_factory.cc
@@ -8,11 +8,13 @@
 namespace {
 
 // Report a single hard-coded supported format to clients.
-media::VideoCaptureFormat kSupportedFormat(gfx::Size(),
+media::VideoCaptureFormat kSupportedFormat(gfx::Size(640, 480),
                                            25.0f,
                                            media::PIXEL_FORMAT_I420,
                                            media::PIXEL_STORAGE_CPU);
 
+// Wraps a raw pointer to a media::VideoCaptureDevice and allows us to
+// create a std::unique_ptr<media::VideoCaptureDevice> that delegates to it.
 class RawPointerVideoCaptureDevice : public media::VideoCaptureDevice {
  public:
   explicit RawPointerVideoCaptureDevice(media::VideoCaptureDevice* device)
@@ -35,6 +37,9 @@
   void TakePhoto(TakePhotoCallback callback) override {
     device_->TakePhoto(std::move(callback));
   }
+  void OnUtilizationReport(int frame_feedback_id, double utilization) override {
+    device_->OnUtilizationReport(frame_feedback_id, utilization);
+  }
 
  private:
   media::VideoCaptureDevice* device_;
diff --git a/services/video_capture/test/mock_device_test.cc b/services/video_capture/test/mock_device_test.cc
index 9b976347..8b526503 100644
--- a/services/video_capture/test/mock_device_test.cc
+++ b/services/video_capture/test/mock_device_test.cc
@@ -7,6 +7,11 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "media/capture/video/video_capture_jpeg_decoder.h"
+#include "media/capture/video/video_capture_system_impl.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
 
 namespace {
 
@@ -22,11 +27,31 @@
 
 MockDevice::~MockDevice() = default;
 
+void MockDevice::SendStubFrame(const media::VideoCaptureFormat& format,
+                               int rotation,
+                               int frame_id) {
+  auto stub_frame = media::VideoFrame::CreateZeroInitializedFrame(
+      format.pixel_format, format.frame_size,
+      gfx::Rect(format.frame_size.width(), format.frame_size.height()),
+      format.frame_size, base::TimeDelta());
+  client_->OnIncomingCapturedData(
+      stub_frame->data(0),
+      static_cast<int>(media::VideoFrame::AllocationSize(
+          stub_frame->format(), stub_frame->coded_size())),
+      format, rotation, base::TimeTicks(), base::TimeDelta(), frame_id);
+}
+
 void MockDevice::AllocateAndStart(const media::VideoCaptureParams& params,
                                   std::unique_ptr<Client> client) {
+  client_ = std::move(client);
   DoAllocateAndStart(params, &client);
 }
 
+void MockDevice::StopAndDeAllocate() {
+  DoStopAndDeAllocate();
+  client_.reset();
+}
+
 void MockDevice::GetPhotoCapabilities(GetPhotoCapabilitiesCallback callback) {
   DoGetPhotoCapabilities(&callback);
 }
@@ -51,9 +76,11 @@
   // invoke its AddMockDevice(). Ownership of the MockDeviceFactory is moved
   // to the DeviceFactoryMediaToMojoAdapter.
   mock_device_factory_ = mock_device_factory.get();
+  auto video_capture_system = base::MakeUnique<media::VideoCaptureSystemImpl>(
+      std::move(mock_device_factory));
   mock_device_factory_adapter_ =
       base::MakeUnique<DeviceFactoryMediaToMojoAdapter>(
-          std::move(mock_device_factory), base::Bind(CreateJpegDecoder));
+          std::move(video_capture_system), base::Bind(CreateJpegDecoder));
 
   mock_factory_binding_ = base::MakeUnique<mojo::Binding<mojom::DeviceFactory>>(
       mock_device_factory_adapter_.get(), mojo::MakeRequest(&factory_));
@@ -63,6 +90,13 @@
   mock_device_factory_->AddMockDevice(&mock_device_, mock_descriptor);
 
   // Obtain the mock device from the factory
+  base::RunLoop wait_loop;
+  EXPECT_CALL(device_infos_receiver_, Run(_))
+      .WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
+  factory_->GetDeviceInfos(device_infos_receiver_.Get());
+  // We must wait for the response to GetDeviceInfos before calling
+  // CreateDevice.
+  wait_loop.Run();
   factory_->CreateDevice(
       mock_descriptor.device_id, mojo::MakeRequest(&device_proxy_),
       base::Bind([](mojom::DeviceAccessResultCode result_code) {}));
diff --git a/services/video_capture/test/mock_device_test.h b/services/video_capture/test/mock_device_test.h
index 1133118c..637f635 100644
--- a/services/video_capture/test/mock_device_test.h
+++ b/services/video_capture/test/mock_device_test.h
@@ -19,17 +19,24 @@
 
 namespace video_capture {
 
+// To ensure correct operation, this mock device holds on to the |client|
+// that is passed to it in AllocateAndStart() and releases it on
+// StopAndDeAllocate().
 class MockDevice : public media::VideoCaptureDevice {
  public:
   MockDevice();
   ~MockDevice() override;
 
+  void SendStubFrame(const media::VideoCaptureFormat& format,
+                     int rotation,
+                     int frame_id);
+
   // media::VideoCaptureDevice:
   MOCK_METHOD2(DoAllocateAndStart,
                void(const media::VideoCaptureParams& params,
                     std::unique_ptr<Client>* client));
   MOCK_METHOD0(RequestRefreshFrame, void());
-  MOCK_METHOD0(StopAndDeAllocate, void());
+  MOCK_METHOD0(DoStopAndDeAllocate, void());
   MOCK_METHOD1(DoGetPhotoCapabilities,
                void(GetPhotoCapabilitiesCallback* callback));
   MOCK_METHOD2(DoSetPhotoOptions,
@@ -41,10 +48,14 @@
 
   void AllocateAndStart(const media::VideoCaptureParams& params,
                         std::unique_ptr<Client> client) override;
+  void StopAndDeAllocate() override;
   void GetPhotoCapabilities(GetPhotoCapabilitiesCallback callback) override;
   void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
   void TakePhoto(TakePhotoCallback callback) override;
+
+ private:
+  std::unique_ptr<Client> client_;
 };
 
 // Reusable test setup for testing with a single mock device.
diff --git a/services/video_capture/test/mock_device_unittest.cc b/services/video_capture/test/mock_device_unittest.cc
index b0f7d42..28a5f72 100644
--- a/services/video_capture/test/mock_device_unittest.cc
+++ b/services/video_capture/test/mock_device_unittest.cc
@@ -16,19 +16,10 @@
 
 // Tests that the service stops the capture device when the client closes the
 // connection to the device proxy.
-TEST_F(MockVideoCaptureDeviceTest,
-       DISABLED_DeviceIsStoppedWhenDiscardingDeviceProxy) {
+TEST_F(MockVideoCaptureDeviceTest, DeviceIsStoppedWhenDiscardingDeviceProxy) {
   base::RunLoop wait_loop;
 
-  // The mock device must hold on to the device client that is passed to it.
-  std::unique_ptr<media::VideoCaptureDevice::Client> device_client;
-  EXPECT_CALL(mock_device_, DoAllocateAndStart(_, _))
-      .WillOnce(Invoke([&device_client](
-          const media::VideoCaptureParams& params,
-          std::unique_ptr<media::VideoCaptureDevice::Client>* client) {
-        device_client.reset(client->release());
-      }));
-  EXPECT_CALL(mock_device_, StopAndDeAllocate())
+  EXPECT_CALL(mock_device_, DoStopAndDeAllocate())
       .WillOnce(Invoke([&wait_loop]() { wait_loop.Quit(); }));
 
   device_proxy_->Start(requested_settings_, std::move(mock_receiver_proxy_));
@@ -39,19 +30,10 @@
 
 // Tests that the service stops the capture device when the client closes the
 // connection to the client proxy it provided to the service.
-TEST_F(MockVideoCaptureDeviceTest,
-       DISABLED_DeviceIsStoppedWhenDiscardingDeviceClient) {
+TEST_F(MockVideoCaptureDeviceTest, DeviceIsStoppedWhenDiscardingDeviceClient) {
   base::RunLoop wait_loop;
 
-  // The mock device must hold on to the device client that is passed to it.
-  std::unique_ptr<media::VideoCaptureDevice::Client> device_client;
-  EXPECT_CALL(mock_device_, DoAllocateAndStart(_, _))
-      .WillOnce(Invoke([&device_client](
-          const media::VideoCaptureParams& params,
-          std::unique_ptr<media::VideoCaptureDevice::Client>* client) {
-        device_client.reset(client->release());
-      }));
-  EXPECT_CALL(mock_device_, StopAndDeAllocate())
+  EXPECT_CALL(mock_device_, DoStopAndDeAllocate())
       .WillOnce(Invoke([&wait_loop]() { wait_loop.Quit(); }));
 
   device_proxy_->Start(requested_settings_, std::move(mock_receiver_proxy_));
@@ -60,4 +42,43 @@
   wait_loop.Run();
 }
 
+// Tests that a utilization reported to a video_capture.mojom.Device via
+// OnReceiverReportingUtilization() arrives at the corresponding
+// media::VideoCaptureDevice.
+TEST_F(MockVideoCaptureDeviceTest, ReceiverUtilizationIsForwardedToDevice) {
+  base::RunLoop run_loop;
+  const media::VideoCaptureFormat stub_frame_format(gfx::Size(320, 200), 25.0f,
+                                                    media::PIXEL_FORMAT_I420);
+  const int arbitrary_rotation = 0;
+  const int arbitrary_frame_feedback_id = 654;
+  const double arbitrary_utilization = 0.12345;
+
+  EXPECT_CALL(*mock_receiver_, DoOnFrameReadyInBuffer(_, _, _, _))
+      .WillOnce(Invoke([this, &arbitrary_utilization](
+                           int32_t buffer_id, int32_t frame_feedback_id,
+                           mojom::ScopedAccessPermissionPtr*,
+                           media::mojom::VideoFrameInfoPtr*) {
+        device_proxy_->OnReceiverReportingUtilization(frame_feedback_id,
+                                                      arbitrary_utilization);
+      }));
+
+  EXPECT_CALL(mock_device_, OnUtilizationReport(arbitrary_frame_feedback_id,
+                                                arbitrary_utilization))
+      .Times(1);
+
+  device_proxy_->Start(requested_settings_, std::move(mock_receiver_proxy_));
+  run_loop.RunUntilIdle();
+
+  // Simulate device sending a frame, which should trigger |mock_receiver|
+  // DoOnFrameReadyInBuffer() getting called.
+  base::RunLoop run_loop_2;
+  mock_device_.SendStubFrame(stub_frame_format, arbitrary_rotation,
+                             arbitrary_frame_feedback_id);
+  run_loop_2.RunUntilIdle();
+
+  base::RunLoop run_loop_3;
+  mock_receiver_.reset();
+  run_loop_3.RunUntilIdle();
+}
+
 }  // namespace video_capture
diff --git a/services/video_capture/test/mock_receiver.cc b/services/video_capture/test/mock_receiver.cc
index 5665911..34d11199 100644
--- a/services/video_capture/test/mock_receiver.cc
+++ b/services/video_capture/test/mock_receiver.cc
@@ -11,9 +11,19 @@
 
 MockReceiver::~MockReceiver() = default;
 
-void MockReceiver::OnIncomingCapturedVideoFrame(
-    media::mojom::VideoFramePtr frame) {
-  OnIncomingCapturedVideoFramePtr(&frame);
+void MockReceiver::OnNewBufferHandle(
+    int32_t buffer_id,
+    mojo::ScopedSharedBufferHandle buffer_handle) {
+  DoOnNewBufferHandle(buffer_id, &buffer_handle);
+}
+
+void MockReceiver::OnFrameReadyInBuffer(
+    int32_t buffer_id,
+    int32_t frame_feedback_id,
+    mojom::ScopedAccessPermissionPtr access_permission,
+    media::mojom::VideoFrameInfoPtr frame_info) {
+  DoOnFrameReadyInBuffer(buffer_id, frame_feedback_id, &access_permission,
+                         &frame_info);
 }
 
 }  // namespace video_capture
diff --git a/services/video_capture/test/mock_receiver.h b/services/video_capture/test/mock_receiver.h
index 5e8a1656..294e48a6 100644
--- a/services/video_capture/test/mock_receiver.h
+++ b/services/video_capture/test/mock_receiver.h
@@ -18,14 +18,26 @@
   ~MockReceiver() override;
 
   // Use forwarding method to work around gmock not supporting move-only types.
-  void OnIncomingCapturedVideoFrame(media::mojom::VideoFramePtr frame) override;
+  void OnNewBufferHandle(int32_t buffer_id,
+                         mojo::ScopedSharedBufferHandle buffer_handle) override;
+  void OnFrameReadyInBuffer(
+      int32_t buffer_id,
+      int32_t frame_feedback_id,
+      mojom::ScopedAccessPermissionPtr access_permission,
+      media::mojom::VideoFrameInfoPtr frame_info) override;
 
-  MOCK_METHOD1(OnIncomingCapturedVideoFramePtr,
-               void(const media::mojom::VideoFramePtr* frame));
+  MOCK_METHOD2(DoOnNewBufferHandle,
+               void(int32_t, mojo::ScopedSharedBufferHandle*));
+  MOCK_METHOD4(DoOnFrameReadyInBuffer,
+               void(int32_t buffer_id,
+                    int32_t frame_feedback_id,
+                    mojom::ScopedAccessPermissionPtr*,
+                    media::mojom::VideoFrameInfoPtr*));
+  MOCK_METHOD1(OnBufferRetired, void(int32_t));
   MOCK_METHOD0(OnError, void());
   MOCK_METHOD1(OnLog, void(const std::string&));
   MOCK_METHOD0(OnStarted, void());
-  MOCK_METHOD1(OnBufferDestroyed, void(int32_t));
+  MOCK_METHOD0(OnStartedUsingGpuDecode, void());
 
  private:
   const mojo::Binding<mojom::Receiver> binding_;
diff --git a/services/video_capture/test/service_unittest.cc b/services/video_capture/test/service_unittest.cc
index bc74500..8b4b4bf3 100644
--- a/services/video_capture/test/service_unittest.cc
+++ b/services/video_capture/test/service_unittest.cc
@@ -21,7 +21,7 @@
 
 // Tests that an answer arrives from the service when calling
 // GetDeviceInfos().
-TEST_F(VideoCaptureServiceTest, DISABLED_GetDeviceInfosCallbackArrives) {
+TEST_F(VideoCaptureServiceTest, GetDeviceInfosCallbackArrives) {
   base::RunLoop wait_loop;
   EXPECT_CALL(device_info_receiver_, Run(_))
       .Times(Exactly(1))
@@ -31,7 +31,7 @@
   wait_loop.Run();
 }
 
-TEST_F(VideoCaptureServiceTest, DISABLED_FakeDeviceFactoryEnumeratesOneDevice) {
+TEST_F(VideoCaptureServiceTest, FakeDeviceFactoryEnumeratesOneDevice) {
   base::RunLoop wait_loop;
   size_t num_devices_enumerated = 0;
   EXPECT_CALL(device_info_receiver_, Run(_))
@@ -50,8 +50,7 @@
 
 // Tests that VideoCaptureDeviceFactory::CreateDeviceProxy() returns an error
 // code when trying to create a device for an invalid descriptor.
-TEST_F(VideoCaptureServiceTest,
-       DISABLED_ErrorCodeOnCreateDeviceForInvalidDescriptor) {
+TEST_F(VideoCaptureServiceTest, ErrorCodeOnCreateDeviceForInvalidDescriptor) {
   const std::string invalid_device_id = "invalid";
   base::RunLoop wait_loop;
   mojom::DevicePtr fake_device_proxy;
@@ -61,6 +60,7 @@
               Run(mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND))
       .Times(1)
       .WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
+  factory_->GetDeviceInfos(device_info_receiver_.Get());
   factory_->CreateDevice(invalid_device_id,
                          mojo::MakeRequest(&fake_device_proxy),
                          create_device_proxy_callback.Get());
diff --git a/third_party/WebKit/LayoutTests/fragmentation/thead-near-start-of-first-fragmentainer.html b/third_party/WebKit/LayoutTests/fragmentation/thead-near-start-of-first-fragmentainer.html
new file mode 100644
index 0000000..f605086
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/thead-near-start-of-first-fragmentainer.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<p>Below there should be a black square surrounded by a rather thick
+    (10px wide) hotpink border on all sides.</p>
+<div style="columns:2; column-fill:auto; height:300px;">
+    <div style="height:10px;"></div>
+    <table id="table" style="border-spacing:10px; width:120px; background:hotpink;">
+        <thead style="break-inside:avoid;">
+            <tr>
+                <td id="cell" style="padding:0;">
+                    <div id="pete" style="width:99px; height:100px; background:black;"></div>
+                </td>
+            </tr>
+        </thead>
+    </table>
+</div>
+<script>
+</script>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(() => {
+    document.body.offsetTop;
+    document.getElementById("pete").style.width = "100px";
+    assert_equals(document.getElementById("cell").offsetTop, 10);
+    assert_equals(document.getElementById("table").offsetHeight, 120);
+}, "THEAD near the top of the first fragmentainer");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/resources/thorough-util.js b/third_party/WebKit/LayoutTests/http/tests/fetch/resources/thorough-util.js
index 053c7c2..31838e2 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fetch/resources/thorough-util.js
+++ b/third_party/WebKit/LayoutTests/http/tests/fetch/resources/thorough-util.js
@@ -345,15 +345,11 @@
   // iterable.
   ['content-length', 'content-type', 'x-serviceworker-serverheader'].forEach(
     function(name) {
-      for (var value of headers.getAll(name))
-        ret.push([name, value]);
+      for (var header of headers){
+        ret.push(header);
+      }
     });
 
-  // Original code:
-  // for (var header of headers) {
-  //   ret.push(header);
-  // }
-
   return ret;
 }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/headers.js b/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/headers.js
index babfaf7c..97c656b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/headers.js
+++ b/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/headers.js
@@ -128,8 +128,8 @@
       assert_equals(headersObject, headers);
     }, thisObject);
 
-    // 'append()', 'getAll()'
-    var allValues = headers.getAll('X-Fetch-Test');
+    // 'append()'
+    var allValues = headers.get('X-Fetch-Test').split(', ');
     assert_equals(allValues.length, 1);
     assert_equals(size(headers), 4);
     headers.append('X-FETCH-TEST', 'response test field - append');
@@ -138,13 +138,13 @@
     assert_equals(headers.get('X-FETCH-Test'),
                   'response test field - updated, response test field - append',
                   'the value of the first header added should be returned.');
-    allValues = headers.getAll('X-FETch-TEST');
+    allValues = headers.get('X-FETch-TEST').split(', ');
     assert_equals(allValues.length, 2);
     assert_equals(allValues[0], 'response test field - updated');
     assert_equals(allValues[1], 'response test field - append');
     headers.set('X-FETch-Test', 'response test field - set');
     assert_equals(size(headers), 5, 'the second header should be deleted');
-    allValues = headers.getAll('X-Fetch-Test');
+    allValues = headers.get('X-Fetch-Test').split(', ');
     assert_equals(allValues.length, 1, 'the second header should be deleted');
     assert_equals(allValues[0], 'response test field - set');
     headers.append('X-Fetch-TEST', 'response test field - append');
@@ -157,16 +157,16 @@
     assert_equals(size(headers), 2, 'headers size should match');
     assert_equals(headers.get('a'), 'b');
     assert_equals(headers.get('c'), 'd, e');
-    assert_equals(headers.getAll('c')[0], 'd');
-    assert_equals(headers.getAll('c')[1], 'e');
+    assert_equals(headers.get('c').split(', ')[0], 'd');
+    assert_equals(headers.get('c').split(', ')[1], 'e');
 
     // new Headers with Headers
     var headers2 = new Headers(headers);
     assert_equals(size(headers2), 2, 'headers size should match');
     assert_equals(headers2.get('a'), 'b');
     assert_equals(headers2.get('c'), 'd, e');
-    assert_equals(headers2.getAll('c')[0], 'd');
-    assert_equals(headers2.getAll('c')[1], 'e');
+    assert_equals(headers2.get('c').split(', ')[0], 'd');
+    assert_equals(headers2.get('c').split(', ')[1], 'e');
     headers.set('a', 'x');
     assert_equals(headers.get('a'), 'x');
     assert_equals(headers2.get('a'), 'b');
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/request.js b/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/request.js
index b6aba93..e03381f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/request.js
+++ b/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/request.js
@@ -113,44 +113,44 @@
     assert_equals(request2.mode, 'cors', 'Request.mode should match');
     assert_equals(request2.credentials, 'omit',
                   'Request.credentials should match');
-    assert_equals(request2.headers.getAll('X-Fetch-Foo')[0], 'foo1',
+    assert_equals(request2.headers.get('X-Fetch-Foo').split(', ')[0], 'foo1',
                   'Request.headers should match');
-    assert_equals(request2.headers.getAll('X-Fetch-Foo')[1], 'foo2',
+    assert_equals(request2.headers.get('X-Fetch-Foo').split(', ')[1], 'foo2',
                   'Request.headers should match');
-    assert_equals(request2.headers.getAll('X-Fetch-Bar')[0], 'bar',
+    assert_equals(request2.headers.get('X-Fetch-Bar').split(', ')[0], 'bar',
                   'Request.headers should match');
     var request3 = new Request(URL,
                                {headers: [['X-Fetch-Foo', 'foo1'],
                                           ['X-Fetch-Foo', 'foo2'],
                                           ['X-Fetch-Bar', 'bar']]});
-    assert_equals(request3.headers.getAll('X-Fetch-Foo')[0], 'foo1',
+    assert_equals(request3.headers.get('X-Fetch-Foo').split(', ')[0], 'foo1',
                   'Request.headers should match');
-    assert_equals(request3.headers.getAll('X-Fetch-Foo')[1], 'foo2',
+    assert_equals(request3.headers.get('X-Fetch-Foo').split(', ')[1], 'foo2',
                   'Request.headers should match');
-    assert_equals(request3.headers.getAll('X-Fetch-Bar')[0], 'bar',
+    assert_equals(request3.headers.get('X-Fetch-Bar').split(', ')[0], 'bar',
                   'Request.headers should match');
     var request4 = new Request(URL,
                                {headers: {'X-Fetch-Foo': 'foo1',
                                           'X-Fetch-Foo': 'foo2',
                                           'X-Fetch-Bar': 'bar'}});
-    assert_equals(request4.headers.getAll('X-Fetch-Foo')[0], 'foo2',
+    assert_equals(request4.headers.get('X-Fetch-Foo').split(', ')[0], 'foo2',
                   'Request.headers should match');
-    assert_equals(request4.headers.getAll('X-Fetch-Bar')[0], 'bar',
+    assert_equals(request4.headers.get('X-Fetch-Bar').split(', ')[0], 'bar',
                   'Request.headers should match');
     // https://github.com/whatwg/fetch/issues/479
     var request5 = new Request(request, {headers: undefined});
-    assert_equals(request5.headers.getAll('X-Fetch-Foo')[0], 'foo1',
+    assert_equals(request5.headers.get('X-Fetch-Foo').split(', ')[0], 'foo1',
                   'Request.headers should match');
-    assert_equals(request5.headers.getAll('X-Fetch-Foo')[1], 'foo2',
+    assert_equals(request5.headers.get('X-Fetch-Foo').split(', ')[1], 'foo2',
                   'Request.headers should match');
-    assert_equals(request5.headers.getAll('X-Fetch-Bar')[0], 'bar',
+    assert_equals(request5.headers.get('X-Fetch-Bar').split(', ')[0], 'bar',
                   'Request.headers should match');
     var request6 = new Request(request, {});
-    assert_equals(request6.headers.getAll('X-Fetch-Foo')[0], 'foo1',
+    assert_equals(request6.headers.get('X-Fetch-Foo').split(', ')[0], 'foo1',
                   'Request.headers should match');
-    assert_equals(request6.headers.getAll('X-Fetch-Foo')[1], 'foo2',
+    assert_equals(request6.headers.get('X-Fetch-Foo').split(', ')[1], 'foo2',
                   'Request.headers should match');
-    assert_equals(request6.headers.getAll('X-Fetch-Bar')[0], 'bar',
+    assert_equals(request6.headers.get('X-Fetch-Bar').split(', ')[0], 'bar',
                   'Request.headers should match');
     assert_throws(new TypeError(),
                   () => { new Request(request, {headers: null}) },
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/doc-write-sync-third-party-script-reload-expected.txt b/third_party/WebKit/LayoutTests/http/tests/loading/doc-write-sync-third-party-script-reload-expected.txt
index 1d06d6e5..055f2cd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/doc-write-sync-third-party-script-reload-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/doc-write-sync-third-party-script-reload-expected.txt
@@ -4,12 +4,12 @@
 CONSOLE WARNING: line 47: A Parser-blocking, cross site (i.e. different eTLD+1) script, http://localhost:8000/loading/resources/js-loaded.js?reload, is invoked via document.write. The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity. If blocked in this page load, it will be confirmed in a subsequent console message.See https://www.chromestatus.com/feature/5718547946799104 for more details.
 CONSOLE ERROR: Network request for the parser-blocking, cross site (i.e. different eTLD+1) script, http://localhost:8000/loading/resources/js-loaded.js?reload, invoked via document.write was BLOCKED by the browser due to poor network connectivity. 
 main frame - didStartProvisionalLoadForFrame
-main frame - didFailLoadWithError
+main frame - didFinishLoadForFrame
 main frame - didCommitLoadForFrame
 CONSOLE WARNING: line 47: A Parser-blocking, cross site (i.e. different eTLD+1) script, http://localhost:8000/loading/resources/js-loaded.js?reload, is invoked via document.write. The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity. If blocked in this page load, it will be confirmed in a subsequent console message.See https://www.chromestatus.com/feature/5718547946799104 for more details.
 CONSOLE WARNING: line 47: A Parser-blocking, cross site (i.e. different eTLD+1) script, http://localhost:8000/loading/resources/js-loaded.js?reload, is invoked via document.write. The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity. If blocked in this page load, it will be confirmed in a subsequent console message.See https://www.chromestatus.com/feature/5718547946799104 for more details.
 main frame - didStartProvisionalLoadForFrame
-main frame - didFailLoadWithError
+main frame - didFinishLoadForFrame
 main frame - didCommitLoadForFrame
 CONSOLE WARNING: line 47: A Parser-blocking, cross site (i.e. different eTLD+1) script, http://localhost:8000/loading/resources/js-loaded.js?reload, is invoked via document.write. The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity. If blocked in this page load, it will be confirmed in a subsequent console message.See https://www.chromestatus.com/feature/5718547946799104 for more details.
 CONSOLE WARNING: line 47: A Parser-blocking, cross site (i.e. different eTLD+1) script, http://localhost:8000/loading/resources/js-loaded.js?reload, is invoked via document.write. The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity. If blocked in this page load, it will be confirmed in a subsequent console message.See https://www.chromestatus.com/feature/5718547946799104 for more details.
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 552dddd..58596a0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -450,7 +450,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/container-backgrounds-on-cell-resize-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/table/container-backgrounds-on-cell-resize-expected.html
new file mode 100644
index 0000000..3725b8a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/container-backgrounds-on-cell-resize-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<style>
+  tr { height: 30px }
+</style>
+Should repaint the backgrounds of column (yellow), section (blue) and row (green) when cells resize.
+<table id="table" style="width: 300px">
+  <colgroup>
+    <col style="background: yellow">
+  </colgroup>
+  <thead style="background: blue">
+    <tr>
+      <td>A</td><td style="width: 200px">B</td><td>C</td>
+    </tr>
+  </thead>
+  <tbody>
+    <tr style="background: green">
+      <td>A</td><td>B</td><td>C</td>
+    </tr>
+  </tbody>
+  <tfoot>
+    <tr>
+      <td>A</td><td>B</td><td>C</td>
+    </tr>
+  </tfoot>
+</table>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/container-backgrounds-on-cell-resize.html b/third_party/WebKit/LayoutTests/paint/invalidation/table/container-backgrounds-on-cell-resize.html
new file mode 100644
index 0000000..ac60509
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/container-backgrounds-on-cell-resize.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+  tr { height: 30px }
+</style>
+Should repaint the backgrounds of column (yellow), section (blue) and row (green) when cells resize.
+<table style="width: 300px">
+  <colgroup>
+    <col style="background: yellow">
+  </colgroup>
+  <thead style="background: blue">
+    <tr>
+      <td>A</td><td id="cell" style="width: 100px">B</td><td>C</td>
+    </tr>
+  </thead>
+  <tbody>
+    <tr style="background: green">
+      <td>A</td><td>B</td><td>C</td>
+    </tr>
+  </tbody>
+  <tfoot>
+    <tr>
+      <td>A</td><td>B</td><td>C</td>
+    </tr>
+  </tfoot>
+</table>
+<script src="../../../resources/run-after-layout-and-paint.js"></script>
+<script>
+runAfterLayoutAndPaint(function() {
+  cell.style.width = '200px';
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 66b8cdd..e46102a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -237,7 +237,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 4cd21f2..b741254 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -250,7 +250,6 @@
 [Worker]     method entries
 [Worker]     method forEach
 [Worker]     method get
-[Worker]     method getAll
 [Worker]     method has
 [Worker]     method keys
 [Worker]     method set
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
index 17c7398..3dce0fe5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -2921,7 +2921,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index 90fe4db..e06c0a1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -245,7 +245,6 @@
 [Worker]     method entries
 [Worker]     method forEach
 [Worker]     method get
-[Worker]     method getAll
 [Worker]     method has
 [Worker]     method keys
 [Worker]     method set
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
index 69683cdb..47bf4bb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -2850,7 +2850,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 8280e05..ff02c2e 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -449,7 +449,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-dedicated-worker-expected.txt
index b8097e42..4e45ce1 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -458,7 +458,6 @@
 [Worker]     method entries
 [Worker]     method forEach
 [Worker]     method get
-[Worker]     method getAll
 [Worker]     method has
 [Worker]     method keys
 [Worker]     method set
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 1b63fab21..2d69493 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
@@ -3550,7 +3550,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-shared-worker-expected.txt
index ffce2e4..adee98cd 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -453,7 +453,6 @@
 [Worker]     method entries
 [Worker]     method forEach
 [Worker]     method get
-[Worker]     method getAll
 [Worker]     method has
 [Worker]     method keys
 [Worker]     method set
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 552dddd..58596a0 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -450,7 +450,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 56ef204..23cdb68d 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -237,7 +237,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 4f1d65c..77ad9a51 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -250,7 +250,6 @@
 [Worker]     method entries
 [Worker]     method forEach
 [Worker]     method get
-[Worker]     method getAll
 [Worker]     method has
 [Worker]     method keys
 [Worker]     method set
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index fe9a79453..da1ef84 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -245,7 +245,6 @@
 [Worker]     method entries
 [Worker]     method forEach
 [Worker]     method get
-[Worker]     method getAll
 [Worker]     method has
 [Worker]     method keys
 [Worker]     method set
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index f5485e1f..a9b52f5f 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -458,7 +458,6 @@
 [Worker]     method entries
 [Worker]     method forEach
 [Worker]     method get
-[Worker]     method getAll
 [Worker]     method has
 [Worker]     method keys
 [Worker]     method set
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 d6d736ba..4bc76773 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3550,7 +3550,6 @@
     method entries
     method forEach
     method get
-    method getAll
     method has
     method keys
     method set
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index ce13cfa..79ddbf95 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -453,7 +453,6 @@
 [Worker]     method entries
 [Worker]     method forEach
 [Worker]     method get
-[Worker]     method getAll
 [Worker]     method has
 [Worker]     method keys
 [Worker]     method set
diff --git a/third_party/WebKit/Source/bindings/core/v8/SharedPersistent.h b/third_party/WebKit/Source/bindings/core/v8/SharedPersistent.h
index 886275b..d50999b 100644
--- a/third_party/WebKit/Source/bindings/core/v8/SharedPersistent.h
+++ b/third_party/WebKit/Source/bindings/core/v8/SharedPersistent.h
@@ -28,42 +28,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef SharedPersistent_h
-#define SharedPersistent_h
-
-#include "bindings/core/v8/ScopedPersistent.h"
-#include "platform/wtf/PassRefPtr.h"
-#include "platform/wtf/RefCounted.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-template <typename T>
-class SharedPersistent : public RefCounted<SharedPersistent<T>> {
-  WTF_MAKE_NONCOPYABLE(SharedPersistent);
-
- public:
-  static PassRefPtr<SharedPersistent<T>> Create(v8::Local<T> value,
-                                                v8::Isolate* isolate) {
-    return AdoptRef(new SharedPersistent<T>(value, isolate));
-  }
-
-  v8::Local<T> NewLocal(v8::Isolate* isolate) const {
-    return value_.NewLocal(isolate);
-  }
-
-  bool IsEmpty() { return value_.IsEmpty(); }
-
-  bool operator==(const SharedPersistent<T>& other) {
-    return value_ == other.value_;
-  }
-
- private:
-  explicit SharedPersistent(v8::Local<T> value, v8::Isolate* isolate)
-      : value_(isolate, value) {}
-  ScopedPersistent<T> value_;
-};
-
-}  // namespace blink
-
-#endif  // SharedPersistent_h
+// This file has been moved to platform/bindings/SharedPersistent.h.
+// TODO(adithyas): Remove this file.
+#include "platform/bindings/SharedPersistent.h"
diff --git a/third_party/WebKit/Source/bindings/core/v8/ToV8.h b/third_party/WebKit/Source/bindings/core/v8/ToV8.h
index 10c1cd9..36a3675 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ToV8.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ToV8.h
@@ -2,306 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ToV8_h
-#define ToV8_h
-
-// ToV8() provides C++ -> V8 conversion. Note that ToV8() can return an empty
-// handle. Call sites must check IsEmpty() before using return value.
-
-#include <utility>
-
-#include "bindings/core/v8/DOMDataStore.h"
-#include "bindings/core/v8/IDLDictionaryBase.h"
-#include "bindings/core/v8/ScriptState.h"
-#include "bindings/core/v8/ScriptValue.h"
-#include "bindings/core/v8/ScriptWrappable.h"
-#include "bindings/core/v8/V8Binding.h"
-#include "core/CoreExport.h"
-#include "core/dom/ArrayBufferViewHelpers.h"
-#include "platform/heap/Handle.h"
-#include "platform/wtf/Forward.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-// ScriptWrappable
-
-inline v8::Local<v8::Value> ToV8(ScriptWrappable* impl,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  if (UNLIKELY(!impl))
-    return v8::Null(isolate);
-  v8::Local<v8::Value> wrapper = DOMDataStore::GetWrapper(impl, isolate);
-  if (!wrapper.IsEmpty())
-    return wrapper;
-
-  wrapper = impl->Wrap(isolate, creation_context);
-  DCHECK(!wrapper.IsEmpty());
-  return wrapper;
-}
-
-// Primitives
-
-inline v8::Local<v8::Value> ToV8(const String& value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return V8String(isolate, value);
-}
-
-inline v8::Local<v8::Value> ToV8(const char* value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return V8String(isolate, value);
-}
-
-template <size_t sizeOfValue>
-inline v8::Local<v8::Value> ToV8SignedIntegerInternal(int64_t value,
-                                                      v8::Isolate*);
-
-template <>
-inline v8::Local<v8::Value> ToV8SignedIntegerInternal<4>(int64_t value,
-                                                         v8::Isolate* isolate) {
-  return v8::Integer::New(isolate, static_cast<int32_t>(value));
-}
-
-template <>
-inline v8::Local<v8::Value> ToV8SignedIntegerInternal<8>(int64_t value,
-                                                         v8::Isolate* isolate) {
-  int32_t value_in32_bit = static_cast<int32_t>(value);
-  if (value_in32_bit == value)
-    return v8::Integer::New(isolate, value);
-  // V8 doesn't have a 64-bit integer implementation.
-  return v8::Number::New(isolate, value);
-}
-
-template <size_t sizeOfValue>
-inline v8::Local<v8::Value> ToV8UnsignedIntegerInternal(uint64_t value,
-                                                        v8::Isolate*);
-
-template <>
-inline v8::Local<v8::Value> ToV8UnsignedIntegerInternal<4>(
-    uint64_t value,
-    v8::Isolate* isolate) {
-  return v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(value));
-}
-
-template <>
-inline v8::Local<v8::Value> ToV8UnsignedIntegerInternal<8>(
-    uint64_t value,
-    v8::Isolate* isolate) {
-  uint32_t value_in32_bit = static_cast<uint32_t>(value);
-  if (value_in32_bit == value)
-    return v8::Integer::NewFromUnsigned(isolate, value);
-  // V8 doesn't have a 64-bit integer implementation.
-  return v8::Number::New(isolate, value);
-}
-
-inline v8::Local<v8::Value> ToV8(int value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return ToV8SignedIntegerInternal<sizeof value>(value, isolate);
-}
-
-inline v8::Local<v8::Value> ToV8(long value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return ToV8SignedIntegerInternal<sizeof value>(value, isolate);
-}
-
-inline v8::Local<v8::Value> ToV8(long long value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return ToV8SignedIntegerInternal<sizeof value>(value, isolate);
-}
-
-inline v8::Local<v8::Value> ToV8(unsigned value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return ToV8UnsignedIntegerInternal<sizeof value>(value, isolate);
-}
-
-inline v8::Local<v8::Value> ToV8(unsigned long value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return ToV8UnsignedIntegerInternal<sizeof value>(value, isolate);
-}
-
-inline v8::Local<v8::Value> ToV8(unsigned long long value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return ToV8UnsignedIntegerInternal<sizeof value>(value, isolate);
-}
-
-inline v8::Local<v8::Value> ToV8(double value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return v8::Number::New(isolate, value);
-}
-
-inline v8::Local<v8::Value> ToV8(bool value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return v8::Boolean::New(isolate, value);
-}
-
-// Identity operator
-
-inline v8::Local<v8::Value> ToV8(v8::Local<v8::Value> value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate*) {
-  return value;
-}
-
-// Undefined
-
-struct ToV8UndefinedGenerator {
-  DISALLOW_NEW();
-};  // Used only for having toV8 return v8::Undefined.
-
-inline v8::Local<v8::Value> ToV8(const ToV8UndefinedGenerator& value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return v8::Undefined(isolate);
-}
-
-// ScriptValue
-
-inline v8::Local<v8::Value> ToV8(const ScriptValue& value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  if (value.IsEmpty())
-    return v8::Undefined(isolate);
-  return value.V8Value();
-}
-
-// Dictionary
-
-inline v8::Local<v8::Value> ToV8(const IDLDictionaryBase& value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return value.ToV8Impl(creation_context, isolate);
-}
-
-// Array
-
-// Declare the function here but define it later so it can call the ToV8()
-// overloads below.
-template <typename Sequence>
-inline v8::Local<v8::Value> ToV8SequenceInternal(
-    const Sequence&,
-    v8::Local<v8::Object> creation_context,
-    v8::Isolate*);
-
-template <typename T, size_t inlineCapacity>
-inline v8::Local<v8::Value> ToV8(const Vector<T, inlineCapacity>& value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return ToV8SequenceInternal(value, creation_context, isolate);
-}
-
-template <typename T, size_t inlineCapacity>
-inline v8::Local<v8::Value> ToV8(const HeapVector<T, inlineCapacity>& value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  return ToV8SequenceInternal(value, creation_context, isolate);
-}
-
-// The following two overloads are also used to convert record<K,V> IDL types
-// back into ECMAScript Objects.
-template <typename T>
-inline v8::Local<v8::Value> ToV8(const Vector<std::pair<String, T>>& value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  v8::Local<v8::Object> object;
-  {
-    v8::Context::Scope context_scope(creation_context->CreationContext());
-    object = v8::Object::New(isolate);
-  }
-  for (unsigned i = 0; i < value.size(); ++i) {
-    v8::Local<v8::Value> v8_value = ToV8(value[i].second, object, isolate);
-    if (v8_value.IsEmpty())
-      v8_value = v8::Undefined(isolate);
-    if (!V8CallBoolean(object->CreateDataProperty(
-            isolate->GetCurrentContext(), V8String(isolate, value[i].first),
-            v8_value)))
-      return v8::Local<v8::Value>();
-  }
-  return object;
-}
-
-template <typename T>
-inline v8::Local<v8::Value> ToV8(const HeapVector<std::pair<String, T>>& value,
-                                 v8::Local<v8::Object> creation_context,
-                                 v8::Isolate* isolate) {
-  v8::Local<v8::Object> object;
-  {
-    v8::Context::Scope context_scope(creation_context->CreationContext());
-    object = v8::Object::New(isolate);
-  }
-  for (unsigned i = 0; i < value.size(); ++i) {
-    v8::Local<v8::Value> v8_value = ToV8(value[i].second, object, isolate);
-    if (v8_value.IsEmpty())
-      v8_value = v8::Undefined(isolate);
-    if (!V8CallBoolean(object->CreateDataProperty(
-            isolate->GetCurrentContext(), V8String(isolate, value[i].first),
-            v8_value)))
-      return v8::Local<v8::Value>();
-  }
-  return object;
-}
-
-template <typename Sequence>
-inline v8::Local<v8::Value> ToV8SequenceInternal(
-    const Sequence& sequence,
-    v8::Local<v8::Object> creation_context,
-    v8::Isolate* isolate) {
-  v8::Local<v8::Array> array;
-  {
-    v8::Context::Scope context_scope(creation_context->CreationContext());
-    array = v8::Array::New(isolate, sequence.size());
-  }
-  uint32_t index = 0;
-  typename Sequence::const_iterator end = sequence.end();
-  for (typename Sequence::const_iterator iter = sequence.begin(); iter != end;
-       ++iter) {
-    v8::Local<v8::Value> value = ToV8(*iter, array, isolate);
-    if (value.IsEmpty())
-      value = v8::Undefined(isolate);
-    if (!V8CallBoolean(array->CreateDataProperty(isolate->GetCurrentContext(),
-                                                 index++, value)))
-      return v8::Local<v8::Value>();
-  }
-  return array;
-}
-
-// In all cases allow script state instead of creation context + isolate.
-// Use this function only if the call site does not otherwise need the global,
-// since v8::Context::Global is heavy.
-template <typename T>
-inline v8::Local<v8::Value> ToV8(T&& value, ScriptState* script_state) {
-  return ToV8(std::forward<T>(value), script_state->GetContext()->Global(),
-              script_state->GetIsolate());
-}
-
-// Only declare ToV8(void*,...) for checking function overload mismatch.
-// This ToV8(void*,...) should be never used. So we will find mismatch
-// because of "unresolved external symbol".
-// Without ToV8(void*, ...), call to toV8 with T* will match with
-// ToV8(bool, ...) if T is not a subclass of ScriptWrappable or if T is
-// declared but not defined (so it's not clear that T is a subclass of
-// ScriptWrappable).
-// This hack helps detect such unwanted implicit conversions from T* to bool.
-v8::Local<v8::Value> ToV8(void* value,
-                          v8::Local<v8::Object> creation_context,
-                          v8::Isolate*) = delete;
-
-// Cannot define in ScriptValue because of the circular dependency between toV8
-// and ScriptValue
-template <typename T>
-inline ScriptValue ScriptValue::From(ScriptState* script_state, T&& value) {
-  return ScriptValue(script_state, ToV8(std::forward<T>(value), script_state));
-}
-
-}  // namespace blink
-
-#endif  // ToV8ForPlatform_h
+// This file has been moved to platform/bindings/ToV8.h.
+// TODO(adithyas): Remove this file.
+#include "platform/bindings/ToV8.h"
diff --git a/third_party/WebKit/Source/bindings/core/v8/ToV8ForCore.h b/third_party/WebKit/Source/bindings/core/v8/ToV8ForCore.h
index 077c84a3..9fe4095 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ToV8ForCore.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ToV8ForCore.h
@@ -8,6 +8,8 @@
 // ToV8() provides C++ -> V8 conversion. Note that ToV8() can return an empty
 // handle. Call sites must check IsEmpty() before using return value.
 
+#include "bindings/core/v8/IDLDictionaryBase.h"
+#include "bindings/core/v8/ScriptValue.h"
 #include "bindings/core/v8/ToV8.h"
 #include "bindings/core/v8/V8NodeFilterCondition.h"
 #include "core/dom/ArrayBufferViewHelpers.h"
@@ -52,6 +54,31 @@
   return value ? value->Callback(isolate) : v8::Null(isolate).As<v8::Value>();
 }
 
+// Dictionary
+
+inline v8::Local<v8::Value> ToV8(const IDLDictionaryBase& value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return value.ToV8Impl(creation_context, isolate);
+}
+
+// ScriptValue
+
+inline v8::Local<v8::Value> ToV8(const ScriptValue& value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  if (value.IsEmpty())
+    return v8::Undefined(isolate);
+  return value.V8Value();
+}
+
+// Cannot define in ScriptValue because of the circular dependency between toV8
+// and ScriptValue
+template <typename T>
+inline ScriptValue ScriptValue::From(ScriptState* script_state, T&& value) {
+  return ScriptValue(script_state, ToV8(std::forward<T>(value), script_state));
+}
+
 }  // namespace blink
 
 #endif  // ToV8ForCore_h
diff --git a/third_party/WebKit/Source/bindings/core/v8/TraceWrapperMember.h b/third_party/WebKit/Source/bindings/core/v8/TraceWrapperMember.h
index 79833c33..43f94492 100644
--- a/third_party/WebKit/Source/bindings/core/v8/TraceWrapperMember.h
+++ b/third_party/WebKit/Source/bindings/core/v8/TraceWrapperMember.h
@@ -2,146 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef TraceWrapperMember_h
-#define TraceWrapperMember_h
-
-#include "bindings/core/v8/ScriptWrappableVisitor.h"
-#include "platform/heap/HeapAllocator.h"
-
-namespace blink {
-
-class HeapObjectHeader;
-template <typename T>
-class Member;
-
-/**
- * TraceWrapperMember is used for Member fields that should participate in
- * wrapper tracing, i.e., strongly hold a ScriptWrappable alive. All
- * TraceWrapperMember fields must be traced in the class' traceWrappers method.
- */
-template <class T>
-class TraceWrapperMember : public Member<T> {
-  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-
- public:
-  TraceWrapperMember(void* parent, T* raw) : Member<T>(raw), parent_(parent) {
-#if DCHECK_IS_ON()
-    if (parent_) {
-      HeapObjectHeader::CheckFromPayload(parent_);
-    }
-#endif
-    // We don't require a write barrier here as TraceWrapperMember is used for
-    // the following scenarios:
-    // - Initial initialization: The write barrier will not fire as the parent
-    //   is initially white.
-    // - Wrapping when inserting into a container: The write barrier will fire
-    //   upon establishing the move into the container.
-    // - Assignment to a field: The regular assignment operator will fire the
-    //   write barrier.
-    // Note that support for black allocation would require a barrier here.
-  }
-  TraceWrapperMember(WTF::HashTableDeletedValueType x)
-      : Member<T>(x), parent_(nullptr) {}
-
-  /**
-   * Copying a TraceWrapperMember means that its backpointer will also be
-   * copied.
-   */
-  TraceWrapperMember(const TraceWrapperMember& other) { *this = other; }
-
-  TraceWrapperMember& operator=(const TraceWrapperMember& other) {
-    DCHECK(!other.raw_ || other.parent_);
-    parent_ = other.parent_;
-    Member<T>::operator=(other);
-    ScriptWrappableVisitor::WriteBarrier(parent_, other);
-    return *this;
-  }
-
-  TraceWrapperMember& operator=(const Member<T>& other) {
-    DCHECK(!TraceWrapperMemberIsNotInitialized());
-    Member<T>::operator=(other);
-    ScriptWrappableVisitor::WriteBarrier(parent_, other);
-    return *this;
-  }
-
-  TraceWrapperMember& operator=(T* other) {
-    DCHECK(!TraceWrapperMemberIsNotInitialized());
-    Member<T>::operator=(other);
-    ScriptWrappableVisitor::WriteBarrier(parent_, other);
-    return *this;
-  }
-
-  TraceWrapperMember& operator=(std::nullptr_t) {
-    // No need for a write barrier when assigning nullptr.
-    Member<T>::operator=(nullptr);
-    return *this;
-  }
-
-  void* Parent() { return parent_; }
-
- private:
-  bool TraceWrapperMemberIsNotInitialized() { return !parent_; }
-
-  /**
-   * The parent object holding strongly onto the actual Member.
-   */
-  void* parent_;
-};
-
-/**
- * Swaps two HeapVectors specialized for TraceWrapperMember. The custom swap
- * function is required as TraceWrapperMember contains ownership information
- * which is not copyable but has to be explicitly specified.
- */
-template <typename T>
-void swap(HeapVector<TraceWrapperMember<T>>& a,
-          HeapVector<TraceWrapperMember<T>>& b,
-          void* parent_for_a,
-          void* parent_for_b) {
-  HeapVector<TraceWrapperMember<T>> temp;
-  temp.ReserveCapacity(a.size());
-  for (auto item : a) {
-    temp.push_back(TraceWrapperMember<T>(parent_for_b, item.Get()));
-  }
-  a.clear();
-  a.ReserveCapacity(b.size());
-  for (auto item : b) {
-    a.push_back(TraceWrapperMember<T>(parent_for_a, item.Get()));
-  }
-  b.clear();
-  b.ReserveCapacity(temp.size());
-  for (auto item : temp) {
-    b.push_back(TraceWrapperMember<T>(parent_for_b, item.Get()));
-  }
-}
-
-/**
- * Swaps two HeapVectors, one containing TraceWrapperMember and one with
- * regular Members. The custom swap function is required as
- * TraceWrapperMember contains ownership information which is not copyable
- * but has to be explicitly specified.
- */
-template <typename T>
-void swap(HeapVector<TraceWrapperMember<T>>& a,
-          HeapVector<Member<T>>& b,
-          void* parent_for_a) {
-  HeapVector<TraceWrapperMember<T>> temp;
-  temp.ReserveCapacity(a.size());
-  for (auto item : a) {
-    temp.push_back(TraceWrapperMember<T>(item.Parent(), item.Get()));
-  }
-  a.clear();
-  a.ReserveCapacity(b.size());
-  for (auto item : b) {
-    a.push_back(TraceWrapperMember<T>(parent_for_a, item.Get()));
-  }
-  b.clear();
-  b.ReserveCapacity(temp.size());
-  for (auto item : temp) {
-    b.push_back(item.Get());
-  }
-}
-
-}  // namespace blink
-
-#endif  // TraceWrapperMember_h
+// This file has been moved to platform/bindings/TraceWrapperMember.h.
+// TODO(adithyas): Remove this file.
+#include "platform/bindings/TraceWrapperMember.h"
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index e0671b9..959fc43 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -536,7 +536,7 @@
           this,
           &Document::UpdateFocusAppearanceTimerFired),
       css_target_(nullptr),
-      load_event_progress_(kLoadEventNotRun),
+      load_event_progress_(kLoadEventCompleted),
       start_time_(CurrentTime()),
       script_runner_(ScriptRunner::Create(this)),
       xml_version_("1.0"),
@@ -2813,9 +2813,6 @@
 
   if (frame_)
     frame_->Loader().DidExplicitOpen();
-  if (load_event_progress_ != kLoadEventInProgress &&
-      PageDismissalEventBeingDispatched() == kNoDismissal)
-    load_event_progress_ = kLoadEventNotRun;
 }
 
 void Document::DetachParser() {
@@ -2830,12 +2827,11 @@
   DetachParser();
   SetParsingState(kFinishedParsing);
   SetReadyState(kComplete);
+  SuppressLoadEvent();
 }
 
 DocumentParser* Document::ImplicitOpen(
     ParserSynchronizationPolicy parser_sync_policy) {
-  DetachParser();
-
   RemoveChildren();
   DCHECK(!focused_element_);
 
@@ -2849,11 +2845,16 @@
     parser_sync_policy = kForceSynchronousParsing;
   }
 
+  DetachParser();
   parser_sync_policy_ = parser_sync_policy;
   parser_ = CreateParser();
   DocumentParserTiming::From(*this).MarkParserStart();
   SetParsingState(kParsing);
   SetReadyState(kLoading);
+  if (load_event_progress_ != kLoadEventInProgress &&
+      PageDismissalEventBeingDispatched() == kNoDismissal) {
+    load_event_progress_ = kLoadEventNotRun;
+  }
 
   return parser_;
 }
@@ -2995,30 +2996,15 @@
       !GetScriptableDocumentParser()->IsParsing())
     return;
 
-  if (DocumentParser* parser = parser_)
-    parser->Finish();
-
-  if (!frame_) {
-    // Because we have no frame, we don't know if all loading has completed,
-    // so we just call implicitClose() immediately. FIXME: This might fire
-    // the load event prematurely
-    // <http://bugs.webkit.org/show_bug.cgi?id=14568>.
-    ImplicitClose();
-    return;
-  }
-
-  frame_->Loader().CheckCompleted();
+  parser_->Finish();
+  if (!parser_ || !parser_->IsParsing())
+    SetReadyState(kComplete);
+  CheckCompleted();
 }
 
 void Document::ImplicitClose() {
   DCHECK(!InStyleRecalc());
-  if (ProcessingLoadEvent() || !parser_)
-    return;
-  if (GetFrame() &&
-      GetFrame()->GetNavigationScheduler().LocationChangePending()) {
-    SuppressLoadEvent();
-    return;
-  }
+  DCHECK(parser_);
 
   load_event_progress_ = kLoadEventInProgress;
 
@@ -3100,6 +3086,69 @@
     AccessSVGExtensions().StartAnimations();
 }
 
+static bool AllDescendantsAreComplete(Frame* frame) {
+  if (!frame)
+    return true;
+  for (Frame* child = frame->Tree().FirstChild(); child;
+       child = child->Tree().TraverseNext(frame)) {
+    if (child->IsLoading())
+      return false;
+  }
+  return true;
+}
+
+bool Document::ShouldComplete() {
+  return parsing_state_ == kFinishedParsing && HaveImportsLoaded() &&
+         !fetcher_->BlockingRequestCount() && !IsDelayingLoadEvent() &&
+         load_event_progress_ != kLoadEventInProgress &&
+         AllDescendantsAreComplete(frame_);
+}
+
+void Document::CheckCompleted() {
+  if (!ShouldComplete())
+    return;
+
+  if (frame_) {
+    frame_->Client()->RunScriptsAtDocumentIdle();
+
+    // Injected scripts may have disconnected this frame.
+    if (!frame_)
+      return;
+
+    // Check again, because runScriptsAtDocumentIdle() may have delayed the load
+    // event.
+    if (!ShouldComplete())
+      return;
+  }
+
+  // OK, completed. Fire load completion events as needed.
+  SetReadyState(kComplete);
+  if (LoadEventStillNeeded())
+    ImplicitClose();
+
+  // The readystatechanged or load event may have disconnected this frame.
+  if (!frame_ || !frame_->IsAttached())
+    return;
+  frame_->GetNavigationScheduler().StartTimer();
+  View()->HandleLoadCompleted();
+  // The document itself is complete, but if a child frame was restarted due to
+  // an event, this document is still considered to be in progress.
+  if (!AllDescendantsAreComplete(frame_))
+    return;
+
+  // No need to repeat if we've already notified this load as finished.
+  if (!Loader()->SentDidFinishLoad()) {
+    if (frame_->IsMainFrame())
+      ViewportDescription().ReportMobilePageStats(frame_);
+    Loader()->SetSentDidFinishLoad();
+    frame_->Client()->DispatchDidFinishLoad();
+    if (!frame_)
+      return;
+  }
+
+  frame_->Loader().DidFinishNavigation();
+}
+
 bool Document::DispatchBeforeUnloadEvent(ChromeClient& chrome_client,
                                          bool is_reload,
                                          bool& did_allow_navigation) {
@@ -6043,8 +6092,8 @@
   DCHECK(load_event_delay_count_);
   --load_event_delay_count_;
 
-  if (!load_event_delay_count_ && GetFrame())
-    GetFrame()->Loader().CheckCompleted();
+  if (!load_event_delay_count_)
+    CheckCompleted();
 }
 
 void Document::CheckLoadEventSoon() {
@@ -6066,8 +6115,7 @@
 }
 
 void Document::LoadEventDelayTimerFired(TimerBase*) {
-  if (GetFrame())
-    GetFrame()->Loader().CheckCompleted();
+  CheckCompleted();
 }
 
 void Document::LoadPluginsSoon() {
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 315cdd0..177068b 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -567,8 +567,8 @@
   void close(ExceptionState&);
   // This is used internally and does not handle exceptions.
   void close();
-  // implicitClose() actually does the work of closing the input stream.
-  void ImplicitClose();
+
+  void CheckCompleted();
 
   bool DispatchBeforeUnloadEvent(ChromeClient&,
                                  bool is_reload,
@@ -681,9 +681,6 @@
   enum ParsingState { kParsing, kInDOMContentLoaded, kFinishedParsing };
   void SetParsingState(ParsingState);
   bool Parsing() const { return parsing_state_ == kParsing; }
-  bool IsInDOMContentLoaded() const {
-    return parsing_state_ == kInDOMContentLoaded;
-  }
   bool HasFinishedParsing() const { return parsing_state_ == kFinishedParsing; }
 
   bool ShouldScheduleLayout() const;
@@ -1052,9 +1049,6 @@
   bool LoadEventStillNeeded() const {
     return load_event_progress_ == kLoadEventNotRun;
   }
-  bool ProcessingLoadEvent() const {
-    return load_event_progress_ == kLoadEventInProgress;
-  }
   bool LoadEventFinished() const {
     return load_event_progress_ >= kLoadEventCompleted;
   }
@@ -1172,7 +1166,6 @@
   }
   HTMLImportLoader* ImportLoader() const;
 
-  bool HaveImportsLoaded() const;
   void DidLoadAllImports();
 
   void AdjustFloatQuadsForScrollAndAbsoluteZoom(Vector<FloatQuad>&,
@@ -1379,6 +1372,10 @@
   void UpdateStyle();
   void NotifyLayoutTreeOfSubtreeChanges();
 
+  // ImplicitClose() actually does the work of closing the input stream.
+  void ImplicitClose();
+  bool ShouldComplete();
+
   void DetachParser();
 
   void BeginLifecycleUpdatesIfRenderingReady();
@@ -1443,6 +1440,8 @@
   void RunExecutionContextTask(std::unique_ptr<ExecutionContextTask>,
                                bool instrumenting);
 
+  bool HaveImportsLoaded() const;
+
   DocumentLifecycle lifecycle_;
 
   bool has_nodes_with_placeholder_style_;
diff --git a/third_party/WebKit/Source/core/dom/DocumentTest.cpp b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
index 773f9b3..c79b959 100644
--- a/third_party/WebKit/Source/core/dom/DocumentTest.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
@@ -727,10 +727,10 @@
   MockValidationMessageClient* mock_client = new MockValidationMessageClient();
   GetDocument().GetSettings()->SetScriptEnabled(true);
   GetPage().SetValidationMessageClient(mock_client);
-  // implicitOpen()-implicitClose() makes Document.loadEventFinished()
+  // ImplicitOpen()-CancelParsing() makes Document.loadEventFinished()
   // true. It's necessary to kick unload process.
   GetDocument().ImplicitOpen(kForceSynchronousParsing);
-  GetDocument().ImplicitClose();
+  GetDocument().CancelParsing();
   GetDocument().AppendChild(GetDocument().createElement("html"));
   SetHtmlInnerHTML("<body><input required></body>");
   Element* script = GetDocument().createElement("script");
diff --git a/third_party/WebKit/Source/core/dom/IncrementLoadEventDelayCount.h b/third_party/WebKit/Source/core/dom/IncrementLoadEventDelayCount.h
index dc32d65..7086378 100644
--- a/third_party/WebKit/Source/core/dom/IncrementLoadEventDelayCount.h
+++ b/third_party/WebKit/Source/core/dom/IncrementLoadEventDelayCount.h
@@ -6,6 +6,7 @@
 #define IncrementLoadEventDelayCount_h
 
 #include <memory>
+#include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Noncopyable.h"
@@ -16,7 +17,7 @@
 
 // A helper class that will increment a document's loadEventDelayCount on
 // contruction and decrement it on destruction (semantics similar to RefPtr).
-class IncrementLoadEventDelayCount {
+class CORE_EXPORT IncrementLoadEventDelayCount {
   USING_FAST_MALLOC(IncrementLoadEventDelayCount);
   WTF_MAKE_NONCOPYABLE(IncrementLoadEventDelayCount);
 
diff --git a/third_party/WebKit/Source/core/frame/DOMWindowTimers.cpp b/third_party/WebKit/Source/core/frame/DOMWindowTimers.cpp
index ccc2ed4..01caf94 100644
--- a/third_party/WebKit/Source/core/frame/DOMWindowTimers.cpp
+++ b/third_party/WebKit/Source/core/frame/DOMWindowTimers.cpp
@@ -72,7 +72,7 @@
       return false;
     return true;
   }
-  ASSERT_NOT_REACHED();
+  NOTREACHED();
   return false;
 }
 
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index ae7344b..68973928 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -39,7 +39,7 @@
       return "M62, around October 2017";
   }
 
-  ASSERT_NOT_REACHED();
+  NOTREACHED();
   return nullptr;
 }
 
diff --git a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp
index f7375a5..dc6790aa 100644
--- a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp
+++ b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp
@@ -243,7 +243,7 @@
       break;
 #endif
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
       break;
   }
 }
@@ -302,7 +302,7 @@
         // DOMWindows may outlive their documents, so we shouldn't remove their
         // handlers here.
       } else {
-        ASSERT_NOT_REACHED();
+        NOTREACHED();
       }
     }
     for (size_t i = 0; i < targets_to_remove.size(); ++i)
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 94240cc..0a34de2e 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -1711,7 +1711,13 @@
     }
   }
 
-  if (!HasViewportConstrainedObjects())
+  if (GetFrame().GetDocument() && !IsInPerformLayout())
+    MarkViewportConstrainedObjectsForLayout(width_changed, height_changed);
+}
+
+void FrameView::MarkViewportConstrainedObjectsForLayout(bool width_changed,
+                                                        bool height_changed) {
+  if (!HasViewportConstrainedObjects() || !(width_changed || height_changed))
     return;
 
   for (const auto& viewport_constrained_object :
@@ -4114,7 +4120,7 @@
 
   if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
     // Don't scroll the FrameView!
-    ASSERT_NOT_REACHED();
+    NOTREACHED();
   }
 
   scroll_offset_ = offset;
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index 2421a68d..80a588093 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -228,6 +228,8 @@
   void DidUpdateElasticOverscroll();
 
   void ViewportSizeChanged(bool width_changed, bool height_changed);
+  void MarkViewportConstrainedObjectsForLayout(bool width_changed,
+                                               bool height_changed);
 
   AtomicString MediaType() const;
   void SetMediaType(const AtomicString&);
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index 1cc3c86..6d8352e8 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -530,21 +530,24 @@
 
 void LocalDOMWindow::SendOrientationChangeEvent() {
   ASSERT(RuntimeEnabledFeatures::orientationEventEnabled());
-  ASSERT(GetFrame()->IsMainFrame());
+  DCHECK(GetFrame()->IsLocalRoot());
 
   // Before dispatching the event, build a list of all frames in the page
   // to send the event to, to mitigate side effects from event handlers
   // potentially interfering with others.
-  HeapVector<Member<Frame>> frames;
-  for (Frame* f = GetFrame(); f; f = f->Tree().TraverseNext())
-    frames.push_back(f);
+  HeapVector<Member<LocalFrame>> frames;
+  frames.push_back(GetFrame());
+  for (size_t i = 0; i < frames.size(); i++) {
+    for (Frame* child = frames[i]->Tree().FirstChild(); child;
+         child = child->Tree().NextSibling()) {
+      if (child->IsLocalFrame())
+        frames.push_back(ToLocalFrame(child));
+    }
+  }
 
-  for (size_t i = 0; i < frames.size(); ++i) {
-    if (!frames[i]->IsLocalFrame())
-      continue;
-    ToLocalFrame(frames[i].Get())
-        ->DomWindow()
-        ->DispatchEvent(Event::Create(EventTypeNames::orientationchange));
+  for (LocalFrame* frame : frames) {
+    frame->DomWindow()->DispatchEvent(
+        Event::Create(EventTypeNames::orientationchange));
   }
 }
 
diff --git a/third_party/WebKit/Source/core/frame/SubresourceIntegrity.cpp b/third_party/WebKit/Source/core/frame/SubresourceIntegrity.cpp
index 1a886368..c96242a 100644
--- a/third_party/WebKit/Source/core/frame/SubresourceIntegrity.cpp
+++ b/third_party/WebKit/Source/core/frame/SubresourceIntegrity.cpp
@@ -90,7 +90,7 @@
       length = WTF_ARRAY_LENGTH(kWeakerThanSha512);
       break;
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
   };
 
   for (size_t i = 0; i < length; i++) {
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.cpp b/third_party/WebKit/Source/core/frame/UseCounter.cpp
index d2123e1..29616c7 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.cpp
+++ b/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -1093,11 +1093,11 @@
     // chromium/src/tools/metrics/histograms to update the UMA histogram names.
 
     case CSSPropertyInvalid:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
       return 0;
   }
 
-  ASSERT_NOT_REACHED();
+  NOTREACHED();
   return 0;
 }
 
diff --git a/third_party/WebKit/Source/core/frame/VisualViewport.cpp b/third_party/WebKit/Source/core/frame/VisualViewport.cpp
index 69454fc..32be070 100644
--- a/third_party/WebKit/Source/core/frame/VisualViewport.cpp
+++ b/third_party/WebKit/Source/core/frame/VisualViewport.cpp
@@ -856,7 +856,7 @@
   } else if (graphics_layer == root_transform_layer_.get()) {
     name = "Root Transform Layer";
   } else {
-    ASSERT_NOT_REACHED();
+    NOTREACHED();
   }
 
   return name;
diff --git a/third_party/WebKit/Source/core/frame/VisualViewport.h b/third_party/WebKit/Source/core/frame/VisualViewport.h
index e633fa2..bf82d7d 100644
--- a/third_party/WebKit/Source/core/frame/VisualViewport.h
+++ b/third_party/WebKit/Source/core/frame/VisualViewport.h
@@ -246,7 +246,7 @@
 
   // GraphicsLayerClient implementation.
   bool NeedsRepaint(const GraphicsLayer&) const {
-    ASSERT_NOT_REACHED();
+    NOTREACHED();
     return true;
   }
   IntRect ComputeInterestRect(const GraphicsLayer*, const IntRect&) const;
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
index 8fe15e7..399514c 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
@@ -145,7 +145,7 @@
     case kContentSecurityPolicyHeaderTypeReport:
       return UseCounter::kContentSecurityPolicyReportOnly;
   }
-  ASSERT_NOT_REACHED();
+  NOTREACHED();
   return UseCounter::kNumberOfFeatures;
 }
 
@@ -866,7 +866,7 @@
     case WebURLRequest::kRequestContextUnspecified:
       return true;
   }
-  ASSERT_NOT_REACHED();
+  NOTREACHED();
   return true;
 }
 
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp
index ed535ae..e04c8af5b 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp
@@ -51,10 +51,8 @@
 void HTMLImportTreeRoot::StateDidChange() {
   HTMLImport::StateDidChange();
 
-  if (!GetState().IsReady())
-    return;
-  if (LocalFrame* frame = document_->GetFrame())
-    frame->Loader().CheckCompleted();
+  if (GetState().IsReady())
+    document_->CheckCompleted();
 }
 
 void HTMLImportTreeRoot::ScheduleRecalcState() {
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index da142b1..4d9a51e 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -118,6 +118,26 @@
          isHTMLInputElement(ToShadowRoot(target_node)->host());
 }
 
+bool ShouldShowIBeamForNode(const Node* node, const HitTestResult& result) {
+  if (!node)
+    return false;
+
+  bool layout_object_selectable = false;
+  if (LayoutObject* layout_object = node->GetLayoutObject()) {
+    PaintLayer* layer = layout_object->EnclosingLayer();
+    if (layer->GetScrollableArea() &&
+        layer->GetScrollableArea()->IsPointInResizeControl(
+            result.RoundedPointInMainFrame(), kResizerForPointer)) {
+      return false;
+    }
+
+    layout_object_selectable =
+        layout_object->IsText() && node->CanStartSelection();
+  }
+
+  return HasEditableStyle(*node) || layout_object_selectable;
+}
+
 }  // namespace
 
 using namespace HTMLNames;
@@ -537,26 +557,16 @@
     return PointerCursor();
   }
 
-  bool editable = (node && HasEditableStyle(*node));
-
   const bool is_over_link =
       !GetSelectionController().MouseDownMayStartSelect() &&
       result.IsOverLink();
   if (UseHandCursor(node, is_over_link))
     return HandCursor();
 
-  bool in_resizer = false;
-  LayoutObject* layout_object = node ? node->GetLayoutObject() : nullptr;
-  if (layout_object && frame_->View()) {
-    PaintLayer* layer = layout_object->EnclosingLayer();
-    in_resizer = layer->GetScrollableArea() &&
-                 layer->GetScrollableArea()->IsPointInResizeControl(
-                     result.RoundedPointInMainFrame(), kResizerForPointer);
-  }
-
   // During selection, use an I-beam no matter what we're over.
   // If a drag may be starting or we're capturing mouse events for a particular
-  // node, don't treat this as a selection.
+  // node, don't treat this as a selection. Note calling
+  // ComputeVisibleSelectionInDOMTreeDeprecated may update layout.
   if (mouse_event_manager_->MousePressed() &&
       GetSelectionController().MouseDownMayStartSelect() &&
       !mouse_event_manager_->MouseDownMayStartDrag() &&
@@ -567,9 +577,7 @@
     return i_beam;
   }
 
-  if ((editable || (layout_object && layout_object->IsText() &&
-                    node->CanStartSelection())) &&
-      !in_resizer && !result.GetScrollbar())
+  if (ShouldShowIBeamForNode(node, result))
     return i_beam;
   return PointerCursor();
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
index 87e7a70..f4c4d5bf 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
@@ -35,6 +35,7 @@
 #include "core/layout/SubtreeLayoutScope.h"
 #include "core/paint/ObjectPaintInvalidator.h"
 #include "core/paint/PaintLayer.h"
+#include "core/paint/TableCellPaintInvalidator.h"
 #include "core/paint/TableCellPainter.h"
 #include "platform/geometry/FloatQuad.h"
 #include "platform/geometry/TransformState.h"
@@ -1491,4 +1492,14 @@
   return LayoutBlock::HasLineIfEmpty();
 }
 
+PaintInvalidationReason LayoutTableCell::InvalidatePaint(
+    const PaintInvalidatorContext& context) const {
+  return TableCellPaintInvalidator(*this, context).InvalidatePaint();
+}
+
+PaintInvalidationReason LayoutTableCell::InvalidatePaint(
+    const PaintInvalidationState& state) {
+  return LayoutBlockFlow::InvalidatePaint(state);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.h b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
index d9e7a61..b626fde 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCell.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
@@ -348,6 +348,11 @@
                             const LayoutPoint& layer_offset,
                             const LayoutRect& container_rect) const override;
 
+  PaintInvalidationReason InvalidatePaint(
+      const PaintInvalidatorContext&) const override;
+  PaintInvalidationReason InvalidatePaint(
+      const PaintInvalidationState&) override;
+
  private:
   friend class LayoutTableCellTest;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
index 2a3e34a..8f0a6e4 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
@@ -2066,7 +2066,7 @@
   if (!pagination_strut) {
     LayoutUnit page_logical_height =
         PageLogicalHeightForOffset(row_object.LogicalTop());
-    if (page_logical_height && Table()->Header() &&
+    if (page_logical_height && Table()->Header() && Table()->Header() != this &&
         Table()->RowOffsetFromRepeatingHeader()) {
       offset_from_top_of_page =
           page_logical_height -
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index 9ce9659..eed357ee 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -402,23 +402,31 @@
   }
 
   HistoryCommitType history_commit_type = LoadTypeToCommitType(load_type_);
-  FrameLoader& loader = GetFrameLoader();
-  if (state_ < kCommitted) {
-    if (state_ == kNotStarted)
+  switch (state_) {
+    case kNotStarted:
       probe::frameClearedScheduledClientNavigation(frame_);
-    state_ = kSentDidFinishLoad;
-    GetLocalFrameClient().DispatchDidFailProvisionalLoad(error,
-                                                         history_commit_type);
-    if (!frame_)
-      return;
-    loader.DetachProvisionalDocumentLoader(this);
-  } else if (state_ == kCommitted) {
-    if (frame_->GetDocument()->Parser())
-      frame_->GetDocument()->Parser()->StopParsing();
-    state_ = kSentDidFinishLoad;
-    GetLocalFrameClient().DispatchDidFailLoad(error, history_commit_type);
+    // Fall-through
+    case kProvisional:
+      state_ = kSentDidFinishLoad;
+      GetLocalFrameClient().DispatchDidFailProvisionalLoad(error,
+                                                           history_commit_type);
+      if (frame_)
+        GetFrameLoader().DetachProvisionalDocumentLoader(this);
+      break;
+    case kCommitted:
+      if (frame_->GetDocument()->Parser())
+        frame_->GetDocument()->Parser()->StopParsing();
+      state_ = kSentDidFinishLoad;
+      GetLocalFrameClient().DispatchDidFailLoad(error, history_commit_type);
+      if (frame_)
+        frame_->GetDocument()->CheckCompleted();
+      break;
+    case kSentDidFinishLoad:
+      // TODO(japhet): Why do we need to call DidFinishNavigation() again?
+      GetFrameLoader().DidFinishNavigation();
+      break;
   }
-  loader.CheckCompleted();
+  DCHECK_EQ(kSentDidFinishLoad, state_);
 }
 
 void DocumentLoader::FinishedLoading(double finish_time) {
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 2fb04743..0848403 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -476,10 +476,11 @@
 }
 
 void FrameFetchContext::DidLoadResource(Resource* resource) {
+  if (!GetDocument())
+    return;
+  FirstMeaningfulPaintDetector::From(*GetDocument()).CheckNetworkStable();
   if (resource->IsLoadEventBlockingResourceType())
-    GetFrame()->Loader().CheckCompleted();
-  if (GetDocument())
-    FirstMeaningfulPaintDetector::From(*GetDocument()).CheckNetworkStable();
+    GetDocument()->CheckCompleted();
 }
 
 void FrameFetchContext::AddResourceTiming(const ResourceTimingInfo& info) {
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
index b015d0d..f5b4624 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
@@ -665,6 +665,11 @@
 }
 
 TEST_F(FrameFetchContextTest, SubResourceCachePolicy) {
+  // Reset load event state: if the load event is finished, we ignore the
+  // DocumentLoader load type.
+  document->open();
+  ASSERT_FALSE(document->LoadEventFinished());
+
   // Default case
   ResourceRequest request("http://www.example.com/mock");
   EXPECT_EQ(WebCachePolicy::kUseProtocolCachePolicy,
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 8a6cdc1..60e56ecb 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -446,7 +446,7 @@
         document_loader_ ? document_loader_->IsCommittedButEmpty() : true);
   }
 
-  CheckCompleted();
+  frame_->GetDocument()->CheckCompleted();
 
   if (!frame_->View())
     return;
@@ -458,15 +458,6 @@
                   kNavigationToDifferentDocument);
 }
 
-static bool AllDescendantsAreComplete(Frame* frame) {
-  for (Frame* child = frame->Tree().FirstChild(); child;
-       child = child->Tree().TraverseNext(frame)) {
-    if (child->IsLoading())
-      return false;
-  }
-  return true;
-}
-
 bool FrameLoader::AllAncestorsAreComplete() const {
   for (Frame* ancestor = frame_; ancestor;
        ancestor = ancestor->Tree().Parent()) {
@@ -476,96 +467,15 @@
   return true;
 }
 
-static bool ShouldComplete(Document* document) {
-  if (!document->GetFrame())
-    return false;
-  if (document->Parsing() || document->IsInDOMContentLoaded())
-    return false;
-  if (!document->HaveImportsLoaded())
-    return false;
-  if (document->Fetcher()->BlockingRequestCount())
-    return false;
-  if (document->IsDelayingLoadEvent())
-    return false;
-  return AllDescendantsAreComplete(document->GetFrame());
-}
-
-static bool ShouldSendFinishNotification(LocalFrame* frame) {
-  // Don't send didFinishLoad more than once per DocumentLoader.
-  if (frame->Loader().GetDocumentLoader()->SentDidFinishLoad())
-    return false;
-
-  // We might have declined to run the load event due to an imminent
-  // content-initiated navigation.
-  if (!frame->GetDocument()->LoadEventFinished())
-    return false;
-
-  // An event might have restarted a child frame.
-  if (!AllDescendantsAreComplete(frame))
-    return false;
-
-  // Don't notify if the frame is being detached.
-  if (!frame->IsAttached())
-    return false;
-
-  return true;
-}
-
-static bool ShouldSendCompleteNotification(LocalFrame* frame) {
-  // FIXME: We might have already sent stop notifications and be re-completing.
-  if (!frame->IsLoading())
-    return false;
-  // Only send didStopLoading() if there are no navigations in progress at all,
-  // whether committed, provisional, or pending.
-  return frame->Loader().GetDocumentLoader()->SentDidFinishLoad() &&
-         !frame->Loader().HasProvisionalNavigation();
-}
-
-void FrameLoader::CheckCompleted() {
-  if (!ShouldComplete(frame_->GetDocument()))
+void FrameLoader::DidFinishNavigation() {
+  // We should have either finished the provisional or committed navigation if
+  // this is called. Only delcare the whole frame finished if neither is in
+  // progress.
+  DCHECK(document_loader_->SentDidFinishLoad() || !HasProvisionalNavigation());
+  if (!document_loader_->SentDidFinishLoad() || HasProvisionalNavigation())
     return;
 
-  if (Client()) {
-    Client()->RunScriptsAtDocumentIdle();
-
-    // Injected scripts may have disconnected this frame.
-    if (!Client())
-      return;
-
-    // Check again, because runScriptsAtDocumentIdle() may have delayed the load
-    // event.
-    if (!ShouldComplete(frame_->GetDocument()))
-      return;
-  }
-
-  // OK, completed.
-  frame_->GetDocument()->SetReadyState(Document::kComplete);
-  if (frame_->GetDocument()->LoadEventStillNeeded())
-    frame_->GetDocument()->ImplicitClose();
-
-  frame_->GetNavigationScheduler().StartTimer();
-
-  if (frame_->View())
-    frame_->View()->HandleLoadCompleted();
-
-  // The readystatechanged or load event may have disconnected this frame.
-  if (!frame_->Client())
-    return;
-
-  if (ShouldSendFinishNotification(frame_)) {
-    // Report mobile vs. desktop page statistics. This will only report on
-    // Android.
-    if (frame_->IsMainFrame())
-      frame_->GetDocument()->GetViewportDescription().ReportMobilePageStats(
-          frame_);
-    document_loader_->SetSentDidFinishLoad();
-    Client()->DispatchDidFinishLoad();
-    // Finishing the load can detach the frame when running layout tests.
-    if (!frame_->Client())
-      return;
-  }
-
-  if (ShouldSendCompleteNotification(frame_)) {
+  if (frame_->IsLoading()) {
     progress_tracker_->ProgressCompleted();
     // Retry restoring scroll offset since finishing loading disables content
     // size clamping.
@@ -577,7 +487,7 @@
 
   Frame* parent = frame_->Tree().Parent();
   if (parent && parent->IsLocalFrame())
-    ToLocalFrame(parent)->Loader().CheckCompleted();
+    ToLocalFrame(parent)->GetDocument()->CheckCompleted();
 }
 
 void FrameLoader::CheckTimerFired(TimerBase*) {
@@ -585,7 +495,7 @@
     if (page->Suspended())
       return;
   }
-  CheckCompleted();
+  frame_->GetDocument()->CheckCompleted();
 }
 
 void FrameLoader::ScheduleCheckCompleted() {
@@ -693,7 +603,7 @@
 
   document_loader_->GetInitialScrollState().was_scrolled_by_user = false;
 
-  CheckCompleted();
+  frame_->GetDocument()->CheckCompleted();
 
   frame_->DomWindow()->StatePopped(state_object
                                        ? std::move(state_object)
@@ -1065,10 +975,9 @@
       ToLocalFrame(child)->Loader().StopAllLoaders();
   }
 
-  frame_->GetDocument()->SuppressLoadEvent();
+  frame_->GetDocument()->CancelParsing();
   if (document_loader_)
     document_loader_->Fetcher()->StopFetching();
-  frame_->GetDocument()->CancelParsing();
   if (!protect_provisional_loader_)
     DetachDocumentLoader(provisional_document_loader_);
 
@@ -1315,6 +1224,7 @@
 void FrameLoader::DetachProvisionalDocumentLoader(DocumentLoader* loader) {
   DCHECK_EQ(loader, provisional_document_loader_);
   DetachDocumentLoader(provisional_document_loader_);
+  DidFinishNavigation();
 }
 
 bool FrameLoader::ShouldPerformFragmentNavigation(bool is_form_submission,
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.h b/third_party/WebKit/Source/core/loader/FrameLoader.h
index 010f24d..75fbc7e 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.h
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.h
@@ -159,7 +159,7 @@
   void Detach();
 
   void FinishedParsing();
-  void CheckCompleted();
+  void DidFinishNavigation();
 
   // This prepares the FrameLoader for the next commit. It will dispatch unload
   // events, abort XHR requests and detach the document. Returns true if the
diff --git a/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp b/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp
index b0199e0..7dc10a88 100644
--- a/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp
+++ b/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp
@@ -509,6 +509,8 @@
 
   Cancel();
   redirect_ = redirect;
+  if (redirect_->IsLocationChange())
+    frame_->GetDocument()->SuppressLoadEvent();
   StartTimer();
 }
 
diff --git a/third_party/WebKit/Source/core/page/PageVisibilityState.cpp b/third_party/WebKit/Source/core/page/PageVisibilityState.cpp
index 683b710..7af36ff 100644
--- a/third_party/WebKit/Source/core/page/PageVisibilityState.cpp
+++ b/third_party/WebKit/Source/core/page/PageVisibilityState.cpp
@@ -42,7 +42,7 @@
       return "prerender";
   }
 
-  ASSERT_NOT_REACHED();
+  NOTREACHED();
   return String();
 }
 
diff --git a/third_party/WebKit/Source/core/page/SpatialNavigation.cpp b/third_party/WebKit/Source/core/page/SpatialNavigation.cpp
index 76fef104d..4daebfc 100644
--- a/third_party/WebKit/Source/core/page/SpatialNavigation.cpp
+++ b/third_party/WebKit/Source/core/page/SpatialNavigation.cpp
@@ -102,7 +102,7 @@
     case kWebFocusTypeDown:
       return a.MaxX() > b.X() && a.X() < b.MaxX();
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
       return false;
   }
 }
@@ -136,7 +136,7 @@
     case kWebFocusTypeDown:
       return Below(target_rect, cur_rect);
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
       return false;
   }
 }
@@ -219,7 +219,7 @@
         dy = pixels_per_line_step;
         break;
       default:
-        ASSERT_NOT_REACHED();
+        NOTREACHED();
         return false;
     }
 
@@ -264,7 +264,7 @@
         dy = pixels_per_line_step;
         break;
       default:
-        ASSERT_NOT_REACHED();
+        NOTREACHED();
         return false;
     }
 
@@ -351,7 +351,7 @@
                       container->GetLayoutBox()->ClientHeight() <
                   container->GetLayoutBox()->ScrollHeight());
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
       return false;
   }
 }
@@ -382,7 +382,7 @@
     case kWebFocusTypeDown:
       return rect.Height() + offset.Height() < size.Height();
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
       return false;
   }
 }
@@ -475,7 +475,7 @@
         entry_point.SetY(starting_rect.MaxY());
       break;
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
   }
 
   switch (type) {
@@ -518,7 +518,7 @@
       }
       break;
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
   }
 }
 
@@ -607,7 +607,7 @@
           (x_axis + orthogonal_bias) * kOrthogonalWeightForUpDown;
       break;
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
       return;
   }
 
@@ -668,7 +668,7 @@
       virtual_starting_rect.SetHeight(width);
       break;
     default:
-      ASSERT_NOT_REACHED();
+      NOTREACHED();
   }
 
   return virtual_starting_rect;
diff --git a/third_party/WebKit/Source/core/page/TouchAdjustment.cpp b/third_party/WebKit/Source/core/page/TouchAdjustment.cpp
index 0be208d..1a806da 100644
--- a/third_party/WebKit/Source/core/page/TouchAdjustment.cpp
+++ b/third_party/WebKit/Source/core/page/TouchAdjustment.cpp
@@ -223,7 +223,7 @@
         std::tie(start_pos, end_pos) = text_layout_object->SelectionStartEnd();
         break;
       default:
-        ASSERT_NOT_REACHED();
+        NOTREACHED();
         return;
     }
     Vector<FloatQuad> quads;
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollStateCallback.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollStateCallback.cpp
index 79a995d..f08ce90 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollStateCallback.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollStateCallback.cpp
@@ -21,7 +21,7 @@
   if (native_scroll_behavior == kAfter)
     return WebNativeScrollBehavior::kPerformAfterNativeScroll;
 
-  ASSERT_NOT_REACHED();
+  NOTREACHED();
   return WebNativeScrollBehavior::kDisableNativeScroll;
 }
 
diff --git a/third_party/WebKit/Source/core/paint/BUILD.gn b/third_party/WebKit/Source/core/paint/BUILD.gn
index 29258112..c5dad31 100644
--- a/third_party/WebKit/Source/core/paint/BUILD.gn
+++ b/third_party/WebKit/Source/core/paint/BUILD.gn
@@ -172,6 +172,8 @@
     "ScrollbarManager.h",
     "ScrollbarPainter.cpp",
     "ScrollbarPainter.h",
+    "TableCellPaintInvalidator.cpp",
+    "TableCellPaintInvalidator.h",
     "TableCellPainter.cpp",
     "TableCellPainter.h",
     "TablePaintInvalidator.cpp",
diff --git a/third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h b/third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h
index c6ca772..70ddf33 100644
--- a/third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h
+++ b/third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h
@@ -25,11 +25,10 @@
 
 class FindPaintOffsetNeedingUpdateScope {
  public:
-  FindPaintOffsetNeedingUpdateScope(
-      const LayoutObject& object,
-      const PaintPropertyTreeBuilderContext& context)
+  FindPaintOffsetNeedingUpdateScope(const LayoutObject& object,
+                                    bool& is_actually_needed)
       : object_(object),
-        context_(context),
+        is_actually_needed_(is_actually_needed),
         old_paint_offset_(object.PaintOffset()) {
     if (object.PaintProperties() &&
         object.PaintProperties()->PaintOffsetTranslation()) {
@@ -39,7 +38,7 @@
   }
 
   ~FindPaintOffsetNeedingUpdateScope() {
-    if (context_.is_actually_needed)
+    if (is_actually_needed_)
       return;
     DCHECK_OBJECT_PROPERTY_EQ(object_, &old_paint_offset_,
                               &object_.PaintOffset());
@@ -53,7 +52,7 @@
 
  private:
   const LayoutObject& object_;
-  const PaintPropertyTreeBuilderContext& context_;
+  const bool& is_actually_needed_;
   LayoutPoint old_paint_offset_;
   RefPtr<const TransformPaintPropertyNode> old_paint_offset_translation_;
 };
diff --git a/third_party/WebKit/Source/core/paint/FindPropertiesNeedingUpdate.h b/third_party/WebKit/Source/core/paint/FindPropertiesNeedingUpdate.h
index b01b69e..4ef680a 100644
--- a/third_party/WebKit/Source/core/paint/FindPropertiesNeedingUpdate.h
+++ b/third_party/WebKit/Source/core/paint/FindPropertiesNeedingUpdate.h
@@ -18,7 +18,8 @@
 // properties needed an update but were not marked as such. If paint properties
 // will change, the object must be marked as needing a paint property update
 // using {FrameView, LayoutObject}::setNeedsPaintPropertyUpdate() or by forcing
-// a subtree update (see: PaintPropertyTreeBuilderContext::forceSubtreeUpdate).
+// a subtree update (see:
+// PaintPropertyTreeBuilderContext::force_subtree_update).
 //
 // Both scope classes work by recording the paint property state of an object
 // before rebuilding properties, forcing the properties to get updated, then
@@ -49,12 +50,11 @@
 
 class FindFrameViewPropertiesNeedingUpdateScope {
  public:
-  FindFrameViewPropertiesNeedingUpdateScope(
-      FrameView* frame_view,
-      PaintPropertyTreeBuilderContext& context)
+  FindFrameViewPropertiesNeedingUpdateScope(FrameView* frame_view,
+                                            bool force_subtree_update)
       : frame_view_(frame_view),
         needed_paint_property_update_(frame_view->NeedsPaintPropertyUpdate()),
-        needed_forced_subtree_update_(context.force_subtree_update) {
+        needed_forced_subtree_update_(force_subtree_update) {
     // No need to check if an update was already needed.
     if (needed_paint_property_update_ || needed_forced_subtree_update_)
       return;
@@ -80,7 +80,7 @@
     // 1) The FrameView should have been marked as needing an update with
     //    FrameView::setNeedsPaintPropertyUpdate().
     // 2) The PrePaintTreeWalk should have had a forced subtree update (see:
-    //    PaintPropertyTreeBuilderContext::forceSubtreeUpdate).
+    //    PaintPropertyTreeBuilderContext::force_subtree_update).
     DCHECK_FRAMEVIEW_PROPERTY_EQ(original_pre_translation_,
                                  frame_view_->PreTranslation());
     DCHECK_FRAMEVIEW_PROPERTY_EQ(original_content_clip_,
@@ -107,12 +107,11 @@
 
 class FindObjectPropertiesNeedingUpdateScope {
  public:
-  FindObjectPropertiesNeedingUpdateScope(
-      const LayoutObject& object,
-      PaintPropertyTreeBuilderContext& context)
+  FindObjectPropertiesNeedingUpdateScope(const LayoutObject& object,
+                                         bool force_subtree_update)
       : object_(object),
         needed_paint_property_update_(object.NeedsPaintPropertyUpdate()),
-        needed_forced_subtree_update_(context.force_subtree_update),
+        needed_forced_subtree_update_(force_subtree_update),
         original_paint_offset_(object.PaintOffset()) {
     // No need to check if an update was already needed.
     if (needed_paint_property_update_ || needed_forced_subtree_update_)
@@ -153,7 +152,7 @@
     // 1) The LayoutObject should have been marked as needing an update with
     //    LayoutObject::setNeedsPaintPropertyUpdate().
     // 2) The PrePaintTreeWalk should have had a forced subtree update (see:
-    //    PaintPropertyTreeBuilderContext::forceSubtreeUpdate).
+    //    PaintPropertyTreeBuilderContext::force_subtree_update).
     if (original_properties_ && object_properties) {
       DCHECK_OBJECT_PROPERTY_EQ(object_, original_properties_->Transform(),
                                 object_properties->Transform());
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
index 7b84d3e..17402de1 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
@@ -107,9 +107,9 @@
 
     auto container_contents_properties =
         context.paint_invalidation_container->ContentsProperties();
-    if (context.tree_builder_context_->current.transform ==
+    if (context.tree_builder_context_->fragments[0].current.transform ==
             container_contents_properties.Transform() &&
-        context.tree_builder_context_->current.clip ==
+        context.tree_builder_context_->fragments[0].current.clip ==
             container_contents_properties.Clip()) {
       result = LayoutRect(rect);
     } else {
@@ -118,13 +118,14 @@
       // snapping, when transforms are applied. If there is no transform,
       // enclosingIntRect is applied in the last step of paint invalidation
       // (see CompositedLayerMapping::setContentsNeedDisplayInRect()).
-      if (!is_svg_child && context.tree_builder_context_->current.transform !=
-                               container_contents_properties.Transform())
+      if (!is_svg_child &&
+          context.tree_builder_context_->fragments[0].current.transform !=
+              container_contents_properties.Transform())
         rect = Rect(EnclosingIntRect(rect));
 
       PropertyTreeState current_tree_state(
-          context.tree_builder_context_->current.transform,
-          context.tree_builder_context_->current.clip, nullptr);
+          context.tree_builder_context_->fragments[0].current.transform,
+          context.tree_builder_context_->fragments[0].current.clip, nullptr);
 
       FloatClipRect float_rect((FloatRect(rect)));
       GeometryMapper::SourceToDestinationVisualRect(
@@ -181,12 +182,12 @@
 
     const auto* container_transform =
         context.paint_invalidation_container->ContentsProperties().Transform();
-    if (context.tree_builder_context_->current.transform !=
+    if (context.tree_builder_context_->fragments[0].current.transform !=
         container_transform) {
       FloatRect rect = FloatRect(FloatPoint(point), FloatSize());
       GeometryMapper::SourceToDestinationRect(
-          context.tree_builder_context_->current.transform, container_transform,
-          rect);
+          context.tree_builder_context_->fragments[0].current.transform,
+          container_transform, rect);
       point = LayoutPoint(rect.Location());
     }
 
@@ -265,28 +266,33 @@
       const PaintPropertyTreeBuilderContext& tree_builder_context)
       : tree_builder_context_(
             const_cast<PaintPropertyTreeBuilderContext&>(tree_builder_context)),
-        saved_context_(tree_builder_context_.current) {
+        saved_context_(tree_builder_context_.fragments[0].current) {
     DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
 
-    if (frame_view.ContentClip() == saved_context_.clip)
-      tree_builder_context_.current.clip = saved_context_.clip->Parent();
+    if (frame_view.ContentClip() == saved_context_.clip) {
+      tree_builder_context_.fragments[0].current.clip =
+          saved_context_.clip->Parent();
+    }
     if (const auto* scroll_translation = frame_view.ScrollTranslation()) {
-      if (scroll_translation->ScrollNode() == saved_context_.scroll)
-        tree_builder_context_.current.scroll = saved_context_.scroll->Parent();
+      if (scroll_translation->ScrollNode() == saved_context_.scroll) {
+        tree_builder_context_.fragments[0].current.scroll =
+            saved_context_.scroll->Parent();
+      }
       if (scroll_translation == saved_context_.transform) {
-        tree_builder_context_.current.transform =
+        tree_builder_context_.fragments[0].current.transform =
             saved_context_.transform->Parent();
       }
     }
   }
 
   ~ScopedUndoFrameViewContentClipAndScroll() {
-    tree_builder_context_.current = saved_context_;
+    tree_builder_context_.fragments[0].current = saved_context_;
   }
 
  private:
   PaintPropertyTreeBuilderContext& tree_builder_context_;
-  PaintPropertyTreeBuilderContext::ContainingBlockContext saved_context_;
+  PaintPropertyTreeBuilderFragmentContext::ContainingBlockContext
+      saved_context_;
 };
 
 }  // namespace
@@ -377,7 +383,7 @@
   // The paint offset should already be updated through
   // PaintPropertyTreeBuilder::updatePropertiesForSelf.
   DCHECK(context.tree_builder_context_);
-  DCHECK(context.tree_builder_context_->current.paint_offset ==
+  DCHECK(context.tree_builder_context_->fragments[0].current.paint_offset ==
          object.PaintOffset());
 
   Optional<ScopedUndoFrameViewContentClipAndScroll>
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index ce48c55f..1e2d5f0 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -555,6 +555,31 @@
   return Layer()->size().Width();
 }
 
+LayoutSize PaintLayerScrollableArea::ClientSize() const {
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
+    bool is_main_frame_root_layer =
+        layer_.IsRootLayer() && Box().GetDocument().GetFrame()->IsMainFrame();
+    if (is_main_frame_root_layer) {
+      LayoutSize result(Box().GetFrameView()->GetLayoutSize());
+      result -= IntSize(VerticalScrollbarWidth(), HorizontalScrollbarHeight());
+      return result;
+    }
+  }
+  return LayoutSize(Box().ClientWidth(), Box().ClientHeight());
+}
+
+IntSize PaintLayerScrollableArea::PixelSnappedClientSize() const {
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
+    bool is_main_frame_root_layer =
+        layer_.IsRootLayer() && Box().GetDocument().GetFrame()->IsMainFrame();
+    if (is_main_frame_root_layer) {
+      return ExcludeScrollbars(Box().GetFrameView()->GetLayoutSize());
+    }
+  }
+  return IntSize(Box().PixelSnappedClientWidth(),
+                 Box().PixelSnappedClientHeight());
+}
+
 IntSize PaintLayerScrollableArea::ContentsSize() const {
   return IntSize(PixelSnappedScrollWidth(), PixelSnappedScrollHeight());
 }
@@ -827,12 +852,12 @@
 
     // Set up the range (and page step/line step).
     if (Scrollbar* horizontal_scrollbar = this->HorizontalScrollbar()) {
-      int client_width = Box().PixelSnappedClientWidth();
+      int client_width = PixelSnappedClientSize().Width();
       horizontal_scrollbar->SetProportion(client_width,
                                           OverflowRect().Width().ToInt());
     }
     if (Scrollbar* vertical_scrollbar = this->VerticalScrollbar()) {
-      int client_height = Box().PixelSnappedClientHeight();
+      int client_height = PixelSnappedClientSize().Height();
       vertical_scrollbar->SetProportion(client_height,
                                         OverflowRect().Height().ToInt());
     }
@@ -929,14 +954,14 @@
   // converse problem seems to happen much less frequently in practice, so we
   // bias the logic towards preventing unwanted horizontal scrollbars, which
   // are more common and annoying.
-  int client_width = Box().PixelSnappedClientWidth();
+  int client_width = PixelSnappedClientSize().Width();
   if (NeedsRelayout() && !HadVerticalScrollbarBeforeRelayout())
     client_width += VerticalScrollbarWidth();
   return PixelSnappedScrollWidth() > client_width;
 }
 
 bool PaintLayerScrollableArea::HasVerticalOverflow() const {
-  return PixelSnappedScrollHeight() > Box().PixelSnappedClientHeight();
+  return PixelSnappedScrollHeight() > PixelSnappedClientSize().Height();
 }
 
 bool PaintLayerScrollableArea::HasScrollableHorizontalOverflow() const {
@@ -1044,12 +1069,12 @@
 void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
   UpdateScrollDimensions();
   if (Scrollbar* horizontal_scrollbar = this->HorizontalScrollbar()) {
-    int client_width = Box().PixelSnappedClientWidth();
+    int client_width = PixelSnappedClientSize().Width();
     horizontal_scrollbar->SetProportion(client_width,
                                         OverflowRect().Width().ToInt());
   }
   if (Scrollbar* vertical_scrollbar = this->VerticalScrollbar()) {
-    int client_height = Box().PixelSnappedClientHeight();
+    int client_height = PixelSnappedClientSize().Height();
     vertical_scrollbar->SetProportion(client_height,
                                       OverflowRect().Height().ToInt());
   }
@@ -1704,10 +1729,9 @@
           .AbsoluteToLocalQuad(FloatQuad(FloatRect(rect)), kUseTransforms)
           .BoundingBox());
   local_expose_rect.Move(-Box().BorderLeft(), -Box().BorderTop());
-  LayoutRect layer_bounds(
-      LayoutPoint(), LayoutSize(Box().ClientWidth(), Box().ClientHeight()));
+  LayoutRect visible_rect(LayoutPoint(), ClientSize());
   LayoutRect r = ScrollAlignment::GetRectToExpose(
-      layer_bounds, local_expose_rect, align_x, align_y);
+      visible_rect, local_expose_rect, align_x, align_y);
 
   ScrollOffset old_scroll_offset = GetScrollOffset();
   ScrollOffset new_scroll_offset(ClampScrollOffset(RoundedIntSize(
@@ -1717,8 +1741,8 @@
   local_expose_rect.Move(-LayoutSize(scroll_offset_difference));
 
   LayoutRect intersect =
-      LocalToAbsolute(Box(), Intersection(layer_bounds, local_expose_rect));
-  if (intersect.IsEmpty() && !layer_bounds.IsEmpty() &&
+      LocalToAbsolute(Box(), Intersection(visible_rect, local_expose_rect));
+  if (intersect.IsEmpty() && !visible_rect.IsEmpty() &&
       !local_expose_rect.IsEmpty()) {
     return LocalToAbsolute(Box(), local_expose_rect);
   }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
index a00b42b..c9683ae 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
@@ -297,6 +297,16 @@
   CompositorAnimationHost* GetCompositorAnimationHost() const override;
   CompositorAnimationTimeline* GetCompositorAnimationTimeline() const override;
 
+  // These are temporary convenience methods.  They delegate to Box() methods,
+  // which will be up-to-date when UpdateAfterLayout runs.  By contrast,
+  // VisibleContentRect() is based on layer_.Size(), which isn't updated
+  // until later, when UpdateLayerPosition runs.  A future patch will cause
+  // layer_.Size() to be updated effectively simultaneously with Box()
+  // sizing.  When that lands, these methods should be removed in favor of
+  // using VisibleContentRect() and/or layer_.Size() everywhere.
+  LayoutSize ClientSize() const;
+  IntSize PixelSnappedClientSize() const;
+
   void VisibleSizeChanged();
 
   // FIXME: We shouldn't allow access to m_overflowRect outside this class.
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 99a5ed9..a7a8c6a 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -27,11 +27,10 @@
 
 namespace blink {
 
-PaintPropertyTreeBuilderContext::PaintPropertyTreeBuilderContext()
-    : container_for_absolute_position(nullptr),
-      current_effect(EffectPaintPropertyNode::Root()),
-      input_clip_of_current_effect(ClipPaintPropertyNode::Root()),
-      force_subtree_update(false) {
+PaintPropertyTreeBuilderFragmentContext::
+    PaintPropertyTreeBuilderFragmentContext()
+    : current_effect(EffectPaintPropertyNode::Root()),
+      input_clip_of_current_effect(ClipPaintPropertyNode::Root()) {
   current.clip = absolute_position.clip = fixed_position.clip =
       ClipPaintPropertyNode::Root();
   current.transform = absolute_position.transform = fixed_position.transform =
@@ -130,7 +129,11 @@
 
 void PaintPropertyTreeBuilder::UpdateProperties(
     FrameView& frame_view,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderContext& full_context) {
+  if (full_context.fragments.IsEmpty())
+    full_context.fragments.push_back(PaintPropertyTreeBuilderFragmentContext());
+
+  PaintPropertyTreeBuilderFragmentContext& context = full_context.fragments[0];
   if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
     // With root layer scrolling, the LayoutView (a LayoutObject) properties are
     // updated like other objects (see updatePropertiesAndContextForSelf and
@@ -140,26 +143,28 @@
     context.current.rendering_context_id = 0;
     context.current.should_flatten_inherited_transform = true;
     context.absolute_position = context.current;
-    context.container_for_absolute_position = nullptr;
+    full_context.container_for_absolute_position = nullptr;
     context.fixed_position = context.current;
     return;
   }
 
 #if DCHECK_IS_ON()
-  FindFrameViewPropertiesNeedingUpdateScope check_scope(&frame_view, context);
+  FindFrameViewPropertiesNeedingUpdateScope check_scope(
+      &frame_view, full_context.is_actually_needed);
 #endif
 
-  if (frame_view.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+  if (frame_view.NeedsPaintPropertyUpdate() ||
+      full_context.force_subtree_update) {
     TransformationMatrix frame_translate;
     frame_translate.Translate(
         frame_view.X() + context.current.paint_offset.X(),
         frame_view.Y() + context.current.paint_offset.Y());
-    context.force_subtree_update |= UpdatePreTranslation(
+    full_context.force_subtree_update |= UpdatePreTranslation(
         frame_view, context.current.transform, frame_translate, FloatPoint3D());
 
     FloatRoundedRect content_clip(
         IntRect(IntPoint(), frame_view.VisibleContentSize()));
-    context.force_subtree_update |=
+    full_context.force_subtree_update |=
         UpdateContentClip(frame_view, context.current.clip,
                           frame_view.PreTranslation(), content_clip);
 
@@ -180,7 +185,7 @@
       auto reasons =
           GetMainThreadScrollingReasons(frame_view, ancestor_reasons);
 
-      context.force_subtree_update |= UpdateScrollTranslation(
+      full_context.force_subtree_update |= UpdateScrollTranslation(
           frame_view, frame_view.PreTranslation(), frame_scroll, FloatPoint3D(),
           context.current.scroll, scroll_clip, scroll_bounds,
           user_scrollable_horizontal, user_scrollable_vertical, reasons,
@@ -190,7 +195,7 @@
         // Ensure pre-existing properties are cleared if there is no scrolling.
         frame_view.SetScrollTranslation(nullptr);
         // Rebuild all descendant properties because a property was removed.
-        context.force_subtree_update = true;
+        full_context.force_subtree_update = true;
       }
     }
   }
@@ -214,7 +219,7 @@
   context.current.rendering_context_id = 0;
   context.current.should_flatten_inherited_transform = true;
   context.absolute_position = context.current;
-  context.container_for_absolute_position = nullptr;
+  full_context.container_for_absolute_position = nullptr;
   context.fixed_position = context.current;
   context.fixed_position.transform = fixed_transform_node;
   context.fixed_position.scroll = fixed_scroll_node;
@@ -243,7 +248,8 @@
 
 void PaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
     const LayoutBoxModelObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
   if (NeedsPaintOffsetTranslation(object) &&
       // As an optimization, skip these paint offset translation nodes when
       // the offset is an identity. An exception is the layout view because root
@@ -264,7 +270,7 @@
     LayoutPoint fractional_paint_offset =
         LayoutPoint(context.current.paint_offset - rounded_paint_offset);
 
-    context.force_subtree_update |= properties.UpdatePaintOffsetTranslation(
+    force_subtree_update |= properties.UpdatePaintOffsetTranslation(
         context.current.transform,
         TransformationMatrix().Translate(rounded_paint_offset.X(),
                                          rounded_paint_offset.Y()),
@@ -282,7 +288,7 @@
     }
   } else {
     if (auto* properties = object.GetMutableForPainting().PaintProperties())
-      context.force_subtree_update |= properties->ClearPaintOffsetTranslation();
+      force_subtree_update |= properties->ClearPaintOffsetTranslation();
   }
 }
 
@@ -299,24 +305,25 @@
 // creating a transform node for SVG-specific transforms without 3D.
 void PaintPropertyTreeBuilder::UpdateTransformForNonRootSVG(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
   DCHECK(object.IsSVGChild());
   // SVG does not use paint offset internally, except for SVGForeignObject which
   // has different SVG and HTML coordinate spaces.
   DCHECK(object.IsSVGForeignObject() ||
          context.current.paint_offset == LayoutPoint());
 
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     AffineTransform transform = object.LocalToSVGParentTransform();
     if (NeedsTransformForNonRootSVG(object)) {
       // The origin is included in the local transform, so leave origin empty.
       auto& properties = *object.GetMutableForPainting().PaintProperties();
-      context.force_subtree_update |= properties.UpdateTransform(
+      force_subtree_update |= properties.UpdateTransform(
           context.current.transform, TransformationMatrix(transform),
           FloatPoint3D());
     } else {
       if (auto* properties = object.GetMutableForPainting().PaintProperties())
-        context.force_subtree_update |= properties->ClearTransform();
+        force_subtree_update |= properties->ClearTransform();
     }
   }
 
@@ -372,13 +379,14 @@
 
 void PaintPropertyTreeBuilder::UpdateTransform(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
   if (object.IsSVGChild()) {
-    UpdateTransformForNonRootSVG(object, context);
+    UpdateTransformForNonRootSVG(object, context, force_subtree_update);
     return;
   }
 
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     const ComputedStyle& style = object.StyleRef();
 
     // A transform node is allocated for transforms, preserves-3d and any
@@ -411,13 +419,13 @@
               : CompositorElementId();
 
       auto& properties = *object.GetMutableForPainting().PaintProperties();
-      context.force_subtree_update |= properties.UpdateTransform(
+      force_subtree_update |= properties.UpdateTransform(
           context.current.transform, matrix, TransformOrigin(box),
           context.current.should_flatten_inherited_transform,
           rendering_context_id, compositing_reasons, compositor_element_id);
     } else {
       if (auto* properties = object.GetMutableForPainting().PaintProperties())
-        context.force_subtree_update |= properties->ClearTransform();
+        force_subtree_update |= properties->ClearTransform();
     }
   }
 
@@ -529,11 +537,12 @@
 
 void PaintPropertyTreeBuilder::UpdateEffect(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
   const ComputedStyle& style = object.StyleRef();
 
   // TODO(trchen): Can't omit effect node if we have 3D children.
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     const ClipPaintPropertyNode* output_clip =
         context.input_clip_of_current_effect;
 
@@ -554,7 +563,7 @@
       bool has_mask = ComputeMaskParameters(
           mask_clip, mask_color_filter, object, context.current.paint_offset);
       if (has_mask) {
-        context.force_subtree_update |= properties.UpdateMaskClip(
+        force_subtree_update |= properties.UpdateMaskClip(
             context.current.clip, context.current.transform,
             FloatRoundedRect(mask_clip));
         output_clip = properties.MaskClip();
@@ -565,7 +574,7 @@
         compositing_reasons |= kCompositingReasonIsolateCompositedDescendants;
       } else {
         if (auto* properties = object.GetMutableForPainting().PaintProperties())
-          context.force_subtree_update |= properties->ClearMaskClip();
+          force_subtree_update |= properties->ClearMaskClip();
       }
 
       SkBlendMode blend_mode =
@@ -582,7 +591,7 @@
       DCHECK(!style.HasCurrentOpacityAnimation() ||
              compositing_reasons != kCompositingReasonNone);
 
-      context.force_subtree_update |= properties.UpdateEffect(
+      force_subtree_update |= properties.UpdateEffect(
           context.current_effect, context.current.transform, output_clip,
           kColorFilterNone, CompositorFilterOperations(), style.Opacity(),
           blend_mode, compositing_reasons, compositor_element_id);
@@ -592,19 +601,19 @@
         // yet. Adding CompositingReasonSquashingDisallowed forces mask not
         // getting squashed into a child effect. Have no compositing reason
         // otherwise.
-        context.force_subtree_update |= properties.UpdateMask(
+        force_subtree_update |= properties.UpdateMask(
             properties.Effect(), context.current.transform, output_clip,
             mask_color_filter, CompositorFilterOperations(), 1.f,
             SkBlendMode::kDstIn, kCompositingReasonSquashingDisallowed,
             CompositorElementId());
       } else {
-        context.force_subtree_update |= properties.ClearMask();
+        force_subtree_update |= properties.ClearMask();
       }
     } else {
       if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
-        context.force_subtree_update |= properties->ClearEffect();
-        context.force_subtree_update |= properties->ClearMask();
-        context.force_subtree_update |= properties->ClearMaskClip();
+        force_subtree_update |= properties->ClearEffect();
+        force_subtree_update |= properties->ClearMask();
+        force_subtree_update |= properties->ClearMaskClip();
       }
     }
   }
@@ -628,10 +637,11 @@
 
 void PaintPropertyTreeBuilder::UpdateFilter(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
   const ComputedStyle& style = object.StyleRef();
 
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     if (NeedsFilter(object)) {
       CompositorFilterOperations filter =
           ToLayoutBoxModelObject(object)
@@ -677,13 +687,13 @@
              compositing_reasons != kCompositingReasonNone);
 
       auto& properties = *object.GetMutableForPainting().PaintProperties();
-      context.force_subtree_update |= properties.UpdateFilter(
+      force_subtree_update |= properties.UpdateFilter(
           context.current_effect, context.current.transform, output_clip,
           kColorFilterNone, std::move(filter), 1.f, SkBlendMode::kSrcOver,
           compositing_reasons, compositor_element_id);
     } else {
       if (auto* properties = object.GetMutableForPainting().PaintProperties())
-        context.force_subtree_update |= properties->ClearFilter();
+        force_subtree_update |= properties->ClearFilter();
     }
   }
 
@@ -705,8 +715,9 @@
 
 void PaintPropertyTreeBuilder::UpdateCssClip(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     if (NeedsCssClip(object)) {
       // Create clip node for descendants that are not fixed position.
       // We don't have to setup context.absolutePosition.clip here because this
@@ -716,12 +727,12 @@
       LayoutRect clip_rect =
           ToLayoutBox(object).ClipRect(context.current.paint_offset);
       auto& properties = *object.GetMutableForPainting().PaintProperties();
-      context.force_subtree_update |= properties.UpdateCssClip(
+      force_subtree_update |= properties.UpdateCssClip(
           context.current.clip, context.current.transform,
           FloatRoundedRect(FloatRect(clip_rect)));
     } else {
       if (auto* properties = object.GetMutableForPainting().PaintProperties())
-        context.force_subtree_update |= properties->ClearCssClip();
+        force_subtree_update |= properties->ClearCssClip();
     }
   }
 
@@ -732,8 +743,9 @@
 
 void PaintPropertyTreeBuilder::UpdateLocalBorderBoxContext(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
-  if (!object.NeedsPaintPropertyUpdate() && !context.force_subtree_update)
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
+  if (!object.NeedsPaintPropertyUpdate() && !force_subtree_update)
     return;
 
   // We only need to cache the local border box properties for layered objects.
@@ -761,8 +773,9 @@
 // TODO(trchen): Remove this once we bake the paint offset into frameRect.
 void PaintPropertyTreeBuilder::UpdateScrollbarPaintOffset(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
-  if (!object.NeedsPaintPropertyUpdate() && !context.force_subtree_update)
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
+  if (!object.NeedsPaintPropertyUpdate() && !force_subtree_update)
     return;
 
   if (NeedsScrollbarPaintOffset(object)) {
@@ -771,11 +784,11 @@
     auto paint_offset = TransformationMatrix().Translate(
         rounded_paint_offset.X(), rounded_paint_offset.Y());
     auto& properties = *object.GetMutableForPainting().PaintProperties();
-    context.force_subtree_update |= properties.UpdateScrollbarPaintOffset(
+    force_subtree_update |= properties.UpdateScrollbarPaintOffset(
         context.current.transform, paint_offset, FloatPoint3D());
   } else {
     if (auto* properties = object.GetMutableForPainting().PaintProperties())
-      context.force_subtree_update |= properties->ClearScrollbarPaintOffset();
+      force_subtree_update |= properties->ClearScrollbarPaintOffset();
   }
 }
 
@@ -785,8 +798,9 @@
 
 void PaintPropertyTreeBuilder::UpdateOverflowClip(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     if (NeedsOverflowScroll(object)) {
       const LayoutBox& box = ToLayoutBox(object);
       LayoutRect clip_rect;
@@ -798,21 +812,20 @@
       if (box.StyleRef().HasBorderRadius()) {
         auto inner_border = box.StyleRef().GetRoundedInnerBorderFor(
             LayoutRect(context.current.paint_offset, box.Size()));
-        context.force_subtree_update |= properties.UpdateInnerBorderRadiusClip(
+        force_subtree_update |= properties.UpdateInnerBorderRadiusClip(
             context.current.clip, context.current.transform, inner_border);
         current_clip = properties.InnerBorderRadiusClip();
       } else {
-        context.force_subtree_update |= properties.ClearInnerBorderRadiusClip();
+        force_subtree_update |= properties.ClearInnerBorderRadiusClip();
       }
 
-      context.force_subtree_update |=
+      force_subtree_update |=
           properties.UpdateOverflowClip(current_clip, context.current.transform,
                                         FloatRoundedRect(FloatRect(clip_rect)));
     } else {
       if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
-        context.force_subtree_update |=
-            properties->ClearInnerBorderRadiusClip();
-        context.force_subtree_update |= properties->ClearOverflowClip();
+        force_subtree_update |= properties->ClearInnerBorderRadiusClip();
+        force_subtree_update |= properties->ClearOverflowClip();
       }
       return;
     }
@@ -840,8 +853,9 @@
 
 void PaintPropertyTreeBuilder::UpdatePerspective(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     if (NeedsPerspective(object)) {
       const ComputedStyle& style = object.StyleRef();
       // The perspective node must not flatten (else nothing will get
@@ -852,13 +866,13 @@
       FloatPoint3D origin = PerspectiveOrigin(ToLayoutBox(object)) +
                             ToLayoutSize(context.current.paint_offset);
       auto& properties = *object.GetMutableForPainting().PaintProperties();
-      context.force_subtree_update |= properties.UpdatePerspective(
+      force_subtree_update |= properties.UpdatePerspective(
           context.current.transform, matrix, origin,
           context.current.should_flatten_inherited_transform,
           context.current.rendering_context_id);
     } else {
       if (auto* properties = object.GetMutableForPainting().PaintProperties())
-        context.force_subtree_update |= properties->ClearPerspective();
+        force_subtree_update |= properties->ClearPerspective();
     }
   }
 
@@ -875,25 +889,23 @@
 
 void PaintPropertyTreeBuilder::UpdateSvgLocalToBorderBoxTransform(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
   if (!object.IsSVGRoot())
     return;
 
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     AffineTransform transform_to_border_box =
         SVGRootPainter(ToLayoutSVGRoot(object))
             .TransformToPixelSnappedBorderBox(context.current.paint_offset);
     if (!transform_to_border_box.IsIdentity() &&
         NeedsSVGLocalToBorderBoxTransform(object)) {
       auto& properties = *object.GetMutableForPainting().PaintProperties();
-      context.force_subtree_update |=
-          properties.UpdateSvgLocalToBorderBoxTransform(
-              context.current.transform, transform_to_border_box,
-              FloatPoint3D());
+      force_subtree_update |= properties.UpdateSvgLocalToBorderBoxTransform(
+          context.current.transform, transform_to_border_box, FloatPoint3D());
     } else {
       if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
-        context.force_subtree_update |=
-            properties->ClearSvgLocalToBorderBoxTransform();
+        force_subtree_update |= properties->ClearSvgLocalToBorderBoxTransform();
       }
     }
   }
@@ -935,8 +947,9 @@
 
 void PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     if (NeedsScrollTranslation(object)) {
       const LayoutBox& box = ToLayoutBox(object);
       auto* scrollable_area = box.GetScrollableArea();
@@ -959,14 +972,14 @@
       if (auto* existing_scroll_translation = properties.ScrollTranslation()) {
         auto* existing_scroll_node = existing_scroll_translation->ScrollNode();
         if (existing_scroll_node->GetMainThreadScrollingReasons() != reasons)
-          context.force_subtree_update = true;
+          force_subtree_update = true;
       }
 
       CompositorElementId compositor_element_id =
           CreateDomNodeBasedCompositorElementId(object);
       TransformationMatrix matrix = TransformationMatrix().Translate(
           -scroll_offset.Width(), -scroll_offset.Height());
-      context.force_subtree_update |= properties.UpdateScrollTranslation(
+      force_subtree_update |= properties.UpdateScrollTranslation(
           context.current.transform, matrix, FloatPoint3D(),
           context.current.should_flatten_inherited_transform,
           context.current.rendering_context_id, kCompositingReasonNone,
@@ -976,7 +989,7 @@
     } else {
       // Ensure pre-existing properties are cleared.
       if (auto* properties = object.GetMutableForPainting().PaintProperties())
-        context.force_subtree_update |= properties->ClearScrollTranslation();
+        force_subtree_update |= properties->ClearScrollTranslation();
     }
   }
 
@@ -995,14 +1008,13 @@
 
 void PaintPropertyTreeBuilder::UpdateOutOfFlowContext(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
   if (object.IsLayoutBlock())
     context.paint_offset_for_float = context.current.paint_offset;
 
-  if (object.CanContainAbsolutePositionObjects()) {
+  if (object.CanContainAbsolutePositionObjects())
     context.absolute_position = context.current;
-    context.container_for_absolute_position = &object;
-  }
 
   if (object.IsLayoutView()) {
     if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
@@ -1033,8 +1045,8 @@
     if (context.fixed_position.clip == css_clip->Parent()) {
       context.fixed_position.clip = css_clip;
     } else {
-      if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
-        context.force_subtree_update |= properties.UpdateCssClipFixedPosition(
+      if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
+        force_subtree_update |= properties.UpdateCssClipFixedPosition(
             context.fixed_position.clip,
             const_cast<TransformPaintPropertyNode*>(
                 css_clip->LocalTransformSpace()),
@@ -1046,15 +1058,16 @@
     }
   }
 
-  if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
+  if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
     if (auto* properties = object.GetMutableForPainting().PaintProperties())
-      context.force_subtree_update |= properties->ClearCssClipFixedPosition();
+      force_subtree_update |= properties->ClearCssClipFixedPosition();
   }
 }
 
 void PaintPropertyTreeBuilder::UpdatePaintOffset(
     const LayoutBoxModelObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderFragmentContext& context,
+    const LayoutObject* container_for_absolute_position) {
   if (object.IsFloating())
     context.current.paint_offset = context.paint_offset_for_float;
 
@@ -1070,12 +1083,12 @@
       context.current.paint_offset += object.OffsetForInFlowPosition();
       break;
     case EPosition::kAbsolute: {
-      DCHECK(context.container_for_absolute_position == object.Container());
+      DCHECK(container_for_absolute_position == object.Container());
       context.current = context.absolute_position;
 
       // Absolutely positioned content in an inline should be positioned
       // relative to the inline.
-      const LayoutObject* container = context.container_for_absolute_position;
+      const LayoutObject* container = container_for_absolute_position;
       if (container && container->IsInFlowPositioned() &&
           container->IsLayoutInline()) {
         DCHECK(object.IsBox());
@@ -1099,7 +1112,7 @@
     // TODO(pdr): Several calls in this function walk back up the tree to
     // calculate containers (e.g., physicalLocation, offsetForInFlowPosition*).
     // The containing block and other containers can be stored on
-    // PaintPropertyTreeBuilderContext instead of recomputing them.
+    // PaintPropertyTreeBuilderFragmentContext instead of recomputing them.
     context.current.paint_offset.MoveBy(ToLayoutBox(object).PhysicalLocation());
     // This is a weird quirk that table cells paint as children of table rows,
     // but their location have the row's location baked-in.
@@ -1115,20 +1128,25 @@
 
 void PaintPropertyTreeBuilder::UpdateForObjectLocationAndSize(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    const LayoutObject* container_for_absolute_position,
+    bool& is_actually_needed,
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
 #if DCHECK_IS_ON()
-  FindPaintOffsetNeedingUpdateScope check_scope(object, context);
+  FindPaintOffsetNeedingUpdateScope check_scope(object, is_actually_needed);
 #endif
 
   if (object.IsBoxModelObject()) {
-    UpdatePaintOffset(ToLayoutBoxModelObject(object), context);
-    UpdatePaintOffsetTranslation(ToLayoutBoxModelObject(object), context);
+    UpdatePaintOffset(ToLayoutBoxModelObject(object), context,
+                      container_for_absolute_position);
+    UpdatePaintOffsetTranslation(ToLayoutBoxModelObject(object), context,
+                                 force_subtree_update);
   }
 
   if (object.PaintOffset() != context.current.paint_offset) {
     // Many paint properties depend on paint offset so we force an update of
     // the entire subtree on paint offset changes.
-    context.force_subtree_update = true;
+    force_subtree_update = true;
 
     if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
       object.GetMutableForPainting().SetShouldDoFullPaintInvalidation(
@@ -1166,7 +1184,7 @@
 
 void PaintPropertyTreeBuilder::UpdatePaintProperties(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderContext& full_context) {
   bool needs_paint_properties =
       NeedsPaintOffsetTranslation(object) || NeedsTransform(object) ||
       NeedsEffect(object) || NeedsTransformForNonRootSVG(object) ||
@@ -1182,62 +1200,80 @@
   } else {
     object.GetMutableForPainting().ClearPaintProperties();
     if (had_paint_properties)
-      context.force_subtree_update = true;
+      full_context.force_subtree_update = true;
   }
 }
 
 void PaintPropertyTreeBuilder::UpdatePropertiesForSelf(
     const LayoutObject& object,
-    PaintPropertyTreeBuilderContext& context) {
+    PaintPropertyTreeBuilderContext& full_context) {
+  PaintPropertyTreeBuilderFragmentContext& context = full_context.fragments[0];
   if (object.IsSVGHiddenContainer()) {
     // SVG resources are painted within one or more other locations in the
     // SVG during paint, and hence have their own independent paint property
     // trees, paint offset, etc.
-    context = PaintPropertyTreeBuilderContext();
+    context = PaintPropertyTreeBuilderFragmentContext();
   }
 
-  UpdatePaintProperties(object, context);
+  UpdatePaintProperties(object, full_context);
+
+  bool is_actually_needed = false;
+#if DCHECK_IS_ON()
+  is_actually_needed = full_context.is_actually_needed;
+#endif
 
   // This is not in FindObjectPropertiesNeedingUpdateScope because paint offset
   // can change without needsPaintPropertyUpdate.
-  UpdateForObjectLocationAndSize(object, context);
+  UpdateForObjectLocationAndSize(
+      object, full_context.container_for_absolute_position, is_actually_needed,
+      context, full_context.force_subtree_update);
 
 #if DCHECK_IS_ON()
-  FindObjectPropertiesNeedingUpdateScope check_needs_update_scope(object,
-                                                                  context);
+  FindObjectPropertiesNeedingUpdateScope check_needs_update_scope(
+      object, full_context.force_subtree_update);
 #endif
 
   if (object.IsBoxModelObject() || object.IsSVG()) {
-    UpdateTransform(object, context);
-    UpdateCssClip(object, context);
+    UpdateTransform(object, context, full_context.force_subtree_update);
+    UpdateCssClip(object, context, full_context.force_subtree_update);
     if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
-      UpdateEffect(object, context);
-      UpdateFilter(object, context);
+      UpdateEffect(object, context, full_context.force_subtree_update);
+      UpdateFilter(object, context, full_context.force_subtree_update);
     }
-    UpdateLocalBorderBoxContext(object, context);
-    if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
-      UpdateScrollbarPaintOffset(object, context);
+    UpdateLocalBorderBoxContext(object, context,
+                                full_context.force_subtree_update);
+    if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
+      UpdateScrollbarPaintOffset(object, context,
+                                 full_context.force_subtree_update);
+    }
   }
 }
 
 void PaintPropertyTreeBuilder::UpdatePropertiesForChildren(
     const LayoutObject& object,
     PaintPropertyTreeBuilderContext& context) {
-#if DCHECK_IS_ON()
-  FindObjectPropertiesNeedingUpdateScope check_needs_update_scope(object,
-                                                                  context);
-#endif
-
   if (!object.IsBoxModelObject() && !object.IsSVG())
     return;
 
-  UpdateOverflowClip(object, context);
-  UpdatePerspective(object, context);
-  UpdateSvgLocalToBorderBoxTransform(object, context);
-  UpdateScrollAndScrollTranslation(object, context);
-  UpdateOutOfFlowContext(object, context);
+  for (auto& fragment_context : context.fragments) {
+#if DCHECK_IS_ON()
+    FindObjectPropertiesNeedingUpdateScope check_needs_update_scope(
+        object, context.force_subtree_update);
+#endif
+    UpdateOverflowClip(object, fragment_context, context.force_subtree_update);
+    UpdatePerspective(object, fragment_context, context.force_subtree_update);
+    UpdateSvgLocalToBorderBoxTransform(object, fragment_context,
+                                       context.force_subtree_update);
+    UpdateScrollAndScrollTranslation(object, fragment_context,
+                                     context.force_subtree_update);
+    UpdateOutOfFlowContext(object, fragment_context,
+                           context.force_subtree_update);
 
-  context.force_subtree_update |= object.SubtreeNeedsPaintPropertyUpdate();
+    context.force_subtree_update |= object.SubtreeNeedsPaintPropertyUpdate();
+  }
+
+  if (object.CanContainAbsolutePositionObjects())
+    context.container_for_absolute_position = &object;
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
index 4f668ba9..871cb8e 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
@@ -21,12 +21,12 @@
 // The context for PaintPropertyTreeBuilder.
 // It's responsible for bookkeeping tree state in other order, for example, the
 // most recent position container seen.
-struct PaintPropertyTreeBuilderContext {
-  USING_FAST_MALLOC(PaintPropertyTreeBuilderContext);
+struct PaintPropertyTreeBuilderFragmentContext {
+  USING_FAST_MALLOC(PaintPropertyTreeBuilderFragmentContext);
 
  public:
   // Initializes all property tree nodes to the roots.
-  PaintPropertyTreeBuilderContext();
+  PaintPropertyTreeBuilderFragmentContext();
 
   // State that propagates on the containing block chain (and so is adjusted
   // when an absolute or fixed position object is encountered).
@@ -68,7 +68,6 @@
   // are also inherited by containing block tree instead of DOM tree, thus they
   // are included in the additional context too.
   ContainingBlockContext absolute_position;
-  const LayoutObject* container_for_absolute_position;
 
   ContainingBlockContext fixed_position;
 
@@ -87,6 +86,24 @@
   // This variable represents the input cull of current effect, also serves as
   // output clip of child effects that don't have a hard clip.
   const ClipPaintPropertyNode* input_clip_of_current_effect;
+};
+
+struct PaintPropertyTreeBuilderContext {
+  USING_FAST_MALLOC(PaintPropertyTreeBuilderContext);
+
+ public:
+  PaintPropertyTreeBuilderContext()
+      : container_for_absolute_position(nullptr),
+        force_subtree_update(false)
+#if DCHECK_IS_ON()
+        ,
+        is_actually_needed(true)
+#endif
+  {
+  }
+
+  Vector<PaintPropertyTreeBuilderFragmentContext> fragments;
+  const LayoutObject* container_for_absolute_position;
 
   // True if a change has forced all properties in a subtree to be updated. This
   // can be set due to paint offset changes or when the structure of the
@@ -96,7 +113,7 @@
 #if DCHECK_IS_ON()
   // When DCHECK_IS_ON() we create PaintPropertyTreeBuilderContext even if not
   // needed. See FindPaintOffsetAndVisualRectNeedingUpdate.h.
-  bool is_actually_needed = true;
+  bool is_actually_needed;
 #endif
 };
 
@@ -122,45 +139,68 @@
                                    PaintPropertyTreeBuilderContext&);
 
  private:
-  ALWAYS_INLINE static void UpdatePaintOffset(const LayoutBoxModelObject&,
-                                              PaintPropertyTreeBuilderContext&);
+  ALWAYS_INLINE static void UpdatePaintOffset(
+      const LayoutBoxModelObject&,
+      PaintPropertyTreeBuilderFragmentContext&,
+      const LayoutObject* container_for_absolute_position);
   ALWAYS_INLINE static void UpdatePaintOffsetTranslation(
       const LayoutBoxModelObject&,
-      PaintPropertyTreeBuilderContext&);
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
   ALWAYS_INLINE static void UpdateForObjectLocationAndSize(
       const LayoutObject&,
-      PaintPropertyTreeBuilderContext&);
-  ALWAYS_INLINE static void UpdateTransform(const LayoutObject&,
-                                            PaintPropertyTreeBuilderContext&);
+      const LayoutObject* container_for_absolute_position,
+      bool& is_actually_needed,
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
+  ALWAYS_INLINE static void UpdateTransform(
+      const LayoutObject&,
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
   ALWAYS_INLINE static void UpdateTransformForNonRootSVG(
       const LayoutObject&,
-      PaintPropertyTreeBuilderContext&);
-  ALWAYS_INLINE static void UpdateEffect(const LayoutObject&,
-                                         PaintPropertyTreeBuilderContext&);
-  ALWAYS_INLINE static void UpdateFilter(const LayoutObject&,
-                                         PaintPropertyTreeBuilderContext&);
-  ALWAYS_INLINE static void UpdateCssClip(const LayoutObject&,
-                                          PaintPropertyTreeBuilderContext&);
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
+  ALWAYS_INLINE static void UpdateEffect(
+      const LayoutObject&,
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
+  ALWAYS_INLINE static void UpdateFilter(
+      const LayoutObject&,
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
+  ALWAYS_INLINE static void UpdateCssClip(
+      const LayoutObject&,
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
   ALWAYS_INLINE static void UpdateLocalBorderBoxContext(
       const LayoutObject&,
-      PaintPropertyTreeBuilderContext&);
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
   ALWAYS_INLINE static void UpdateScrollbarPaintOffset(
       const LayoutObject&,
-      PaintPropertyTreeBuilderContext&);
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
   ALWAYS_INLINE static void UpdateOverflowClip(
       const LayoutObject&,
-      PaintPropertyTreeBuilderContext&);
-  ALWAYS_INLINE static void UpdatePerspective(const LayoutObject&,
-                                              PaintPropertyTreeBuilderContext&);
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
+  ALWAYS_INLINE static void UpdatePerspective(
+      const LayoutObject&,
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
   ALWAYS_INLINE static void UpdateSvgLocalToBorderBoxTransform(
       const LayoutObject&,
-      PaintPropertyTreeBuilderContext&);
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
   ALWAYS_INLINE static void UpdateScrollAndScrollTranslation(
       const LayoutObject&,
-      PaintPropertyTreeBuilderContext&);
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
   ALWAYS_INLINE static void UpdateOutOfFlowContext(
       const LayoutObject&,
-      PaintPropertyTreeBuilderContext&);
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
 
   // Ensure the ObjectPaintProperties object is created if it will be needed, or
   // cleared otherwise.
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
index d333389..fec8cba6 100644
--- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
+++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
@@ -129,7 +129,8 @@
 }
 
 LayoutRect PrePaintTreeWalk::ComputeClipRectForContext(
-    const PaintPropertyTreeBuilderContext::ContainingBlockContext& context,
+    const PaintPropertyTreeBuilderFragmentContext::ContainingBlockContext&
+        context,
     const EffectPaintPropertyNode* effect,
     const PropertyTreeState& ancestor_state,
     const LayoutPoint& ancestor_paint_offset) {
@@ -194,28 +195,30 @@
       context.ancestor_transformed_or_root_paint_layer->GetLayoutObject()
           .PaintOffset();
 
-  const auto* effect = context.tree_builder_context->current_effect;
-  auto overflow_clip_rect =
-      ComputeClipRectForContext(context.tree_builder_context->current, effect,
-                                ancestor_state, ancestor_paint_offset);
+  // TODO(chrishtr): generalize this for multicol.
+  const auto* effect =
+      context.tree_builder_context->fragments[0].current_effect;
+  auto overflow_clip_rect = ComputeClipRectForContext(
+      context.tree_builder_context->fragments[0].current, effect,
+      ancestor_state, ancestor_paint_offset);
 #ifdef CHECK_CLIP_RECTS
   CHECK(overflow_clip_rect == old_clip_rects.OverflowClipRect().Rect())
       << " new=" << overflow_clip_rect.ToString()
       << " old=" << old_clip_rects.OverflowClipRect().Rect().ToString();
 #endif
 
-  auto fixed_clip_rect =
-      ComputeClipRectForContext(context.tree_builder_context->fixed_position,
-                                effect, ancestor_state, ancestor_paint_offset);
+  auto fixed_clip_rect = ComputeClipRectForContext(
+      context.tree_builder_context->fragments[0].fixed_position, effect,
+      ancestor_state, ancestor_paint_offset);
 #ifdef CHECK_CLIP_RECTS
   CHECK(fixed_clip_rect == old_clip_rects.FixedClipRect().Rect())
       << " new=" << fixed_clip_rect.ToString()
       << " old=" << old_clip_rects.FixedClipRect().Rect().ToString();
 #endif
 
-  auto pos_clip_rect =
-      ComputeClipRectForContext(context.tree_builder_context->absolute_position,
-                                effect, ancestor_state, ancestor_paint_offset);
+  auto pos_clip_rect = ComputeClipRectForContext(
+      context.tree_builder_context->fragments[0].absolute_position, effect,
+      ancestor_state, ancestor_paint_offset);
 #ifdef CHECK_CLIP_RECTS
   CHECK(pos_clip_rect == old_clip_rects.PosClipRect().Rect())
       << " new=" << pos_clip_rect.ToString()
@@ -308,11 +311,12 @@
     FrameView* frame_view = layout_part.ChildFrameView();
     if (frame_view) {
       if (context.tree_builder_context) {
-        context.tree_builder_context->current.paint_offset +=
+        context.tree_builder_context->fragments[0].current.paint_offset +=
             layout_part.ReplacedContentRect().Location() -
             frame_view->FrameRect().Location();
-        context.tree_builder_context->current.paint_offset =
-            RoundedIntPoint(context.tree_builder_context->current.paint_offset);
+        context.tree_builder_context->fragments[0].current.paint_offset =
+            RoundedIntPoint(context.tree_builder_context->fragments[0]
+                                .current.paint_offset);
       }
       Walk(*frame_view, context);
     }
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.h b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.h
index 058c50a9..4e6e989 100644
--- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.h
+++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.h
@@ -37,7 +37,7 @@
   // Returns the clip applied to children for the given containing block context
   // + effect, in the space of ancestorState adjusted by ancestorPaintOffset.
   ALWAYS_INLINE LayoutRect ComputeClipRectForContext(
-      const PaintPropertyTreeBuilderContext::ContainingBlockContext&,
+      const PaintPropertyTreeBuilderFragmentContext::ContainingBlockContext&,
       const EffectPaintPropertyNode*,
       const PropertyTreeState& ancestor_state,
       const LayoutPoint& ancestor_paint_offset);
diff --git a/third_party/WebKit/Source/core/paint/TableCellPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/TableCellPaintInvalidator.cpp
new file mode 100644
index 0000000..d8daf48d
--- /dev/null
+++ b/third_party/WebKit/Source/core/paint/TableCellPaintInvalidator.cpp
@@ -0,0 +1,61 @@
+// 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 "core/paint/TableCellPaintInvalidator.h"
+
+#include "core/layout/LayoutTable.h"
+#include "core/layout/LayoutTableCell.h"
+#include "core/layout/LayoutTableCol.h"
+#include "core/layout/LayoutTableRow.h"
+#include "core/layout/LayoutTableSection.h"
+#include "core/paint/BlockPaintInvalidator.h"
+#include "core/paint/ObjectPaintInvalidator.h"
+#include "core/paint/PaintInvalidator.h"
+#include "core/paint/PaintLayer.h"
+
+namespace blink {
+
+PaintInvalidationReason TableCellPaintInvalidator::InvalidatePaint() {
+  // The cell's containing row and section paint backgrounds behind the cell.
+  // If the cell's geometry changed, invalidate the background display items.
+  if (context_.old_location != context_.new_location ||
+      cell_.Size() != cell_.PreviousSize()) {
+    const auto& row = *cell_.Row();
+    if (row.GetPaintInvalidationReason() == kPaintInvalidationNone &&
+        row.StyleRef().HasBackground()) {
+      if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled())
+        context_.parent_context->painting_layer->SetNeedsRepaint();
+      else
+        ObjectPaintInvalidator(row).SlowSetPaintingLayerNeedsRepaint();
+      row.InvalidateDisplayItemClients(kPaintInvalidationForcedByLayout);
+    }
+
+    const auto& section = *row.Section();
+    if (section.GetPaintInvalidationReason() == kPaintInvalidationNone) {
+      bool section_paints_background = section.StyleRef().HasBackground();
+      if (!section_paints_background) {
+        auto col_and_colgroup = section.Table()->ColElementAtAbsoluteColumn(
+            cell_.AbsoluteColumnIndex());
+        if ((col_and_colgroup.col &&
+             col_and_colgroup.col->StyleRef().HasBackground()) ||
+            (col_and_colgroup.colgroup &&
+             col_and_colgroup.colgroup->StyleRef().HasBackground()))
+          section_paints_background = true;
+      }
+      if (section_paints_background) {
+        if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()) {
+          context_.parent_context->parent_context->painting_layer
+              ->SetNeedsRepaint();
+        } else {
+          ObjectPaintInvalidator(section).SlowSetPaintingLayerNeedsRepaint();
+        }
+        section.InvalidateDisplayItemClients(kPaintInvalidationForcedByLayout);
+      }
+    }
+  }
+
+  return BlockPaintInvalidator(cell_).InvalidatePaint(context_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/TableCellPaintInvalidator.h b/third_party/WebKit/Source/core/paint/TableCellPaintInvalidator.h
new file mode 100644
index 0000000..d47b582
--- /dev/null
+++ b/third_party/WebKit/Source/core/paint/TableCellPaintInvalidator.h
@@ -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.
+
+#ifndef TableCellPaintInvalidator_h
+#define TableCellPaintInvalidator_h
+
+#include "platform/graphics/PaintInvalidationReason.h"
+#include "platform/wtf/Allocator.h"
+
+namespace blink {
+
+class LayoutTableCell;
+struct PaintInvalidatorContext;
+
+class TableCellPaintInvalidator {
+  STACK_ALLOCATED();
+
+ public:
+  TableCellPaintInvalidator(const LayoutTableCell& cell,
+                            const PaintInvalidatorContext& context)
+      : cell_(cell), context_(context) {}
+
+  PaintInvalidationReason InvalidatePaint();
+
+ private:
+  const LayoutTableCell& cell_;
+  const PaintInvalidatorContext& context_;
+};
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
index 5a33e7b..7dd63702 100644
--- a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
@@ -504,8 +504,8 @@
       // the load event, but if we miss that train (deferred programmatic
       // element insertion for example) we need to initialize the time container
       // here.
-      if (!GetDocument().Parsing() && !GetDocument().ProcessingLoadEvent() &&
-          GetDocument().LoadEventFinished() && !TimeContainer()->IsStarted())
+      if (!GetDocument().Parsing() && GetDocument().LoadEventFinished() &&
+          !TimeContainer()->IsStarted())
         TimeContainer()->Start();
     }
   }
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
index 24d28d73..afde4f7 100644
--- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
+++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -1638,7 +1638,7 @@
 
   ClearVariablesForLoading();
 
-  response_document_->ImplicitClose();
+  response_document_->CheckCompleted();
 
   if (!response_document_->WellFormed())
     response_document_ = nullptr;
diff --git a/third_party/WebKit/Source/modules/fetch/Headers.cpp b/third_party/WebKit/Source/modules/fetch/Headers.cpp
index b8b6e61a..8c3be95 100644
--- a/third_party/WebKit/Source/modules/fetch/Headers.cpp
+++ b/third_party/WebKit/Source/modules/fetch/Headers.cpp
@@ -167,21 +167,6 @@
   return result;
 }
 
-Vector<String> Headers::getAll(const String& name,
-                               ExceptionState& exception_state) {
-  // "The getAll(|name|) method, when invoked, must run these steps:"
-  // "1. If |name| is not a name, throw a TypeError."
-  if (!FetchHeaderList::IsValidHeaderName(name)) {
-    exception_state.ThrowTypeError("Invalid name");
-    return Vector<String>();
-  }
-  // "2. Return the values of all headers in header list whose name is |name|,
-  //     in list order, and the empty sequence otherwise."
-  Vector<String> result;
-  header_list_->GetAll(name, result);
-  return result;
-}
-
 bool Headers::has(const String& name, ExceptionState& exception_state) {
   // "The has(|name|) method, when invoked, must run these steps:"
   // "1. If |name| is not a name, throw a TypeError."
diff --git a/third_party/WebKit/Source/modules/fetch/Headers.h b/third_party/WebKit/Source/modules/fetch/Headers.h
index 3c41b2d2..de5ffab2 100644
--- a/third_party/WebKit/Source/modules/fetch/Headers.h
+++ b/third_party/WebKit/Source/modules/fetch/Headers.h
@@ -46,7 +46,6 @@
   void append(const String& name, const String& value, ExceptionState&);
   void remove(const String& key, ExceptionState&);
   String get(const String& key, ExceptionState&);
-  Vector<String> getAll(const String& key, ExceptionState&);
   bool has(const String& key, ExceptionState&);
   void set(const String& key, const String& value, ExceptionState&);
 
diff --git a/third_party/WebKit/Source/modules/fetch/Headers.idl b/third_party/WebKit/Source/modules/fetch/Headers.idl
index 3255e90..dd68f2d 100644
--- a/third_party/WebKit/Source/modules/fetch/Headers.idl
+++ b/third_party/WebKit/Source/modules/fetch/Headers.idl
@@ -20,7 +20,6 @@
     [RaisesException] void append(ByteString name, ByteString value);
     [ImplementedAs=remove, RaisesException] void delete(ByteString key);
     [RaisesException] ByteString? get(ByteString key);
-    [RaisesException, Measure] sequence<ByteString> getAll(ByteString name);
     [RaisesException] boolean has(ByteString key);
     [RaisesException] void set(ByteString key, ByteString value);
     iterable<ByteString, ByteString>;
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 31e7f16d..c568635 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -488,8 +488,11 @@
     "bindings/ScriptWrappableVisitor.cpp",
     "bindings/ScriptWrappableVisitor.h",
     "bindings/ScriptWrappableVisitorVerifier.h",
+    "bindings/SharedPersistent.h",
     "bindings/StringResource.cpp",
     "bindings/StringResource.h",
+    "bindings/ToV8.h",
+    "bindings/TraceWrapperMember.h",
     "bindings/TraceWrapperV8Reference.h",
     "bindings/V0CustomElementBinding.cpp",
     "bindings/V0CustomElementBinding.h",
diff --git a/third_party/WebKit/Source/platform/bindings/SharedPersistent.h b/third_party/WebKit/Source/platform/bindings/SharedPersistent.h
new file mode 100644
index 0000000..5677ef4
--- /dev/null
+++ b/third_party/WebKit/Source/platform/bindings/SharedPersistent.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SharedPersistent_h
+#define SharedPersistent_h
+
+#include "platform/bindings/ScopedPersistent.h"
+#include "platform/wtf/PassRefPtr.h"
+#include "platform/wtf/RefCounted.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+template <typename T>
+class SharedPersistent : public RefCounted<SharedPersistent<T>> {
+  WTF_MAKE_NONCOPYABLE(SharedPersistent);
+
+ public:
+  static PassRefPtr<SharedPersistent<T>> Create(v8::Local<T> value,
+                                                v8::Isolate* isolate) {
+    return AdoptRef(new SharedPersistent<T>(value, isolate));
+  }
+
+  v8::Local<T> NewLocal(v8::Isolate* isolate) const {
+    return value_.NewLocal(isolate);
+  }
+
+  bool IsEmpty() { return value_.IsEmpty(); }
+
+  bool operator==(const SharedPersistent<T>& other) {
+    return value_ == other.value_;
+  }
+
+ private:
+  explicit SharedPersistent(v8::Local<T> value, v8::Isolate* isolate)
+      : value_(isolate, value) {}
+  ScopedPersistent<T> value_;
+};
+
+}  // namespace blink
+
+#endif  // SharedPersistent_h
diff --git a/third_party/WebKit/Source/platform/bindings/ToV8.h b/third_party/WebKit/Source/platform/bindings/ToV8.h
new file mode 100644
index 0000000..1cfa16a
--- /dev/null
+++ b/third_party/WebKit/Source/platform/bindings/ToV8.h
@@ -0,0 +1,278 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ToV8_h
+#define ToV8_h
+
+// ToV8() provides C++ -> V8 conversion. Note that ToV8() can return an empty
+// handle. Call sites must check IsEmpty() before using return value.
+
+#include <utility>
+
+#include "platform/bindings/DOMDataStore.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/bindings/V8Binding.h"
+#include "platform/heap/Handle.h"
+#include "platform/wtf/Forward.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+// ScriptWrappable
+
+inline v8::Local<v8::Value> ToV8(ScriptWrappable* impl,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  if (UNLIKELY(!impl))
+    return v8::Null(isolate);
+  v8::Local<v8::Value> wrapper = DOMDataStore::GetWrapper(impl, isolate);
+  if (!wrapper.IsEmpty())
+    return wrapper;
+
+  wrapper = impl->Wrap(isolate, creation_context);
+  DCHECK(!wrapper.IsEmpty());
+  return wrapper;
+}
+
+// Primitives
+
+inline v8::Local<v8::Value> ToV8(const String& value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return V8String(isolate, value);
+}
+
+inline v8::Local<v8::Value> ToV8(const char* value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return V8String(isolate, value);
+}
+
+template <size_t sizeOfValue>
+inline v8::Local<v8::Value> ToV8SignedIntegerInternal(int64_t value,
+                                                      v8::Isolate*);
+
+template <>
+inline v8::Local<v8::Value> ToV8SignedIntegerInternal<4>(int64_t value,
+                                                         v8::Isolate* isolate) {
+  return v8::Integer::New(isolate, static_cast<int32_t>(value));
+}
+
+template <>
+inline v8::Local<v8::Value> ToV8SignedIntegerInternal<8>(int64_t value,
+                                                         v8::Isolate* isolate) {
+  int32_t value_in32_bit = static_cast<int32_t>(value);
+  if (value_in32_bit == value)
+    return v8::Integer::New(isolate, value);
+  // V8 doesn't have a 64-bit integer implementation.
+  return v8::Number::New(isolate, value);
+}
+
+template <size_t sizeOfValue>
+inline v8::Local<v8::Value> ToV8UnsignedIntegerInternal(uint64_t value,
+                                                        v8::Isolate*);
+
+template <>
+inline v8::Local<v8::Value> ToV8UnsignedIntegerInternal<4>(
+    uint64_t value,
+    v8::Isolate* isolate) {
+  return v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(value));
+}
+
+template <>
+inline v8::Local<v8::Value> ToV8UnsignedIntegerInternal<8>(
+    uint64_t value,
+    v8::Isolate* isolate) {
+  uint32_t value_in32_bit = static_cast<uint32_t>(value);
+  if (value_in32_bit == value)
+    return v8::Integer::NewFromUnsigned(isolate, value);
+  // V8 doesn't have a 64-bit integer implementation.
+  return v8::Number::New(isolate, value);
+}
+
+inline v8::Local<v8::Value> ToV8(int value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return ToV8SignedIntegerInternal<sizeof value>(value, isolate);
+}
+
+inline v8::Local<v8::Value> ToV8(long value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return ToV8SignedIntegerInternal<sizeof value>(value, isolate);
+}
+
+inline v8::Local<v8::Value> ToV8(long long value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return ToV8SignedIntegerInternal<sizeof value>(value, isolate);
+}
+
+inline v8::Local<v8::Value> ToV8(unsigned value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return ToV8UnsignedIntegerInternal<sizeof value>(value, isolate);
+}
+
+inline v8::Local<v8::Value> ToV8(unsigned long value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return ToV8UnsignedIntegerInternal<sizeof value>(value, isolate);
+}
+
+inline v8::Local<v8::Value> ToV8(unsigned long long value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return ToV8UnsignedIntegerInternal<sizeof value>(value, isolate);
+}
+
+inline v8::Local<v8::Value> ToV8(double value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return v8::Number::New(isolate, value);
+}
+
+inline v8::Local<v8::Value> ToV8(bool value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return v8::Boolean::New(isolate, value);
+}
+
+// Identity operator
+
+inline v8::Local<v8::Value> ToV8(v8::Local<v8::Value> value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate*) {
+  return value;
+}
+
+// Undefined
+
+struct ToV8UndefinedGenerator {
+  DISALLOW_NEW();
+};  // Used only for having toV8 return v8::Undefined.
+
+inline v8::Local<v8::Value> ToV8(const ToV8UndefinedGenerator& value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return v8::Undefined(isolate);
+}
+
+// Array
+
+// Declare the function here but define it later so it can call the ToV8()
+// overloads below.
+template <typename Sequence>
+inline v8::Local<v8::Value> ToV8SequenceInternal(
+    const Sequence&,
+    v8::Local<v8::Object> creation_context,
+    v8::Isolate*);
+
+template <typename T, size_t inlineCapacity>
+inline v8::Local<v8::Value> ToV8(const Vector<T, inlineCapacity>& value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return ToV8SequenceInternal(value, creation_context, isolate);
+}
+
+template <typename T, size_t inlineCapacity>
+inline v8::Local<v8::Value> ToV8(const HeapVector<T, inlineCapacity>& value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  return ToV8SequenceInternal(value, creation_context, isolate);
+}
+
+// The following two overloads are also used to convert record<K,V> IDL types
+// back into ECMAScript Objects.
+template <typename T>
+inline v8::Local<v8::Value> ToV8(const Vector<std::pair<String, T>>& value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  v8::Local<v8::Object> object;
+  {
+    v8::Context::Scope context_scope(creation_context->CreationContext());
+    object = v8::Object::New(isolate);
+  }
+  for (unsigned i = 0; i < value.size(); ++i) {
+    v8::Local<v8::Value> v8_value = ToV8(value[i].second, object, isolate);
+    if (v8_value.IsEmpty())
+      v8_value = v8::Undefined(isolate);
+    if (!V8CallBoolean(object->CreateDataProperty(
+            isolate->GetCurrentContext(), V8String(isolate, value[i].first),
+            v8_value)))
+      return v8::Local<v8::Value>();
+  }
+  return object;
+}
+
+template <typename T>
+inline v8::Local<v8::Value> ToV8(const HeapVector<std::pair<String, T>>& value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  v8::Local<v8::Object> object;
+  {
+    v8::Context::Scope context_scope(creation_context->CreationContext());
+    object = v8::Object::New(isolate);
+  }
+  for (unsigned i = 0; i < value.size(); ++i) {
+    v8::Local<v8::Value> v8_value = ToV8(value[i].second, object, isolate);
+    if (v8_value.IsEmpty())
+      v8_value = v8::Undefined(isolate);
+    if (!V8CallBoolean(object->CreateDataProperty(
+            isolate->GetCurrentContext(), V8String(isolate, value[i].first),
+            v8_value)))
+      return v8::Local<v8::Value>();
+  }
+  return object;
+}
+
+template <typename Sequence>
+inline v8::Local<v8::Value> ToV8SequenceInternal(
+    const Sequence& sequence,
+    v8::Local<v8::Object> creation_context,
+    v8::Isolate* isolate) {
+  v8::Local<v8::Array> array;
+  {
+    v8::Context::Scope context_scope(creation_context->CreationContext());
+    array = v8::Array::New(isolate, sequence.size());
+  }
+  uint32_t index = 0;
+  typename Sequence::const_iterator end = sequence.end();
+  for (typename Sequence::const_iterator iter = sequence.begin(); iter != end;
+       ++iter) {
+    v8::Local<v8::Value> value = ToV8(*iter, array, isolate);
+    if (value.IsEmpty())
+      value = v8::Undefined(isolate);
+    if (!V8CallBoolean(array->CreateDataProperty(isolate->GetCurrentContext(),
+                                                 index++, value)))
+      return v8::Local<v8::Value>();
+  }
+  return array;
+}
+
+// In all cases allow script state instead of creation context + isolate.
+// Use this function only if the call site does not otherwise need the global,
+// since v8::Context::Global is heavy.
+template <typename T>
+inline v8::Local<v8::Value> ToV8(T&& value, ScriptState* script_state) {
+  return ToV8(std::forward<T>(value), script_state->GetContext()->Global(),
+              script_state->GetIsolate());
+}
+
+// Only declare ToV8(void*,...) for checking function overload mismatch.
+// This ToV8(void*,...) should be never used. So we will find mismatch
+// because of "unresolved external symbol".
+// Without ToV8(void*, ...), call to toV8 with T* will match with
+// ToV8(bool, ...) if T is not a subclass of ScriptWrappable or if T is
+// declared but not defined (so it's not clear that T is a subclass of
+// ScriptWrappable).
+// This hack helps detect such unwanted implicit conversions from T* to bool.
+v8::Local<v8::Value> ToV8(void* value,
+                          v8::Local<v8::Object> creation_context,
+                          v8::Isolate*) = delete;
+
+}  // namespace blink
+
+#endif  // ToV8ForPlatform_h
diff --git a/third_party/WebKit/Source/platform/bindings/TraceWrapperMember.h b/third_party/WebKit/Source/platform/bindings/TraceWrapperMember.h
new file mode 100644
index 0000000..1cc4f8df
--- /dev/null
+++ b/third_party/WebKit/Source/platform/bindings/TraceWrapperMember.h
@@ -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.
+
+#ifndef TraceWrapperMember_h
+#define TraceWrapperMember_h
+
+#include "platform/bindings/ScriptWrappableVisitor.h"
+#include "platform/heap/HeapAllocator.h"
+
+namespace blink {
+
+class HeapObjectHeader;
+template <typename T>
+class Member;
+
+/**
+ * TraceWrapperMember is used for Member fields that should participate in
+ * wrapper tracing, i.e., strongly hold a ScriptWrappable alive. All
+ * TraceWrapperMember fields must be traced in the class' traceWrappers method.
+ */
+template <class T>
+class TraceWrapperMember : public Member<T> {
+  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
+
+ public:
+  TraceWrapperMember(void* parent, T* raw) : Member<T>(raw), parent_(parent) {
+#if DCHECK_IS_ON()
+    if (parent_) {
+      HeapObjectHeader::CheckFromPayload(parent_);
+    }
+#endif
+    // We don't require a write barrier here as TraceWrapperMember is used for
+    // the following scenarios:
+    // - Initial initialization: The write barrier will not fire as the parent
+    //   is initially white.
+    // - Wrapping when inserting into a container: The write barrier will fire
+    //   upon establishing the move into the container.
+    // - Assignment to a field: The regular assignment operator will fire the
+    //   write barrier.
+    // Note that support for black allocation would require a barrier here.
+  }
+  TraceWrapperMember(WTF::HashTableDeletedValueType x)
+      : Member<T>(x), parent_(nullptr) {}
+
+  /**
+   * Copying a TraceWrapperMember means that its backpointer will also be
+   * copied.
+   */
+  TraceWrapperMember(const TraceWrapperMember& other) { *this = other; }
+
+  TraceWrapperMember& operator=(const TraceWrapperMember& other) {
+    DCHECK(!other.raw_ || other.parent_);
+    parent_ = other.parent_;
+    Member<T>::operator=(other);
+    ScriptWrappableVisitor::WriteBarrier(parent_, other);
+    return *this;
+  }
+
+  TraceWrapperMember& operator=(const Member<T>& other) {
+    DCHECK(!TraceWrapperMemberIsNotInitialized());
+    Member<T>::operator=(other);
+    ScriptWrappableVisitor::WriteBarrier(parent_, other);
+    return *this;
+  }
+
+  TraceWrapperMember& operator=(T* other) {
+    DCHECK(!TraceWrapperMemberIsNotInitialized());
+    Member<T>::operator=(other);
+    ScriptWrappableVisitor::WriteBarrier(parent_, other);
+    return *this;
+  }
+
+  TraceWrapperMember& operator=(std::nullptr_t) {
+    // No need for a write barrier when assigning nullptr.
+    Member<T>::operator=(nullptr);
+    return *this;
+  }
+
+  void* Parent() { return parent_; }
+
+ private:
+  bool TraceWrapperMemberIsNotInitialized() { return !parent_; }
+
+  /**
+   * The parent object holding strongly onto the actual Member.
+   */
+  void* parent_;
+};
+
+/**
+ * Swaps two HeapVectors specialized for TraceWrapperMember. The custom swap
+ * function is required as TraceWrapperMember contains ownership information
+ * which is not copyable but has to be explicitly specified.
+ */
+template <typename T>
+void swap(HeapVector<TraceWrapperMember<T>>& a,
+          HeapVector<TraceWrapperMember<T>>& b,
+          void* parent_for_a,
+          void* parent_for_b) {
+  HeapVector<TraceWrapperMember<T>> temp;
+  temp.ReserveCapacity(a.size());
+  for (auto item : a) {
+    temp.push_back(TraceWrapperMember<T>(parent_for_b, item.Get()));
+  }
+  a.clear();
+  a.ReserveCapacity(b.size());
+  for (auto item : b) {
+    a.push_back(TraceWrapperMember<T>(parent_for_a, item.Get()));
+  }
+  b.clear();
+  b.ReserveCapacity(temp.size());
+  for (auto item : temp) {
+    b.push_back(TraceWrapperMember<T>(parent_for_b, item.Get()));
+  }
+}
+
+/**
+ * Swaps two HeapVectors, one containing TraceWrapperMember and one with
+ * regular Members. The custom swap function is required as
+ * TraceWrapperMember contains ownership information which is not copyable
+ * but has to be explicitly specified.
+ */
+template <typename T>
+void swap(HeapVector<TraceWrapperMember<T>>& a,
+          HeapVector<Member<T>>& b,
+          void* parent_for_a) {
+  HeapVector<TraceWrapperMember<T>> temp;
+  temp.ReserveCapacity(a.size());
+  for (auto item : a) {
+    temp.push_back(TraceWrapperMember<T>(item.Parent(), item.Get()));
+  }
+  a.clear();
+  a.ReserveCapacity(b.size());
+  for (auto item : b) {
+    a.push_back(TraceWrapperMember<T>(parent_for_a, item.Get()));
+  }
+  b.clear();
+  b.ReserveCapacity(temp.size());
+  for (auto item : temp) {
+    b.push_back(item.Get());
+  }
+}
+
+}  // namespace blink
+
+#endif  // TraceWrapperMember_h
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
index 0d87eec..13ff8e42 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
@@ -27,6 +27,10 @@
 
 namespace blink {
 
+enum {
+  kMaxPendingCompositorFrames = 2,
+};
+
 OffscreenCanvasFrameDispatcherImpl::OffscreenCanvasFrameDispatcherImpl(
     OffscreenCanvasFrameDispatcherClient* client,
     uint32_t client_id,
@@ -399,14 +403,15 @@
     change_size_for_next_commit_ = false;
   }
 
-  compositor_has_pending_frame_ = true;
+  pending_compositor_frames_++;
   sink_->SubmitCompositorFrame(current_local_surface_id_, std::move(frame));
 }
 
 void OffscreenCanvasFrameDispatcherImpl::DidReceiveCompositorFrameAck(
     const cc::ReturnedResourceArray& resources) {
   ReclaimResources(resources);
-  compositor_has_pending_frame_ = false;
+  pending_compositor_frames_--;
+  DCHECK_GE(pending_compositor_frames_, 0);
 }
 
 void OffscreenCanvasFrameDispatcherImpl::SetNeedsBeginFrame(
@@ -426,7 +431,7 @@
       begin_frame_args.source_id, begin_frame_args.sequence_number,
       begin_frame_args.sequence_number, false);
 
-  if (compositor_has_pending_frame_ ||
+  if (pending_compositor_frames_ >= kMaxPendingCompositorFrames ||
       (begin_frame_args.type == cc::BeginFrameArgs::MISSED &&
        base::TimeTicks::Now() > begin_frame_args.deadline)) {
     sink_->BeginFrameDidNotSwap(current_begin_frame_ack_);
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
index 9bfbbbb..a7732413 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
@@ -64,7 +64,7 @@
   int height_;
   bool change_size_for_next_commit_;
   bool needs_begin_frame_;
-  bool compositor_has_pending_frame_ = false;
+  int pending_compositor_frames_ = 0;
 
   unsigned next_resource_id_;
   HashMap<unsigned, RefPtr<StaticBitmapImage>> cached_images_;
diff --git a/third_party/WebKit/Source/web/WebFrame.cpp b/third_party/WebKit/Source/web/WebFrame.cpp
index 78684536..5725f356 100644
--- a/third_party/WebKit/Source/web/WebFrame.cpp
+++ b/third_party/WebKit/Source/web/WebFrame.cpp
@@ -4,8 +4,10 @@
 
 #include "public/web/WebFrame.h"
 
+#include <algorithm>
 #include "bindings/core/v8/WindowProxyManager.h"
 #include "core/HTMLNames.h"
+#include "core/dom/IncrementLoadEventDelayCount.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/RemoteFrame.h"
@@ -22,7 +24,6 @@
 #include "web/RemoteFrameOwner.h"
 #include "web/WebLocalFrameImpl.h"
 #include "web/WebRemoteFrameImpl.h"
-#include <algorithm>
 
 namespace blink {
 
@@ -40,6 +41,16 @@
   if (!old_frame->PrepareForCommit())
     return false;
 
+  // If there is a local parent, it might incorrectly declare itself complete
+  // during the detach phase of this swap. Suppress its completion until swap is
+  // over, at which point its completion will be correctly dependent on its
+  // newly swapped-in child.
+  std::unique_ptr<IncrementLoadEventDelayCount> delay_parent_load =
+      parent_ && parent_->IsWebLocalFrame()
+          ? IncrementLoadEventDelayCount::Create(
+                *ToWebLocalFrameImpl(parent_)->GetFrame()->GetDocument())
+          : nullptr;
+
   if (parent_) {
     if (parent_->first_child_ == this)
       parent_->first_child_ = frame;
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
index b862efd..bd371af 100644
--- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
@@ -488,7 +488,7 @@
   if (Parent() && Parent()->IsWebLocalFrame()) {
     WebLocalFrameImpl* parent_frame =
         ToWebLocalFrameImpl(Parent()->ToWebLocalFrame());
-    parent_frame->GetFrame()->Loader().CheckCompleted();
+    parent_frame->GetFrame()->GetDocument()->CheckCompleted();
   }
 }
 
diff --git a/tools/boilerplate.py b/tools/boilerplate.py
index 8d63438..03e71f5 100755
--- a/tools/boilerplate.py
+++ b/tools/boilerplate.py
@@ -39,7 +39,7 @@
 
 def _CppHeader(filename):
   guard = filename.upper() + '_'
-  for char in '/.+':
+  for char in '/\\.+':
     guard = guard.replace(char, '_')
   return '\n'.join([
     '',
@@ -69,8 +69,13 @@
   return False
 
 
+def _FilePathSlashesToCpp(filename):
+  return filename.replace('\\', '/')
+
+
 def _CppImplementation(filename):
-  return '\n#include "' + _RemoveTestSuffix(filename) + '.h"\n'
+  return '\n#include "' + _FilePathSlashesToCpp(_RemoveTestSuffix(filename)) \
+    + '.h"\n'
 
 
 def _ObjCppImplementation(filename):
@@ -94,7 +99,7 @@
   elif filename.endswith('.mm'):
     contents += _ObjCppImplementation(filename)
 
-  fd = open(filename, 'w')
+  fd = open(filename, 'wb')
   fd.write(contents)
   fd.close()
 
diff --git a/tools/chrome_proxy/webdriver/common.py b/tools/chrome_proxy/webdriver/common.py
index 4dfc2fa0..2143f6e 100644
--- a/tools/chrome_proxy/webdriver/common.py
+++ b/tools/chrome_proxy/webdriver/common.py
@@ -166,7 +166,8 @@
       # Override flags given in code with any command line arguments.
       for override_arg in shlex.split(self._flags.browser_args):
         arg_key = GetDictKey(override_arg)
-        if arg_key in original_args:
+        if (arg_key in original_args
+            and original_args[arg_key] in self._chrome_args):
           self._chrome_args.remove(original_args[arg_key])
           self._logger.info('Removed Chrome flag. %s', original_args[arg_key])
         self._chrome_args.add(override_arg)
diff --git a/tools/chrome_proxy/webdriver/variations_combinations.py b/tools/chrome_proxy/webdriver/variations_combinations.py
new file mode 100644
index 0000000..3471a41
--- /dev/null
+++ b/tools/chrome_proxy/webdriver/variations_combinations.py
@@ -0,0 +1,101 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import re
+import sys
+import time
+import unittest
+
+import common
+
+
+combinations = [
+  # One object for each set of tests to run with the given variations.
+  {
+    'label': 'dummy example',
+    'tests': [
+      # Of the form <file_name>.<class_name>.<method_name>
+      # Also accepts wildcard (*) as matching anything.
+      "lite_page.LitePage.testLitePage",
+      "lite_page.LitePage.testLitePageFallback",
+      "quic*"
+    ],
+    'variations': [
+      "DataReductionProxyUseQuic/Enabled",
+      "DataCompressionProxyLoFi/Enabled_Preview",
+      "DataCompressionProxyLitePageFallback/Enabled"
+    ],
+    'variations-params': [
+      "DataCompressionProxyLoFi.Enabled_Preview:effective_connection_type/4G"
+    ]
+  }
+]
+
+
+def GetAllTestsFromRegexList(test_list, test_suite_iter):
+  """A helper function to make a test suite from tests matching the given list.
+
+  Args:
+    test_list: a string list of all tests to run, allowing for simple regex
+    test_suite_iter: An iterator of all test suites to search
+  Returns:
+    a test suite with all the tests specified by the test_list
+  """
+  id_to_test_map = {}
+  for test_suite in test_suite_iter:
+    for test_case in test_suite:
+      for test_method in test_case:
+        id_to_test_map[test_method.id()] = test_method
+  my_test_suite = unittest.TestSuite()
+  for test_spec in test_list:
+    regex = re.compile('^' + test_spec.replace('.', '\\.').replace('*', '.*')
+      + '$')
+    for test_id in sorted(id_to_test_map):
+      if regex.match(test_id):
+        my_test_suite.addTest(id_to_test_map[test_id])
+  return my_test_suite
+
+def ParseFlagsWithExtraBrowserArgs(extra_args):
+  """Generates a function to override common.ParseFlags.
+
+  The returned function will honor everything in the original ParseFlags(), but
+  adds on additional browser_args.
+
+  Args:
+    extra_args: The extra browser agruments to add.
+  Returns:
+    A function to override common.ParseFlags with additional browser_args.
+  """
+  original_flags = common.ParseFlags()
+  def AddExtraBrowserArgs():
+    original_flags.browser_args = ((original_flags.browser_args if
+      original_flags.browser_args else '') + ' ' + extra_args)
+    return original_flags
+  return AddExtraBrowserArgs
+
+def main():
+  """Runs each set of tests against its set of variations.
+
+  For each test combination, the above variation specifications will be used to
+  setup the browser arguments for each test given above that will be run.
+  """
+  flags = common.ParseFlags()
+  for variation_test in combinations:
+    # Set browser arguments to use the given variations.
+    extra_args = '--force-fieldtrials=' + '/'.join(variation_test['variations'])
+    extra_args += ' --force-fieldtrial-params=' + ','.join(
+      variation_test['variations-params'])
+    common.ParseFlags = ParseFlagsWithExtraBrowserArgs(extra_args)
+    # Run the given tests.
+    loader = unittest.TestLoader()
+    test_suite_iter = loader.discover(os.path.dirname(__file__), pattern='*.py')
+    my_test_suite = GetAllTestsFromRegexList(variation_test['tests'],
+      test_suite_iter)
+    testRunner = unittest.runner.TextTestRunner(verbosity=2,
+      failfast=flags.failfast, buffer=(not flags.disable_buffer))
+    testRunner.run(my_test_suite)
+
+if __name__ == '__main__':
+  main()
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0651c72..bfb4c9f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -37547,6 +37547,14 @@
   </summary>
 </histogram>
 
+<histogram name="Net.RedirectWithUnadvertisedContentEncoding" enum="Boolean">
+  <owner>eustas@chromium.org</owner>
+  <summary>
+    True for redirect responses with unadvertised &quot;Content-Encoding&quot;.
+    False for valid redirect responses. See http://crbug.com/714514
+  </summary>
+</histogram>
+
 <histogram name="Net.RenegotiationExtensionSupported">
   <obsolete>
     Deprecated 03/2015. No longer tracked.
diff --git a/ui/android/java/src/org/chromium/ui/UiUtils.java b/ui/android/java/src/org/chromium/ui/UiUtils.java
index dcfda26..cfe14ed 100644
--- a/ui/android/java/src/org/chromium/ui/UiUtils.java
+++ b/ui/android/java/src/org/chromium/ui/UiUtils.java
@@ -151,8 +151,7 @@
                                 Context.INPUT_METHOD_SERVICE);
                 // Third-party touches disk on showSoftInput call. http://crbug.com/619824,
                 // http://crbug.com/635118
-                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-                StrictMode.allowThreadDiskWrites();
+                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
                 try {
                     imm.showSoftInput(view, 0);
                 } catch (IllegalArgumentException e) {
diff --git a/ui/app_list/views/search_result_list_view.cc b/ui/app_list/views/search_result_list_view.cc
index dda5431..8b7e4b93 100644
--- a/ui/app_list/views/search_result_list_view.cc
+++ b/ui/app_list/views/search_result_list_view.cc
@@ -223,7 +223,10 @@
 
 void SearchResultListView::AnimationEnded(const gfx::Animation* animation) {
   DCHECK_EQ(auto_launch_animation_.get(), animation);
-  view_delegate_->OpenSearchResult(results()->GetItemAt(0), true, ui::EF_NONE);
+  if (results()->item_count() > 0) {
+    view_delegate_->OpenSearchResult(results()->GetItemAt(0), true,
+                                     ui::EF_NONE);
+  }
 
   // The auto-launch has to be canceled explicitly. Think that one of searcher
   // is extremely slow. Sometimes the events would happen in the following
diff --git a/ui/aura/test/ui_controls_factory_ozone.cc b/ui/aura/test/ui_controls_factory_ozone.cc
index 403757b9..cc3589e 100644
--- a/ui/aura/test/ui_controls_factory_ozone.cc
+++ b/ui/aura/test/ui_controls_factory_ozone.cc
@@ -21,6 +21,9 @@
 namespace test {
 namespace {
 
+// Mask of the mouse buttons currently down.
+unsigned g_button_down_mask = 0;
+
 class UIControlsOzone : public ui_controls::UIControlsAura {
  public:
   UIControlsOzone(WindowTreeHost* host) : host_(host) {}
@@ -42,7 +45,7 @@
       bool alt,
       bool command,
       const base::Closure& closure) override {
-    int flags = button_down_mask_;
+    int flags = g_button_down_mask;
 
     if (control) {
       flags |= ui::EF_CONTROL_DOWN;
@@ -111,12 +114,12 @@
 
     ui::EventType event_type;
 
-    if (button_down_mask_)
+    if (g_button_down_mask)
       event_type = ui::ET_MOUSE_DRAGGED;
     else
       event_type = ui::ET_MOUSE_MOVED;
 
-    PostMouseEvent(event_type, host_location, button_down_mask_, 0);
+    PostMouseEvent(event_type, host_location, g_button_down_mask, 0);
 
     RunClosureAfterAllPendingUIEvents(closure);
     return true;
@@ -157,14 +160,14 @@
     }
 
     if (state & ui_controls::DOWN) {
-      button_down_mask_ |= flag;
+      g_button_down_mask |= flag;
       PostMouseEvent(ui::ET_MOUSE_PRESSED, host_location,
-                     button_down_mask_ | flag, flag);
+                     g_button_down_mask | flag, flag);
     }
     if (state & ui_controls::UP) {
-      button_down_mask_ &= ~flag;
+      g_button_down_mask &= ~flag;
       PostMouseEvent(ui::ET_MOUSE_RELEASED, host_location,
-                     button_down_mask_ | flag, flag);
+                     g_button_down_mask | flag, flag);
     }
 
     RunClosureAfterAllPendingUIEvents(closure);
@@ -229,9 +232,6 @@
 
   WindowTreeHost* host_;
 
-  // Mask of the mouse buttons currently down.
-  unsigned button_down_mask_ = 0;
-
   DISALLOW_COPY_AND_ASSIGN(UIControlsOzone);
 };
 
diff --git a/ui/gfx/mojo/buffer_types_struct_traits.cc b/ui/gfx/mojo/buffer_types_struct_traits.cc
index 52be89b..14a98a86 100644
--- a/ui/gfx/mojo/buffer_types_struct_traits.cc
+++ b/ui/gfx/mojo/buffer_types_struct_traits.cc
@@ -75,12 +75,7 @@
   mojo::Handle mojo_handle = scoped_handle.release();
   return mojo::MakeScopedHandle(mojo_handle);
 #else  // defined(OS_MACOSX)
-  base::PlatformFile platform_file = base::kInvalidPlatformFile;
-#if defined(OS_WIN)
-  platform_file = handle.handle.GetHandle();
-#else
-  platform_file = handle.handle.fd;
-#endif
+  base::PlatformFile platform_file = handle.handle.GetHandle();
   return mojo::WrapPlatformFile(platform_file);
 #endif  // defined(OS_MACOSX)
 }
@@ -137,7 +132,8 @@
       out->handle =
           base::SharedMemoryHandle(platform_file, base::GetCurrentProcId());
 #else
-      out->handle = base::SharedMemoryHandle(platform_file, true);
+      out->handle =
+          base::SharedMemoryHandle(base::FileDescriptor(platform_file, true));
 #endif
 #endif  // defined(OS_MACOSX)
     }
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory.cc b/ui/ozone/platform/wayland/wayland_surface_factory.cc
index 11a2ad1..1adb2d74 100644
--- a/ui/ozone/platform/wayland/wayland_surface_factory.cc
+++ b/ui/ozone/platform/wayland/wayland_surface_factory.cc
@@ -68,7 +68,7 @@
     return nullptr;
 
   wl::Object<wl_shm_pool> pool(wl_shm_create_pool(
-      connection_->shm(), shared_memory->handle().fd, length));
+      connection_->shm(), shared_memory->handle().GetHandle(), length));
   if (!pool)
     return nullptr;
   wl::Object<wl_buffer> buffer(