diff --git a/DEPS b/DEPS
index d385cbf5..86ef17b 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '0e8fc8b9e6a138cf4a66b421fb824679df717329',
+  'skia_revision': '1951f3ddbddcf5e7cdfe151981d13a1bdb6a3baa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index b7680b1a..60090e1 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -216,6 +216,7 @@
         r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
         r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
         r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
+        r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
         r"^ui[\\\/]base[\\\/]material_design[\\\/]"
             "material_design_controller\.cc$",
         r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 5764c4a..e28ad84 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -160,6 +160,10 @@
 void AshTestHelper::TearDown() {
   // Tear down the shell.
   Shell::DeleteInstance();
+
+  // Suspend the tear down until all resources are returned via
+  // MojoCompositorFrameSinkClient::ReclaimResources()
+  RunAllPendingInMessageLoop();
   material_design_state_.reset();
   test::MaterialDesignControllerTestAPI::Uninitialize();
   ash_test_environment_->TearDown();
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 6ffa428..88d5d7f 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -512,6 +512,8 @@
     "memory/shared_memory_handle.h",
     "memory/shared_memory_handle_mac.cc",
     "memory/shared_memory_handle_win.cc",
+    "memory/shared_memory_helper.cc",
+    "memory/shared_memory_helper.h",
     "memory/shared_memory_mac.cc",
     "memory/shared_memory_nacl.cc",
     "memory/shared_memory_posix.cc",
@@ -925,6 +927,8 @@
     "trace_event/category_registry.cc",
     "trace_event/category_registry.h",
     "trace_event/common/trace_event_common.h",
+    "trace_event/event_name_filter.cc",
+    "trace_event/event_name_filter.h",
     "trace_event/heap_profiler.h",
     "trace_event/heap_profiler_allocation_context.cc",
     "trace_event/heap_profiler_allocation_context.h",
@@ -934,6 +938,8 @@
     "trace_event/heap_profiler_allocation_register.h",
     "trace_event/heap_profiler_allocation_register_posix.cc",
     "trace_event/heap_profiler_allocation_register_win.cc",
+    "trace_event/heap_profiler_event_filter.cc",
+    "trace_event/heap_profiler_event_filter.h",
     "trace_event/heap_profiler_heap_dump_writer.cc",
     "trace_event/heap_profiler_heap_dump_writer.h",
     "trace_event/heap_profiler_stack_frame_deduplicator.cc",
@@ -976,6 +982,8 @@
     "trace_event/trace_event_argument.h",
     "trace_event/trace_event_etw_export_win.cc",
     "trace_event/trace_event_etw_export_win.h",
+    "trace_event/trace_event_filter.cc",
+    "trace_event/trace_event_filter.h",
     "trace_event/trace_event_impl.cc",
     "trace_event/trace_event_impl.h",
     "trace_event/trace_event_memory_overhead.cc",
@@ -1166,6 +1174,8 @@
       "memory/discardable_memory_allocator.h",
       "memory/discardable_shared_memory.cc",
       "memory/discardable_shared_memory.h",
+      "memory/shared_memory_helper.cc",
+      "memory/shared_memory_helper.h",
       "memory/shared_memory_posix.cc",
       "native_library.cc",
       "native_library_posix.cc",
@@ -1244,6 +1254,8 @@
     ]
 
     sources -= [
+      "memory/shared_memory_helper.cc",
+      "memory/shared_memory_helper.h",
       "message_loop/message_pump_libevent.cc",
       "strings/string16.cc",
     ]
@@ -2024,6 +2036,7 @@
     "timer/timer_unittest.cc",
     "tools_sanity_unittest.cc",
     "trace_event/blame_context_unittest.cc",
+    "trace_event/event_name_filter_unittest.cc",
     "trace_event/heap_profiler_allocation_context_tracker_unittest.cc",
     "trace_event/heap_profiler_allocation_register_unittest.cc",
     "trace_event/heap_profiler_heap_dump_writer_unittest.cc",
@@ -2037,6 +2050,8 @@
     "trace_event/trace_category_unittest.cc",
     "trace_event/trace_config_unittest.cc",
     "trace_event/trace_event_argument_unittest.cc",
+    "trace_event/trace_event_filter_test_utils.cc",
+    "trace_event/trace_event_filter_test_utils.h",
     "trace_event/trace_event_synthetic_delay_unittest.cc",
     "trace_event/trace_event_system_stats_monitor_unittest.cc",
     "trace_event/trace_event_unittest.cc",
diff --git a/base/debug/activity_tracker.h b/base/debug/activity_tracker.h
index 20d3547..789905e 100644
--- a/base/debug/activity_tracker.h
+++ b/base/debug/activity_tracker.h
@@ -26,6 +26,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/location.h"
 #include "base/metrics/persistent_memory_allocator.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_checker.h"
 #include "base/threading/thread_local_storage.h"
@@ -361,6 +362,9 @@
   void SetString(StringPiece name, StringPiece value) {
     Set(name, STRING_VALUE, value.data(), value.length());
   }
+  void SetString(StringPiece name, StringPiece16 value) {
+    SetString(name, UTF16ToUTF8(value));
+  }
   void SetBool(StringPiece name, bool value) {
     char cvalue = value ? 1 : 0;
     Set(name, BOOL_VALUE, &cvalue, sizeof(cvalue));
diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h
index f68c861..e88568c 100644
--- a/base/memory/shared_memory.h
+++ b/base/memory/shared_memory.h
@@ -34,7 +34,10 @@
 
 // Options for creating a shared memory object.
 struct BASE_EXPORT SharedMemoryCreateOptions {
-#if !(defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The type of OS primitive that should back the SharedMemory object.
+  SharedMemoryHandle::Type type = SharedMemoryHandle::MACH;
+#else
   // DEPRECATED (crbug.com/345734):
   // If NULL, the object is anonymous.  This pointer is owned by the caller
   // and must live through the call to Create().
@@ -46,7 +49,7 @@
   // shared memory must not exist.  This flag is meaningless unless
   // name_deprecated is non-NULL.
   bool open_existing_deprecated = false;
-#endif  // !(defined(OS_MACOSX) && !defined(OS_IOS))
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 
   // Size of the shared memory object to be created.
   // When opening an existing object, this has no effect.
@@ -101,7 +104,7 @@
   // The caller is responsible for destroying the duplicated OS primitive.
   static SharedMemoryHandle DuplicateHandle(const SharedMemoryHandle& handle);
 
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_POSIX)
   // This method requires that the SharedMemoryHandle is backed by a POSIX fd.
   static int GetFdFromSharedMemoryHandle(const SharedMemoryHandle& handle);
 #endif
@@ -255,13 +258,16 @@
  private:
 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID) && \
     !(defined(OS_MACOSX) && !defined(OS_IOS))
-  bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly);
   bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
 #endif
+
   enum ShareMode {
     SHARE_READONLY,
     SHARE_CURRENT_MODE,
   };
+
+  bool Share(SharedMemoryHandle* new_handle, ShareMode share_mode);
+
   bool ShareToProcessCommon(ProcessHandle process,
                             SharedMemoryHandle* new_handle,
                             bool close_self,
@@ -276,6 +282,12 @@
 #elif defined(OS_MACOSX) && !defined(OS_IOS)
   // The OS primitive that backs the shared memory region.
   SharedMemoryHandle shm_;
+
+  // The mechanism by which the memory is mapped. Only valid if |memory_| is not
+  // |nullptr|.
+  SharedMemoryHandle::Type mapped_memory_mechanism_;
+
+  int readonly_mapped_file_;
 #elif defined(OS_POSIX)
   int                mapped_file_;
   int                readonly_mapped_file_;
diff --git a/base/memory/shared_memory_handle.h b/base/memory/shared_memory_handle.h
index c3fd7ae..7f59d08 100644
--- a/base/memory/shared_memory_handle.h
+++ b/base/memory/shared_memory_handle.h
@@ -15,6 +15,7 @@
 #elif defined(OS_MACOSX) && !defined(OS_IOS)
 #include <mach/mach.h>
 #include "base/base_export.h"
+#include "base/file_descriptor_posix.h"
 #include "base/macros.h"
 #include "base/process/process_handle.h"
 #elif defined(OS_POSIX)
@@ -83,9 +84,25 @@
 #else
 class BASE_EXPORT SharedMemoryHandle {
  public:
+  enum Type {
+    // The SharedMemoryHandle is backed by a POSIX fd.
+    POSIX,
+    // The SharedMemoryHandle is backed by the Mach primitive "memory object".
+    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
+  // takes ownership of the |fd| if |auto_close| is true. Unfortunately, it's
+  // common for existing code to make shallow copies of SharedMemoryHandle, and
+  // the one that is finally passed into a base::SharedMemory is the one that
+  // "consumes" the fd.
+  explicit SharedMemoryHandle(const base::FileDescriptor& file_descriptor);
+
   // Makes a Mach-based SharedMemoryHandle of the given size. On error,
   // subsequent calls to IsValid() return false.
   explicit SharedMemoryHandle(mach_vm_size_t size);
@@ -104,7 +121,8 @@
   // OS primitives.
   SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
 
-  // Duplicates the underlying OS resources.
+  // Duplicates the underlying OS resources. Assumes the SharedMemoryHandle is
+  // of type MACH.
   SharedMemoryHandle Duplicate() const;
 
   // Comparison operators.
@@ -120,7 +138,7 @@
   mach_port_t GetMemoryObject() const;
 
   // Returns false on a failure to determine the size. On success, populates the
-  // output variable |size|. Returns 0 if the handle is invalid.
+  // output variable |size|.
   bool GetSize(size_t* size) const;
 
   // The SharedMemoryHandle must be valid.
@@ -136,24 +154,36 @@
   bool OwnershipPassesToIPC() const;
 
  private:
+  friend class SharedMemory;
+
   // Shared code between copy constructor and operator=.
   void CopyRelevantData(const SharedMemoryHandle& handle);
 
-  mach_port_t memory_object_ = MACH_PORT_NULL;
+  Type type_;
 
-  // The size of the shared memory region when |type_| is MACH. Only
-  // relevant if |memory_object_| is not |MACH_PORT_NULL|.
-  mach_vm_size_t size_ = 0;
+  // Each instance of a SharedMemoryHandle is backed either by a POSIX fd or a
+  // mach port. |type_| determines the backing member.
+  union {
+    FileDescriptor file_descriptor_;
 
-  // The pid of the process in which |memory_object_| is usable. Only
-  // relevant if |memory_object_| is not |MACH_PORT_NULL|.
-  base::ProcessId pid_ = 0;
+    struct {
+      mach_port_t memory_object_;
 
-  // Whether passing this object as a parameter to an IPC message passes
-  // ownership of |memory_object_| to the IPC stack. This is meant to mimic
-  // the behavior of the |auto_close| parameter of FileDescriptor.
-  // Defaults to |false|.
-  bool ownership_passes_to_ipc_ = false;
+      // The size of the shared memory region when |type_| is MACH. Only
+      // relevant if |memory_object_| is not |MACH_PORT_NULL|.
+      mach_vm_size_t size_;
+
+      // The pid of the process in which |memory_object_| is usable. Only
+      // relevant if |memory_object_| is not |MACH_PORT_NULL|.
+      base::ProcessId pid_;
+
+      // Whether passing this object as a parameter to an IPC message passes
+      // ownership of |memory_object_| to the IPC stack. This is meant to mimic
+      // the behavior of the |auto_close| parameter of FileDescriptor.
+      // Defaults to |false|.
+      bool ownership_passes_to_ipc_;
+    };
+  };
 };
 #endif
 
diff --git a/base/memory/shared_memory_handle_mac.cc b/base/memory/shared_memory_handle_mac.cc
index ad470bea..f590c78 100644
--- a/base/memory/shared_memory_handle_mac.cc
+++ b/base/memory/shared_memory_handle_mac.cc
@@ -10,13 +10,20 @@
 #include <unistd.h>
 
 #include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
 #include "base/posix/eintr_wrapper.h"
 
 namespace base {
 
-SharedMemoryHandle::SharedMemoryHandle() {}
+SharedMemoryHandle::SharedMemoryHandle()
+    : type_(MACH), memory_object_(MACH_PORT_NULL) {}
+
+SharedMemoryHandle::SharedMemoryHandle(
+    const base::FileDescriptor& file_descriptor)
+    : type_(POSIX), file_descriptor_(file_descriptor) {}
 
 SharedMemoryHandle::SharedMemoryHandle(mach_vm_size_t size) {
+  type_ = MACH;
   mach_port_t named_right;
   kern_return_t kr = mach_make_memory_entry_64(
       mach_task_self(),
@@ -39,7 +46,8 @@
 SharedMemoryHandle::SharedMemoryHandle(mach_port_t memory_object,
                                        mach_vm_size_t size,
                                        base::ProcessId pid)
-    : memory_object_(memory_object),
+    : type_(MACH),
+      memory_object_(memory_object),
       size_(size),
       pid_(pid),
       ownership_passes_to_ipc_(false) {}
@@ -53,6 +61,7 @@
   if (this == &handle)
     return *this;
 
+  type_ = handle.type_;
   CopyRelevantData(handle);
   return *this;
 }
@@ -74,8 +83,16 @@
   if (!IsValid() && !handle.IsValid())
     return true;
 
-  return memory_object_ == handle.memory_object_ && size_ == handle.size_ &&
-         pid_ == handle.pid_;
+  if (type_ != handle.type_)
+    return false;
+
+  switch (type_) {
+    case POSIX:
+      return file_descriptor_.fd == handle.file_descriptor_.fd;
+    case MACH:
+      return memory_object_ == handle.memory_object_ && size_ == handle.size_ &&
+             pid_ == handle.pid_;
+  }
 }
 
 bool SharedMemoryHandle::operator!=(const SharedMemoryHandle& handle) const {
@@ -83,10 +100,16 @@
 }
 
 bool SharedMemoryHandle::IsValid() const {
-  return memory_object_ != MACH_PORT_NULL;
+  switch (type_) {
+    case POSIX:
+      return file_descriptor_.fd >= 0;
+    case MACH:
+      return memory_object_ != MACH_PORT_NULL;
+  }
 }
 
 mach_port_t SharedMemoryHandle::GetMemoryObject() const {
+  DCHECK_EQ(type_, MACH);
   return memory_object_;
 }
 
@@ -96,8 +119,19 @@
     return true;
   }
 
-  *size = size_;
-  return true;
+  switch (type_) {
+    case SharedMemoryHandle::POSIX:
+      struct stat st;
+      if (fstat(file_descriptor_.fd, &st) != 0)
+        return false;
+      if (st.st_size < 0)
+        return false;
+      *size = st.st_size;
+      return true;
+    case SharedMemoryHandle::MACH:
+      *size = size_;
+      return true;
+  }
 }
 
 bool SharedMemoryHandle::MapAt(off_t offset,
@@ -105,42 +139,69 @@
                                void** memory,
                                bool read_only) {
   DCHECK(IsValid());
-  DCHECK_EQ(pid_, GetCurrentProcId());
-  kern_return_t kr = mach_vm_map(
-      mach_task_self(),
-      reinterpret_cast<mach_vm_address_t*>(memory),  // Output parameter
-      bytes,
-      0,  // Alignment mask
-      VM_FLAGS_ANYWHERE, memory_object_, offset,
-      FALSE,                                           // Copy
-      VM_PROT_READ | (read_only ? 0 : VM_PROT_WRITE),  // Current protection
-      VM_PROT_WRITE | VM_PROT_READ | VM_PROT_IS_MASK,  // Maximum protection
-      VM_INHERIT_NONE);
-  return kr == KERN_SUCCESS;
+  switch (type_) {
+    case SharedMemoryHandle::POSIX:
+      *memory = mmap(nullptr, bytes, PROT_READ | (read_only ? 0 : PROT_WRITE),
+                     MAP_SHARED, file_descriptor_.fd, offset);
+      return *memory != MAP_FAILED;
+    case SharedMemoryHandle::MACH:
+      DCHECK_EQ(pid_, GetCurrentProcId());
+      kern_return_t kr = mach_vm_map(
+          mach_task_self(),
+          reinterpret_cast<mach_vm_address_t*>(memory),    // Output parameter
+          bytes,
+          0,                                               // Alignment mask
+          VM_FLAGS_ANYWHERE,
+          memory_object_,
+          offset,
+          FALSE,                                           // Copy
+          VM_PROT_READ | (read_only ? 0 : VM_PROT_WRITE),  // Current protection
+          VM_PROT_WRITE | VM_PROT_READ | VM_PROT_IS_MASK,  // Maximum protection
+          VM_INHERIT_NONE);
+      return kr == KERN_SUCCESS;
+  }
 }
 
 void SharedMemoryHandle::Close() const {
   if (!IsValid())
     return;
 
-  kern_return_t kr = mach_port_deallocate(mach_task_self(), memory_object_);
-  if (kr != KERN_SUCCESS)
-    DPLOG(ERROR) << "Error deallocating mach port: " << kr;
+  switch (type_) {
+    case POSIX:
+      if (IGNORE_EINTR(close(file_descriptor_.fd)) < 0)
+        DPLOG(ERROR) << "Error closing fd";
+      break;
+    case MACH:
+      kern_return_t kr = mach_port_deallocate(mach_task_self(), memory_object_);
+      if (kr != KERN_SUCCESS)
+        MACH_DLOG(ERROR, kr) << "Error deallocating mach port";
+      break;
+  }
 }
 
 void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
+  DCHECK_EQ(type_, MACH);
   ownership_passes_to_ipc_ = ownership_passes;
 }
 
 bool SharedMemoryHandle::OwnershipPassesToIPC() const {
+  DCHECK_EQ(type_, MACH);
   return ownership_passes_to_ipc_;
 }
 
 void SharedMemoryHandle::CopyRelevantData(const SharedMemoryHandle& handle) {
-  memory_object_ = handle.memory_object_;
-  size_ = handle.size_;
-  pid_ = handle.pid_;
-  ownership_passes_to_ipc_ = handle.ownership_passes_to_ipc_;
+  type_ = handle.type_;
+  switch (type_) {
+    case POSIX:
+      file_descriptor_ = handle.file_descriptor_;
+      break;
+    case MACH:
+      memory_object_ = handle.memory_object_;
+      size_ = handle.size_;
+      pid_ = handle.pid_;
+      ownership_passes_to_ipc_ = handle.ownership_passes_to_ipc_;
+      break;
+  }
 }
 
 }  // namespace base
diff --git a/base/memory/shared_memory_helper.cc b/base/memory/shared_memory_helper.cc
new file mode 100644
index 0000000..7fbfb7a
--- /dev/null
+++ b/base/memory/shared_memory_helper.cc
@@ -0,0 +1,98 @@
+// 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 "base/memory/shared_memory_helper.h"
+
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+struct ScopedPathUnlinkerTraits {
+  static const FilePath* InvalidValue() { return nullptr; }
+
+  static void Free(const FilePath* path) {
+    if (unlink(path->value().c_str()))
+      PLOG(WARNING) << "unlink";
+  }
+};
+
+// Unlinks the FilePath when the object is destroyed.
+using ScopedPathUnlinker =
+    ScopedGeneric<const FilePath*, ScopedPathUnlinkerTraits>;
+
+#if !defined(OS_ANDROID)
+bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
+                                 ScopedFILE* fp,
+                                 ScopedFD* readonly_fd,
+                                 FilePath* path) {
+#if !(defined(OS_MACOSX) && !defined(OS_IOS))
+  // It doesn't make sense to have a open-existing private piece of shmem
+  DCHECK(!options.open_existing_deprecated);
+#endif  // !(defined(OS_MACOSX) && !defined(OS_IOS)
+  // Q: Why not use the shm_open() etc. APIs?
+  // A: Because they're limited to 4mb on OS X.  FFFFFFFUUUUUUUUUUU
+  FilePath directory;
+  ScopedPathUnlinker path_unlinker;
+  if (!GetShmemTempDir(options.executable, &directory))
+    return false;
+
+  fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path));
+
+  if (!*fp)
+    return false;
+
+  // Deleting the file prevents anyone else from mapping it in (making it
+  // private), and prevents the need for cleanup (once the last fd is
+  // closed, it is truly freed).
+  path_unlinker.reset(path);
+
+  if (options.share_read_only) {
+    // Also open as readonly so that we can ShareReadOnlyToProcess.
+    readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
+    if (!readonly_fd->is_valid()) {
+      DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
+      fp->reset();
+      return false;
+    }
+  }
+  return true;
+}
+
+bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd, int* mapped_file,
+                    int* readonly_mapped_file) {
+  DCHECK_EQ(-1, *mapped_file);
+  DCHECK_EQ(-1, *readonly_mapped_file);
+  if (fp == NULL)
+    return false;
+
+  // This function theoretically can block on the disk, but realistically
+  // the temporary files we create will just go into the buffer cache
+  // and be deleted before they ever make it out to disk.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  if (readonly_fd.is_valid()) {
+    struct stat st = {};
+    if (fstat(fileno(fp.get()), &st))
+      NOTREACHED();
+
+    struct stat readonly_st = {};
+    if (fstat(readonly_fd.get(), &readonly_st))
+      NOTREACHED();
+    if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) {
+      LOG(ERROR) << "writable and read-only inodes don't match; bailing";
+      return false;
+    }
+  }
+
+  *mapped_file = HANDLE_EINTR(dup(fileno(fp.get())));
+  if (*mapped_file == -1) {
+    NOTREACHED() << "Call to dup failed, errno=" << errno;
+  }
+  *readonly_mapped_file = readonly_fd.release();
+
+  return true;
+}
+#endif  // !defined(OS_ANDROID)
+
+}  // namespace base
diff --git a/base/memory/shared_memory_helper.h b/base/memory/shared_memory_helper.h
new file mode 100644
index 0000000..b515828
--- /dev/null
+++ b/base/memory/shared_memory_helper.h
@@ -0,0 +1,33 @@
+// 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 BASE_MEMORY_SHARED_MEMORY_HELPER_H_
+#define BASE_MEMORY_SHARED_MEMORY_HELPER_H_
+
+#include "base/memory/shared_memory.h"
+
+#include <fcntl.h>
+
+namespace base {
+
+#if !defined(OS_ANDROID)
+// Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
+// with the fdopened FILE. |readonly_fd| is populated with the opened fd if
+// options.share_read_only is true. |path| is populated with the location of
+// the file before it was unlinked.
+// Returns false if there's an unhandled failure.
+bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
+                                 ScopedFILE* fp,
+                                 ScopedFD* readonly_fd,
+                                 FilePath* path);
+
+// Takes the outputs of CreateAnonymousSharedMemory and maps them properly to
+// |mapped_file| or |readonly_mapped_file|, depending on which one is populated.
+bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd, int* mapped_file,
+                    int* readonly_mapped_file);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_SHARED_MEMORY_HELPER_H_
diff --git a/base/memory/shared_memory_mac.cc b/base/memory/shared_memory_mac.cc
index a8f09555..d376daa 100644
--- a/base/memory/shared_memory_mac.cc
+++ b/base/memory/shared_memory_mac.cc
@@ -4,22 +4,33 @@
 
 #include "base/memory/shared_memory.h"
 
+#include <errno.h>
 #include <mach/mach_vm.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
-#include "base/mac/foundation_util.h"
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_mach_vm.h"
+#include "base/memory/shared_memory_helper.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/safe_strerror.h"
 #include "base/process/process_metrics.h"
-#include "base/profiler/scoped_tracker.h"
 #include "base/scoped_generic.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif  // OS_MACOSX
+
 namespace base {
 
 namespace {
@@ -67,13 +78,21 @@
   return true;
 }
 
+
 }  // namespace
 
 SharedMemory::SharedMemory()
-    : mapped_size_(0), memory_(NULL), read_only_(false), requested_size_(0) {}
+    : mapped_memory_mechanism_(SharedMemoryHandle::MACH),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0) {}
 
 SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
     : shm_(handle),
+      mapped_memory_mechanism_(SharedMemoryHandle::POSIX),
+      readonly_mapped_file_(-1),
       mapped_size_(0),
       memory_(NULL),
       read_only_(read_only),
@@ -101,8 +120,7 @@
 
 // static
 size_t SharedMemory::GetHandleLimit() {
-  // This should be effectively unlimited on OS X.
-  return 10000;
+  return GetMaxFds();
 }
 
 // static
@@ -111,6 +129,12 @@
   return handle.Duplicate();
 }
 
+// static
+int SharedMemory::GetFdFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle) {
+  return handle.file_descriptor_.fd;
+}
+
 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
   return CreateAnonymous(size) && Map(size);
 }
@@ -125,20 +149,53 @@
 // Chromium mostly only uses the unique/private shmem as specified by
 // "name == L"". The exception is in the StatsTable.
 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
-  // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
-  // is fixed.
-  tracked_objects::ScopedTracker tracking_profile1(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "466437 SharedMemory::Create::Start"));
   DCHECK(!shm_.IsValid());
   if (options.size == 0) return false;
 
   if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
     return false;
 
-  shm_ = SharedMemoryHandle(options.size);
+  if (options.type == SharedMemoryHandle::MACH) {
+    shm_ = SharedMemoryHandle(options.size);
+    requested_size_ = options.size;
+    return shm_.IsValid();
+  }
+
+  // This function theoretically can block on the disk. Both profiling of real
+  // users and local instrumentation shows that this is a real problem.
+  // https://code.google.com/p/chromium/issues/detail?id=466437
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  ScopedFILE fp;
+  ScopedFD readonly_fd;
+
+  FilePath path;
+  bool result = CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
+  if (!result)
+    return false;
+
+  if (!fp) {
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+    return false;
+  }
+
+  // Get current size.
+  struct stat stat;
+  if (fstat(fileno(fp.get()), &stat) != 0)
+    return false;
+  const size_t current_size = stat.st_size;
+  if (current_size != options.size) {
+    if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0)
+      return false;
+  }
   requested_size_ = options.size;
-  return shm_.IsValid();
+
+  int mapped_file = -1;
+  result = PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file,
+                          &readonly_mapped_file_);
+
+  shm_ = SharedMemoryHandle(FileDescriptor(mapped_file, false));
+  return result;
 }
 
 bool SharedMemory::MapAt(off_t offset, size_t bytes) {
@@ -154,6 +211,7 @@
     mapped_size_ = bytes;
     DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
                       (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+    mapped_memory_mechanism_ = shm_.type_;
   } else {
     memory_ = NULL;
   }
@@ -165,16 +223,30 @@
   if (memory_ == NULL)
     return false;
 
-  mach_vm_deallocate(mach_task_self(),
-                     reinterpret_cast<mach_vm_address_t>(memory_),
-                     mapped_size_);
+  switch (mapped_memory_mechanism_) {
+    case SharedMemoryHandle::POSIX:
+      munmap(memory_, mapped_size_);
+      break;
+    case SharedMemoryHandle::MACH:
+      mach_vm_deallocate(mach_task_self(),
+                         reinterpret_cast<mach_vm_address_t>(memory_),
+                         mapped_size_);
+      break;
+  }
+
   memory_ = NULL;
   mapped_size_ = 0;
   return true;
 }
 
 SharedMemoryHandle SharedMemory::handle() const {
-  return shm_;
+  switch (shm_.type_) {
+    case SharedMemoryHandle::POSIX:
+      return SharedMemoryHandle(
+          FileDescriptor(shm_.file_descriptor_.fd, false));
+    case SharedMemoryHandle::MACH:
+      return shm_;
+  }
 }
 
 SharedMemoryHandle SharedMemory::TakeHandle() {
@@ -186,33 +258,70 @@
 void SharedMemory::Close() {
   shm_.Close();
   shm_ = SharedMemoryHandle();
+  if (shm_.type_ == SharedMemoryHandle::POSIX) {
+    if (readonly_mapped_file_ > 0) {
+      if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0)
+        PLOG(ERROR) << "close";
+      readonly_mapped_file_ = -1;
+    }
+  }
+}
+
+bool SharedMemory::Share(SharedMemoryHandle* new_handle, ShareMode share_mode) {
+  if (shm_.type_ == SharedMemoryHandle::MACH) {
+    DCHECK(shm_.IsValid());
+
+    bool success = false;
+    switch (share_mode) {
+      case SHARE_CURRENT_MODE:
+        *new_handle = shm_.Duplicate();
+        success = true;
+        break;
+      case SHARE_READONLY:
+        success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_);
+        break;
+    }
+
+    if (success)
+      new_handle->SetOwnershipPassesToIPC(true);
+
+    return success;
+  }
+
+  int handle_to_dup = -1;
+  switch (share_mode) {
+    case SHARE_CURRENT_MODE:
+      handle_to_dup = shm_.file_descriptor_.fd;
+      break;
+    case SHARE_READONLY:
+      // We could imagine re-opening the file from /dev/fd, but that can't make
+      // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
+      CHECK_GE(readonly_mapped_file_, 0);
+      handle_to_dup = readonly_mapped_file_;
+      break;
+  }
+
+  const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
+  if (new_fd < 0) {
+    DPLOG(ERROR) << "dup() failed.";
+    return false;
+  }
+
+  new_handle->file_descriptor_.fd = new_fd;
+  new_handle->type_ = SharedMemoryHandle::POSIX;
+
+  return true;
 }
 
 bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
                                         SharedMemoryHandle* new_handle,
                                         bool close_self,
                                         ShareMode share_mode) {
-  DCHECK(shm_.IsValid());
-
-  bool success = false;
-  switch (share_mode) {
-    case SHARE_CURRENT_MODE:
-      *new_handle = shm_.Duplicate();
-      success = true;
-      break;
-    case SHARE_READONLY:
-      success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_);
-      break;
-  }
-
-  if (success)
-    new_handle->SetOwnershipPassesToIPC(true);
-
+  bool success = Share(new_handle, share_mode);
   if (close_self) {
     Unmap();
     Close();
   }
-
   return success;
 }
 
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
index 783bdfc..3a18faa 100644
--- a/base/memory/shared_memory_posix.cc
+++ b/base/memory/shared_memory_posix.cc
@@ -14,12 +14,13 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
+#include "base/memory/shared_memory_helper.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/safe_strerror.h"
 #include "base/process/process_metrics.h"
-#include "base/profiler/scoped_tracker.h"
 #include "base/scoped_generic.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 
 #if defined(OS_ANDROID)
@@ -29,77 +30,6 @@
 
 namespace base {
 
-namespace {
-
-struct ScopedPathUnlinkerTraits {
-  static FilePath* InvalidValue() { return nullptr; }
-
-  static void Free(FilePath* path) {
-    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
-    // is fixed.
-    tracked_objects::ScopedTracker tracking_profile(
-        FROM_HERE_WITH_EXPLICIT_FUNCTION(
-            "466437 SharedMemory::Create::Unlink"));
-    if (unlink(path->value().c_str()))
-      PLOG(WARNING) << "unlink";
-  }
-};
-
-// Unlinks the FilePath when the object is destroyed.
-typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
-
-#if !defined(OS_ANDROID)
-// Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
-// with the fdopened FILE. |readonly_fd| is populated with the opened fd if
-// options.share_read_only is true. |path| is populated with the location of
-// the file before it was unlinked.
-// Returns false if there's an unhandled failure.
-bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
-                                 ScopedFILE* fp,
-                                 ScopedFD* readonly_fd,
-                                 FilePath* path) {
-  // It doesn't make sense to have a open-existing private piece of shmem
-  DCHECK(!options.open_existing_deprecated);
-  // Q: Why not use the shm_open() etc. APIs?
-  // A: Because they're limited to 4mb on OS X.  FFFFFFFUUUUUUUUUUU
-  FilePath directory;
-  ScopedPathUnlinker path_unlinker;
-  if (GetShmemTempDir(options.executable, &directory)) {
-    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
-    // is fixed.
-    tracked_objects::ScopedTracker tracking_profile(
-        FROM_HERE_WITH_EXPLICIT_FUNCTION(
-            "466437 SharedMemory::Create::OpenTemporaryFile"));
-    fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path));
-
-    // Deleting the file prevents anyone else from mapping it in (making it
-    // private), and prevents the need for cleanup (once the last fd is
-    // closed, it is truly freed).
-    if (*fp)
-      path_unlinker.reset(path);
-  }
-
-  if (*fp) {
-    if (options.share_read_only) {
-      // TODO(erikchen): Remove ScopedTracker below once
-      // http://crbug.com/466437 is fixed.
-      tracked_objects::ScopedTracker tracking_profile(
-          FROM_HERE_WITH_EXPLICIT_FUNCTION(
-              "466437 SharedMemory::Create::OpenReadonly"));
-      // Also open as readonly so that we can ShareReadOnlyToProcess.
-      readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
-      if (!readonly_fd->is_valid()) {
-        DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
-        fp->reset();
-        return false;
-      }
-    }
-  }
-  return true;
-}
-#endif  // !defined(OS_ANDROID)
-}
-
 SharedMemory::SharedMemory()
     : mapped_file_(-1),
       readonly_mapped_file_(-1),
@@ -185,11 +115,6 @@
 // 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) {
-  // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
-  // is fixed.
-  tracked_objects::ScopedTracker tracking_profile1(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "466437 SharedMemory::Create::Start"));
   DCHECK_EQ(-1, mapped_file_);
   if (options.size == 0) return false;
 
@@ -292,7 +217,8 @@
     return false;
   }
 
-  return PrepareMapFile(std::move(fp), std::move(readonly_fd));
+  return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_,
+                        &readonly_mapped_file_);
 }
 
 // Our current implementation of shmem is with mmap()ing of files.
@@ -324,7 +250,8 @@
     DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
     return false;
   }
-  return PrepareMapFile(std::move(fp), std::move(readonly_fd));
+  return PrepareMapFile(std::move(fp), std::move(readonly_fd), &mapped_file_,
+                        &readonly_mapped_file_);
 }
 #endif  // !defined(OS_ANDROID)
 
@@ -401,44 +328,6 @@
 }
 
 #if !defined(OS_ANDROID)
-bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
-  DCHECK_EQ(-1, mapped_file_);
-  DCHECK_EQ(-1, readonly_mapped_file_);
-  if (fp == NULL)
-    return false;
-
-  // This function theoretically can block on the disk, but realistically
-  // the temporary files we create will just go into the buffer cache
-  // and be deleted before they ever make it out to disk.
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
-
-  struct stat st = {};
-  if (fstat(fileno(fp.get()), &st))
-    NOTREACHED();
-  if (readonly_fd.is_valid()) {
-    struct stat readonly_st = {};
-    if (fstat(readonly_fd.get(), &readonly_st))
-      NOTREACHED();
-    if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) {
-      LOG(ERROR) << "writable and read-only inodes don't match; bailing";
-      return false;
-    }
-  }
-
-  mapped_file_ = HANDLE_EINTR(dup(fileno(fp.get())));
-  if (mapped_file_ == -1) {
-    if (errno == EMFILE) {
-      LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
-      return false;
-    } else {
-      NOTREACHED() << "Call to dup failed, errno=" << errno;
-    }
-  }
-  readonly_mapped_file_ = readonly_fd.release();
-
-  return true;
-}
-
 // For the given shmem named |mem_name|, return a filename to mmap()
 // (and possibly create).  Modifies |filename|.  Return false on
 // error, or true of we are happy.
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc
index f29865c..19dedccb 100644
--- a/base/memory/shared_memory_unittest.cc
+++ b/base/memory/shared_memory_unittest.cc
@@ -316,8 +316,6 @@
   }
 }
 
-// The Mach functionality is tested in shared_memory_mac_unittest.cc.
-#if !(defined(OS_MACOSX) && !defined(OS_IOS))
 TEST(SharedMemoryTest, ShareReadOnly) {
   StringPiece contents = "Hello World";
 
@@ -325,6 +323,10 @@
   SharedMemoryCreateOptions options;
   options.size = contents.size();
   options.share_read_only = true;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+  options.type = SharedMemoryHandle::POSIX;
+#endif
   ASSERT_TRUE(writable_shmem.Create(options));
   ASSERT_TRUE(writable_shmem.Map(options.size));
   memcpy(writable_shmem.memory(), contents.data(), contents.size());
@@ -400,7 +402,6 @@
 #error Unexpected platform; write a test that tries to make 'handle' writable.
 #endif  // defined(OS_POSIX) || defined(OS_WIN)
 }
-#endif  // !(defined(OS_MACOSX) && !defined(OS_IOS))
 
 TEST(SharedMemoryTest, ShareToSelf) {
   StringPiece contents = "Hello World";
@@ -474,7 +475,7 @@
   EXPECT_EQ(old_address, memory.memory());
 }
 
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_POSIX)
 // This test is not applicable for iOS (crbug.com/399384).
 #if !defined(OS_IOS)
 // Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
@@ -485,6 +486,10 @@
   SharedMemoryCreateOptions options;
   options.size = kTestSize;
   options.executable = true;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+  options.type = SharedMemoryHandle::POSIX;
+#endif
 
   EXPECT_TRUE(shared_memory.Create(options));
   EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size()));
@@ -518,6 +523,10 @@
   SharedMemory shared_memory;
   SharedMemoryCreateOptions options;
   options.size = kTestSize;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+  options.type = SharedMemoryHandle::POSIX;
+#endif
   // Set a file mode creation mask that gives all permissions.
   ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
 
@@ -540,6 +549,10 @@
   SharedMemory shared_memory;
   SharedMemoryCreateOptions options;
   options.size = kTestSize;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+  options.type = SharedMemoryHandle::POSIX;
+#endif
 
   // Set a file mode creation mask that gives all permissions.
   ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
@@ -556,7 +569,7 @@
 }
 #endif  // !defined(OS_ANDROID)
 
-#endif  // defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+#endif  // defined(OS_POSIX)
 
 // Map() will return addresses which are aligned to the platform page size, this
 // varies from platform to platform though.  Since we'd like to advertise a
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index b53c932..aed51bf 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -12,7 +12,6 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/metrics/field_trial_param_associator.h"
-#include "base/pickle.h"
 #include "base/process/memory.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -69,70 +68,6 @@
 const size_t kFieldTrialAllocationSize = 128 << 10;  // 128 KiB
 #endif
 
-// We create one FieldTrialEntry per field trial in shared memory, via
-// AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle
-// object that we unpickle and read from. Any changes to this structure requires
-// a bump in kFieldTrialType id defined above.
-struct FieldTrialEntry {
-  // Expected size for 32/64-bit check.
-  static constexpr size_t kExpectedInstanceSize = 8;
-
-  // Whether or not this field trial is activated. This is really just a boolean
-  // but marked as a uint32_t for portability reasons.
-  uint32_t activated;
-
-  // Size of the pickled structure, NOT the total size of this entry.
-  uint32_t pickle_size;
-
-  // Returns an iterator over the data containing names and params.
-  PickleIterator GetPickleIterator() const {
-    const char* src =
-        reinterpret_cast<const char*>(this) + sizeof(FieldTrialEntry);
-
-    Pickle pickle(src, pickle_size);
-    return PickleIterator(pickle);
-  }
-
-  // Takes the iterator and writes out the first two items into |trial_name| and
-  // |group_name|.
-  bool ReadStringPair(PickleIterator* iter,
-                      StringPiece* trial_name,
-                      StringPiece* group_name) const {
-    if (!iter->ReadStringPiece(trial_name))
-      return false;
-    if (!iter->ReadStringPiece(group_name))
-      return false;
-    return true;
-  }
-
-  // Calling this is only valid when the entry is initialized. That is, it
-  // resides in shared memory and has a pickle containing the trial name and
-  // group name following it.
-  bool GetTrialAndGroupName(StringPiece* trial_name,
-                            StringPiece* group_name) const {
-    PickleIterator iter = GetPickleIterator();
-    return ReadStringPair(&iter, trial_name, group_name);
-  }
-
-  // Calling this is only valid when the entry is initialized as well. Reads the
-  // parameters following the trial and group name and stores them as key-value
-  // mappings in |params|.
-  bool GetParams(std::map<std::string, std::string>* params) const {
-    PickleIterator iter = GetPickleIterator();
-    StringPiece tmp;
-    if (!ReadStringPair(&iter, &tmp, &tmp))
-      return false;
-
-    while (true) {
-      StringPiece key;
-      StringPiece value;
-      if (!ReadStringPair(&iter, &key, &value))
-        return key.empty();  // Non-empty is bad: got one of a pair.
-      (*params)[key.as_string()] = value.as_string();
-    }
-  }
-};
-
 // Writes out string1 and then string2 to pickle.
 bool WriteStringPair(Pickle* pickle,
                      const StringPiece& string1,
@@ -314,6 +249,49 @@
 
 FieldTrial::State::~State() {}
 
+bool FieldTrial::FieldTrialEntry::GetTrialAndGroupName(
+    StringPiece* trial_name,
+    StringPiece* group_name) const {
+  PickleIterator iter = GetPickleIterator();
+  return ReadStringPair(&iter, trial_name, group_name);
+}
+
+bool FieldTrial::FieldTrialEntry::GetParams(
+    std::map<std::string, std::string>* params) const {
+  PickleIterator iter = GetPickleIterator();
+  StringPiece tmp;
+  // Skip reading trial and group name.
+  if (!ReadStringPair(&iter, &tmp, &tmp))
+    return false;
+
+  while (true) {
+    StringPiece key;
+    StringPiece value;
+    if (!ReadStringPair(&iter, &key, &value))
+      return key.empty();  // Non-empty is bad: got one of a pair.
+    (*params)[key.as_string()] = value.as_string();
+  }
+}
+
+PickleIterator FieldTrial::FieldTrialEntry::GetPickleIterator() const {
+  const char* src =
+      reinterpret_cast<const char*>(this) + sizeof(FieldTrialEntry);
+
+  Pickle pickle(src, pickle_size);
+  return PickleIterator(pickle);
+}
+
+bool FieldTrial::FieldTrialEntry::ReadStringPair(
+    PickleIterator* iter,
+    StringPiece* trial_name,
+    StringPiece* group_name) const {
+  if (!iter->ReadStringPiece(trial_name))
+    return false;
+  if (!iter->ReadStringPiece(group_name))
+    return false;
+  return true;
+}
+
 void FieldTrial::Disable() {
   DCHECK(!group_reported_);
   enable_field_trial_ = false;
@@ -742,8 +720,9 @@
   FieldTrial::FieldTrialRef ref;
   while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
          SharedPersistentMemoryAllocator::kReferenceNull) {
-    const FieldTrialEntry* entry =
-        allocator->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
+    const FieldTrial::FieldTrialEntry* entry =
+        allocator->GetAsObject<const FieldTrial::FieldTrialEntry>(
+            ref, kFieldTrialType);
 
     StringPiece trial_name;
     StringPiece group_name;
@@ -985,10 +964,12 @@
   if (!global_)
     return;
   if (is_locked) {
-    AddToAllocatorWhileLocked(field_trial);
+    AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
+                              field_trial);
   } else {
     AutoLock auto_lock(global_->lock_);
-    AddToAllocatorWhileLocked(field_trial);
+    AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
+                              field_trial);
   }
 }
 
@@ -1047,13 +1028,14 @@
   if (!field_trial->ref_)
     return false;
 
-  const FieldTrialEntry* entry =
-      global_->field_trial_allocator_->GetAsObject<const FieldTrialEntry>(
-          field_trial->ref_, kFieldTrialType);
+  const FieldTrial::FieldTrialEntry* entry =
+      global_->field_trial_allocator_
+          ->GetAsObject<const FieldTrial::FieldTrialEntry>(field_trial->ref_,
+                                                           kFieldTrialType);
 
   size_t allocated_size =
       global_->field_trial_allocator_->GetAllocSize(field_trial->ref_);
-  size_t actual_size = sizeof(FieldTrialEntry) + entry->pickle_size;
+  size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size;
   if (allocated_size < actual_size)
     return false;
 
@@ -1083,9 +1065,9 @@
   while ((prev_ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
          FieldTrialAllocator::kReferenceNull) {
     // Get the existing field trial entry in shared memory.
-    const FieldTrialEntry* prev_entry =
-        allocator->GetAsObject<const FieldTrialEntry>(prev_ref,
-                                                      kFieldTrialType);
+    const FieldTrial::FieldTrialEntry* prev_entry =
+        allocator->GetAsObject<const FieldTrial::FieldTrialEntry>(
+            prev_ref, kFieldTrialType);
     StringPiece trial_name;
     StringPiece group_name;
     if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name))
@@ -1095,17 +1077,19 @@
     Pickle pickle;
     pickle.WriteString(trial_name);
     pickle.WriteString(group_name);
-    size_t total_size = sizeof(FieldTrialEntry) + pickle.size();
+    size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
     FieldTrial::FieldTrialRef new_ref =
         allocator->Allocate(total_size, kFieldTrialType);
-    FieldTrialEntry* new_entry =
-        allocator->GetAsObject<FieldTrialEntry>(new_ref, kFieldTrialType);
+    FieldTrial::FieldTrialEntry* new_entry =
+        allocator->GetAsObject<FieldTrial::FieldTrialEntry>(new_ref,
+                                                            kFieldTrialType);
     new_entry->activated = prev_entry->activated;
     new_entry->pickle_size = pickle.size();
 
     // TODO(lawrencewu): Modify base::Pickle to be able to write over a section
     // in memory, so we can avoid this memcpy.
-    char* dst = reinterpret_cast<char*>(new_entry) + sizeof(FieldTrialEntry);
+    char* dst = reinterpret_cast<char*>(new_entry) +
+                sizeof(FieldTrial::FieldTrialEntry);
     memcpy(dst, pickle.data(), pickle.size());
 
     // Update the ref on the field trial and add it to the list to be made
@@ -1123,6 +1107,34 @@
   }
 }
 
+// static
+void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(
+    PersistentMemoryAllocator* allocator) {
+  if (!global_)
+    return;
+  AutoLock auto_lock(global_->lock_);
+  for (const auto& registered : global_->registered_) {
+    AddToAllocatorWhileLocked(allocator, registered.second);
+  }
+}
+
+// static
+std::vector<const FieldTrial::FieldTrialEntry*>
+FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(
+    PersistentMemoryAllocator const& allocator) {
+  std::vector<const FieldTrial::FieldTrialEntry*> entries;
+  FieldTrial::FieldTrialRef ref;
+  FieldTrialAllocator::Iterator iter(&allocator);
+  while ((ref = iter.GetNextOfType(kFieldTrialType)) !=
+         FieldTrialAllocator::kReferenceNull) {
+    const FieldTrial::FieldTrialEntry* entry =
+        allocator.GetAsObject<const FieldTrial::FieldTrialEntry>(
+            ref, kFieldTrialType);
+    entries.push_back(entry);
+  }
+  return entries;
+}
+
 #if defined(OS_WIN)
 // static
 bool FieldTrialList::CreateTrialsFromHandleSwitch(
@@ -1159,8 +1171,9 @@
   FieldTrial::FieldTrialRef ref;
   while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
          FieldTrialAllocator::kReferenceNull) {
-    const FieldTrialEntry* entry =
-        shalloc->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
+    const FieldTrial::FieldTrialEntry* entry =
+        shalloc->GetAsObject<const FieldTrial::FieldTrialEntry>(
+            ref, kFieldTrialType);
 
     StringPiece trial_name;
     StringPiece group_name;
@@ -1210,7 +1223,8 @@
 
   // Add all existing field trials.
   for (const auto& registered : global_->registered_) {
-    AddToAllocatorWhileLocked(registered.second);
+    AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
+                              registered.second);
   }
 
   // Add all existing features.
@@ -1227,9 +1241,9 @@
 #endif
 
 // static
-void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
-  FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
-
+void FieldTrialList::AddToAllocatorWhileLocked(
+    PersistentMemoryAllocator* allocator,
+    FieldTrial* field_trial) {
   // Don't do anything if the allocator hasn't been instantiated yet.
   if (allocator == nullptr)
     return;
@@ -1254,7 +1268,7 @@
     return;
   }
 
-  size_t total_size = sizeof(FieldTrialEntry) + pickle.size();
+  size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
   FieldTrial::FieldTrialRef ref =
       allocator->Allocate(total_size, kFieldTrialType);
   if (ref == FieldTrialAllocator::kReferenceNull) {
@@ -1262,14 +1276,15 @@
     return;
   }
 
-  FieldTrialEntry* entry =
-      allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType);
+  FieldTrial::FieldTrialEntry* entry =
+      allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, kFieldTrialType);
   entry->activated = trial_state.activated;
   entry->pickle_size = pickle.size();
 
   // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in
   // memory, so we can avoid this memcpy.
-  char* dst = reinterpret_cast<char*>(entry) + sizeof(FieldTrialEntry);
+  char* dst =
+      reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry);
   memcpy(dst, pickle.data(), pickle.size());
 
   allocator->MakeIterable(ref);
@@ -1289,13 +1304,15 @@
   if (ref == FieldTrialAllocator::kReferenceNull) {
     // It's fine to do this even if the allocator hasn't been instantiated
     // yet -- it'll just return early.
-    AddToAllocatorWhileLocked(field_trial);
+    AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
+                              field_trial);
   } else {
     // It's also okay to do this even though the callee doesn't have a lock --
     // the only thing that happens on a stale read here is a slight performance
     // hit from the child re-synchronizing activation state.
-    FieldTrialEntry* entry =
-        allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType);
+    FieldTrial::FieldTrialEntry* entry =
+        allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref,
+                                                            kFieldTrialType);
     entry->activated = true;
   }
 }
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 7fedb37..8a84bae 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -73,6 +73,7 @@
 #include "base/memory/shared_memory.h"
 #include "base/metrics/persistent_memory_allocator.h"
 #include "base/observer_list_threadsafe.h"
+#include "base/pickle.h"
 #include "base/process/launch.h"
 #include "base/strings/string_piece.h"
 #include "base/synchronization/lock.h"
@@ -133,6 +134,43 @@
     ~State();
   };
 
+  // We create one FieldTrialEntry per field trial in shared memory, via
+  // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a
+  // base::Pickle object that we unpickle and read from. Any changes to this
+  // structure requires a bump in kFieldTrialType id defined in the .cc file.
+  struct BASE_EXPORT FieldTrialEntry {
+    // Expected size for 32/64-bit check.
+    static constexpr size_t kExpectedInstanceSize = 8;
+
+    // Whether or not this field trial is activated. This is really just a
+    // boolean but marked as a uint32_t for portability reasons.
+    uint32_t activated;
+
+    // Size of the pickled structure, NOT the total size of this entry.
+    uint32_t pickle_size;
+
+    // Calling this is only valid when the entry is initialized. That is, it
+    // resides in shared memory and has a pickle containing the trial name and
+    // group name following it.
+    bool GetTrialAndGroupName(StringPiece* trial_name,
+                              StringPiece* group_name) const;
+
+    // Calling this is only valid when the entry is initialized as well. Reads
+    // the parameters following the trial and group name and stores them as
+    // key-value mappings in |params|.
+    bool GetParams(std::map<std::string, std::string>* params) const;
+
+   private:
+    // Returns an iterator over the data containing names and params.
+    PickleIterator GetPickleIterator() const;
+
+    // Takes the iterator and writes out the first two items into |trial_name|
+    // and |group_name|.
+    bool ReadStringPair(PickleIterator* iter,
+                        StringPiece* trial_name,
+                        StringPiece* group_name) const;
+  };
+
   typedef std::vector<ActiveGroup> ActiveGroups;
 
   // A return value to indicate that a given instance has not yet had a group
@@ -577,6 +615,18 @@
   // Clears all the params in the allocator.
   static void ClearParamsFromSharedMemoryForTesting();
 
+  // Dumps field trial state to an allocator so that it can be analyzed after a
+  // crash.
+  static void DumpAllFieldTrialsToPersistentAllocator(
+      PersistentMemoryAllocator* allocator);
+
+  // Retrieves field trial state from an allocator so that it can be analyzed
+  // after a crash. The pointers in the returned vector are into the persistent
+  // memory segment and so are only valid as long as the allocator is valid.
+  static std::vector<const FieldTrial::FieldTrialEntry*>
+  GetAllFieldTrialsFromPersistentAllocator(
+      PersistentMemoryAllocator const& allocator);
+
  private:
   // Allow tests to access our innards for testing purposes.
   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, InstantiateAllocator);
@@ -620,7 +670,8 @@
 
   // Adds the field trial to the allocator. Caller must hold a lock before
   // calling this.
-  static void AddToAllocatorWhileLocked(FieldTrial* field_trial);
+  static void AddToAllocatorWhileLocked(PersistentMemoryAllocator* allocator,
+                                        FieldTrial* field_trial);
 
   // Activate the corresponding field trial entry struct in shared memory.
   static void ActivateFieldTrialEntryWhileLocked(FieldTrial* field_trial);
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index 05776a11..7dcbf659 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -1326,4 +1326,47 @@
   EXPECT_EQ("*Trial1/Group1/", check_string);
 }
 
+TEST(FieldTrialListTest, DumpAndFetchFromSharedMemory) {
+  std::string trial_name("Trial1");
+  std::string group_name("Group1");
+
+  // Create a field trial with some params.
+  FieldTrialList field_trial_list(nullptr);
+  FieldTrialList::CreateFieldTrial(trial_name, group_name);
+  std::map<std::string, std::string> params;
+  params["key1"] = "value1";
+  params["key2"] = "value2";
+  FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
+      trial_name, group_name, params);
+
+  std::unique_ptr<base::SharedMemory> shm(new SharedMemory());
+  // 4 KiB is enough to hold the trials only created for this test.
+  shm.get()->CreateAndMapAnonymous(4 << 10);
+  // We _could_ use PersistentMemoryAllocator, this just has less params.
+  SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false);
+
+  // Dump and subsequently retrieve the field trial to |allocator|.
+  FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(&allocator);
+  std::vector<const FieldTrial::FieldTrialEntry*> entries =
+      FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(allocator);
+
+  // Check that we have the entry we put in.
+  EXPECT_EQ(1u, entries.size());
+  const FieldTrial::FieldTrialEntry* entry = entries[0];
+
+  // Check that the trial and group names match.
+  StringPiece shm_trial_name;
+  StringPiece shm_group_name;
+  entry->GetTrialAndGroupName(&shm_trial_name, &shm_group_name);
+  EXPECT_EQ(trial_name, shm_trial_name);
+  EXPECT_EQ(group_name, shm_group_name);
+
+  // Check that the params match.
+  std::map<std::string, std::string> shm_params;
+  entry->GetParams(&shm_params);
+  EXPECT_EQ(2u, shm_params.size());
+  EXPECT_EQ("value1", shm_params["key1"]);
+  EXPECT_EQ("value2", shm_params["key2"]);
+}
+
 }  // namespace base
diff --git a/base/trace_event/category_registry.h b/base/trace_event/category_registry.h
index 80e7cb2..9c08efa 100644
--- a/base/trace_event/category_registry.h
+++ b/base/trace_event/category_registry.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 BASE_TRACE_EVENT_CATEGORY_H_
-#define BASE_TRACE_EVENT_CATEGORY_H_
+#ifndef BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
+#define BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -90,4 +90,4 @@
 }  // namespace trace_event
 }  // namespace base
 
-#endif  // BASE_TRACE_EVENT_CATEGORY_H_
+#endif  // BASE_TRACE_EVENT_CATEGORY_REGISTRY_H_
diff --git a/base/trace_event/event_name_filter.cc b/base/trace_event/event_name_filter.cc
new file mode 100644
index 0000000..8d0058c
--- /dev/null
+++ b/base/trace_event/event_name_filter.cc
@@ -0,0 +1,26 @@
+// 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 "base/trace_event/event_name_filter.h"
+
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const char EventNameFilter::kName[] = "event_whitelist_predicate";
+
+EventNameFilter::EventNameFilter(
+    std::unique_ptr<EventNamesWhitelist> event_names_whitelist)
+    : event_names_whitelist_(std::move(event_names_whitelist)) {}
+
+EventNameFilter::~EventNameFilter() {}
+
+bool EventNameFilter::FilterTraceEvent(const TraceEvent& trace_event) const {
+  return event_names_whitelist_->count(trace_event.name()) != 0;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/event_name_filter.h b/base/trace_event/event_name_filter.h
new file mode 100644
index 0000000..19333b3
--- /dev/null
+++ b/base/trace_event/event_name_filter.h
@@ -0,0 +1,46 @@
+// 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 BASE_TRACE_EVENT_EVENT_NAME_FILTER_H_
+#define BASE_TRACE_EVENT_EVENT_NAME_FILTER_H_
+
+#include <memory>
+#include <string>
+#include <unordered_set>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/trace_event_filter.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEvent;
+
+// Filters trace events by checking the full name against a whitelist.
+// The current implementation is quite simple and dumb and just uses a
+// hashtable which requires char* to std::string conversion. It could be smarter
+// and use a bloom filter trie. However, today this is used too rarely to
+// justify that cost.
+class BASE_EXPORT EventNameFilter : public TraceEventFilter {
+ public:
+  using EventNamesWhitelist = std::unordered_set<std::string>;
+  static const char kName[];
+
+  EventNameFilter(std::unique_ptr<EventNamesWhitelist>);
+  ~EventNameFilter() override;
+
+  // TraceEventFilter implementation.
+  bool FilterTraceEvent(const TraceEvent&) const override;
+
+ private:
+  std::unique_ptr<const EventNamesWhitelist> event_names_whitelist_;
+
+  DISALLOW_COPY_AND_ASSIGN(EventNameFilter);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_EVENT_NAME_FILTER_H_
diff --git a/base/trace_event/event_name_filter_unittest.cc b/base/trace_event/event_name_filter_unittest.cc
new file mode 100644
index 0000000..0bc2a4d
--- /dev/null
+++ b/base/trace_event/event_name_filter_unittest.cc
@@ -0,0 +1,41 @@
+// 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 "base/trace_event/event_name_filter.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+const TraceEvent& MakeTraceEvent(const char* name) {
+  static TraceEvent event;
+  event.Reset();
+  event.Initialize(0, TimeTicks(), ThreadTicks(), 'b', nullptr, name, "", 0, 0,
+                   0, nullptr, nullptr, nullptr, nullptr, 0);
+  return event;
+}
+
+TEST(TraceEventNameFilterTest, Whitelist) {
+  auto empty_whitelist = MakeUnique<EventNameFilter::EventNamesWhitelist>();
+  auto filter = MakeUnique<EventNameFilter>(std::move(empty_whitelist));
+
+  // No events should be filtered if the whitelist is empty.
+  EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("foo")));
+
+  auto whitelist = MakeUnique<EventNameFilter::EventNamesWhitelist>();
+  whitelist->insert("foo");
+  whitelist->insert("bar");
+  filter = MakeUnique<EventNameFilter>(std::move(whitelist));
+  EXPECT_TRUE(filter->FilterTraceEvent(MakeTraceEvent("foo")));
+  EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("fooz")));
+  EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("afoo")));
+  EXPECT_TRUE(filter->FilterTraceEvent(MakeTraceEvent("bar")));
+  EXPECT_FALSE(filter->FilterTraceEvent(MakeTraceEvent("foobar")));
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_event_filter.cc b/base/trace_event/heap_profiler_event_filter.cc
new file mode 100644
index 0000000..6c91c91
--- /dev/null
+++ b/base/trace_event/heap_profiler_event_filter.cc
@@ -0,0 +1,67 @@
+// 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 "base/trace_event/heap_profiler_event_filter.h"
+
+#include "base/trace_event/category_registry.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/trace_category.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+inline bool IsPseudoStackEnabled() {
+  return AllocationContextTracker::capture_mode() ==
+         AllocationContextTracker::CaptureMode::PSEUDO_STACK;
+}
+
+inline AllocationContextTracker* GetThreadLocalTracker() {
+  return AllocationContextTracker::GetInstanceForCurrentThread();
+}
+
+}  // namespace
+
+// static
+const char HeapProfilerEventFilter::kName[] = "heap_profiler_predicate";
+
+HeapProfilerEventFilter::HeapProfilerEventFilter() {}
+HeapProfilerEventFilter::~HeapProfilerEventFilter() {}
+
+bool HeapProfilerEventFilter::FilterTraceEvent(
+    const TraceEvent& trace_event) const {
+  if (!IsPseudoStackEnabled())
+    return true;
+
+  // TODO(primiano): Add support for events with copied name crbug.com/581079.
+  if (trace_event.flags() & TRACE_EVENT_FLAG_COPY)
+    return true;
+
+  const auto* category = CategoryRegistry::GetCategoryByStatePtr(
+      trace_event.category_group_enabled());
+  AllocationContextTracker::PseudoStackFrame frame = {category->name(),
+                                                      trace_event.name()};
+  if (trace_event.phase() == TRACE_EVENT_PHASE_BEGIN ||
+      trace_event.phase() == TRACE_EVENT_PHASE_COMPLETE) {
+    GetThreadLocalTracker()->PushPseudoStackFrame(frame);
+  } else if (trace_event.phase() == TRACE_EVENT_PHASE_END) {
+    // The pop for |TRACE_EVENT_PHASE_COMPLETE| events is in |EndEvent|.
+    GetThreadLocalTracker()->PopPseudoStackFrame(frame);
+  }
+  // Do not filter-out any events and always return true. TraceLog adds the
+  // event only if it is enabled for recording.
+  return true;
+}
+
+void HeapProfilerEventFilter::EndEvent(const char* category_name,
+                                       const char* event_name) const {
+  if (IsPseudoStackEnabled())
+    GetThreadLocalTracker()->PopPseudoStackFrame({category_name, event_name});
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/heap_profiler_event_filter.h b/base/trace_event/heap_profiler_event_filter.h
new file mode 100644
index 0000000..47368a1
--- /dev/null
+++ b/base/trace_event/heap_profiler_event_filter.h
@@ -0,0 +1,40 @@
+// 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 BASE_TRACE_EVENT_HEAP_PROFILER_EVENT_FILTER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_EVENT_FILTER_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/trace_event_filter.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEvent;
+
+// This filter unconditionally accepts all events and pushes/pops them from the
+// thread-local AllocationContextTracker instance as they are seen.
+// This is used to cheaply construct the heap profiler pseudo stack without
+// having to actually record all events.
+class BASE_EXPORT HeapProfilerEventFilter : public TraceEventFilter {
+ public:
+  static const char kName[];
+
+  HeapProfilerEventFilter();
+  ~HeapProfilerEventFilter() override;
+
+  // TraceEventFilter implementation.
+  bool FilterTraceEvent(const TraceEvent& trace_event) const override;
+  void EndEvent(const char* category_name,
+                const char* event_name) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HeapProfilerEventFilter);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_EVENT_FILTER_H_
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 28d5d56..e9a9f34d 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -19,6 +19,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/heap_profiler.h"
 #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/heap_profiler_event_filter.h"
 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
 #include "base/trace_event/heap_profiler_type_name_deduplicator.h"
 #include "base/trace_event/malloc_dump_provider.h"
@@ -210,7 +211,7 @@
       !(TraceLog::GetInstance()->enabled_modes() & TraceLog::FILTERING_MODE)) {
     // Create trace config with heap profiling filter.
     TraceConfig::EventFilterConfig heap_profiler_filter_config(
-        TraceLog::TraceEventFilter::kHeapProfilerPredicate);
+        HeapProfilerEventFilter::kName);
     heap_profiler_filter_config.AddIncludedCategory("*");
     heap_profiler_filter_config.AddIncludedCategory(
         MemoryDumpManager::kTraceCategory);
diff --git a/base/trace_event/trace_config.cc b/base/trace_event/trace_config.cc
index 9a17adb9..9891ab6 100644
--- a/base/trace_event/trace_config.cc
+++ b/base/trace_event/trace_config.cc
@@ -169,6 +169,20 @@
   args_ = std::move(args);
 }
 
+bool TraceConfig::EventFilterConfig::GetArgAsSet(
+    const char* key,
+    std::unordered_set<std::string>* out_set) const {
+  const ListValue* list = nullptr;
+  if (!args_->GetList(key, &list))
+    return false;
+  for (size_t i = 0; i < list->GetSize(); ++i) {
+    std::string value;
+    if (list->GetString(i, &value))
+      out_set->insert(value);
+  }
+  return true;
+}
+
 bool TraceConfig::EventFilterConfig::IsCategoryGroupEnabled(
     const char* category_group_name) const {
   CStringTokenizer category_group_tokens(
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h
index c10ed47..214d078 100644
--- a/base/trace_event/trace_config.h
+++ b/base/trace_event/trace_config.h
@@ -7,8 +7,10 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <set>
 #include <string>
+#include <unordered_set>
 #include <vector>
 
 #include "base/base_export.h"
@@ -82,7 +84,7 @@
     HeapProfiler heap_profiler_options;
   };
 
-  class EventFilterConfig {
+  class BASE_EXPORT EventFilterConfig {
    public:
     EventFilterConfig(const std::string& predicate_name);
     EventFilterConfig(const EventFilterConfig& tc);
@@ -94,6 +96,7 @@
     void AddIncludedCategory(const std::string& category);
     void AddExcludedCategory(const std::string& category);
     void SetArgs(std::unique_ptr<base::DictionaryValue> args);
+    bool GetArgAsSet(const char* key, std::unordered_set<std::string>*) const;
 
     bool IsCategoryGroupEnabled(const char* category_group_name) const;
 
diff --git a/base/trace_event/trace_config_unittest.cc b/base/trace_event/trace_config_unittest.cc
index c040299..aed57ec 100644
--- a/base/trace_event/trace_config_unittest.cc
+++ b/base/trace_event/trace_config_unittest.cc
@@ -432,6 +432,11 @@
   base::JSONWriter::Write(*event_filter.filter_args(), &json_out);
   EXPECT_STREQ(json_out.c_str(),
                "{\"event_name_whitelist\":[\"a snake\",\"a dog\"]}");
+  std::unordered_set<std::string> filter_values;
+  EXPECT_TRUE(event_filter.GetArgAsSet("event_name_whitelist", &filter_values));
+  EXPECT_EQ(2u, filter_values.size());
+  EXPECT_EQ(1u, filter_values.count("a snake"));
+  EXPECT_EQ(1u, filter_values.count("a dog"));
 
   const char config_string_2[] = "{\"included_categories\":[\"*\"]}";
   TraceConfig tc2(config_string_2);
diff --git a/base/trace_event/trace_event_filter.cc b/base/trace_event/trace_event_filter.cc
new file mode 100644
index 0000000..6265295
--- /dev/null
+++ b/base/trace_event/trace_event_filter.cc
@@ -0,0 +1,17 @@
+// 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 "base/trace_event/trace_event_filter.h"
+
+namespace base {
+namespace trace_event {
+
+TraceEventFilter::TraceEventFilter() {}
+TraceEventFilter::~TraceEventFilter() {}
+
+void TraceEventFilter::EndEvent(const char* category_name,
+                                const char* event_name) const {}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_filter.h b/base/trace_event/trace_event_filter.h
new file mode 100644
index 0000000..48c6711
--- /dev/null
+++ b/base/trace_event/trace_event_filter.h
@@ -0,0 +1,51 @@
+// 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 BASE_TRACE_EVENT_TRACE_EVENT_FILTER_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_FILTER_H_
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEvent;
+
+// TraceEventFilter is like iptables for TRACE_EVENT macros. Filters can be
+// enabled on a per-category basis, hence a single filter instance can serve
+// more than a TraceCategory. There are two use cases for filters:
+// 1. Snooping TRACE_EVENT macros without adding them to the TraceLog. This is
+//    possible by setting the ENABLED_FOR_FILTERING flag on a category w/o
+//    ENABLED_FOR_RECORDING (see TraceConfig for user-facing configuration).
+// 2. Filtering TRACE_EVENT macros before they are added to the TraceLog. This
+//    requires both the ENABLED_FOR_FILTERING and ENABLED_FOR_RECORDING flags
+//    on the category.
+// More importantly, filters must be thread-safe. The FilterTraceEvent and
+// EndEvent methods can be called concurrently as trace macros are hit on
+// different threads.
+class BASE_EXPORT TraceEventFilter {
+ public:
+  TraceEventFilter();
+  virtual ~TraceEventFilter();
+
+  // If the category is ENABLED_FOR_RECORDING, the event is added iff all the
+  // filters enabled for the category return true. false causes the event to be
+  // discarded.
+  virtual bool FilterTraceEvent(const TraceEvent& trace_event) const = 0;
+
+  // Notifies the end of a duration event when the RAII macro goes out of scope.
+  virtual void EndEvent(const char* category_name,
+                        const char* event_name) const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TraceEventFilter);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_FILTER_H_
diff --git a/base/trace_event/trace_event_filter_test_utils.cc b/base/trace_event/trace_event_filter_test_utils.cc
new file mode 100644
index 0000000..06548b04
--- /dev/null
+++ b/base/trace_event/trace_event_filter_test_utils.cc
@@ -0,0 +1,61 @@
+// 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 "base/trace_event/trace_event_filter_test_utils.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+TestEventFilter::HitsCounter* g_hits_counter;
+}  // namespace;
+
+// static
+const char TestEventFilter::kName[] = "testing_predicate";
+bool TestEventFilter::filter_return_value_;
+
+// static
+std::unique_ptr<TraceEventFilter> TestEventFilter::Factory(
+    const std::string& predicate_name) {
+  std::unique_ptr<TraceEventFilter> res;
+  if (predicate_name == kName)
+    res.reset(new TestEventFilter());
+  return res;
+}
+
+TestEventFilter::TestEventFilter() {}
+TestEventFilter::~TestEventFilter() {}
+
+bool TestEventFilter::FilterTraceEvent(const TraceEvent& trace_event) const {
+  if (g_hits_counter)
+    g_hits_counter->filter_trace_event_hit_count++;
+  return filter_return_value_;
+}
+
+void TestEventFilter::EndEvent(const char* category_name,
+                               const char* name) const {
+  if (g_hits_counter)
+    g_hits_counter->end_event_hit_count++;
+}
+
+TestEventFilter::HitsCounter::HitsCounter() {
+  Reset();
+  DCHECK(!g_hits_counter);
+  g_hits_counter = this;
+}
+
+TestEventFilter::HitsCounter::~HitsCounter() {
+  DCHECK(g_hits_counter);
+  g_hits_counter = nullptr;
+}
+
+void TestEventFilter::HitsCounter::Reset() {
+  filter_trace_event_hit_count = 0;
+  end_event_hit_count = 0;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_filter_test_utils.h b/base/trace_event/trace_event_filter_test_utils.h
new file mode 100644
index 0000000..419068b22
--- /dev/null
+++ b/base/trace_event/trace_event_filter_test_utils.h
@@ -0,0 +1,53 @@
+// 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 BASE_TRACE_EVENT_TRACE_EVENT_FILTER_TEST_UTILS_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_FILTER_TEST_UTILS_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/trace_event/trace_event_filter.h"
+
+namespace base {
+namespace trace_event {
+
+class TestEventFilter : public TraceEventFilter {
+ public:
+  struct HitsCounter {
+    HitsCounter();
+    ~HitsCounter();
+    void Reset();
+    size_t filter_trace_event_hit_count;
+    size_t end_event_hit_count;
+  };
+
+  static const char kName[];
+
+  // Factory method for TraceLog::SetFilterFactoryForTesting().
+  static std::unique_ptr<TraceEventFilter> Factory(
+      const std::string& predicate_name);
+
+  TestEventFilter();
+  ~TestEventFilter() override;
+
+  // TraceEventFilter implementation.
+  bool FilterTraceEvent(const TraceEvent& trace_event) const override;
+  void EndEvent(const char* category_name, const char* name) const override;
+
+  static void set_filter_return_value(bool value) {
+    filter_return_value_ = value;
+  }
+
+ private:
+  static bool filter_return_value_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestEventFilter);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_FILTER_TEST_UTILS_H_
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index 2fae243..c22f660 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -30,8 +30,12 @@
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
+#include "base/trace_event/event_name_filter.h"
+#include "base/trace_event/heap_profiler_event_filter.h"
 #include "base/trace_event/trace_buffer.h"
 #include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_filter.h"
+#include "base/trace_event/trace_event_filter_test_utils.h"
 #include "base/trace_event/trace_event_synthetic_delay.h"
 #include "base/values.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -2956,45 +2960,6 @@
   EXPECT_EQ(filter, config.ToCategoryFilterString());
 }
 
-class TestEventFilter : public TraceLog::TraceEventFilter {
- public:
-  bool FilterTraceEvent(const TraceEvent& trace_event) const override {
-    filter_trace_event_hit_count_++;
-    return filter_return_value_;
-  }
-
-  void EndEvent(const char* category_group, const char* name) override {
-    end_event_hit_count_++;
-  }
-
-  static void set_filter_return_value(bool value) {
-    filter_return_value_ = value;
-  }
-
-  static size_t filter_trace_event_hit_count() {
-    return filter_trace_event_hit_count_;
-  }
-  static size_t end_event_hit_count() { return end_event_hit_count_; }
-
-  static void clear_counts() {
-    filter_trace_event_hit_count_ = 0;
-    end_event_hit_count_ = 0;
-  }
-
- private:
-  static size_t filter_trace_event_hit_count_;
-  static size_t end_event_hit_count_;
-  static bool filter_return_value_;
-};
-
-size_t TestEventFilter::filter_trace_event_hit_count_ = 0;
-size_t TestEventFilter::end_event_hit_count_ = 0;
-bool TestEventFilter::filter_return_value_ = false;
-
-std::unique_ptr<TraceLog::TraceEventFilter> ConstructTestEventFilter() {
-  return WrapUnique(new TestEventFilter);
-}
-
 TEST_F(TraceEventTestFixture, TraceFilteringMode) {
   const char config_json[] =
       "{"
@@ -3007,8 +2972,9 @@
       "}";
 
   // Run RECORDING_MODE within FILTERING_MODE:
+  TestEventFilter::HitsCounter filter_hits_counter;
   TestEventFilter::set_filter_return_value(true);
-  TraceLog::SetTraceEventFilterConstructorForTesting(ConstructTestEventFilter);
+  TraceLog::GetInstance()->SetFilterFactoryForTesting(TestEventFilter::Factory);
 
   // Only filtering mode is enabled with test filters.
   TraceLog::GetInstance()->SetEnabled(TraceConfig(config_json),
@@ -3048,10 +3014,10 @@
   EXPECT_FALSE(FindMatchingValue("name", "name1"));
   EXPECT_TRUE(FindMatchingValue("cat", "c2"));
   EXPECT_TRUE(FindMatchingValue("name", "name2"));
-  EXPECT_EQ(6u, TestEventFilter::filter_trace_event_hit_count());
-  EXPECT_EQ(3u, TestEventFilter::end_event_hit_count());
+  EXPECT_EQ(6u, filter_hits_counter.filter_trace_event_hit_count);
+  EXPECT_EQ(3u, filter_hits_counter.end_event_hit_count);
   Clear();
-  TestEventFilter::clear_counts();
+  filter_hits_counter.Reset();
 
   // Run FILTERING_MODE within RECORDING_MODE:
   // Only recording mode is enabled and all events must be recorded.
@@ -3090,10 +3056,9 @@
   EXPECT_TRUE(FindMatchingValue("name", "name2"));
   EXPECT_FALSE(FindMatchingValue("cat", "c1"));
   EXPECT_FALSE(FindMatchingValue("name", "name1"));
-  EXPECT_EQ(1u, TestEventFilter::filter_trace_event_hit_count());
-  EXPECT_EQ(1u, TestEventFilter::end_event_hit_count());
+  EXPECT_EQ(1u, filter_hits_counter.filter_trace_event_hit_count);
+  EXPECT_EQ(1u, filter_hits_counter.end_event_hit_count);
   Clear();
-  TestEventFilter::clear_counts();
 }
 
 TEST_F(TraceEventTestFixture, EventFiltering) {
@@ -3111,8 +3076,10 @@
       "  ]"
       "}";
 
+  TestEventFilter::HitsCounter filter_hits_counter;
   TestEventFilter::set_filter_return_value(true);
-  TraceLog::SetTraceEventFilterConstructorForTesting(ConstructTestEventFilter);
+  TraceLog::GetInstance()->SetFilterFactoryForTesting(TestEventFilter::Factory);
+
   TraceConfig trace_config(config_json);
   TraceLog::GetInstance()->SetEnabled(
       trace_config, TraceLog::RECORDING_MODE | TraceLog::FILTERING_MODE);
@@ -3127,9 +3094,8 @@
 
   EndTraceAndFlush();
 
-  EXPECT_EQ(3u, TestEventFilter::filter_trace_event_hit_count());
-  EXPECT_EQ(1u, TestEventFilter::end_event_hit_count());
-  TestEventFilter::clear_counts();
+  EXPECT_EQ(3u, filter_hits_counter.filter_trace_event_hit_count);
+  EXPECT_EQ(1u, filter_hits_counter.end_event_hit_count);
 }
 
 TEST_F(TraceEventTestFixture, EventWhitelistFiltering) {
@@ -3150,7 +3116,7 @@
       "    "
       "  ]"
       "}",
-      TraceLog::TraceEventFilter::kEventWhitelistPredicate);
+      EventNameFilter::kName);
 
   TraceConfig trace_config(config_json);
   TraceLog::GetInstance()->SetEnabled(
@@ -3182,7 +3148,7 @@
       "     }"
       "  ]"
       "}",
-      TraceLog::TraceEventFilter::kHeapProfilerPredicate);
+      HeapProfilerEventFilter::kName);
 
   TraceConfig trace_config(config_json);
   TraceLog::GetInstance()->SetEnabled(
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
index 4b21437..edfd648 100644
--- a/base/trace_event/trace_log.cc
+++ b/base/trace_event/trace_log.cc
@@ -32,8 +32,10 @@
 #include "base/threading/worker_pool.h"
 #include "base/time/time.h"
 #include "base/trace_event/category_registry.h"
+#include "base/trace_event/event_name_filter.h"
 #include "base/trace_event/heap_profiler.h"
 #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/heap_profiler_event_filter.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/process_memory_dump.h"
@@ -84,82 +86,11 @@
 const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
 const int kThreadFlushTimeoutMs = 3000;
 
-const char kEventNameWhitelist[] = "event_name_whitelist";
-
 #define MAX_TRACE_EVENT_FILTERS 32
 
 // List of TraceEventFilter objects from the most recent tracing session.
-base::LazyInstance<std::vector<std::unique_ptr<TraceLog::TraceEventFilter>>>::
-    Leaky g_category_group_filters = LAZY_INSTANCE_INITIALIZER;
-
-class EventNameFilter : public TraceLog::TraceEventFilter {
- public:
-  EventNameFilter(const base::DictionaryValue* filter_args) {
-    const base::ListValue* whitelist = nullptr;
-    if (filter_args->GetList(kEventNameWhitelist, &whitelist)) {
-      for (size_t i = 0; i < whitelist->GetSize(); ++i) {
-        std::string event_name;
-        if (!whitelist->GetString(i, &event_name))
-          continue;
-
-        whitelist_.insert(event_name);
-      }
-    }
-  }
-
-  bool FilterTraceEvent(const TraceEvent& trace_event) const override {
-    return ContainsKey(whitelist_, trace_event.name());
-  }
-
- private:
-  std::unordered_set<std::string> whitelist_;
-};
-
-// This filter is used to record trace events as pseudo stack for the heap
-// profiler. It does not filter-out any events from the trace, ie. the behavior
-// of trace events being added to TraceLog remains same: the events are added
-// iff enabled for recording and not filtered-out by any other filter.
-class HeapProfilerFilter : public TraceLog::TraceEventFilter {
- public:
-  HeapProfilerFilter() {}
-
-  bool FilterTraceEvent(const TraceEvent& trace_event) const override {
-    if (AllocationContextTracker::capture_mode() !=
-        AllocationContextTracker::CaptureMode::PSEUDO_STACK) {
-      return true;
-    }
-
-    // TODO(primiano): Add support for events with copied name crbug.com/581079.
-    if (trace_event.flags() & TRACE_EVENT_FLAG_COPY)
-      return true;
-
-    const char* category_name =
-        TraceLog::GetCategoryGroupName(trace_event.category_group_enabled());
-    if (trace_event.phase() == TRACE_EVENT_PHASE_BEGIN ||
-        trace_event.phase() == TRACE_EVENT_PHASE_COMPLETE) {
-      AllocationContextTracker::GetInstanceForCurrentThread()
-          ->PushPseudoStackFrame({category_name, trace_event.name()});
-    } else if (trace_event.phase() == TRACE_EVENT_PHASE_END) {
-      // The pop for |TRACE_EVENT_PHASE_COMPLETE| events is in |EndEvent|.
-      AllocationContextTracker::GetInstanceForCurrentThread()
-          ->PopPseudoStackFrame({category_name, trace_event.name()});
-    }
-    // Do not filter-out any events and always return true. TraceLog adds the
-    // event only if it is enabled for recording.
-    return true;
-  }
-
-  void EndEvent(const char* name, const char* category_group) override {
-    if (AllocationContextTracker::capture_mode() ==
-        AllocationContextTracker::CaptureMode::PSEUDO_STACK) {
-      AllocationContextTracker::GetInstanceForCurrentThread()
-          ->PopPseudoStackFrame({category_group, name});
-    }
-  }
-};
-
-TraceLog::TraceEventFilterConstructorForTesting
-    g_trace_event_filter_constructor_for_testing = nullptr;
+base::LazyInstance<std::vector<std::unique_ptr<TraceEventFilter>>>::Leaky
+    g_category_group_filters = LAZY_INSTANCE_INITIALIZER;
 
 // The name of the current thread. This is used to decide if the current
 // thread name has changed. We combine all the seen thread names into the
@@ -232,17 +163,14 @@
 }
 
 template <typename Function>
-void ForEachCategoryGroupFilter(const unsigned char* category_group_enabled,
-                                Function filter_fn) {
+void ForEachCategoryFilter(const unsigned char* category_group_enabled,
+                           Function filter_fn) {
   const TraceCategory* category =
       CategoryRegistry::GetCategoryByStatePtr(category_group_enabled);
   uint32_t filter_bitmap = category->enabled_filters();
-  int index = 0;
-  while (filter_bitmap) {
+  for (int index = 0; filter_bitmap != 0; filter_bitmap >>= 1, index++) {
     if (filter_bitmap & 1 && g_category_group_filters.Get()[index])
       filter_fn(g_category_group_filters.Get()[index].get());
-    filter_bitmap = filter_bitmap >> 1;
-    index++;
   }
 }
 
@@ -429,7 +357,8 @@
       trace_config_(TraceConfig()),
       thread_shared_chunk_index_(0),
       generation_(0),
-      use_worker_thread_(false) {
+      use_worker_thread_(false),
+      filter_factory_for_testing_(nullptr) {
   CategoryRegistry::Initialize();
 
 #if defined(OS_NACL)  // NaCl shouldn't expose the process id.
@@ -516,6 +445,7 @@
 }
 
 void TraceLog::UpdateCategoryState(TraceCategory* category) {
+  lock_.AssertAcquired();
   DCHECK(category->is_valid());
   unsigned char state_flags = 0;
   if (enabled_modes_ & RECORDING_MODE &&
@@ -556,6 +486,7 @@
 }
 
 void TraceLog::UpdateCategoryRegistry() {
+  lock_.AssertAcquired();
   CreateFiltersForTraceConfig();
   for (TraceCategory& category : CategoryRegistry::GetAllCategories()) {
     UpdateCategoryState(&category);
@@ -571,7 +502,7 @@
   if (g_category_group_filters.Get().size())
     return;
 
-  for (auto& event_filter : enabled_event_filters_) {
+  for (auto& filter_config : enabled_event_filters_) {
     if (g_category_group_filters.Get().size() >= MAX_TRACE_EVENT_FILTERS) {
       NOTREACHED()
           << "Too many trace event filters installed in the current session";
@@ -579,17 +510,17 @@
     }
 
     std::unique_ptr<TraceEventFilter> new_filter;
-    if (event_filter.predicate_name() ==
-        TraceEventFilter::kEventWhitelistPredicate) {
-      new_filter = MakeUnique<EventNameFilter>(event_filter.filter_args());
-    } else if (event_filter.predicate_name() ==
-               TraceEventFilter::kHeapProfilerPredicate) {
-      new_filter = MakeUnique<HeapProfilerFilter>();
-    } else if (event_filter.predicate_name() == "testing_predicate") {
-      CHECK(g_trace_event_filter_constructor_for_testing);
-      new_filter = g_trace_event_filter_constructor_for_testing();
+    const std::string& predicate_name = filter_config.predicate_name();
+    if (predicate_name == EventNameFilter::kName) {
+      auto whitelist = MakeUnique<std::unordered_set<std::string>>();
+      CHECK(filter_config.GetArgAsSet("event_name_whitelist", &*whitelist));
+      new_filter = MakeUnique<EventNameFilter>(std::move(whitelist));
+    } else if (predicate_name == HeapProfilerEventFilter::kName) {
+      new_filter = MakeUnique<HeapProfilerEventFilter>();
     } else {
-      NOTREACHED();
+      if (filter_factory_for_testing_)
+        new_filter = filter_factory_for_testing_(predicate_name);
+      CHECK(new_filter) << "Unknown trace filter " << predicate_name;
     }
     g_category_group_filters.Get().push_back(std::move(new_filter));
   }
@@ -791,9 +722,8 @@
   if (modes_to_disable & FILTERING_MODE)
     enabled_event_filters_.clear();
 
-  if (modes_to_disable & RECORDING_MODE) {
+  if (modes_to_disable & RECORDING_MODE)
     trace_config_.Clear();
-  }
 
   UpdateCategoryRegistry();
 
@@ -1338,7 +1268,7 @@
                                 arg_values, convertable_values, flags);
 
     disabled_by_filters = true;
-    ForEachCategoryGroupFilter(
+    ForEachCategoryFilter(
         category_group_enabled, [&new_trace_event, &disabled_by_filters](
                                     TraceEventFilter* trace_event_filter) {
           if (trace_event_filter->FilterTraceEvent(*new_trace_event))
@@ -1468,10 +1398,10 @@
                                 const char* name,
                                 TraceEventHandle handle) {
   const char* category_name = GetCategoryGroupName(category_group_enabled);
-  ForEachCategoryGroupFilter(
+  ForEachCategoryFilter(
       category_group_enabled,
       [name, category_name](TraceEventFilter* trace_event_filter) {
-        trace_event_filter->EndEvent(name, category_name);
+        trace_event_filter->EndEvent(category_name, name);
       });
 }
 
@@ -1612,11 +1542,6 @@
   CategoryRegistry::ResetForTesting();
 }
 
-void TraceLog::SetTraceEventFilterConstructorForTesting(
-    TraceEventFilterConstructorForTesting predicate) {
-  g_trace_event_filter_constructor_for_testing = predicate;
-}
-
 TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
   return GetEventByHandleInternal(handle, NULL);
 }
diff --git a/base/trace_event/trace_log.h b/base/trace_event/trace_log.h
index 68a7fbb..88b6e588 100644
--- a/base/trace_event/trace_log.h
+++ b/base/trace_event/trace_log.h
@@ -35,6 +35,7 @@
 class TraceBuffer;
 class TraceBufferChunk;
 class TraceEvent;
+class TraceEventFilter;
 class TraceEventMemoryOverhead;
 
 struct BASE_EXPORT TraceLogStatus {
@@ -278,27 +279,16 @@
 
   // Exposed for unittesting:
 
+  // Testing factory for TraceEventFilter.
+  typedef std::unique_ptr<TraceEventFilter> (*FilterFactoryForTesting)(
+      const std::string& /* predicate_name */);
+  void SetFilterFactoryForTesting(FilterFactoryForTesting factory) {
+    filter_factory_for_testing_ = factory;
+  }
+
   // Allows deleting our singleton instance.
   static void DeleteForTesting();
 
-  class BASE_EXPORT TraceEventFilter {
-   public:
-    static const char* const kEventWhitelistPredicate;
-    static const char* const kHeapProfilerPredicate;
-
-    TraceEventFilter() {}
-    virtual ~TraceEventFilter() {}
-    virtual bool FilterTraceEvent(const TraceEvent& trace_event) const = 0;
-    virtual void EndEvent(const char* category_group, const char* name) {}
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(TraceEventFilter);
-  };
-  typedef std::unique_ptr<TraceEventFilter> (
-      *TraceEventFilterConstructorForTesting)(void);
-  static void SetTraceEventFilterConstructorForTesting(
-      TraceEventFilterConstructorForTesting predicate);
-
   // Allow tests to inspect TraceEvents.
   TraceEvent* GetEventByHandle(TraceEventHandle handle);
 
@@ -506,6 +496,8 @@
   subtle::AtomicWord generation_;
   bool use_worker_thread_;
 
+  FilterFactoryForTesting filter_factory_for_testing_;
+
   DISALLOW_COPY_AND_ASSIGN(TraceLog);
 };
 
diff --git a/base/trace_event/trace_log_constants.cc b/base/trace_event/trace_log_constants.cc
index b72ca1b..65dca2e 100644
--- a/base/trace_event/trace_log_constants.cc
+++ b/base/trace_event/trace_log_constants.cc
@@ -22,11 +22,5 @@
 const TraceLog::InternalTraceOptions
     TraceLog::kInternalEnableArgumentFilter = 1 << 5;
 
-// TraceEventFilter predicate names used in trace config.
-const char* const TraceLog::TraceEventFilter::kEventWhitelistPredicate =
-    "event_whitelist_predicate";
-const char* const TraceLog::TraceEventFilter::kHeapProfilerPredicate =
-    "heap_profiler_predicate";
-
 }  // namespace trace_event
 }  // namespace base
diff --git a/chrome/android/java/res/layout/payment_option_edit_icon.xml b/chrome/android/java/res/layout/payment_option_edit_icon.xml
index 8772eb31..c5fc4c4 100644
--- a/chrome/android/java/res/layout/payment_option_edit_icon.xml
+++ b/chrome/android/java/res/layout/payment_option_edit_icon.xml
@@ -2,9 +2,10 @@
 <!-- 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. -->
-     
+
 <LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/payments_open_editor_pencil_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:contentDescription="@string/payments_edit_button">
@@ -25,4 +26,4 @@
             android:src="@drawable/bookmark_edit_normal"
             android:contentDescription="@null"
             android:importantForAccessibility="no" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/chrome/android/java/res/values/ids.xml b/chrome/android/java/res/values/ids.xml
index e1e15dd6d..eda12d6 100644
--- a/chrome/android/java/res/values/ids.xml
+++ b/chrome/android/java/res/values/ids.xml
@@ -67,7 +67,7 @@
     <item type="id" name="payments_edit_cancel_button" />
     <item type="id" name="payments_edit_done_button" />
     <item type="id" name="payments_edit_checkbox" />
-    
+
     <!-- Password update prompt -->
     <item type="id" name="password_infobar_accounts_spinner" />
 </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
index 99b835a2..8845139 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
@@ -62,7 +62,8 @@
      * [ phone number field ] <----- phone is always present and required.
      */
     @Override
-    public void edit(@Nullable AutofillAddress toEdit, final Callback<AutofillAddress> callback) {
+    public void edit(
+            @Nullable final AutofillAddress toEdit, final Callback<AutofillAddress> callback) {
         super.edit(toEdit, callback);
 
         if (mAutofillProfileBridge == null) mAutofillProfileBridge = new AutofillProfileBridge();
@@ -167,11 +168,12 @@
         mPhoneField.setValue(profile.getPhoneNumber());
         editor.addField(mPhoneField);
 
-        // If the user clicks [Cancel], send a null address back to the caller.
+        // If the user clicks [Cancel], send |toEdit| address back to the caller, which was the
+        // original state (could be null, a complete address, a partial address).
         editor.setCancelCallback(new Runnable() {
             @Override
             public void run() {
-                callback.onResult(null);
+                callback.onResult(toEdit);
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
index 37591677..b33dcac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
@@ -293,11 +293,12 @@
         // Allow saving new cards on disk.
         if (isNewCard) addSaveCardCheckbox(editor);
 
-        // If the user clicks [Cancel], send a null card back to the caller.
+        // If the user clicks [Cancel], send |toEdit| card back to the caller (will return original
+        // state, which could be null, a full card, or a partial card).
         editor.setCancelCallback(new Runnable() {
             @Override
             public void run() {
-                callback.onResult(null);
+                callback.onResult(toEdit);
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
index 3751513a..7924e096 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
@@ -96,7 +96,8 @@
     }
 
     @Override
-    public void edit(@Nullable AutofillContact toEdit, final Callback<AutofillContact> callback) {
+    public void edit(
+            @Nullable final AutofillContact toEdit, final Callback<AutofillContact> callback) {
         super.edit(toEdit, callback);
 
         final AutofillContact contact = toEdit == null
@@ -135,10 +136,12 @@
         if (phoneField != null) editor.addField(phoneField);
         if (emailField != null) editor.addField(emailField);
 
+        // If the user clicks [Cancel], send |toEdit| contact back to the caller, which was the
+        // original state (could be null, a complete contact, a partial contact).
         editor.setCancelCallback(new Runnable() {
             @Override
             public void run() {
-                callback.onResult(null);
+                callback.onResult(toEdit);
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 764709df..c2ad5659 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -902,19 +902,22 @@
         }
         mAddressEditor.edit(toEdit, new Callback<AutofillAddress>() {
             @Override
-            public void onResult(AutofillAddress completeAddress) {
+            public void onResult(AutofillAddress editedAddress) {
                 if (mUI == null) return;
 
-                if (completeAddress == null) {
-                    mShippingAddressesSection.setSelectedItemIndex(SectionInformation.NO_SELECTION);
+                // |editedAddress| could be null if something went wrong or user was adding a new
+                // address and cancelled out.
+                if (editedAddress == null) {
                     providePaymentInformation();
                 } else {
                     // Set the shipping address label.
-                    completeAddress.setShippingAddressLabelWithCountry();
+                    editedAddress.setShippingAddressLabelWithCountry();
 
-                    if (toEdit == null) mShippingAddressesSection.addAndSelectItem(completeAddress);
-                    mCardEditor.updateBillingAddressIfComplete(completeAddress);
-                    mClient.onShippingAddressChange(completeAddress.toPaymentAddress());
+                    // We add a new item if the user was in the "add" flow and the result in
+                    // |editedAddress| is non-null.
+                    if (toEdit == null) mShippingAddressesSection.addAndSelectItem(editedAddress);
+                    mCardEditor.updateBillingAddressIfComplete(editedAddress);
+                    mClient.onShippingAddressChange(editedAddress.toPaymentAddress());
                 }
             }
         });
@@ -928,13 +931,15 @@
         }
         mContactEditor.edit(toEdit, new Callback<AutofillContact>() {
             @Override
-            public void onResult(AutofillContact completeContact) {
+            public void onResult(AutofillContact editedContact) {
                 if (mUI == null) return;
 
-                if (completeContact == null) {
-                    mContactSection.setSelectedItemIndex(SectionInformation.NO_SELECTION);
-                } else if (toEdit == null) {
-                    mContactSection.addAndSelectItem(completeContact);
+                // |editedContact| could be null if something went wrong or user was adding a
+                // contact and cancelled out of that flow. In the following block we add an item to
+                // the list if we were in the "add" flow, and the result in |editedContact| is
+                // non-null.
+                if (toEdit == null && editedContact != null) {
+                    mContactSection.addAndSelectItem(editedContact);
                 }
 
                 mUI.updateSection(PaymentRequestUI.TYPE_CONTACT_DETAILS, mContactSection);
@@ -950,13 +955,14 @@
         }
         mCardEditor.edit(toEdit, new Callback<AutofillPaymentInstrument>() {
             @Override
-            public void onResult(AutofillPaymentInstrument completeCard) {
+            public void onResult(AutofillPaymentInstrument editedCard) {
                 if (mUI == null) return;
 
-                if (completeCard == null) {
-                    mPaymentMethodsSection.setSelectedItemIndex(SectionInformation.NO_SELECTION);
-                } else if (toEdit == null) {
-                    mPaymentMethodsSection.addAndSelectItem(completeCard);
+                // |editedCard| could be null if something went wrong or user was adding a card
+                // and cancelled out of that flow. In the following block we add an item to the list
+                // if we were in the "add" flow and the result in |editedCard| is non-null.
+                if (toEdit == null && editedCard != null) {
+                    mPaymentMethodsSection.addAndSelectItem(editedCard);
                 }
 
                 updateInstrumentModifiedTotals();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java
index fe2200e..d934a8c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java
@@ -427,6 +427,9 @@
                     if (mObserverForTest != null) mObserverForTest.onPaymentRequestReadyToEdit();
                 }
             });
+        } else {
+            // The first field will be focused, we are ready to edit.
+            if (mObserverForTest != null) mObserverForTest.onPaymentRequestReadyToEdit();
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
index a8ecda78..4579b54 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
@@ -893,6 +893,11 @@
                 }
             }
 
+            /** Returns whether this OptionRow's RadioButton is checked. */
+            public boolean isChecked() {
+                return ((RadioButton) mButton).isChecked();
+            }
+
             /** Change the label for the row. */
             public void setLabel(int stringId) {
                 setLabel(getContext().getString(stringId));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
index 0d248749..5c243dc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
@@ -131,6 +131,40 @@
         expectResultContains(new String[] {"Request cancelled"});
     }
 
+    /** Test that going into the editor and cancelling will leave the row checked. */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testEditContactAndCancelEditorShouldKeepContactSelected()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
+        expectContactDetailsRowIsSelected(0);
+        clickInContactInfoAndWait(R.id.payments_open_editor_pencil_button, mReadyToEdit);
+
+        // Cancel the editor.
+        clickInEditorAndWait(R.id.payments_edit_cancel_button, mReadyForInput);
+
+        // Expect the row to still be selected in the Contact Details section.
+        expectContactDetailsRowIsSelected(0);
+    }
+
+    /** Test that going into the "add" flow and cancelling will leave existing row checked. */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testAddContactAndCancelEditorShouldKeepContactSelected()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
+        expectContactDetailsRowIsSelected(0);
+        clickInContactInfoAndWait(R.id.payments_add_option_button, mReadyToEdit);
+
+        // Cancel the editor.
+        clickInEditorAndWait(R.id.payments_edit_cancel_button, mReadyForInput);
+
+        // Expect the existing row to still be selected in the Contact Details section.
+        expectContactDetailsRowIsSelected(0);
+    }
+
     /** Quickly pressing on "add contact info" and then "cancel" should not crash. */
     @MediumTest
     @Feature({"Payments"})
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
index 94d6b6b0..be0b9c9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
@@ -85,6 +85,40 @@
         runTest(HAVE_INSTRUMENTS, DELAYED_RESPONSE);
     }
 
+    /** Test that going into the editor and cancelling will leave the row checked. */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testEditPaymentMethodAndCancelEditorShouldKeepCardSelected()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickInPaymentMethodAndWait(R.id.payments_section, mReadyForInput);
+        expectPaymentMethodRowIsSelected(0);
+        clickInPaymentMethodAndWait(R.id.payments_add_option_button, mReadyToEdit);
+
+        // Cancel the editor.
+        clickInCardEditorAndWait(R.id.payments_edit_cancel_button, mReadyForInput);
+
+        // Expect the existing row to still be selected in the Shipping Address section.
+        expectPaymentMethodRowIsSelected(0);
+    }
+
+    /** Test that going into "add" flow editor and cancelling will leave existing row checked. */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testAddPaymentMethodAndCancelEditorShouldKeepExistingCardSelected()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickInPaymentMethodAndWait(R.id.payments_section, mReadyForInput);
+        expectPaymentMethodRowIsSelected(0);
+        clickInPaymentMethodAndWait(R.id.payments_open_editor_pencil_button, mReadyToEdit);
+
+        // Cancel the editor.
+        clickInCardEditorAndWait(R.id.payments_edit_cancel_button, mReadyForInput);
+
+        // Expect the row to still be selected in the Shipping Address section.
+        expectPaymentMethodRowIsSelected(0);
+    }
+
     private void runTest(int instrumentPresence, int responseSpeed) throws InterruptedException,
             ExecutionException, TimeoutException  {
         installPaymentApp(instrumentPresence, responseSpeed);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java
index 7776ede..b82b016 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java
@@ -113,4 +113,38 @@
         assertTrue(getShippingAddressOptionRowAtIndex(0).getLabelText().toString().equals(
                 "Seb Doe\nGoogle, 340 Main St, Los Angeles, CA 90291\n555-555-5555"));
     }
+
+    /** Test that going into the editor and cancelling will leave the row checked. */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testEditShippingAddressAndCancelEditorShouldKeepAddressSelected()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickInShippingSummaryAndWait(R.id.payments_section, mReadyForInput);
+        expectShippingAddressRowIsSelected(0);
+        clickInShippingAddressAndWait(R.id.payments_open_editor_pencil_button, mReadyToEdit);
+
+        // Cancel the editor.
+        clickInEditorAndWait(R.id.payments_edit_cancel_button, mReadyForInput);
+
+        // Expect the row to still be selected in the Shipping Address section.
+        expectShippingAddressRowIsSelected(0);
+    }
+
+    /** Test that going into the "add" flow  and cancelling will leave the existing row checked. */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testAddShippingAddressAndCancelEditorShouldKeepAddressSelected()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickInShippingSummaryAndWait(R.id.payments_section, mReadyForInput);
+        expectShippingAddressRowIsSelected(0);
+        clickInShippingAddressAndWait(R.id.payments_add_option_button, mReadyToEdit);
+
+        // Cancel the editor.
+        clickInEditorAndWait(R.id.payments_edit_cancel_button, mReadyForInput);
+
+        // Expect the existing row to still be selected in the Shipping Address section.
+        expectShippingAddressRowIsSelected(0);
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
index d2f1ea49..7612cd0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
@@ -321,7 +321,7 @@
         });
     }
 
-    /**  Returns the the number of payment instruments. */
+    /**  Returns the number of payment instruments. */
     protected int getNumberOfPaymentInstruments() throws ExecutionException {
         return ThreadUtils.runOnUiThreadBlocking(new Callable<Integer>() {
             @Override
@@ -332,7 +332,7 @@
         });
     }
 
-    /**  Returns the the number of contact detail suggestions. */
+    /**  Returns the number of contact detail suggestions. */
     protected int getNumberOfContactDetailSuggestions() throws ExecutionException {
         return ThreadUtils.runOnUiThreadBlocking(new Callable<Integer>() {
             @Override
@@ -595,6 +595,57 @@
         });
     }
 
+    /**  Will fail if the OptionRow at |index| is not selected in Contact Details.*/
+    protected void expectContactDetailsRowIsSelected(final int index)
+            throws ExecutionException, InterruptedException {
+        CriteriaHelper.pollInstrumentationThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                boolean isSelected = ((OptionSection) mUI.getContactDetailsSectionForTest())
+                                             .getOptionRowAtIndex(index)
+                                             .isChecked();
+                if (!isSelected) {
+                    updateFailureReason("Contact Details row at " + index + " was not selected.");
+                }
+                return isSelected;
+            }
+        });
+    }
+
+    /**  Will fail if the OptionRow at |index| is not selected in Shipping Address section.*/
+    protected void expectShippingAddressRowIsSelected(final int index)
+            throws ExecutionException, InterruptedException {
+        CriteriaHelper.pollInstrumentationThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                boolean isSelected = ((OptionSection) mUI.getShippingAddressSectionForTest())
+                                             .getOptionRowAtIndex(index)
+                                             .isChecked();
+                if (!isSelected) {
+                    updateFailureReason("Shipping Address row at " + index + " was not selected.");
+                }
+                return isSelected;
+            }
+        });
+    }
+
+    /**  Will fail if the OptionRow at |index| is not selected in PaymentMethod section.*/
+    protected void expectPaymentMethodRowIsSelected(final int index)
+            throws ExecutionException, InterruptedException {
+        CriteriaHelper.pollInstrumentationThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                boolean isSelected = ((OptionSection) mUI.getPaymentMethodSectionForTest())
+                                             .getOptionRowAtIndex(index)
+                                             .isChecked();
+                if (!isSelected) {
+                    updateFailureReason("Payment Method row at " + index + " was not selected.");
+                }
+                return isSelected;
+            }
+        });
+    }
+
     @Override
     public void onPaymentRequestReadyForInput(PaymentRequestUI ui) {
         ThreadUtils.assertOnUiThread();
diff --git a/chrome/app/mash/BUILD.gn b/chrome/app/mash/BUILD.gn
index 02bbd48..4ff4877 100644
--- a/chrome/app/mash/BUILD.gn
+++ b/chrome/app/mash/BUILD.gn
@@ -19,10 +19,10 @@
     "//services/service_manager",
     "//services/service_manager/background:lib",
     "//services/service_manager/public/cpp",
+    "//services/service_manager/public/cpp/standalone_service",
     "//services/service_manager/public/interfaces",
     "//services/service_manager/runner:init",
     "//services/service_manager/runner/common",
-    "//services/service_manager/runner/host:child_process_base",
     "//services/service_manager/runner/host:lib",
     "//services/service_manager/standalone:lib",
     "//url",
diff --git a/chrome/app/mash/mash_runner.cc b/chrome/app/mash/mash_runner.cc
index 6f43edb..ddcb260 100644
--- a/chrome/app/mash/mash_runner.cc
+++ b/chrome/app/mash/mash_runner.cc
@@ -32,10 +32,9 @@
 #include "services/service_manager/public/cpp/identity.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
+#include "services/service_manager/public/cpp/standalone_service/standalone_service.h"
 #include "services/service_manager/public/interfaces/service_factory.mojom.h"
 #include "services/service_manager/runner/common/switches.h"
-#include "services/service_manager/runner/host/child_process.h"
-#include "services/service_manager/runner/host/child_process_base.h"
 #include "services/service_manager/runner/init.h"
 #include "services/service_manager/standalone/context.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -93,6 +92,11 @@
   void AdjustCommandLineArgumentsForTarget(
       const service_manager::Identity& target,
       base::CommandLine* command_line) override {
+    if (target.name() == kChromeMashServiceName ||
+        target.name() == content::mojom::kBrowserServiceName) {
+      command_line->SetProgram(
+          base::CommandLine::ForCurrentProcess()->GetProgram());
+    }
     if (target.name() != content::mojom::kBrowserServiceName) {
       // If running anything other than the browser process, launch a mash
       // child process. The new process will execute MashRunner::RunChild().
@@ -189,16 +193,9 @@
 
   service_manager::WaitForDebuggerIfNecessary();
 
-  base::FilePath path =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
-          switches::kChildProcess);
-  if (base::PathExists(path))
-    return service_manager::ChildProcessMain();
-
-  // If the path doesn't exist - try launching this as a packaged service.
   base::i18n::InitializeICU();
   InitializeResources();
-  service_manager::ChildProcessMainWithCallback(
+  service_manager::RunStandaloneService(
       base::Bind(&MashRunner::StartChildApp, base::Unretained(this)));
   return 0;
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4e14096f7..a879ebd3 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3496,6 +3496,7 @@
       "//chrome_elf:dll_hash",
       "//components/browser_watcher",
       "//components/browser_watcher:browser_watcher_client",
+      "//components/browser_watcher:stability_data",
       "//google_update",
       "//third_party/crashpad/crashpad/client:client",
       "//third_party/iaccessible2",
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index f6abb9f..07eddc0 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -31,7 +31,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
 #include "chrome/browser/ui/cocoa/history_menu_bridge.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/user_manager.h"
 #include "chrome/common/chrome_constants.h"
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.cc b/chrome/browser/chrome_browser_field_trials_desktop.cc
index 6b562d56..3634168 100644
--- a/chrome/browser/chrome_browser_field_trials_desktop.cc
+++ b/chrome/browser/chrome_browser_field_trials_desktop.cc
@@ -4,6 +4,10 @@
 
 #include "chrome/browser/chrome_browser_field_trials_desktop.h"
 
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
 #include <map>
 #include <string>
 
@@ -24,6 +28,8 @@
 #include "media/media_features.h"
 
 #if defined(OS_WIN)
+#include "chrome/install_static/install_util.h"
+#include "components/browser_watcher/stability_data_names.h"
 #include "components/browser_watcher/stability_debugging_win.h"
 #endif
 
@@ -102,6 +108,35 @@
   base::debug::GlobalActivityTracker::CreateWithFile(
       stability_file, kMemorySize, kAllocatorId,
       browser_watcher::kStabilityDebuggingFeature.name, kStackDepth);
+
+  // Record basic information: product, version, channel, special build and
+  // platform.
+  base::debug::GlobalActivityTracker* global_tracker =
+      base::debug::GlobalActivityTracker::Get();
+  if (global_tracker) {
+    wchar_t exe_file[MAX_PATH] = {};
+    CHECK(::GetModuleFileName(nullptr, exe_file, arraysize(exe_file)));
+
+    base::string16 product_name;
+    base::string16 version_number;
+    base::string16 channel_name;
+    base::string16 special_build;
+    install_static::GetExecutableVersionDetails(exe_file, &product_name,
+                                                &version_number, &special_build,
+                                                &channel_name);
+
+    base::debug::ActivityUserData& global_data = global_tracker->user_data();
+    global_data.SetString(browser_watcher::kStabilityProduct, product_name);
+    global_data.SetString(browser_watcher::kStabilityVersion, version_number);
+    global_data.SetString(browser_watcher::kStabilityChannel, channel_name);
+    global_data.SetString(browser_watcher::kStabilitySpecialBuild,
+                          special_build);
+#if defined(ARCH_CPU_X86)
+    global_data.SetString(browser_watcher::kStabilityPlatform, "Win32");
+#elif defined(ARCH_CPU_X86_64)
+    global_data.SetString(browser_watcher::kStabilityPlatform, "Win64");
+#endif
+  }
 }
 #endif  // defined(OS_WIN)
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index e4f52d7..85b53d1 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1152,6 +1152,8 @@
     "printing/cups_print_job_notification_manager.h",
     "printing/fake_cups_print_job_manager.cc",
     "printing/fake_cups_print_job_manager.h",
+    "printing/ppd_provider_factory.cc",
+    "printing/ppd_provider_factory.h",
     "printing/printer_pref_manager.cc",
     "printing/printer_pref_manager.h",
     "printing/printer_pref_manager_factory.cc",
diff --git a/chrome/browser/chromeos/printing/ppd_provider_factory.cc b/chrome/browser/chromeos/printing/ppd_provider_factory.cc
new file mode 100644
index 0000000..4c06d9a7
--- /dev/null
+++ b/chrome/browser/chromeos/printing/ppd_provider_factory.cc
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chromeos/printing/ppd_cache.h"
+#include "chromeos/printing/ppd_provider.h"
+#include "content/public/browser/browser_thread.h"
+#include "google_apis/google_api_keys.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace chromeos {
+namespace printing {
+
+std::unique_ptr<PpdProvider> CreateProvider(Profile* profile) {
+  base::FilePath ppd_cache_path =
+      profile->GetPath().Append(FILE_PATH_LITERAL("PPDCache"));
+
+  return PpdProvider::Create(google_apis::GetAPIKey(),
+                             g_browser_process->system_request_context(),
+                             content::BrowserThread::GetTaskRunnerForThread(
+                                 content::BrowserThread::FILE),
+                             PpdCache::Create(ppd_cache_path));
+}
+
+}  // namespace printing
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/ppd_provider_factory.h b/chrome/browser/chromeos/printing/ppd_provider_factory.h
new file mode 100644
index 0000000..9c461ba
--- /dev/null
+++ b/chrome/browser/chromeos/printing/ppd_provider_factory.h
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_PRINTING_PPD_PROVIDER_FACTORY_H_
+#define CHROME_BROWSER_CHROMEOS_PRINTING_PPD_PROVIDER_FACTORY_H_
+
+#include <memory>
+
+class Profile;
+
+namespace chromeos {
+namespace printing {
+
+class PpdProvider;
+
+std::unique_ptr<PpdProvider> CreateProvider(Profile* profile);
+
+}  // namespace printing
+}  // namsepace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_PPD_PROVIDER_FACTORY_H_
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm b/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm
index a3059578..06b30faa 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm
+++ b/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm
@@ -12,7 +12,7 @@
 #include "base/run_loop.h"
 #include "chrome/browser/local_discovery/service_discovery_client.h"
 #include "chrome/browser/local_discovery/service_discovery_client_mac.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/sockaddr_storage.h"
diff --git a/chrome/browser/media/webrtc/desktop_media_list_ash_unittest.cc b/chrome/browser/media/webrtc/desktop_media_list_ash_unittest.cc
index 39d98cc..c970666 100644
--- a/chrome/browser/media/webrtc/desktop_media_list_ash_unittest.cc
+++ b/chrome/browser/media/webrtc/desktop_media_list_ash_unittest.cc
@@ -66,6 +66,9 @@
       .WillRepeatedly(DoDefault());
   list_->StartUpdating(&observer_);
   base::RunLoop().Run();
+
+  // Reset the unique_ptr so the list stops refreshing.
+  list_.reset();
 }
 
 TEST_F(DesktopMediaListAshTest, OneWindow) {
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm
index 7bbdeb9..d35732d 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #import "base/mac/sdk_forward_declarations.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
diff --git a/chrome/browser/resources/settings/people_page/sync_page.html b/chrome/browser/resources/settings/people_page/sync_page.html
index 1e375ac..9380e6db 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.html
+++ b/chrome/browser/resources/settings/people_page/sync_page.html
@@ -45,6 +45,11 @@
         };
       }
 
+      /**
+       * This is currently necessary because a link inside a disabled
+       * paper-checkbox inherits `pointer-events: none;` and will not work.
+       * See: https://github.com/PolymerElements/paper-checkbox/issues/166
+       */
       #paymentLearnMore {
         pointer-events: initial;
       }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 7ebb171c..c29cffcd 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3418,10 +3418,10 @@
   testonly = true
 
   sources = [
-    "cocoa/cocoa_test_helper.h",
-    "cocoa/cocoa_test_helper.mm",
-    "cocoa/run_loop_testing.h",
-    "cocoa/run_loop_testing.mm",
+    "cocoa/test/cocoa_test_helper.h",
+    "cocoa/test/cocoa_test_helper.mm",
+    "cocoa/test/run_loop_testing.h",
+    "cocoa/test/run_loop_testing.mm",
     "find_bar/find_bar_host_unittest_util.h",
     "login/login_handler_test_utils.cc",
     "login/login_handler_test_utils.h",
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 192b309..8fbaf0a 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -116,7 +116,7 @@
 
 #if defined(OS_MACOSX)
 #include "base/mac/scoped_nsautorelease_pool.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #endif
 
 #if defined(OS_WIN)
diff --git a/chrome/browser/ui/cocoa/animatable_image_unittest.mm b/chrome/browser/ui/cocoa/animatable_image_unittest.mm
index 310cbf310..8ffe32b 100644
--- a/chrome/browser/ui/cocoa/animatable_image_unittest.mm
+++ b/chrome/browser/ui/cocoa/animatable_image_unittest.mm
@@ -5,7 +5,7 @@
 #import <Cocoa/Cocoa.h>
 
 #import "chrome/browser/ui/cocoa/animatable_image.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/animatable_view_unittest.mm b/chrome/browser/ui/cocoa/animatable_view_unittest.mm
index 1554ff5..cd4561b 100644
--- a/chrome/browser/ui/cocoa/animatable_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/animatable_view_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/animatable_view.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/app_menu/app_menu_button_cell_unittest.mm b/chrome/browser/ui/cocoa/app_menu/app_menu_button_cell_unittest.mm
index 3c72248..20d56ace 100644
--- a/chrome/browser/ui/cocoa/app_menu/app_menu_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/app_menu/app_menu_button_cell_unittest.mm
@@ -5,7 +5,7 @@
 #include "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/ui/cocoa/app_menu/app_menu_button_cell.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/app_menu/app_menu_controller_unittest.mm b/chrome/browser/ui/cocoa/app_menu/app_menu_controller_unittest.mm
index 8e6f847..34d097b01 100644
--- a/chrome/browser/ui/cocoa/app_menu/app_menu_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/app_menu/app_menu_controller_unittest.mm
@@ -13,8 +13,8 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #import "chrome/browser/ui/cocoa/app_menu/app_menu_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
 #include "chrome/browser/ui/sync/browser_synced_window_delegates_getter.h"
diff --git a/chrome/browser/ui/cocoa/app_menu/menu_tracked_root_view_unittest.mm b/chrome/browser/ui/cocoa/app_menu/menu_tracked_root_view_unittest.mm
index 57accc1..288d52d 100644
--- a/chrome/browser/ui/cocoa/app_menu/menu_tracked_root_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/app_menu/menu_tracked_root_view_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/app_menu/menu_tracked_root_view.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
diff --git a/chrome/browser/ui/cocoa/applescript/apple_event_util_unittest.mm b/chrome/browser/ui/cocoa/applescript/apple_event_util_unittest.mm
index 78ab100..c32e4118 100644
--- a/chrome/browser/ui/cocoa/applescript/apple_event_util_unittest.mm
+++ b/chrome/browser/ui/cocoa/applescript/apple_event_util_unittest.mm
@@ -16,7 +16,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest_mac.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h
index d5e8fb3..093f28b3 100644
--- a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h
@@ -11,7 +11,7 @@
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/app_controller_mac.h"
 #import "chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "testing/platform_test.h"
 
 // The fake object that acts as our app's delegate, useful for testing purposes.
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
index e1f4507b..d77411d8 100644
--- a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
+++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
@@ -13,7 +13,7 @@
 #import "chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.h"
 #import "chrome/browser/ui/cocoa/applescript/constants_applescript.h"
 #import "chrome/browser/ui/cocoa/applescript/window_applescript.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm b/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm
index fc93fcc..ad6f588 100644
--- a/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm
@@ -15,7 +15,7 @@
 #import "chrome/browser/ui/cocoa/applescript/error_applescript.h"
 #import "chrome/browser/ui/cocoa/applescript/tab_applescript.h"
 #import "chrome/browser/ui/cocoa/applescript/window_applescript.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_bubble_controller_unittest.mm
index 58a547b..223d084a 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_bubble_controller_unittest.mm
@@ -4,8 +4,8 @@
 
 #import "chrome/browser/ui/cocoa/autofill/autofill_bubble_controller.h"
 
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 
 class AutofillBubbleControllerTest : public CocoaTest {
 };
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button_unittest.mm
index b63e9aa..37e2eaf 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_pop_up_button_unittest.mm
@@ -6,7 +6,7 @@
 
 #import "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_textfield_unittest.mm b/chrome/browser/ui/cocoa/autofill/autofill_textfield_unittest.mm
index 8fb537a..5a45845 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_textfield_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_textfield_unittest.mm
@@ -6,7 +6,7 @@
 
 #import "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa_unittest.mm b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa_unittest.mm
index 6d698d3..de9d361 100644
--- a/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa_unittest.mm
@@ -10,7 +10,7 @@
 
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "components/autofill/core/browser/suggestion.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm b/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm
index 81961a7a..ef04955 100644
--- a/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm
@@ -11,7 +11,7 @@
 #include "chrome/browser/ui/autofill/save_card_bubble_controller.h"
 #import "chrome/browser/ui/cocoa/autofill/save_card_bubble_view_bridge.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
diff --git a/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm b/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm
index 3a45559d..8b6e867 100644
--- a/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/background_gradient_view.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
index 5bfb3c4d..05466b1 100644
--- a/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
@@ -8,9 +8,9 @@
 #import "base/mac/scoped_objc_class_swizzler.h"
 #import "base/mac/sdk_forward_declarations.h"
 #include "base/macros.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
index f42ebe03..5bd4525c 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
@@ -8,7 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
index 2035789..44ac79c 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
@@ -5,7 +5,7 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h"
 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
index ad3cc0a..c0056eb 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
@@ -24,7 +24,7 @@
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
index 4b506d1d..b84191f 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
@@ -4,7 +4,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/resources/grit/ui_resources.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
index 0e88aab..e555343 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
@@ -12,8 +12,8 @@
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
index ee2fc11..d3c6483 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
@@ -9,7 +9,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 namespace {
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
index 089d304..30fd695b 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
@@ -11,8 +11,8 @@
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/url_drop_target.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
index 2701dd68..577e2af1 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
@@ -4,7 +4,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
index 386d6e2..f4479bb 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
@@ -10,7 +10,7 @@
 #include "chrome/browser/themes/theme_service.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm
index 528969b..c447200c 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm
@@ -12,8 +12,8 @@
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/url_drop_target.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
index 2bd05cb..e1bc569 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
@@ -16,8 +16,8 @@
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h"
 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/managed/managed_bookmark_service.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm
index 0f76df2..a2ac7828 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm
@@ -6,8 +6,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm
index a510d2b..bc2cede9 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm
@@ -7,7 +7,7 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
index 1967ea9..f4282078 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
@@ -8,7 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/test_browser_window.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller_unittest.mm
index 4098467..13b0c00 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller_unittest.mm
@@ -9,7 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm
index b6f9c00..7053de70 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm
@@ -7,7 +7,7 @@
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
index e54b4a7..b17c02e 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
@@ -9,7 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
index f8266e3c..1b45a08 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
@@ -7,7 +7,7 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/ui/browser.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
index cabbd11..c7db807 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
@@ -11,7 +11,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#import "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 
 using bookmarks::BookmarkModel;
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
index d5c13291..2fdac1d 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
@@ -8,7 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller_unittest.mm
index 25a1a8e..c731d99 100644
--- a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller_unittest.mm
@@ -7,9 +7,9 @@
 #include "base/mac/bind_objc_block.h"
 #include "base/mac/foundation_util.h"
 #include "base/time/time.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
 
 typedef CocoaTest ZoomBubbleControllerTest;
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
index 314b494b..76a34bc0 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
@@ -12,7 +12,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_details.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
index c6a79eb2..a22fc45 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -12,11 +12,11 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#import "chrome/browser/ui/cocoa/fast_resize_view.h"
 #include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#import "chrome/browser/ui/cocoa/fast_resize_view.h"
 #include "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/ui/cocoa/bubble_view_unittest.mm b/chrome/browser/ui/cocoa/bubble_view_unittest.mm
index c1b5d9b4..af42b82 100644
--- a/chrome/browser/ui/cocoa/bubble_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/bubble_view_unittest.mm
@@ -5,7 +5,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/bubble_view.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "testing/gtest_mac.h"
 
 class BubbleViewTest : public CocoaTest {
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm b/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm
index fdd0c175..6f13830 100644
--- a/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm
@@ -7,7 +7,7 @@
 #include "base/debug/debugger.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/ui/cocoa/chrome_browser_window.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm b/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
index f6ae5a1..276c4ce 100644
--- a/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/confirm_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/confirm_bubble_controller_unittest.mm
index 23b9ca0..8d60b46 100644
--- a/chrome/browser/ui/cocoa/confirm_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/confirm_bubble_controller_unittest.mm
@@ -9,8 +9,8 @@
 #include "base/compiler_specific.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/confirm_bubble_cocoa.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/confirm_bubble_model.h"
 #import "testing/gtest_mac.h"
 #import "ui/gfx/geometry/point.h"
diff --git a/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm b/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm
index f191e0f..ae2c814e 100644
--- a/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm
@@ -4,8 +4,8 @@
 
 #import "chrome/browser/ui/cocoa/confirm_quit_panel_controller.h"
 
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/confirm_quit.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest_mac.h"
 #include "ui/base/accelerators/platform_accelerator_cocoa.h"
 
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm
index 6bb9ffd0..87e29ce 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h"
 
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "testing/gtest_mac.h"
 
 class ConstrainedWindowAlertTest : public CocoaTest {
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm
index 00fc302..b0e148c 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #import "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm
index 91dc464..6123ce2 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #import "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 class ConstrainedWindowCustomWindowTest : public CocoaTest {
 };
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
index bba0cb4c..6a5feeb 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
@@ -8,8 +8,8 @@
 
 #include "base/mac/sdk_forward_declarations.h"
 #include "base/macros.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "testing/gtest_mac.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac_unittest.mm b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac_unittest.mm
index 01d3d38e..f921a76 100644
--- a/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/content_settings/collected_cookies_mac_unittest.mm
@@ -5,7 +5,7 @@
 #import "chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h"
 
 #include "base/mac/scoped_nsobject.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "testing/gtest_mac.h"
 
 class CollectedCookiesMacTest : public CocoaTest {
diff --git a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_browsertest.mm
index ffe275c5..92fbe2b 100644
--- a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_browsertest.mm
@@ -11,7 +11,7 @@
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/ui/browser.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm b/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm
index 5131689..d73a1e5 100644
--- a/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm
+++ b/chrome/browser/ui/cocoa/content_settings/cookie_details_unittest.mm
@@ -5,7 +5,7 @@
 #include <stdint.h>
 #include "base/strings/sys_string_conversions.h"
 #include "base/time/time.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 #include "chrome/browser/ui/cocoa/content_settings/cookie_details.h"
 #include "net/cookies/canonical_cookie.h"
diff --git a/chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller_unittest.mm b/chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller_unittest.mm
index b1f06721..f997894e 100644
--- a/chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller_unittest.mm
@@ -4,9 +4,9 @@
 
 #include "base/strings/sys_string_conversions.h"
 #include "base/time/time.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/content_settings/cookie_details.h"
 #include "chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_options.h"
 
diff --git a/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm b/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm
index e6f07e9..2d4a61d6 100644
--- a/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/download/download_item_button.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell_unittest.mm b/chrome/browser/ui/cocoa/download/download_item_cell_unittest.mm
index ac8201aa..bb600a64 100644
--- a/chrome/browser/ui/cocoa/download/download_item_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_cell_unittest.mm
@@ -7,7 +7,7 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
 #include "chrome/browser/download/download_item_model.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "content/public/test/mock_download_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm b/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
index ebe8e59c..5223f60 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
@@ -10,9 +10,9 @@
 
 #import "base/mac/scoped_nsobject.h"
 #include "base/run_loop.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/download/download_item_button.h"
 #import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "content/public/test/mock_download_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller_unittest.mm b/chrome/browser/ui/cocoa/download/download_shelf_controller_unittest.mm
index 0de04523..f6d041a 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller_unittest.mm
@@ -13,8 +13,8 @@
 #import "base/mac/scoped_nsobject.h"
 #include "base/run_loop.h"
 #include "chrome/browser/download/download_shelf.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/download/download_item_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
 #include "content/public/test/mock_download_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm b/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm
index a4108f7..b68ba95 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #import "base/mac/scoped_nsobject.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #include "chrome/browser/ui/cocoa/download/download_shelf_mac.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_view_cocoa_unittest.mm b/chrome/browser/ui/cocoa/download/download_shelf_view_cocoa_unittest.mm
index 7f037d78d..7ae6d4de 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_view_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_view_cocoa_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/download/download_shelf_view_cocoa.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm b/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm
index 9427a5c..df2cb63 100644
--- a/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm
@@ -8,8 +8,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
 #include "base/strings/sys_string_conversions.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/download/download_util_mac.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/common/chrome_paths.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
diff --git a/chrome/browser/ui/cocoa/draggable_button_unittest.mm b/chrome/browser/ui/cocoa/draggable_button_unittest.mm
index 2d4ee28..1918373 100644
--- a/chrome/browser/ui/cocoa/draggable_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/draggable_button_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/draggable_button.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
index a74888c..d50e671 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
@@ -23,7 +23,7 @@
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
-#import "chrome/browser/ui/cocoa/run_loop_testing.h"
+#import "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/global_error/global_error.h"
 #include "chrome/browser/ui/global_error/global_error_service.h"
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_test_util_mac.mm b/chrome/browser/ui/cocoa/extensions/browser_action_test_util_mac.mm
index b0e3c7d..2c97e95f 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_action_test_util_mac.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_test_util_mac.mm
@@ -15,12 +15,12 @@
 #include "chrome/browser/ui/browser.h"
 #import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
 #import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
index 773c3c8..dca3226 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
@@ -4,8 +4,8 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller_unittest.mm
index 722b5c27..88dbd1f 100644
--- a/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa_controller_unittest.mm
@@ -12,10 +12,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chooser_controller/mock_chooser_controller.h"
 #import "chrome/browser/ui/cocoa/chooser_content_view_cocoa.h"
-#import "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/extensions/chooser_dialog_cocoa.h"
 #include "chrome/browser/ui/cocoa/spinner_view.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/grit/generated_resources.h"
 #include "skia/ext/skia_utils_mac.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm
index a6c0b1caf..a15c22a3 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm
@@ -13,8 +13,8 @@
 #include "base/strings/utf_string_conversions.h"
 #import "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/permissions/permission_message_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm
index 8c5991c..d8a3b67 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm
@@ -19,8 +19,8 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/browser/ui/extensions/extension_installed_bubble.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
index 98107c9..94457df 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
@@ -8,7 +8,7 @@
 #import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
 #import "chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.h"
-#import "chrome/browser/ui/cocoa/run_loop_testing.h"
+#import "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/extensions/extension_message_bubble_browsertest.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
diff --git a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac_unittest.mm
index 4b416be2..9105354 100644
--- a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac_unittest.mm
@@ -8,9 +8,9 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/grit/components_scaled_resources.h"
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_bridge_unittest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_bridge_unittest.mm
index b58c4ba..1875cfb8 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_bridge_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_bridge_unittest.mm
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_browsertest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_browsertest.mm
index 0ce3c19..d8fdfe2 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_browsertest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_browsertest.mm
@@ -7,7 +7,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/browser/ui/cocoa/find_bar/find_bar_text_field.h"
-#import "chrome/browser/ui/cocoa/run_loop_testing.h"
+#import "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h"
 #include "chrome/browser/ui/find_bar/find_bar.h"
 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller_unittest.mm
index 722c7fe..e24f528 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller_unittest.mm
@@ -5,9 +5,9 @@
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h"
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_text_field.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/find_bar/find_notification_details.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell_unittest.mm
index 286f45e..ffdd30c 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell_unittest.mm
@@ -5,8 +5,8 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_unittest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_unittest.mm
index 30bc8d6..c303735 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_text_field_unittest.mm
@@ -5,9 +5,9 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_text_field.h"
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_view_unittest.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_view_unittest.mm
index bc8a574..ac03eec 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_view_unittest.mm
@@ -5,8 +5,8 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_view_cocoa.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "ui/events/test/cocoa_test_event_utils.h"
diff --git a/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm b/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm
index f590606..942e650 100644
--- a/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm
+++ b/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/ref_counted.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "ui/base/clipboard/clipboard_util_mac.h"
diff --git a/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm
index 6dbf7dc..bf60d32e 100644
--- a/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm
@@ -8,7 +8,7 @@
 
 #include "base/debug/debugger.h"
 #include "base/mac/scoped_nsobject.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm b/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm
index f4a3a59..bc0833c 100644
--- a/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #import "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 namespace {
 
diff --git a/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm b/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
index cf8774f6..ddb04614 100644
--- a/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
@@ -8,8 +8,8 @@
 #include "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm b/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm
index 9386017..9bec13b3 100644
--- a/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/fullscreen_window.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm b/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm
index f5a296f..a032455 100644
--- a/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm
@@ -5,8 +5,8 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
index 634d233..106207a 100644
--- a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
+++ b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
@@ -17,7 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/sessions/chrome_tab_restore_service_client.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/favicon_base/favicon_types.h"
 #include "components/sessions/core/persistent_tab_restore_service.h"
diff --git a/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm
index b2cd398..690b8c8b6 100644
--- a/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm
@@ -10,8 +10,8 @@
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #include "chrome/browser/ui/cocoa/history_menu_bridge.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm b/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm
index 91db9b0..929434b 100644
--- a/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm
@@ -4,7 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/history_overlay_controller.h"
 
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 class HistoryOverlayControllerTest : public CocoaTest {
  public:
diff --git a/chrome/browser/ui/cocoa/hover_close_button_unittest.mm b/chrome/browser/ui/cocoa/hover_close_button_unittest.mm
index 5d19c30..bffe11b 100644
--- a/chrome/browser/ui/cocoa/hover_close_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/hover_close_button_unittest.mm
@@ -5,8 +5,8 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/hover_close_button.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class HoverCloseButtonTest : public CocoaTest {
diff --git a/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm b/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm
index 4a5cc77..28ad9baf 100644
--- a/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm
@@ -4,8 +4,8 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/hung_renderer_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/image_button_cell_unittest.mm b/chrome/browser/ui/cocoa/image_button_cell_unittest.mm
index 8116b68..6fcc36f 100644
--- a/chrome/browser/ui/cocoa/image_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/image_button_cell_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/grit/theme_resources.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm b/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm
index 82b135a5..b9eb019 100644
--- a/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 namespace {
 
diff --git a/chrome/browser/ui/cocoa/info_bubble_window_unittest.mm b/chrome/browser/ui/cocoa/info_bubble_window_unittest.mm
index a222b32..4f83efd1 100644
--- a/chrome/browser/ui/cocoa/info_bubble_window_unittest.mm
+++ b/chrome/browser/ui/cocoa/info_bubble_window_unittest.mm
@@ -7,9 +7,9 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/run_loop.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/info_bubble_window.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "ui/events/test/cocoa_test_event_utils.h"
 
 // Mock BaseBubbleController to pick up -cancel:, but don't call the designated
diff --git a/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm b/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm
index a76c639b..25514e7 100644
--- a/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm
@@ -10,11 +10,11 @@
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
 #include "chrome/browser/ui/cocoa/infobars/mock_confirm_infobar_delegate.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #import "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm b/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm
index 57b43d9..2fa1141 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm
@@ -10,10 +10,10 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/infobars/confirm_infobar_controller.h"
 #include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h"
 #include "chrome/browser/ui/cocoa/infobars/mock_confirm_infobar_delegate.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
 #include "chrome/test/base/testing_profile.h"
 #import "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view_unittest.mm b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view_unittest.mm
index 5ef8e83..9017aa1e8 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view_unittest.mm
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 namespace {
 
diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
index a5e41b0..6d50601 100644
--- a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
@@ -13,10 +13,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #import "chrome/browser/translate/chrome_translate_client.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h"
 #import "chrome/browser/ui/cocoa/infobars/translate_infobar_base.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #import "components/translate/core/browser/options_menu_model.h"
 #import "components/translate/core/browser/translate_infobar_delegate.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
index 9b7d1c1e..e59794e 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
@@ -6,7 +6,6 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
@@ -15,6 +14,7 @@
 #import "chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
index f80514d9..6cf0a8d 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
@@ -9,8 +9,8 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/string_util.h"
 #include "chrome/app/chrome_command_ids.h"  // IDC_*
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/grit/generated_resources.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
index c21c1b61..e231f51 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
@@ -7,12 +7,12 @@
 
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm
index 7ddb6d5..216a598 100644
--- a/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm
@@ -6,7 +6,7 @@
 
 #import "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
 
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm
index 896905df..155343e 100644
--- a/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm
@@ -7,7 +7,7 @@
 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
 
 #include "base/strings/utf_string_conversions.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration_unittest.mm
index 9b4894bf..279677d 100644
--- a/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration_unittest.mm
@@ -8,9 +8,9 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/command_updater.h"
 #include "chrome/browser/command_updater_delegate.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.h"
 #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/password_manager/core/common/password_manager_ui.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration_unittest.mm
index 483456b1..41e9f712 100644
--- a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration_unittest.mm
@@ -6,8 +6,8 @@
 
 #import "chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h"
 
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm
index 5f46266f6..a4db11b 100644
--- a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm
@@ -5,8 +5,8 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/strings/utf_string_conversions.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "ui/base/material_design/material_design_controller.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm b/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm
index 99b67c9..71ebc54d 100644
--- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm
@@ -12,7 +12,7 @@
 #import "chrome/browser/ui/cocoa/browser/zoom_bubble_controller.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/toolbar/test_toolbar_model.h"
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated_unittest.mm b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated_unittest.mm
index 0008b52..5f2345c 100644
--- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated_unittest.mm
+++ b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated_unittest.mm
@@ -9,7 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media/webrtc/desktop_media_list_observer.h"
 #include "chrome/browser/media/webrtc/fake_desktop_media_list.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest_mac.h"
 
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm
index 46a2714..04a1fb1 100644
--- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm
@@ -9,8 +9,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media/webrtc/desktop_media_list_observer.h"
 #include "chrome/browser/media/webrtc/fake_desktop_media_list.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_item.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest_mac.h"
 
diff --git a/chrome/browser/ui/cocoa/menu_button_unittest.mm b/chrome/browser/ui/cocoa/menu_button_unittest.mm
index c5938be..6eb8446 100644
--- a/chrome/browser/ui/cocoa/menu_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/menu_button_unittest.mm
@@ -4,8 +4,8 @@
 
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/menu_button.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 @interface MenuButtonTestDelegate : NSObject<NSMenuDelegate> {
  @private
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
index 5722d835..88eb7cd 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "components/omnibox/browser/suggestion_answer.h"
 #import "testing/gtest_mac.h"
 
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm
index 4c3aa75..616a638 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm
@@ -8,7 +8,7 @@
 #include <stddef.h>
 
 #include "base/macros.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm
index 3040495b..1c7e18c 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 class OmniboxPopupBottomSeparatorViewTest : public CocoaTest {
  public:
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
index fdbdf98..c56e291 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
@@ -11,8 +11,8 @@
 #include "base/macros.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_result.h"
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
index 87434c9..f3d58416 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
@@ -8,7 +8,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h"
 #include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
diff --git a/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller_unittest.mm
index e368440..f75b0b4 100644
--- a/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/account_chooser_view_controller_unittest.mm
@@ -13,10 +13,10 @@
 #include "base/strings/string16.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h"
 #import "chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.h"
 #import "chrome/browser/ui/cocoa/passwords/credential_item_button.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/passwords/password_dialog_controller_mock.h"
 #include "components/autofill/core/common/password_form.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller_unittest.mm
index 870afd01..c46ef8f 100644
--- a/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller_unittest.mm
@@ -8,8 +8,8 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/utf_string_conversions.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/passwords/password_dialog_controller_mock.h"
 #include "components/autofill/core/common/password_form.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h b/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h
index e47288a..572ac2b 100644
--- a/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h
+++ b/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h
@@ -8,9 +8,9 @@
 #include <memory>
 
 #include "base/mac/scoped_nsobject.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/passwords/base_passwords_content_view_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/passwords_model_delegate_mock.h"
 
diff --git a/chrome/browser/ui/cocoa/passwords/confirmation_password_saved_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/confirmation_password_saved_view_controller_unittest.mm
index 26fea09..e9ff521 100644
--- a/chrome/browser/ui/cocoa/passwords/confirmation_password_saved_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/confirmation_password_saved_view_controller_unittest.mm
@@ -8,8 +8,8 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #import "chrome/browser/ui/cocoa/bubble_combobox.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_cocoa_unittest.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_cocoa_unittest.mm
index 712e72e..920a68a 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_cocoa_unittest.mm
@@ -13,12 +13,12 @@
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
 #include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 #include "chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.h"
 #import "chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "chrome/browser/ui/tab_dialogs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
index d28c4fb..406980bf5 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
@@ -11,13 +11,13 @@
 #include "base/metrics/field_trial.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
 #include "chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h"
 #import "chrome/browser/ui/cocoa/passwords/manage_passwords_view_controller.h"
 #import "chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h"
 #import "chrome/browser/ui/cocoa/passwords/signin_promo_view_controller.h"
 #import "chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_list_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/passwords_list_view_controller_unittest.mm
index a5c3470..4117a19 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_list_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_list_view_controller_unittest.mm
@@ -10,10 +10,10 @@
 #include "base/strings/string16.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h"
 #import "chrome/browser/ui/cocoa/passwords/password_item_views.h"
 #import "chrome/browser/ui/cocoa/passwords/passwords_list_view_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "components/password_manager/core/browser/mock_password_store.h"
diff --git a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm
index f35139f7..621e3b11 100644
--- a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm
@@ -8,9 +8,9 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #import "chrome/browser/ui/cocoa/bubble_combobox.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h"
 #import "chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller_unittest.mm
index 9cca7b0..2ffef89 100644
--- a/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller_unittest.mm
@@ -8,11 +8,11 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #import "chrome/browser/ui/cocoa/bubble_combobox.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h"
-#import "chrome/browser/ui/cocoa/passwords/passwords_list_view_controller.h"
 #import "chrome/browser/ui/cocoa/passwords/credentials_selection_view.h"
+#import "chrome/browser/ui/cocoa/passwords/passwords_list_view_controller.h"
 #import "chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm
index 19ab0a4b..015cfbd5 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm
@@ -13,9 +13,9 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #include "chrome/browser/ui/cocoa/info_bubble_window.h"
 #import "chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm
index 7276a61..e5170950 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm
@@ -18,9 +18,9 @@
 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
 #import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #include "chrome/browser/ui/cocoa/info_bubble_window.h"
 #import "chrome/browser/ui/cocoa/profiles/avatar_button_controller.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm
index 69af42c9..b8ab55dc 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm
@@ -25,7 +25,7 @@
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "components/signin/core/browser/fake_account_fetcher_service.h"
diff --git a/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm
index 2d15de7..98dc739 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm
@@ -14,8 +14,8 @@
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/test_browser_window.h"
diff --git a/chrome/browser/ui/cocoa/screen_capture_notification_ui_cocoa_unittest.mm b/chrome/browser/ui/cocoa/screen_capture_notification_ui_cocoa_unittest.mm
index 4014b3b..ef1ee89 100644
--- a/chrome/browser/ui/cocoa/screen_capture_notification_ui_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/screen_capture_notification_ui_cocoa_unittest.mm
@@ -8,7 +8,7 @@
 #include "base/mac/mac_util.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 @interface ScreenCaptureNotificationController (ExposedForTesting)
 - (NSButton*)stopButton;
diff --git a/chrome/browser/ui/cocoa/sprite_view_unittest.mm b/chrome/browser/ui/cocoa/sprite_view_unittest.mm
index 8f183d1..f3bf874 100644
--- a/chrome/browser/ui/cocoa/sprite_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/sprite_view_unittest.mm
@@ -6,8 +6,8 @@
 
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/sprite_view.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
index bfb39d3e..bed808e0 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
@@ -12,7 +12,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #import "chrome/browser/ui/cocoa/bubble_view.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm b/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
index f4dcb49..ff4e819 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
@@ -6,8 +6,8 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/status_icons/status_icon_menu_model.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/status_icons/status_icon_mac.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm
index a01c2c4..409738e 100644
--- a/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm
@@ -5,9 +5,9 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
-#import "chrome/browser/ui/cocoa/styled_text_field_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/styled_text_field_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/styled_text_field_unittest.mm b/chrome/browser/ui/cocoa/styled_text_field_unittest.mm
index 002faa5..0885aa93 100644
--- a/chrome/browser/ui/cocoa/styled_text_field_unittest.mm
+++ b/chrome/browser/ui/cocoa/styled_text_field_unittest.mm
@@ -5,10 +5,10 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/styled_text_field.h"
 #import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
-#import "chrome/browser/ui/cocoa/styled_text_field_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/styled_text_field_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_mac_unittest.mm b/chrome/browser/ui/cocoa/tab_contents/sad_tab_mac_unittest.mm
index 33c0bdc..98bdf0e8 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_mac_unittest.mm
@@ -6,7 +6,7 @@
 
 #import "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "ui/base/cocoa/controls/hyperlink_text_view.h"
diff --git a/chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa_unittest.mm b/chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa_unittest.mm
index 71a15e42..15ed41cddc 100644
--- a/chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa_unittest.mm
@@ -9,7 +9,7 @@
 #include "base/command_line.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/message_loop/message_loop.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/common/chrome_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
index 3da7de33..a648879 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
@@ -11,13 +11,13 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "chrome/browser/ui/cocoa/l10n_util.h"
 #import "chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
index 630cc77..8321fa70 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
@@ -10,12 +10,12 @@
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/new_tab_button.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_view_unittest.mm
index ed816bf..7bbb143 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view_unittest.mm
@@ -5,8 +5,8 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_view_unittest.mm
index 71849e0..01b7c2afe 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view_unittest.mm
@@ -5,8 +5,8 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/chrome/browser/ui/cocoa/cocoa_profile_test.h b/chrome/browser/ui/cocoa/test/cocoa_profile_test.h
similarity index 88%
rename from chrome/browser/ui/cocoa/cocoa_profile_test.h
rename to chrome/browser/ui/cocoa/test/cocoa_profile_test.h
index ed80a8d..2b98dd6b 100644
--- a/chrome/browser/ui/cocoa/cocoa_profile_test.h
+++ b/chrome/browser/ui/cocoa/test/cocoa_profile_test.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_COCOA_PROFILE_TEST_H_
-#define CHROME_BROWSER_UI_COCOA_PROFILE_TEST_H_
+#ifndef CHROME_BROWSER_UI_COCOA_TEST_COCOA_PROFILE_TEST_H_
+#define CHROME_BROWSER_UI_COCOA_TEST_COCOA_PROFILE_TEST_H_
 
 #include <memory>
 
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/test/base/testing_profile_manager.h"
 
 namespace content {
@@ -44,9 +44,7 @@
 
   void TearDown() override;
 
-  TestingProfileManager* testing_profile_manager() {
-    return &profile_manager_;
-  }
+  TestingProfileManager* testing_profile_manager() { return &profile_manager_; }
   TestingProfile* profile() { return profile_; }
   Browser* browser() { return browser_.get(); }
 
@@ -77,4 +75,4 @@
   std::unique_ptr<content::TestBrowserThreadBundle> thread_bundle_;
 };
 
-#endif  // CHROME_BROWSER_UI_COCOA_PROFILE_TEST_H_
+#endif  // CHROME_BROWSER_UI_COCOA_TEST_COCOA_PROFILE_TEST_H_
diff --git a/chrome/browser/ui/cocoa/cocoa_profile_test.mm b/chrome/browser/ui/cocoa/test/cocoa_profile_test.mm
similarity index 96%
rename from chrome/browser/ui/cocoa/cocoa_profile_test.mm
rename to chrome/browser/ui/cocoa/test/cocoa_profile_test.mm
index 4ca8392..707f143 100644
--- a/chrome/browser/ui/cocoa/cocoa_profile_test.mm
+++ b/chrome/browser/ui/cocoa/test/cocoa_profile_test.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.
 
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
@@ -23,8 +23,7 @@
 CocoaProfileTest::CocoaProfileTest()
     : profile_manager_(TestingBrowserProcess::GetGlobal()),
       profile_(NULL),
-      thread_bundle_(new content::TestBrowserThreadBundle) {
-}
+      thread_bundle_(new content::TestBrowserThreadBundle) {}
 
 CocoaProfileTest::~CocoaProfileTest() {
   // Delete the testing profile on the UI thread. But first release the
diff --git a/chrome/browser/ui/cocoa/cocoa_test_helper.h b/chrome/browser/ui/cocoa/test/cocoa_test_helper.h
similarity index 86%
rename from chrome/browser/ui/cocoa/cocoa_test_helper.h
rename to chrome/browser/ui/cocoa/test/cocoa_test_helper.h
index de69e97..8120e93 100644
--- a/chrome/browser/ui/cocoa/cocoa_test_helper.h
+++ b/chrome/browser/ui/cocoa/test/cocoa_test_helper.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_
-#define CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_
+#ifndef CHROME_BROWSER_UI_COCOA_TEST_COCOA_TEST_HELPER_H_
+#define CHROME_BROWSER_UI_COCOA_TEST_COCOA_TEST_HELPER_H_
 
 #import <Cocoa/Cocoa.h>
 
@@ -27,4 +27,4 @@
   CocoaTest();
 };
 
-#endif  // CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_
+#endif  // CHROME_BROWSER_UI_COCOA_TEST_COCOA_TEST_HELPER_H_
diff --git a/chrome/browser/ui/cocoa/cocoa_test_helper.mm b/chrome/browser/ui/cocoa/test/cocoa_test_helper.mm
similarity index 90%
rename from chrome/browser/ui/cocoa/cocoa_test_helper.mm
rename to chrome/browser/ui/cocoa/test/cocoa_test_helper.mm
index 0d6e5ed..0ab828f 100644
--- a/chrome/browser/ui/cocoa/cocoa_test_helper.mm
+++ b/chrome/browser/ui/cocoa/test/cocoa_test_helper.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 "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 #include "base/mac/bundle_locations.h"
 #include "base/path_service.h"
diff --git a/chrome/browser/ui/cocoa/run_loop_testing.h b/chrome/browser/ui/cocoa/test/run_loop_testing.h
similarity index 84%
rename from chrome/browser/ui/cocoa/run_loop_testing.h
rename to chrome/browser/ui/cocoa/test/run_loop_testing.h
index 5269787..46a45ac 100644
--- a/chrome/browser/ui/cocoa/run_loop_testing.h
+++ b/chrome/browser/ui/cocoa/test/run_loop_testing.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_COCOA_RUN_LOOP_TESTING_H_
-#define CHROME_BROWSER_UI_COCOA_RUN_LOOP_TESTING_H_
+#ifndef CHROME_BROWSER_UI_COCOA_TEST_RUN_LOOP_TESTING_H_
+#define CHROME_BROWSER_UI_COCOA_TEST_RUN_LOOP_TESTING_H_
 
 namespace chrome {
 namespace testing {
@@ -26,4 +26,4 @@
 }  // namespace testing
 }  // namespace chrome
 
-#endif  // CHROME_BROWSER_UI_COCOA_RUN_LOOP_TESTING_H_
+#endif  // CHROME_BROWSER_UI_COCOA_TEST_RUN_LOOP_TESTING_H_
diff --git a/chrome/browser/ui/cocoa/run_loop_testing.mm b/chrome/browser/ui/cocoa/test/run_loop_testing.mm
similarity index 90%
rename from chrome/browser/ui/cocoa/run_loop_testing.mm
rename to chrome/browser/ui/cocoa/test/run_loop_testing.mm
index 7dd5afb..cb228caf 100644
--- a/chrome/browser/ui/cocoa/run_loop_testing.mm
+++ b/chrome/browser/ui/cocoa/test/run_loop_testing.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.
 
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 
 #import <Foundation/Foundation.h>
 
@@ -47,9 +47,7 @@
   base::scoped_nsobject<CocoaQuitTask> quit_task(
       [[CocoaQuitTask alloc] initWithMessagePump:message_pump.get()]);
 
-  [quit_task performSelector:@selector(doQuit)
-                  withObject:nil
-                  afterDelay:0];
+  [quit_task performSelector:@selector(doQuit) withObject:nil afterDelay:0];
 
   // Spin the internal loop, running it until the quit task is pumped. Pass NULL
   // because there is no delegate MessageLoop; only the Cocoa work queues will
diff --git a/chrome/browser/ui/cocoa/run_loop_testing_unittest.mm b/chrome/browser/ui/cocoa/test/run_loop_testing_unittest.mm
similarity index 95%
rename from chrome/browser/ui/cocoa/run_loop_testing_unittest.mm
rename to chrome/browser/ui/cocoa/test/run_loop_testing_unittest.mm
index 760f985..a2220de 100644
--- a/chrome/browser/ui/cocoa/run_loop_testing_unittest.mm
+++ b/chrome/browser/ui/cocoa/test/run_loop_testing_unittest.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.
 
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 
 #import <Foundation/Foundation.h>
 
diff --git a/chrome/browser/ui/cocoa/styled_text_field_test_helper.h b/chrome/browser/ui/cocoa/test/styled_text_field_test_helper.h
similarity index 100%
rename from chrome/browser/ui/cocoa/styled_text_field_test_helper.h
rename to chrome/browser/ui/cocoa/test/styled_text_field_test_helper.h
diff --git a/chrome/browser/ui/cocoa/styled_text_field_test_helper.mm b/chrome/browser/ui/cocoa/test/styled_text_field_test_helper.mm
similarity index 88%
rename from chrome/browser/ui/cocoa/styled_text_field_test_helper.mm
rename to chrome/browser/ui/cocoa/test/styled_text_field_test_helper.mm
index 20f566d..43d1e8a 100644
--- a/chrome/browser/ui/cocoa/styled_text_field_test_helper.mm
+++ b/chrome/browser/ui/cocoa/test/styled_text_field_test_helper.mm
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #import <Cocoa/Cocoa.h>
-#import "chrome/browser/ui/cocoa/styled_text_field_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/styled_text_field_test_helper.h"
 
 @implementation StyledTextFieldTestCell
 @synthesize leftMargin = leftMargin_;
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm
index 7fa5b65..ff6c5066 100644
--- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 
 @interface TestAppToolbarButton : NSButton
 @end
diff --git a/chrome/browser/ui/cocoa/toolbar/reload_button_unittest.mm b/chrome/browser/ui/cocoa/toolbar/reload_button_unittest.mm
index 0b22fcd..94e4ba9 100644
--- a/chrome/browser/ui/cocoa/toolbar/reload_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/reload_button_unittest.mm
@@ -8,8 +8,8 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm
index 5ff48e4..0acf351 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm
@@ -6,7 +6,7 @@
 
 #import "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h"
 #import "testing/gtest_mac.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm
index 6e9b34b3..d8217085 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm
@@ -14,10 +14,10 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_list_observer.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 #import "chrome/browser/ui/cocoa/location_bar/translate_decoration.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm
index 52df1e95..0e5534473 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm
index 937bf91..5917d46e 100644
--- a/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm
@@ -9,9 +9,9 @@
 #import "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #include "chrome/browser/ui/translate/translate_bubble_model.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/site_instance.h"
diff --git a/chrome/browser/ui/cocoa/url_drop_target_unittest.mm b/chrome/browser/ui/cocoa/url_drop_target_unittest.mm
index fdd61ce..ab09ffa 100644
--- a/chrome/browser/ui/cocoa/url_drop_target_unittest.mm
+++ b/chrome/browser/ui/cocoa/url_drop_target_unittest.mm
@@ -6,7 +6,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "third_party/ocmock/ocmock_extensions.h"
diff --git a/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm b/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm
index fa550b3..0344b652 100644
--- a/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #import "chrome/browser/ui/cocoa/vertical_gradient_view.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller_unittest.mm
index 9a9ecc2..c0879420 100644
--- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller_unittest.mm
@@ -16,9 +16,9 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/cocoa_profile_test.h"
 #include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
 #import "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h"
 #import "chrome/browser/ui/cocoa/website_settings/split_block_button.h"
 #include "chrome/grit/generated_resources.h"
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_selector_button_unittest.mm b/chrome/browser/ui/cocoa/website_settings/permission_selector_button_unittest.mm
index 9e682ad..300dc4a 100644
--- a/chrome/browser/ui/cocoa/website_settings/permission_selector_button_unittest.mm
+++ b/chrome/browser/ui/cocoa/website_settings/permission_selector_button_unittest.mm
@@ -4,8 +4,8 @@
 
 #import "chrome/browser/ui/cocoa/website_settings/permission_selector_button.h"
 
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
 #include "base/mac/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/browser/ui/website_settings/website_settings_ui.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm
index 1994c84..4823a53 100644
--- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm
@@ -9,7 +9,7 @@
 #include "base/i18n/rtl.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_web_contents_factory.h"
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
index 65f86c0..0b41d0e 100644
--- a/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
+++ b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
@@ -7,7 +7,7 @@
 #import "chrome/browser/ui/cocoa/window_size_autosaver.h"
 
 #include "base/mac/scoped_nsobject.h"
-#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ui/tests/ui_gfx_image_unittest.mm b/chrome/browser/ui/tests/ui_gfx_image_unittest.mm
index 9cf497e..ca25ebe 100644
--- a/chrome/browser/ui/tests/ui_gfx_image_unittest.mm
+++ b/chrome/browser/ui/tests/ui_gfx_image_unittest.mm
@@ -6,7 +6,7 @@
 
 #import "base/mac/mac_util.h"
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/image/image.h"
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
index 869bd7a..1b18839 100644
--- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
+++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -2,8 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <algorithm>
+#include <initializer_list>
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -307,8 +310,8 @@
 // content/test/data/drag_and_drop/event_monitoring.js
 class DOMDragEventWaiter {
  public:
-  explicit DOMDragEventWaiter(const std::string& event_type_to_wait_for,
-                              const content::ToRenderFrameHost& target)
+  DOMDragEventWaiter(const std::string& event_type_to_wait_for,
+                     const content::ToRenderFrameHost& target)
       : target_frame_name_(target.render_frame_host()->GetFrameName()),
         event_type_to_wait_for_(event_type_to_wait_for),
         dom_message_queue_(content::WebContents::FromRenderFrameHost(
@@ -332,13 +335,10 @@
       if (!dom_message_queue_.WaitForMessage(&candidate_event))
         return false;
 
-      got_right_event_type = base::MatchPattern(
-          candidate_event, base::StringPrintf("*\"event_type\":\"%s\"*",
-                                              event_type_to_wait_for_.c_str()));
-
-      got_right_window_name = base::MatchPattern(
-          candidate_event, base::StringPrintf("*\"window_name\":\"%s\"*",
-                                              target_frame_name_.c_str()));
+      got_right_event_type =
+          IsExpectedEventType(candidate_event, event_type_to_wait_for_);
+      got_right_window_name =
+          IsExpectedWindowName(candidate_event, target_frame_name_);
     } while (!got_right_event_type || !got_right_window_name);
 
     if (found_event)
@@ -347,7 +347,29 @@
     return true;
   }
 
+  static bool IsExpectedEventType(const std::string& actual_event_body,
+                                  const std::string& expected_event_type) {
+    return IsExpectedPropertyValue(actual_event_body, "event_type",
+                                   expected_event_type);
+  }
+
+  static bool IsExpectedWindowName(const std::string& actual_event_body,
+                                   const std::string& expected_window_name) {
+    return IsExpectedPropertyValue(actual_event_body, "window_name",
+                                   expected_window_name);
+  }
+
  private:
+  static bool IsExpectedPropertyValue(
+      const std::string& actual_event_body,
+      const std::string& property_name,
+      const std::string& expected_property_value) {
+    return base::MatchPattern(
+        actual_event_body,
+        base::StringPrintf("*\"%s\":\"%s\"*", property_name.c_str(),
+                           expected_property_value.c_str()));
+  }
+
   std::string target_frame_name_;
   std::string event_type_to_wait_for_;
   content::DOMMessageQueue dom_message_queue_;
@@ -412,6 +434,76 @@
   DISALLOW_COPY_AND_ASSIGN(DOMDragEventVerifier);
 };
 
+// Helper for monitoring event notifications from
+// content/test/data/drag_and_drop/event_monitoring.js
+// and counting how many events of a given type were received.
+class DOMDragEventCounter {
+ public:
+  explicit DOMDragEventCounter(const content::ToRenderFrameHost& target)
+      : target_frame_name_(target.render_frame_host()->GetFrameName()),
+        dom_message_queue_(content::WebContents::FromRenderFrameHost(
+            target.render_frame_host())) {}
+
+  // Resets all the accumulated event counts to zeros.
+  void Reset() {
+    StoreAccumulatedEvents();
+    received_events_.clear();
+  }
+
+  // Returns the number of events of the specified |event_type| received since
+  // construction, or since the last time Reset was called.  |event_type| should
+  // be one of possible |type| property values for a DOM drag-and-drop event -
+  // e.g.  "dragenter" or "dragover".
+  int GetNumberOfReceivedEvents(const std::string& event_type) {
+    std::vector<std::string> v({event_type});
+    return GetNumberOfReceivedEvents(v.begin(), v.end());
+  }
+
+  // Returns the number of events of the specified |event_types| received since
+  // construction, or since the last time Reset was called.  Elements of
+  // |event_types| should be one of possible |type| property values for a DOM
+  // drag-and-drop event - e.g.  "dragenter" or "dragover".
+  int GetNumberOfReceivedEvents(
+      std::initializer_list<const char*> event_types) {
+    return GetNumberOfReceivedEvents(event_types.begin(), event_types.end());
+  }
+
+ private:
+  template <typename T>
+  int GetNumberOfReceivedEvents(T event_types_begin, T event_types_end) {
+    StoreAccumulatedEvents();
+
+    auto received_event_has_matching_event_type =
+        [&event_types_begin,
+         &event_types_end](const std::string& received_event) {
+          return std::any_of(event_types_begin, event_types_end,
+                             [&received_event](const std::string& event_type) {
+                               return DOMDragEventWaiter::IsExpectedEventType(
+                                   received_event, event_type);
+                             });
+        };
+
+    return std::count_if(received_events_.begin(), received_events_.end(),
+                         received_event_has_matching_event_type);
+  }
+
+  void StoreAccumulatedEvents() {
+    std::string candidate_event;
+    while (dom_message_queue_.PopMessage(&candidate_event)) {
+      if (DOMDragEventWaiter::IsExpectedWindowName(candidate_event,
+                                                   target_frame_name_)) {
+        received_events_.push_back(candidate_event);
+      }
+    }
+  }
+
+  std::string target_frame_name_;
+  content::DOMMessageQueue dom_message_queue_;
+  std::vector<std::string> received_events_;
+
+  DISALLOW_COPY_AND_ASSIGN(DOMDragEventCounter);
+};
+
 const char kTestPagePath[] = "/drag_and_drop/page.html";
 
 }  // namespace
@@ -425,6 +517,10 @@
   void DragImageBetweenFrames_Step2(DragImageBetweenFrames_TestState*);
   void DragImageBetweenFrames_Step3(DragImageBetweenFrames_TestState*);
 
+  struct CrossSiteDrag_TestState;
+  void CrossSiteDrag_Step2(CrossSiteDrag_TestState*);
+  void CrossSiteDrag_Step3(CrossSiteDrag_TestState*);
+
  protected:
   void SetUpOnMainThread() override {
     host_resolver()->AddRule("*", "127.0.0.1");
@@ -730,6 +826,8 @@
   std::unique_ptr<DOMDragEventWaiter> dragstart_event_waiter;
   std::unique_ptr<DOMDragEventWaiter> drop_event_waiter;
   std::unique_ptr<DOMDragEventWaiter> dragend_event_waiter;
+  std::unique_ptr<DOMDragEventCounter> left_frame_events_counter;
+  std::unique_ptr<DOMDragEventCounter> right_frame_events_counter;
 };
 
 // Scenario: drag an image from the left into the right frame.
@@ -745,6 +843,9 @@
 
   // Setup test expectations.
   DragAndDropBrowserTest::DragImageBetweenFrames_TestState state;
+  state.left_frame_events_counter.reset(new DOMDragEventCounter(left_frame()));
+  state.right_frame_events_counter.reset(
+      new DOMDragEventCounter(right_frame()));
   state.expected_dom_event_data.set_expected_client_position("(55, 50)");
   state.expected_dom_event_data.set_expected_drop_effect("none");
   // (dragstart event handler in image_source.html is asking for "copy" only).
@@ -778,6 +879,18 @@
     EXPECT_TRUE(state->dragstart_event_waiter->WaitForNextMatchingEvent(
         &dragstart_event));
     state->dragstart_event_waiter.reset();
+
+    // Only a single "dragstart" should have fired in the left frame since the
+    // start of the test.  We also allow any number of "dragover" events.
+    EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
+                     "dragstart"));
+    EXPECT_EQ(0, state->left_frame_events_counter->GetNumberOfReceivedEvents(
+                     {"dragleave", "dragenter", "drop", "dragend"}));
+
+    // No events should have fired in the right frame yet.
+    EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
+                     {"dragstart", "dragleave", "dragenter", "dragover", "drop",
+                      "dragend"}));
   }
 
   // While dragging, move mouse within the left frame.
@@ -789,6 +902,8 @@
   {
     DOMDragEventWaiter dragleave_event_waiter("dragleave", left_frame());
     DOMDragEventWaiter dragenter_event_waiter("dragenter", right_frame());
+    state->left_frame_events_counter->Reset();
+    state->right_frame_events_counter->Reset();
     ASSERT_TRUE(SimulateMouseMoveToRightFrame());
 
     {  // Verify dragleave DOM event.
@@ -841,10 +956,28 @@
     }
   }
 
+  // Only a single "dragleave" should have fired in the left frame since the
+  // last checkpoint.  We also allow any number of "dragover" events.
+  EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
+                   "dragleave"));
+  EXPECT_EQ(0, state->left_frame_events_counter->GetNumberOfReceivedEvents(
+                   {"dragstart", "dragenter", "drop", "dragend"}));
+
+  // A single "dragenter" + at least one "dragover" event should have fired in
+  // the right frame since the last checkpoint.
+  EXPECT_EQ(1, state->right_frame_events_counter->GetNumberOfReceivedEvents(
+                   "dragenter"));
+  EXPECT_LE(1, state->right_frame_events_counter->GetNumberOfReceivedEvents(
+                   "dragover"));
+  EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
+                   {"dragstart", "dragleave", "drop", "dragend"}));
+
   // Release the mouse button to end the drag.
   state->drop_event_waiter.reset(new DOMDragEventWaiter("drop", right_frame()));
   state->dragend_event_waiter.reset(
       new DOMDragEventWaiter("dragend", left_frame()));
+  state->left_frame_events_counter->Reset();
+  state->right_frame_events_counter->Reset();
   SimulateMouseUp();
   // The test will continue in DragImageBetweenFrames_Step3.
 }
@@ -880,6 +1013,130 @@
     state->dragend_event_waiter.reset();
     EXPECT_THAT(dragend_event, state->expected_dom_event_data.Matches());
   }
+
+  // Only a single "dragend" should have fired in the left frame since the last
+  // checkpoint.
+  EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
+                   "dragend"));
+  EXPECT_EQ(0,
+            state->left_frame_events_counter->GetNumberOfReceivedEvents(
+                {"dragstart", "dragleave", "dragenter", "dragover", "drop"}));
+
+  // A single "drop" + possibly some "dragover" events should have fired in the
+  // right frame since the last checkpoint.
+  EXPECT_EQ(
+      1, state->right_frame_events_counter->GetNumberOfReceivedEvents("drop"));
+  EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
+                   {"dragstart", "dragleave", "dragenter", "dragend"}));
+}
+
+// There is no known way to execute test-controlled tasks during
+// a drag-and-drop loop run by Windows OS.
+#if defined(OS_WIN)
+#define MAYBE_CrossSiteDrag DISABLED_CrossSiteDrag
+#else
+#define MAYBE_CrossSiteDrag CrossSiteDrag
+#endif
+
+// Data that needs to be shared across multiple test steps below
+// (i.e. across CrossSiteDrag_Step2 and CrossSiteDrag_Step3).
+struct DragAndDropBrowserTest::CrossSiteDrag_TestState {
+  std::unique_ptr<DOMDragEventWaiter> dragend_event_waiter;
+  std::unique_ptr<DOMDragEventCounter> left_frame_events_counter;
+  std::unique_ptr<DOMDragEventCounter> right_frame_events_counter;
+};
+
+// Scenario: drag an image from the left into the right frame when the
+// left-vs-right frames are cross-site.  This is a regression test for
+// https://crbug.com/59081.
+//
+// Test coverage: absence of dragenter, dragover, drop DOM events
+// + presence of dragstart, dragleave and dragend.
+IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, MAYBE_CrossSiteDrag) {
+  std::string left_frame_site = "c.com";  // Always cross-site VS main frame.
+  std::string right_frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
+  ASSERT_TRUE(NavigateToTestPage("a.com"));
+  ASSERT_TRUE(NavigateLeftFrame(left_frame_site, "image_source.html"));
+  ASSERT_TRUE(NavigateRightFrame(right_frame_site, "drop_target.html"));
+
+  // Setup test expectations.
+  DragAndDropBrowserTest::CrossSiteDrag_TestState state;
+  state.left_frame_events_counter.reset(new DOMDragEventCounter(left_frame()));
+  state.right_frame_events_counter.reset(
+      new DOMDragEventCounter(right_frame()));
+
+  // Start the drag in the left frame.
+  DragStartWaiter drag_start_waiter(web_contents());
+  drag_start_waiter.PostTaskWhenDragStarts(
+      base::Bind(&DragAndDropBrowserTest::CrossSiteDrag_Step2,
+                 base::Unretained(this), base::Unretained(&state)));
+  EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
+
+  // The next step of the test (CrossSiteDrag_Step2) runs inside the
+  // nested drag-and-drop message loop - the call below won't return until the
+  // drag-and-drop has already ended.
+  drag_start_waiter.WaitUntilDragStart(nullptr, nullptr, nullptr, nullptr);
+
+  CrossSiteDrag_Step3(&state);
+}
+
+void DragAndDropBrowserTest::CrossSiteDrag_Step2(
+    DragAndDropBrowserTest::CrossSiteDrag_TestState* state) {
+  // While "dragleave" and "drop" events are not expected in this test, we
+  // simulate extra mouse operations for consistency with
+  // DragImageBetweenFrames_Step2.
+  ASSERT_TRUE(SimulateMouseMoveToLeftFrame());
+  for (int i = 0; i < 3; i++) {
+    content::DOMMessageQueue dom_message_queue(web_contents());
+    ASSERT_TRUE(SimulateMouseMoveToRightFrame());
+
+    // No events are expected from the right frame, so we can't wait for a
+    // dragover event here.  Still - we do want to wait until the right frame
+    // has had a chance to process any previous browser IPCs, so that in case
+    // there *is* a bug and a dragover event *does* happen, we won't terminate
+    // the test before the event has had a chance to be reported back to the
+    // browser.
+    std::string expected_response = base::StringPrintf("\"i%d\"", i);
+    right_frame()->ExecuteJavaScriptWithUserGestureForTests(base::UTF8ToUTF16(
+        base::StringPrintf("domAutomationController.setAutomationId(0);\n"
+                           "domAutomationController.send(%s);\n",
+                           expected_response.c_str())));
+
+    // Wait until our response comes back (it might be mixed with responses
+    // carrying events that are sent by event_monitoring.js).
+    std::string actual_response;
+    do {
+      ASSERT_TRUE(dom_message_queue.WaitForMessage(&actual_response));
+    } while (actual_response != expected_response);
+  }
+
+  // Release the mouse button to end the drag.
+  state->dragend_event_waiter.reset(
+      new DOMDragEventWaiter("dragend", left_frame()));
+  SimulateMouseUp();
+  // The test will continue in DragImageBetweenFrames_Step3.
+}
+
+void DragAndDropBrowserTest::CrossSiteDrag_Step3(
+    DragAndDropBrowserTest::CrossSiteDrag_TestState* state) {
+  EXPECT_TRUE(state->dragend_event_waiter->WaitForNextMatchingEvent(nullptr));
+
+  // Since the start of the test the left frame should have seen a single
+  // "dragstart",
+  // and a "dragend" event (and possibly a "dragleave" and some "dragover"
+  // events).
+  EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
+                   "dragstart"));
+  EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
+                   "dragend"));
+  EXPECT_EQ(
+      0, state->left_frame_events_counter->GetNumberOfReceivedEvents("drop"));
+
+  // No events should have fired in the right frame, because it is cross-site
+  // from the source of the drag.  This is the essence of this test.
+  EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
+                   {"dragstart", "dragleave", "dragenter", "dragover", "drop",
+                    "dragend"}));
 }
 
 INSTANTIATE_TEST_CASE_P(
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index de2fc12..1d66c98 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -518,7 +518,8 @@
       manage_cloud_printers_dialog_request_count_(0),
       reported_failed_preview_(false),
       has_logged_printers_count_(false),
-      gaia_cookie_manager_service_(NULL),
+      gaia_cookie_manager_service_(nullptr),
+      printer_backend_proxy_(nullptr),
       weak_factory_(this) {
   ReportUserActionHistogram(PREVIEW_STARTED);
 }
@@ -611,11 +612,27 @@
   return static_cast<PrintPreviewUI*>(web_ui()->GetController());
 }
 
+printing::PrinterBackendProxy* PrintPreviewHandler::printer_backend_proxy() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  if (!printer_backend_proxy_) {
+#if defined(OS_CHROMEOS)
+    // ChromeOS stores printer information in printer prefs which requires a
+    // profile.  Other plaforms retrieve printer information from OS resources.
+    printer_backend_proxy_ =
+        printing::PrinterBackendProxy::Create(Profile::FromWebUI(web_ui()));
+#else
+    printer_backend_proxy_ = printing::PrinterBackendProxy::Create();
+#endif
+  }
+
+  return printer_backend_proxy_.get();
+}
+
 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
   VLOG(1) << "Enumerate printers start";
-  printing::EnumeratePrinters(Profile::FromWebUI(web_ui()),
-                              base::Bind(&PrintPreviewHandler::SetupPrinterList,
-                                         weak_factory_.GetWeakPtr()));
+  printer_backend_proxy()->EnumeratePrinters(base::Bind(
+      &PrintPreviewHandler::SetupPrinterList, weak_factory_.GetWeakPtr()));
 }
 
 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
@@ -1029,8 +1046,8 @@
       base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
                  weak_factory_.GetWeakPtr(), printer_name);
 
-  printing::ConfigurePrinterAndFetchCapabilities(Profile::FromWebUI(web_ui()),
-                                                 printer_name, cb);
+  printer_backend_proxy()->ConfigurePrinterAndFetchCapabilities(printer_name,
+                                                                cb);
 }
 
 void PrintPreviewHandler::OnSigninComplete() {
@@ -1152,11 +1169,8 @@
     const base::ListValue* /*args*/) {
   // Send before SendInitialSettings() to allow cloud printer auto select.
   SendCloudPrintEnabled();
-  base::PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool(), FROM_HERE,
-      base::Bind(&printing::GetDefaultPrinterOnBlockingPoolThread),
-      base::Bind(&PrintPreviewHandler::SendInitialSettings,
-                 weak_factory_.GetWeakPtr()));
+  printer_backend_proxy()->GetDefaultPrinter(base::Bind(
+      &PrintPreviewHandler::SendInitialSettings, weak_factory_.GetWeakPtr()));
 }
 
 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index 42a8f52..56a7379 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -41,6 +41,10 @@
 class Size;
 }
 
+namespace printing {
+class PrinterBackendProxy;
+}
+
 // The handler for Javascript messages related to the print preview dialog.
 class PrintPreviewHandler
     : public content::WebUIMessageHandler,
@@ -111,6 +115,8 @@
 
   PrintPreviewUI* print_preview_ui() const;
 
+  printing::PrinterBackendProxy* printer_backend_proxy();
+
   // Gets the list of printers. |args| is unused.
   void HandleGetPrinters(const base::ListValue* args);
 
@@ -380,6 +386,10 @@
   // notify the test if it was a successful save, only that it was attempted.
   base::Closure pdf_file_saved_closure_;
 
+  // Proxy for calls to the print backend.  Lazily initialized since web_ui() is
+  // not available at construction time.
+  std::unique_ptr<printing::PrinterBackendProxy> printer_backend_proxy_;
+
   base::WeakPtrFactory<PrintPreviewHandler> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PrintPreviewHandler);
diff --git a/chrome/browser/ui/webui/print_preview/printer_backend_proxy.cc b/chrome/browser/ui/webui/print_preview/printer_backend_proxy.cc
index effbb06..f610f77d 100644
--- a/chrome/browser/ui/webui/print_preview/printer_backend_proxy.cc
+++ b/chrome/browser/ui/webui/print_preview/printer_backend_proxy.cc
@@ -52,8 +52,6 @@
   return GetSettingsOnBlockingPool(device_name, basic_info);
 }
 
-}  // namespace
-
 std::string GetDefaultPrinterOnBlockingPoolThread() {
   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
 
@@ -65,21 +63,50 @@
   return default_printer;
 }
 
-void EnumeratePrinters(Profile* /* profile */,
-                       const EnumeratePrintersCallback& cb) {
-  base::PostTaskAndReplyWithResult(
-      content::BrowserThread::GetBlockingPool(), FROM_HERE,
-      base::Bind(&EnumeratePrintersOnBlockingPoolThread), cb);
-}
+// Default implementation of PrinterBackendProxy.  Makes calls directly to
+// the print backend on the appropriate thread.
+class PrinterBackendProxyDefault : public PrinterBackendProxy {
+ public:
+  PrinterBackendProxyDefault() {}
 
-void ConfigurePrinterAndFetchCapabilities(Profile* /* profile */,
-                                          const std::string& device_name,
-                                          const PrinterSetupCallback& cb) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  ~PrinterBackendProxyDefault() override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  }
 
-  base::PostTaskAndReplyWithResult(
-      content::BrowserThread::GetBlockingPool(), FROM_HERE,
-      base::Bind(&FetchCapabilitiesOnBlockingPool, device_name), cb);
+  void GetDefaultPrinter(const DefaultPrinterCallback& cb) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    base::PostTaskAndReplyWithResult(
+        content::BrowserThread::GetBlockingPool(), FROM_HERE,
+        base::Bind(&GetDefaultPrinterOnBlockingPoolThread), cb);
+  }
+
+  void EnumeratePrinters(const EnumeratePrintersCallback& cb) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    base::PostTaskAndReplyWithResult(
+        content::BrowserThread::GetBlockingPool(), FROM_HERE,
+        base::Bind(&EnumeratePrintersOnBlockingPoolThread), cb);
+  }
+
+  void ConfigurePrinterAndFetchCapabilities(
+      const std::string& device_name,
+      const PrinterSetupCallback& cb) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    base::PostTaskAndReplyWithResult(
+        content::BrowserThread::GetBlockingPool(), FROM_HERE,
+        base::Bind(&FetchCapabilitiesOnBlockingPool, device_name), cb);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrinterBackendProxyDefault);
+};
+
+}  // namespace
+
+std::unique_ptr<PrinterBackendProxy> PrinterBackendProxy::Create() {
+  return base::MakeUnique<PrinterBackendProxyDefault>();
 }
 
 }  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/printer_backend_proxy.h b/chrome/browser/ui/webui/print_preview/printer_backend_proxy.h
index d2dff83b..016b6881 100644
--- a/chrome/browser/ui/webui/print_preview/printer_backend_proxy.h
+++ b/chrome/browser/ui/webui/print_preview/printer_backend_proxy.h
@@ -12,28 +12,45 @@
 #include "base/values.h"
 #include "printing/backend/print_backend.h"
 
+#if defined(OS_CHROMEOS)
 class Profile;
+#endif
 
 namespace printing {
 
+using DefaultPrinterCallback =
+    base::Callback<void(const std::string& printer_name)>;
+
 using EnumeratePrintersCallback = base::Callback<void(const PrinterList&)>;
 
 using PrinterSetupCallback =
-    base::Callback<void(std::unique_ptr<base::DictionaryValue>)>;
+    base::Callback<void(std::unique_ptr<base::DictionaryValue> settings)>;
 
-// Returns the name of the default printer.
-std::string GetDefaultPrinterOnBlockingPoolThread();
+class PrinterBackendProxy {
+ public:
+#if defined(OS_CHROMEOS)
+  static std::unique_ptr<PrinterBackendProxy> Create(Profile* profile);
+#else
+  static std::unique_ptr<PrinterBackendProxy> Create();
+#endif
 
-// Retrieves printers for display in the print dialog and calls |cb| with the
-// list.  This method expects to be called on the UI thread.
-void EnumeratePrinters(Profile* profile, const EnumeratePrintersCallback& cb);
+  virtual ~PrinterBackendProxy() = default;
 
-// Verifies printer setup if needed then retrieves printer capabilities for
-// |printer_name|.  |cb| is called with the capabilities dictionary or nullptr
-// if one of the steps failed.
-void ConfigurePrinterAndFetchCapabilities(Profile* profile,
-                                          const std::string& printer_name,
-                                          const PrinterSetupCallback& cb);
+  // Returns the name of the default printer through |cb|.  This method expects
+  // to be called on the UI thread.
+  virtual void GetDefaultPrinter(const DefaultPrinterCallback& cb) = 0;
+
+  // Retrieves printers for display in the print dialog and calls |cb| with the
+  // list.  This method expects to be called on the UI thread.
+  virtual void EnumeratePrinters(const EnumeratePrintersCallback& cb) = 0;
+
+  // Verifies printer setup if needed then retrieves printer capabilities for
+  // |printer_name|.  |cb| is called with the capabilities dictionary or nullptr
+  // if one of the steps failed.
+  virtual void ConfigurePrinterAndFetchCapabilities(
+      const std::string& printer_name,
+      const PrinterSetupCallback& cb) = 0;
+};
 
 }  // namespace printing
 
diff --git a/chrome/browser/ui/webui/print_preview/printer_backend_proxy_chromeos.cc b/chrome/browser/ui/webui/print_preview/printer_backend_proxy_chromeos.cc
index aa1676b1e..2e7c957f 100644
--- a/chrome/browser/ui/webui/print_preview/printer_backend_proxy_chromeos.cc
+++ b/chrome/browser/ui/webui/print_preview/printer_backend_proxy_chromeos.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
 #include "chrome/browser/chromeos/printing/printer_pref_manager.h"
 #include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -19,6 +20,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
+#include "chromeos/printing/ppd_provider.h"
 #include "chromeos/printing/printer_configuration.h"
 #include "content/public/browser/browser_thread.h"
 #include "printing/backend/print_backend_consts.h"
@@ -44,6 +46,14 @@
   return basic_info;
 }
 
+void AddPrintersToList(
+    const std::vector<std::unique_ptr<chromeos::Printer>>& printers,
+    PrinterList* list) {
+  for (const auto& printer : printers) {
+    list->push_back(ToBasicInfo(*printer));
+  }
+}
+
 void FetchCapabilities(std::unique_ptr<chromeos::Printer> printer,
                        const PrinterSetupCallback& cb) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -66,7 +76,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (result != SetupResult::SUCCESS) {
-    LOG(WARNING) << "Print setup failed";
+    LOG(WARNING) << "Print setup failed: " << result;
     // TODO(skau): Open printer settings if this is resolvable.
     PostCallbackError(cb);
     return;
@@ -96,63 +106,114 @@
   PostCallbackError(cb);
 }
 
-std::string GetPPDPath(const chromeos::Printer& printer) {
-  // TODO(skau): Consult the PPD Provider for the correct file path.
-  return printer.ppd_reference().user_supplied_ppd_url;
-}
-
-}  // namespace
-
-std::string GetDefaultPrinterOnBlockingPoolThread() {
-  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
-  // TODO(crbug.com/660898): Add default printers to ChromeOS.
-  return "";
-}
-
-void EnumeratePrinters(Profile* profile, const EnumeratePrintersCallback& cb) {
-  // PrinterPrefManager is not thread safe and must be called from the UI
-  // thread.
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  PrinterList printer_list;
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableNativeCups)) {
-    chromeos::PrinterPrefManager* prefs =
-        chromeos::PrinterPrefManagerFactory::GetForBrowserContext(profile);
-    std::vector<std::unique_ptr<chromeos::Printer>> printers =
-        prefs->GetPrinters();
-    for (const std::unique_ptr<chromeos::Printer>& printer : printers) {
-      printer_list.push_back(ToBasicInfo(*printer));
-    }
-  }
-
-  cb.Run(printer_list);
-}
-
-void ConfigurePrinterAndFetchCapabilities(Profile* profile,
-                                          const std::string& printer_name,
-                                          const PrinterSetupCallback& cb) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  chromeos::PrinterPrefManager* prefs =
-      chromeos::PrinterPrefManagerFactory::GetForBrowserContext(profile);
-  std::unique_ptr<chromeos::Printer> printer = prefs->GetPrinter(printer_name);
-
-  // Check if configuration is viable.
-  bool ipp_everywhere = printer->IsIppEverywhere();
-  std::string ppd_path = GetPPDPath(*printer);
-  if (!ipp_everywhere && ppd_path.empty()) {
-    HandlePrinterSetup(std::move(printer), PPD_NOT_FOUND, cb);
-    return;
-  }
-
+void AddPrinter(std::unique_ptr<chromeos::Printer> printer,
+                const std::string& ppd_path,
+                bool ipp_everywhere,
+                const PrinterSetupCallback& cb) {
   // Always push configuration to CUPS.  It may need an update.
-  std::string printer_uri = printer->uri();
+  const std::string printer_name = printer->id();
+  const std::string printer_uri = printer->uri();
+
   chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->CupsAddPrinter(
       printer_name, printer_uri, ppd_path, ipp_everywhere,
       base::Bind(&OnPrinterAddResult, base::Passed(&printer), cb),
       base::Bind(&OnPrinterAddError, cb));
 }
 
+void PPDResolve(std::unique_ptr<chromeos::Printer> printer,
+                const PrinterSetupCallback& cb,
+                chromeos::printing::PpdProvider::CallbackResultCode result,
+                base::FilePath path) {
+  switch (result) {
+    case chromeos::printing::PpdProvider::SUCCESS: {
+      DCHECK(!path.empty());
+      AddPrinter(std::move(printer), path.value() /* ppd path */,
+                 false /* non-ipp-everywhere */, cb);
+      break;
+    }
+    case chromeos::printing::PpdProvider::NOT_FOUND:
+      HandlePrinterSetup(std::move(printer), PPD_NOT_FOUND, cb);
+      break;
+    default:
+      HandlePrinterSetup(std::move(printer), FAILURE, cb);
+      break;
+  }
+}
+
+class PrinterBackendProxyChromeos : public PrinterBackendProxy {
+ public:
+  explicit PrinterBackendProxyChromeos(Profile* profile) {
+    prefs_ = chromeos::PrinterPrefManagerFactory::GetForBrowserContext(profile);
+    ppd_provider_ = chromeos::printing::CreateProvider(profile);
+  }
+
+  ~PrinterBackendProxyChromeos() override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  }
+
+  void GetDefaultPrinter(const DefaultPrinterCallback& cb) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    // TODO(crbug.com/660898): Add default printers to ChromeOS.
+
+    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+                                     base::Bind(cb, ""));
+  };
+
+  void EnumeratePrinters(const EnumeratePrintersCallback& cb) override {
+    // PrinterPrefManager is not thread safe and must be called from the UI
+    // thread.
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    PrinterList printer_list;
+
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kEnableNativeCups)) {
+      AddPrintersToList(prefs_->GetPrinters(), &printer_list);
+    }
+
+    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+                                     base::Bind(cb, printer_list));
+  };
+
+  void ConfigurePrinterAndFetchCapabilities(
+      const std::string& printer_name,
+      const PrinterSetupCallback& cb) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    std::unique_ptr<chromeos::Printer> printer =
+        prefs_->GetPrinter(printer_name);
+    if (!printer) {
+      // If the printer was removed, the lookup will fail.
+      content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+                                       base::Bind(cb, nullptr));
+      return;
+    }
+
+    if (printer->IsIppEverywhere()) {
+      // ChromeOS registers printer by GUID rather than display name.
+      AddPrinter(std::move(printer), "" /* empty ppd path */,
+                 true /* ipp everywhere */, cb);
+      return;
+    }
+
+    // Ref taken because printer is moved.
+    const chromeos::Printer::PpdReference& ppd_ref = printer->ppd_reference();
+    ppd_provider_->Resolve(ppd_ref,
+                           base::Bind(&PPDResolve, base::Passed(&printer), cb));
+  };
+
+ private:
+  chromeos::PrinterPrefManager* prefs_;
+  std::unique_ptr<chromeos::printing::PpdProvider> ppd_provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrinterBackendProxyChromeos);
+};
+
+}  // namespace
+
+std::unique_ptr<PrinterBackendProxy> PrinterBackendProxy::Create(
+    Profile* profile) {
+  return base::MakeUnique<PrinterBackendProxyChromeos>(profile);
+}
+
 }  // namespace printing
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
index ce039907..0a1b1ab 100644
--- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -15,6 +15,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
 #include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/profiles/profile.h"
@@ -80,13 +81,7 @@
     : printer_discoverer_(nullptr),
       profile_(Profile::FromWebUI(webui)),
       weak_factory_(this) {
-  base::FilePath ppd_cache_path =
-      profile_->GetPath().Append(FILE_PATH_LITERAL("PPDCache"));
-  ppd_provider_ = chromeos::printing::PpdProvider::Create(
-      google_apis::GetAPIKey(), g_browser_process->system_request_context(),
-      content::BrowserThread::GetTaskRunnerForThread(
-          content::BrowserThread::FILE),
-      chromeos::printing::PpdCache::Create(ppd_cache_path));
+  ppd_provider_ = printing::CreateProvider(profile_);
 }
 
 CupsPrintersHandler::~CupsPrintersHandler() {}
diff --git a/chrome/browser/win/enumerate_modules_model.cc b/chrome/browser/win/enumerate_modules_model.cc
index 98aaffa..9b3ceff 100644
--- a/chrome/browser/win/enumerate_modules_model.cc
+++ b/chrome/browser/win/enumerate_modules_model.cc
@@ -518,6 +518,7 @@
 
 void ModuleEnumerator::ScanImplFinish() {
   // TODO(chrisha): Annotate any modules that are suspicious/bad.
+  AnnotateBadModules();
 
   ReportThirdPartyMetrics();
 
@@ -694,6 +695,19 @@
   }
 }
 
+void ModuleEnumerator::AnnotateBadModules() {
+  for (auto& module : *enumerated_modules_) {
+    if (module.name == L"rapportnikko.dll") {
+      base::Version version(base::UTF16ToASCII(module.version));
+      base::Version good("3.6");
+      if (version.CompareTo(good) < 0) {
+        module.status = ModuleStatus::CONFIRMED_BAD;
+        module.recommended_action = RecommendedAction::UNINSTALL;
+      }
+    }
+  }
+}
+
 void ModuleEnumerator::ReportThirdPartyMetrics() {
   static const wchar_t kMicrosoft[] = L"Microsoft ";
   static const wchar_t kGoogle[] = L"Google Inc";
diff --git a/chrome/browser/win/enumerate_modules_model.h b/chrome/browser/win/enumerate_modules_model.h
index 6a1265b8f..f76ea06a 100644
--- a/chrome/browser/win/enumerate_modules_model.h
+++ b/chrome/browser/win/enumerate_modules_model.h
@@ -221,6 +221,9 @@
   // based on the |path_mapping_| vector.
   void CollapsePath(Module* module);
 
+  // Annotate any known third party modules with actions the user can take.
+  void AnnotateBadModules();
+
   // Reports (via UMA) a handful of high-level metrics regarding third party
   // modules in this process. Called by ScanImplFinish.
   void ReportThirdPartyMetrics();
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 04327aca..d7f635d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4514,8 +4514,6 @@
         "../browser/ui/cocoa/bubble_view_unittest.mm",
         "../browser/ui/cocoa/chrome_browser_window_unittest.mm",
         "../browser/ui/cocoa/clickhold_button_cell_unittest.mm",
-        "../browser/ui/cocoa/cocoa_profile_test.h",
-        "../browser/ui/cocoa/cocoa_profile_test.mm",
         "../browser/ui/cocoa/confirm_bubble_controller_unittest.mm",
         "../browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm",
         "../browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm",
@@ -4608,15 +4606,12 @@
         "../browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm",
         "../browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm",
         "../browser/ui/cocoa/profiles/user_manager_mac_unittest.mm",
-        "../browser/ui/cocoa/run_loop_testing_unittest.mm",
         "../browser/ui/cocoa/screen_capture_notification_ui_cocoa_unittest.mm",
         "../browser/ui/cocoa/spinner_view_unittest.mm",
         "../browser/ui/cocoa/sprite_view_unittest.mm",
         "../browser/ui/cocoa/status_bubble_mac_unittest.mm",
         "../browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm",
         "../browser/ui/cocoa/styled_text_field_cell_unittest.mm",
-        "../browser/ui/cocoa/styled_text_field_test_helper.h",
-        "../browser/ui/cocoa/styled_text_field_test_helper.mm",
         "../browser/ui/cocoa/styled_text_field_unittest.mm",
         "../browser/ui/cocoa/tab_contents/sad_tab_mac_unittest.mm",
         "../browser/ui/cocoa/tabs/alert_indicator_button_cocoa_unittest.mm",
@@ -4624,6 +4619,11 @@
         "../browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm",
         "../browser/ui/cocoa/tabs/tab_strip_view_unittest.mm",
         "../browser/ui/cocoa/tabs/tab_view_unittest.mm",
+        "../browser/ui/cocoa/test/cocoa_profile_test.h",
+        "../browser/ui/cocoa/test/cocoa_profile_test.mm",
+        "../browser/ui/cocoa/test/run_loop_testing_unittest.mm",
+        "../browser/ui/cocoa/test/styled_text_field_test_helper.h",
+        "../browser/ui/cocoa/test/styled_text_field_test_helper.mm",
         "../browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm",
         "../browser/ui/cocoa/toolbar/reload_button_unittest.mm",
         "../browser/ui/cocoa/toolbar/toolbar_button_unittest.mm",
diff --git a/chrome/test/base/mash_browser_tests_main.cc b/chrome/test/base/mash_browser_tests_main.cc
index daea62c6..324f992 100644
--- a/chrome/test/base/mash_browser_tests_main.cc
+++ b/chrome/test/base/mash_browser_tests_main.cc
@@ -24,9 +24,8 @@
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/service_runner.h"
+#include "services/service_manager/public/cpp/standalone_service/standalone_service.h"
 #include "services/service_manager/runner/common/switches.h"
-#include "services/service_manager/runner/host/child_process.h"
-#include "services/service_manager/runner/host/child_process_base.h"
 #include "services/service_manager/runner/init.h"
 
 namespace {
@@ -150,23 +149,11 @@
     base::AtExitManager exit_manager;
 #endif
     base::i18n::InitializeICU();
-    service_manager::ChildProcessMainWithCallback(base::Bind(&StartChildApp));
+    service_manager::RunStandaloneService(base::Bind(&StartChildApp));
     *exit_code = 0;
     return true;
   }
 
-  if (command_line.HasSwitch(switches::kChildProcess) &&
-      !command_line.HasSwitch(MojoTestConnector::kTestSwitch)) {
-    base::AtExitManager at_exit;
-    service_manager::InitializeLogging();
-    service_manager::WaitForDebuggerIfNecessary();
-#if !defined(OFFICIAL_BUILD) && defined(OS_WIN)
-    base::RouteStdioToConsole(false);
-#endif
-    *exit_code = service_manager::ChildProcessMain();
-    return true;
-  }
-
   int default_jobs = std::max(1, base::SysInfo::NumberOfProcessors() / 2);
   MashTestLauncherDelegate delegate;
   // --single_process and no primoridal pipe token indicate we were run directly
diff --git a/chrome/test/base/mojo_test_connector.cc b/chrome/test/base/mojo_test_connector.cc
index 0e41bc307f..3334cb5 100644
--- a/chrome/test/base/mojo_test_connector.cc
+++ b/chrome/test/base/mojo_test_connector.cc
@@ -214,8 +214,11 @@
       const service_manager::Identity& target,
       base::CommandLine* command_line) override {
     if (target.name() != kTestName) {
-      if (target.name() == kTestRunnerName)
+      if (target.name() == kTestRunnerName) {
         RemoveMashFromBrowserTests(command_line);
+        command_line->SetProgram(
+            base::CommandLine::ForCurrentProcess()->GetProgram());
+      }
       command_line->AppendSwitch(MojoTestConnector::kMashApp);
       return;
     }
diff --git a/chrome/test/chromedriver/chrome/version.cc b/chrome/test/chromedriver/chrome/version.cc
index 1d92fcc..a401b67 100644
--- a/chrome/test/chromedriver/chrome/version.cc
+++ b/chrome/test/chromedriver/chrome/version.cc
@@ -9,7 +9,7 @@
 namespace {
 
 // This variable must be able to be found and parsed by the upload script.
-const int kMinimumSupportedChromeVersion[] = {53, 0, 2785, 0};
+const int kMinimumSupportedChromeVersion[] = {54, 0, 2840, 0};
 
 }  // namespace
 
diff --git a/chrome/test/chromedriver/test/run_all_tests.py b/chrome/test/chromedriver/test/run_all_tests.py
index a2556d3..3d4d877 100755
--- a/chrome/test/chromedriver/test/run_all_tests.py
+++ b/chrome/test/chromedriver/test/run_all_tests.py
@@ -193,15 +193,15 @@
       # Linux32 builds need to be special-cased, because 1) they are keyed by
       # git hash rather than commit position, and 2) come from a different
       # download site (so we can't just convert the commit position to a hash).
+      versions['56'] = '67002b0fdaa3123f10f96fa2f7965677d531db74'
       versions['55'] = 'e9bc4e0245c9a1e570ed2cf8e12152b9122275f2'
       versions['54'] = '13d140acdaa710770f42790044825b49f99e466c'
-      versions['53'] = 'ac799c2fd50b8fb62b7a8186ff78b025de5b8718'
       # TODO(samuong): speculative fix for crbug.com/611886
       os.environ['CHROME_DEVEL_SANDBOX'] = '/opt/chromium/chrome_sandbox'
     else:
+      versions['56'] = '433020'
       versions['55'] = '423791'
       versions['54'] = '414545'
-      versions['53'] = '403392'
     code = 0
     for version, revision in versions.iteritems():
       if options.chrome_version and version != options.chrome_version:
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index 8886736..3c1d9b3c 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -35,6 +35,10 @@
 #include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/os_crypt/os_crypt.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/model/metadata_batch.h"
+#include "components/sync/protocol/entity_metadata.pb.h"
+#include "components/sync/protocol/model_type_state.pb.h"
 #include "components/webdata/common/web_database.h"
 #include "sql/statement.h"
 #include "sql/transaction.h"
@@ -416,7 +420,8 @@
           InitProfilePhonesTable() && InitProfileTrashTable() &&
           InitMaskedCreditCardsTable() && InitUnmaskedCreditCardsTable() &&
           InitServerCardMetadataTable() && InitServerAddressesTable() &&
-          InitServerAddressMetadataTable());
+          InitServerAddressMetadataTable() && InitAutofillSyncMetadataTable() &&
+          InitModelTypeStateTable());
 }
 
 bool AutofillTable::IsSyncable() {
@@ -463,6 +468,9 @@
     case 67:
       *update_compatible_version = false;
       return MigrateToVersion67AddMaskedCardBillingAddress();
+    case 70:
+      *update_compatible_version = false;
+      return MigrateToVersion70AddSyncMetadata();
   }
   return true;
 }
@@ -1680,6 +1688,122 @@
   return s.Step();
 }
 
+bool AutofillTable::GetAllSyncMetadata(syncer::ModelType model_type,
+                                       syncer::MetadataBatch* metadata_batch) {
+  DCHECK_EQ(model_type, syncer::AUTOFILL)
+      << "Only the AUTOFILL model type is supported";
+  syncer::EntityMetadataMap metadata_records;
+  if (GetAllSyncEntityMetadata(model_type, &metadata_records)) {
+    for (const auto& pair : metadata_records) {
+      // todo(pnoland): add batch transfer of metadata map
+      metadata_batch->AddMetadata(pair.first, pair.second);
+    }
+  } else {
+    return false;
+  }
+
+  sync_pb::ModelTypeState model_type_state;
+  if (GetModelTypeState(model_type, &model_type_state)) {
+    metadata_batch->SetModelTypeState(model_type_state);
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+bool AutofillTable::GetAllSyncEntityMetadata(
+    syncer::ModelType model_type,
+    syncer::EntityMetadataMap* metadata_records) {
+  DCHECK_EQ(model_type, syncer::AUTOFILL)
+      << "Only the AUTOFILL model type is supported";
+
+  sql::Statement s(db_->GetUniqueStatement(
+      "SELECT storage_key, value FROM autofill_sync_metadata"));
+
+  while (s.Step()) {
+    std::string storage_key = s.ColumnString(0);
+    std::string serialized_metadata = s.ColumnString(1);
+    sync_pb::EntityMetadata metadata_record;
+    if (metadata_record.ParseFromString(serialized_metadata)) {
+      metadata_records->insert(std::make_pair(storage_key, metadata_record));
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool AutofillTable::UpdateSyncMetadata(
+    syncer::ModelType model_type,
+    const std::string& storage_key,
+    const sync_pb::EntityMetadata& metadata) {
+  DCHECK_EQ(model_type, syncer::AUTOFILL)
+      << "Only the AUTOFILL model type is supported";
+
+  sql::Statement s(
+      db_->GetUniqueStatement("INSERT OR REPLACE INTO autofill_sync_metadata "
+                              "(storage_key, value) VALUES(?, ?)"));
+  s.BindString(0, storage_key);
+  s.BindString(1, metadata.SerializeAsString());
+
+  return s.Run();
+}
+
+bool AutofillTable::ClearSyncMetadata(syncer::ModelType model_type,
+                                      const std::string& storage_key) {
+  DCHECK_EQ(model_type, syncer::AUTOFILL)
+      << "Only the AUTOFILL model type is supported";
+
+  sql::Statement s(db_->GetUniqueStatement(
+      "DELETE FROM autofill_sync_metadata WHERE storage_key=?"));
+  s.BindString(0, storage_key);
+
+  return s.Run();
+}
+
+bool AutofillTable::GetModelTypeState(syncer::ModelType model_type,
+                                      sync_pb::ModelTypeState* state) {
+  DCHECK_EQ(model_type, syncer::AUTOFILL)
+      << "Only the AUTOFILL model type is supported";
+
+  sql::Statement s(db_->GetUniqueStatement(
+      "SELECT value FROM autofill_model_type_state WHERE id=1"));
+
+  if (!s.Step()) {
+    return false;
+  }
+
+  std::string serialized_state = s.ColumnString(0);
+  return state->ParseFromString(serialized_state);
+}
+
+bool AutofillTable::UpdateModelTypeState(
+    syncer::ModelType model_type,
+    const sync_pb::ModelTypeState& model_type_state) {
+  DCHECK_EQ(model_type, syncer::AUTOFILL)
+      << "Only the AUTOFILL model type is supported";
+
+  // Hardcode the id to force a collision, ensuring that there remains only a
+  // single entry.
+  sql::Statement s(db_->GetUniqueStatement(
+      "INSERT OR REPLACE INTO autofill_model_type_state (id, value) "
+      "VALUES(1,?)"));
+  s.BindString(0, model_type_state.SerializeAsString());
+
+  return s.Run();
+}
+
+bool AutofillTable::ClearModelTypeState(syncer::ModelType model_type) {
+  DCHECK_EQ(model_type, syncer::AUTOFILL)
+      << "Only the AUTOFILL model type is supported";
+
+  sql::Statement s(db_->GetUniqueStatement(
+      "DELETE FROM autofill_model_type_state WHERE id=1"));
+
+  return s.Run();
+}
+
 bool AutofillTable::InitMainTable() {
   if (!db_->DoesTableExist("autofill")) {
     if (!db_->Execute("CREATE TABLE autofill ("
@@ -1879,6 +2003,29 @@
   return true;
 }
 
+bool AutofillTable::InitAutofillSyncMetadataTable() {
+  if (!db_->DoesTableExist("autofill_sync_metadata")) {
+    if (!db_->Execute("CREATE TABLE autofill_sync_metadata ("
+                      "storage_key VARCHAR PRIMARY KEY NOT NULL,"
+                      "value BLOB)")) {
+      NOTREACHED();
+      return false;
+    }
+  }
+  return true;
+}
+
+bool AutofillTable::InitModelTypeStateTable() {
+  if (!db_->DoesTableExist("autofill_model_type_state")) {
+    if (!db_->Execute("CREATE TABLE autofill_model_type_state (id INTEGER "
+                      "PRIMARY KEY, value BLOB)")) {
+      NOTREACHED();
+      return false;
+    }
+  }
+  return true;
+}
+
 bool AutofillTable::MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields() {
   sql::Transaction transaction(db_);
   if (!transaction.Begin())
@@ -2315,4 +2462,15 @@
       "ALTER TABLE masked_credit_cards ADD COLUMN billing_address_id VARCHAR");
 }
 
-}  // namespace autofill
+bool AutofillTable::MigrateToVersion70AddSyncMetadata() {
+  if (!db_->Execute("CREATE TABLE autofill_sync_metadata ("
+                    "storage_key VARCHAR PRIMARY KEY NOT NULL,"
+                    "value BLOB)")) {
+    return false;
+  }
+  return db_->Execute(
+      "CREATE TABLE autofill_model_type_state (id INTEGER PRIMARY KEY, value "
+      "BLOB)");
+}
+
+}  // namespace autofill
\ No newline at end of file
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h
index a8eceb0a..e223d5c 100644
--- a/components/autofill/core/browser/webdata/autofill_table.h
+++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -13,6 +13,8 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/model/metadata_batch.h"
 #include "components/webdata/common/web_database_table.h"
 
 class WebDatabase;
@@ -21,6 +23,11 @@
 class Time;
 }
 
+namespace sync_pb {
+class EntityMetadata;
+class ModelTypeState;
+}
+
 namespace autofill {
 
 class AutofillChange;
@@ -228,6 +235,18 @@
 //                      a form.
 //   use_date           The date this address was last used to fill a form,
 //                      in internal t.
+// autofill_sync_metadata
+//                      Sync-specific metadata for autofill records.
+//
+//   storage_key        A string that uniquely identifies the metadata record
+//                      as well as the corresponding autofill record.
+//   value              The serialized EntityMetadata record.
+//
+// autofill_model_type_state
+//                      Single row table that contains the sync ModelTypeState
+//                      for the autofill model type.
+//
+//   value              The serialized ModelTypeState record.
 
 class AutofillTable : public WebDatabaseTable {
  public:
@@ -403,6 +422,28 @@
   // Clear all profiles.
   bool ClearAutofillProfiles();
 
+  // Read all the stored metadata for |model_type| and fill |metadata_batch|
+  // with it.
+  bool GetAllSyncMetadata(syncer::ModelType model_type,
+                          syncer::MetadataBatch* metadata_batch);
+
+  // Update the metadata row for |model_type|, keyed by |storage_key|, to
+  // contain the contents of |metadata|.
+  bool UpdateSyncMetadata(syncer::ModelType model_type,
+                          const std::string& storage_key,
+                          const sync_pb::EntityMetadata& metadata);
+
+  // Remove the metadata row of type |model_type| keyed by |storage|key|.
+  bool ClearSyncMetadata(syncer::ModelType model_type,
+                         const std::string& storage_key);
+
+  // Update the stored sync state for the |model_type|.
+  bool UpdateModelTypeState(syncer::ModelType model_type,
+                            const sync_pb::ModelTypeState& model_type_state);
+
+  // Clear the stored sync state for |model_type|.
+  bool ClearModelTypeState(syncer::ModelType model_type);
+
   // Table migration functions. NB: These do not and should not rely on other
   // functions in this class. The implementation of a function such as
   // GetCreditCard may change over time, but MigrateToVersionXX should never
@@ -419,6 +460,7 @@
   bool MigrateToVersion65AddServerMetadataTables();
   bool MigrateToVersion66AddCardBillingAddress();
   bool MigrateToVersion67AddMaskedCardBillingAddress();
+  bool MigrateToVersion70AddSyncMetadata();
 
   // Max data length saved in the table, AKA the maximum length allowed for
   // form data.
@@ -474,6 +516,12 @@
                              std::vector<AutofillChange>* changes,
                              base::Time time);
 
+  bool GetAllSyncEntityMetadata(syncer::ModelType model_type,
+                                syncer::EntityMetadataMap* metadata_records);
+
+  bool GetModelTypeState(syncer::ModelType model_type,
+                         sync_pb::ModelTypeState* state);
+
   // Insert a single AutofillEntry into the autofill table.
   bool InsertAutofillEntry(const AutofillEntry& entry);
 
@@ -496,6 +544,8 @@
   bool InitServerCardMetadataTable();
   bool InitServerAddressesTable();
   bool InitServerAddressMetadataTable();
+  bool InitAutofillSyncMetadataTable();
+  bool InitModelTypeStateTable();
 
   DISALLOW_COPY_AND_ASSIGN(AutofillTable);
 };
diff --git a/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index 18277b1..baf9bd9a 100644
--- a/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -35,6 +35,8 @@
 #include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/os_crypt/os_crypt_mocker.h"
+#include "components/sync/protocol/entity_metadata.pb.h"
+#include "components/sync/protocol/model_type_state.pb.h"
 #include "components/webdata/common/web_database.h"
 #include "sql/statement.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -2016,4 +2018,90 @@
   }
 }
 
+TEST_F(AutofillTableTest, GetAllSyncMetadata) {
+  sync_pb::EntityMetadata metadata;
+  std::string storage_key = "storage_key";
+  std::string storage_key2 = "storage_key2";
+  metadata.set_sequence_number(1);
+
+  EXPECT_TRUE(
+      table_->UpdateSyncMetadata(syncer::AUTOFILL, storage_key, metadata));
+
+  sync_pb::ModelTypeState model_type_state;
+  model_type_state.set_initial_sync_done(true);
+
+  EXPECT_TRUE(table_->UpdateModelTypeState(syncer::AUTOFILL, model_type_state));
+
+  metadata.set_sequence_number(2);
+  EXPECT_TRUE(
+      table_->UpdateSyncMetadata(syncer::AUTOFILL, storage_key2, metadata));
+
+  syncer::MetadataBatch metadata_batch;
+  EXPECT_TRUE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
+
+  EXPECT_TRUE(metadata_batch.GetModelTypeState().initial_sync_done());
+
+  syncer::EntityMetadataMap metadata_records = metadata_batch.TakeAllMetadata();
+
+  EXPECT_EQ(metadata_records.size(), 2u);
+  EXPECT_EQ(metadata_records[storage_key].sequence_number(), 1);
+  EXPECT_EQ(metadata_records[storage_key2].sequence_number(), 2);
+
+  // Now check that a model type state update replaces the old value
+  model_type_state.set_initial_sync_done(false);
+  EXPECT_TRUE(table_->UpdateModelTypeState(syncer::AUTOFILL, model_type_state));
+
+  EXPECT_TRUE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
+  EXPECT_FALSE(metadata_batch.GetModelTypeState().initial_sync_done());
+}
+
+TEST_F(AutofillTableTest, WriteThenDeleteSyncMetadata) {
+  sync_pb::EntityMetadata metadata;
+  syncer::MetadataBatch metadata_batch;
+  std::string storage_key = "storage_key";
+  sync_pb::ModelTypeState model_type_state;
+
+  model_type_state.set_initial_sync_done(true);
+
+  metadata.set_client_tag_hash("client_hash");
+
+  // Write the data into the store.
+  EXPECT_TRUE(
+      table_->UpdateSyncMetadata(syncer::AUTOFILL, storage_key, metadata));
+  EXPECT_TRUE(table_->UpdateModelTypeState(syncer::AUTOFILL, model_type_state));
+  // Delete the data we just wrote.
+  EXPECT_TRUE(table_->ClearSyncMetadata(syncer::AUTOFILL, storage_key));
+  // It shouldn't be there any more.
+  EXPECT_TRUE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
+
+  syncer::EntityMetadataMap metadata_records = metadata_batch.TakeAllMetadata();
+  EXPECT_EQ(metadata_records.size(), 0u);
+
+  // Now delete the model type state.
+  EXPECT_TRUE(table_->ClearModelTypeState(syncer::AUTOFILL));
+  EXPECT_FALSE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
+}
+
+TEST_F(AutofillTableTest, CorruptSyncMetadata) {
+  syncer::MetadataBatch metadata_batch;
+  sync_pb::ModelTypeState state;
+  std::string storage_key = "storage_key";
+
+  sql::Statement s(db_->GetSQLConnection()->GetUniqueStatement(
+      "INSERT OR REPLACE INTO autofill_sync_metadata "
+      "(storage_key, value) VALUES(?, ?)"));
+  s.BindString(0, storage_key);
+  s.BindString(1, "unparseable");
+
+  sql::Statement s2(db_->GetSQLConnection()->GetUniqueStatement(
+      "INSERT OR REPLACE INTO autofill_model_type_state "
+      "(rowid, value) VALUES(1, ?)"));
+  s2.BindString(0, "unparseable");
+
+  EXPECT_TRUE(s.Run());
+  EXPECT_TRUE(s2.Run());
+
+  EXPECT_FALSE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
+}
+
 }  // namespace autofill
diff --git a/components/browser_sync/abstract_profile_sync_service_test.cc b/components/browser_sync/abstract_profile_sync_service_test.cc
index c8f79d70..e486261 100644
--- a/components/browser_sync/abstract_profile_sync_service_test.cc
+++ b/components/browser_sync/abstract_profile_sync_service_test.cc
@@ -44,10 +44,6 @@
   void RequestConfigureSyncer(
       syncer::ConfigureReason reason,
       syncer::ModelTypeSet to_download,
-      syncer::ModelTypeSet to_purge,
-      syncer::ModelTypeSet to_journal,
-      syncer::ModelTypeSet to_unapply,
-      syncer::ModelTypeSet to_ignore,
       const syncer::ModelSafeRoutingInfo& routing_info,
       const base::Callback<void(syncer::ModelTypeSet, syncer::ModelTypeSet)>&
           ready_task,
@@ -107,10 +103,6 @@
 void SyncEngineForProfileSyncTest::RequestConfigureSyncer(
     syncer::ConfigureReason reason,
     syncer::ModelTypeSet to_download,
-    syncer::ModelTypeSet to_purge,
-    syncer::ModelTypeSet to_journal,
-    syncer::ModelTypeSet to_unapply,
-    syncer::ModelTypeSet to_ignore,
     const syncer::ModelSafeRoutingInfo& routing_info,
     const base::Callback<void(syncer::ModelTypeSet, syncer::ModelTypeSet)>&
         ready_task,
diff --git a/components/browser_watcher/BUILD.gn b/components/browser_watcher/BUILD.gn
index fede06b9..5d64eed 100644
--- a/components/browser_watcher/BUILD.gn
+++ b/components/browser_watcher/BUILD.gn
@@ -83,6 +83,13 @@
   ]
 }
 
+static_library("stability_data") {
+  sources = [
+    "stability_data_names.cc",
+    "stability_data_names.h",
+  ]
+}
+
 source_set("unit_tests") {
   testonly = true
   sources = [
diff --git a/components/browser_watcher/stability_data_names.cc b/components/browser_watcher/stability_data_names.cc
new file mode 100644
index 0000000..b227065
--- /dev/null
+++ b/components/browser_watcher/stability_data_names.cc
@@ -0,0 +1,15 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/browser_watcher/stability_data_names.h"
+
+namespace browser_watcher {
+
+const char kStabilityChannel[] = "channel";
+const char kStabilityPlatform[] = "platform";
+const char kStabilityProduct[] = "product";
+const char kStabilitySpecialBuild[] = "special-build";
+const char kStabilityVersion[] = "version";
+
+}  // namespace browser_watcher
diff --git a/components/browser_watcher/stability_data_names.h b/components/browser_watcher/stability_data_names.h
new file mode 100644
index 0000000..9c7cfc15
--- /dev/null
+++ b/components/browser_watcher/stability_data_names.h
@@ -0,0 +1,19 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_BROWSER_WATCHER_STABILITY_DATA_NAMES_H_
+#define COMPONENTS_BROWSER_WATCHER_STABILITY_DATA_NAMES_H_
+
+namespace browser_watcher {
+
+// Alphabetical list of stability data names.
+extern const char kStabilityChannel[];
+extern const char kStabilityPlatform[];
+extern const char kStabilityProduct[];
+extern const char kStabilitySpecialBuild[];
+extern const char kStabilityVersion[];
+
+}  // namespace browser_watcher
+
+#endif  // COMPONENTS_BROWSER_WATCHER_STABILITY_DATA_NAMES_H_
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 3e2fc4ae..09758654 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -9,6 +9,10 @@
   sources = [
     "buffer.cc",
     "buffer.h",
+    "compositor_frame_sink.cc",
+    "compositor_frame_sink.h",
+    "compositor_frame_sink_holder.cc",
+    "compositor_frame_sink_holder.h",
     "display.cc",
     "display.h",
     "gamepad.cc",
@@ -154,6 +158,7 @@
     "//base",
     "//base/test:test_support",
     "//device/gamepad:test_helpers",
+    "//mojo/edk/embedder:headers",
   ]
 
   data_deps = [
diff --git a/components/exo/DEPS b/components/exo/DEPS
index 6eb071a..17b1c94c 100644
--- a/components/exo/DEPS
+++ b/components/exo/DEPS
@@ -4,8 +4,15 @@
   "+chromeos/audio/chromeos_sounds.h",
   "+device/gamepad",
   "+gpu",
+  "+mojo/public/cpp",
   "+services/ui/public/cpp",
   "+third_party/khronos",
   "+third_party/skia",
   "+ui",
 ]
+
+specific_include_rules = {
+  "run_all_unittests\.cc": [
+    "+mojo/edk/embedder/embedder.h",
+  ],
+}
diff --git a/components/exo/compositor_frame_sink.cc b/components/exo/compositor_frame_sink.cc
new file mode 100644
index 0000000..9d4ab95
--- /dev/null
+++ b/components/exo/compositor_frame_sink.cc
@@ -0,0 +1,101 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/compositor_frame_sink.h"
+
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_manager.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace exo {
+
+////////////////////////////////////////////////////////////////////////////////
+// ExoComopositorFrameSink, public:
+
+// static
+void CompositorFrameSink::Create(
+    const cc::FrameSinkId& frame_sink_id,
+    cc::SurfaceManager* surface_manager,
+    cc::mojom::MojoCompositorFrameSinkClientPtr client,
+    cc::mojom::MojoCompositorFrameSinkRequest request) {
+  std::unique_ptr<CompositorFrameSink> impl =
+      base::MakeUnique<CompositorFrameSink>(frame_sink_id, surface_manager,
+                                            std::move(client));
+  CompositorFrameSink* compositor_frame_sink = impl.get();
+  compositor_frame_sink->binding_ =
+      mojo::MakeStrongBinding(std::move(impl), std::move(request));
+}
+
+CompositorFrameSink::CompositorFrameSink(
+    const cc::FrameSinkId& frame_sink_id,
+    cc::SurfaceManager* surface_manager,
+    cc::mojom::MojoCompositorFrameSinkClientPtr client)
+    : support_(this, surface_manager, frame_sink_id, nullptr),
+      client_(std::move(client)) {}
+
+CompositorFrameSink::~CompositorFrameSink() {}
+
+////////////////////////////////////////////////////////////////////////////////
+// cc::mojom::MojoCompositorFrameSink overrides:
+
+void CompositorFrameSink::SetNeedsBeginFrame(bool needs_begin_frame) {
+  support_.SetNeedsBeginFrame(needs_begin_frame);
+}
+
+void CompositorFrameSink::SubmitCompositorFrame(
+    const cc::LocalFrameId& local_frame_id,
+    cc::CompositorFrame frame) {
+  support_.SubmitCompositorFrame(local_frame_id, std::move(frame));
+}
+
+void CompositorFrameSink::AddSurfaceReferences(
+    const std::vector<cc::SurfaceReference>& references) {
+  // TODO(fsamuel, staraz): Implement this.
+  NOTIMPLEMENTED();
+}
+
+void CompositorFrameSink::RemoveSurfaceReferences(
+    const std::vector<cc::SurfaceReference>& references) {
+  // TODO(fsamuel, staraz): Implement this.
+  NOTIMPLEMENTED();
+}
+
+void CompositorFrameSink::EvictFrame() {
+  support_.EvictFrame();
+}
+
+void CompositorFrameSink::Require(const cc::LocalFrameId& local_frame_id,
+                                  const cc::SurfaceSequence& sequence) {
+  support_.Require(local_frame_id, sequence);
+}
+
+void CompositorFrameSink::Satisfy(const cc::SurfaceSequence& sequence) {
+  support_.Satisfy(sequence);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// cc::CompositorFrameSinkSupportClient overrides:
+
+void CompositorFrameSink::DidReceiveCompositorFrameAck() {
+  if (client_)
+    client_->DidReceiveCompositorFrameAck();
+}
+
+void CompositorFrameSink::OnBeginFrame(const cc::BeginFrameArgs& args) {
+  if (client_)
+    client_->OnBeginFrame(args);
+}
+
+void CompositorFrameSink::ReclaimResources(
+    const cc::ReturnedResourceArray& resources) {
+  if (client_)
+    client_->ReclaimResources(resources);
+}
+
+void CompositorFrameSink::WillDrawSurface() {
+  if (client_)
+    client_->WillDrawSurface();
+}
+
+}  // namespace exo
diff --git a/components/exo/compositor_frame_sink.h b/components/exo/compositor_frame_sink.h
new file mode 100644
index 0000000..4eace4b
--- /dev/null
+++ b/components/exo/compositor_frame_sink.h
@@ -0,0 +1,61 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_EXO_EXO_COMPOSITOR_FRAME_SINK_H_
+#define COMPONENTS_EXO_EXO_COMPOSITOR_FRAME_SINK_H_
+
+#include "cc/ipc/compositor_frame.mojom.h"
+#include "cc/ipc/mojo_compositor_frame_sink.mojom.h"
+#include "cc/resources/transferable_resource.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
+#include "cc/surfaces/compositor_frame_sink_support_client.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace exo {
+
+class CompositorFrameSink : public cc::CompositorFrameSinkSupportClient,
+                            public cc::mojom::MojoCompositorFrameSink {
+ public:
+  static void Create(const cc::FrameSinkId& frame_sink_id,
+                     cc::SurfaceManager* surface_manager,
+                     cc::mojom::MojoCompositorFrameSinkClientPtr client,
+                     cc::mojom::MojoCompositorFrameSinkRequest request);
+
+  CompositorFrameSink(const cc::FrameSinkId& frame_sink_id,
+                      cc::SurfaceManager* surface_manager,
+                      cc::mojom::MojoCompositorFrameSinkClientPtr client);
+
+  ~CompositorFrameSink() override;
+
+  // Overridden from cc::mojom::MojoCompositorFrameSink:
+  void SetNeedsBeginFrame(bool needs_begin_frame) override;
+  void SubmitCompositorFrame(const cc::LocalFrameId& local_frame_id,
+                             cc::CompositorFrame frame) override;
+  void AddSurfaceReferences(
+      const std::vector<cc::SurfaceReference>& references) override;
+  void RemoveSurfaceReferences(
+      const std::vector<cc::SurfaceReference>& references) override;
+  void EvictFrame() override;
+  void Require(const cc::LocalFrameId& local_frame_id,
+               const cc::SurfaceSequence& sequence) override;
+  void Satisfy(const cc::SurfaceSequence& sequence) override;
+
+  // Overridden from cc::CompositorFrameSinkSupportClient:
+  void DidReceiveCompositorFrameAck() override;
+  void OnBeginFrame(const cc::BeginFrameArgs& args) override;
+  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void WillDrawSurface() override;
+
+ private:
+  cc::CompositorFrameSinkSupport support_;
+  cc::mojom::MojoCompositorFrameSinkClientPtr client_;
+  cc::ReturnedResourceArray surface_returned_resources_;
+  mojo::StrongBindingPtr<cc::mojom::MojoCompositorFrameSink> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorFrameSink);
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_EXO_COMPOSITOR_FRAME_SINK_H_
diff --git a/components/exo/compositor_frame_sink_holder.cc b/components/exo/compositor_frame_sink_holder.cc
new file mode 100644
index 0000000..dd82aff
--- /dev/null
+++ b/components/exo/compositor_frame_sink_holder.cc
@@ -0,0 +1,142 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/compositor_frame_sink_holder.h"
+
+#include "cc/resources/returned_resource.h"
+#include "components/exo/surface.h"
+
+namespace exo {
+
+////////////////////////////////////////////////////////////////////////////////
+// CompositorFrameSinkHolder, public:
+
+CompositorFrameSinkHolder::CompositorFrameSinkHolder(
+    Surface* surface,
+    std::unique_ptr<CompositorFrameSink> frame_sink,
+    cc::mojom::MojoCompositorFrameSinkClientRequest request)
+    : surface_(surface),
+      frame_sink_(std::move(frame_sink)),
+      begin_frame_source_(base::MakeUnique<cc::ExternalBeginFrameSource>(this)),
+      binding_(this, std::move(request)),
+      weak_factory_(this) {
+  surface_->AddSurfaceObserver(this);
+}
+
+bool CompositorFrameSinkHolder::HasReleaseCallbackForResource(
+    cc::ResourceId id) {
+  return release_callbacks_.find(id) != release_callbacks_.end();
+}
+
+void CompositorFrameSinkHolder::AddResourceReleaseCallback(
+    cc::ResourceId id,
+    std::unique_ptr<cc::SingleReleaseCallback> callback) {
+  release_callbacks_[id] = std::make_pair(this, std::move(callback));
+}
+
+void CompositorFrameSinkHolder::ActivateFrameCallbacks(
+    std::list<FrameCallback>* frame_callbacks) {
+  active_frame_callbacks_.splice(active_frame_callbacks_.end(),
+                                 *frame_callbacks);
+  UpdateNeedsBeginFrame();
+}
+
+void CompositorFrameSinkHolder::CancelFrameCallbacks() {
+  // Call pending frame callbacks with a null frame time to indicate that they
+  // have been cancelled.
+  for (const auto& frame_callback : active_frame_callbacks_)
+    frame_callback.Run(base::TimeTicks());
+}
+
+void CompositorFrameSinkHolder::SetNeedsBeginFrame(bool needs_begin_frame) {
+  needs_begin_frame_ = needs_begin_frame;
+  OnNeedsBeginFrames(needs_begin_frame);
+}
+
+void CompositorFrameSinkHolder::Satisfy(const cc::SurfaceSequence& sequence) {
+  frame_sink_->Satisfy(sequence);
+}
+
+void CompositorFrameSinkHolder::Require(const cc::SurfaceId& id,
+                                        const cc::SurfaceSequence& sequence) {
+  frame_sink_->Require(id.local_frame_id(), sequence);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// cc::mojom::MojoCompositorFrameSinkClient overrides:
+
+void CompositorFrameSinkHolder::DidReceiveCompositorFrameAck() {
+  // TODO(staraz): Implement this
+}
+
+void CompositorFrameSinkHolder::OnBeginFrame(const cc::BeginFrameArgs& args) {
+  while (!active_frame_callbacks_.empty()) {
+    active_frame_callbacks_.front().Run(args.frame_time);
+    active_frame_callbacks_.pop_front();
+  }
+  begin_frame_source_->OnBeginFrame(args);
+}
+
+void CompositorFrameSinkHolder::ReclaimResources(
+    const cc::ReturnedResourceArray& resources) {
+  for (auto& resource : resources) {
+    auto it = release_callbacks_.find(resource.id);
+    DCHECK(it != release_callbacks_.end());
+    std::unique_ptr<cc::SingleReleaseCallback> callback =
+        std::move(it->second.second);
+    release_callbacks_.erase(it);
+    callback->Run(resource.sync_token, resource.lost);
+  }
+}
+
+void CompositorFrameSinkHolder::WillDrawSurface() {
+  if (surface_)
+    surface_->WillDraw();
+
+  UpdateNeedsBeginFrame();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// cc::BeginFrameObserver overrides:
+
+const cc::BeginFrameArgs& CompositorFrameSinkHolder::LastUsedBeginFrameArgs()
+    const {
+  return last_begin_frame_args_;
+}
+
+void CompositorFrameSinkHolder::OnBeginFrameSourcePausedChanged(bool paused) {}
+
+////////////////////////////////////////////////////////////////////////////////
+// cc::ExternalBeginFrameSouceClient overrides:
+
+void CompositorFrameSinkHolder::OnNeedsBeginFrames(bool needs_begin_frames) {
+  frame_sink_->SetNeedsBeginFrame(needs_begin_frames);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SurfaceObserver overrides:
+
+void CompositorFrameSinkHolder::OnSurfaceDestroying(Surface* surface) {
+  surface_->RemoveSurfaceObserver(this);
+  surface_ = nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ExoComopositorFrameSink, private:
+
+CompositorFrameSinkHolder::~CompositorFrameSinkHolder() {}
+
+void CompositorFrameSinkHolder::UpdateNeedsBeginFrame() {
+  if (!begin_frame_source_)
+    return;
+
+  bool needs_begin_frame = !active_frame_callbacks_.empty();
+  if (needs_begin_frame == needs_begin_frame_)
+    return;
+
+  needs_begin_frame_ = needs_begin_frame;
+  OnNeedsBeginFrames(needs_begin_frame_);
+}
+
+}  // namespace exo
diff --git a/components/exo/compositor_frame_sink_holder.h b/components/exo/compositor_frame_sink_holder.h
new file mode 100644
index 0000000..59cc987
--- /dev/null
+++ b/components/exo/compositor_frame_sink_holder.h
@@ -0,0 +1,108 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_EXO_COMPOSITOR_FRAME_SINK_HOLDER_H_
+#define COMPONENTS_EXO_COMPOSITOR_FRAME_SINK_HOLDER_H_
+
+#include <list>
+#include <map>
+#include <memory>
+
+#include "cc/ipc/mojo_compositor_frame_sink.mojom.h"
+#include "cc/resources/single_release_callback.h"
+#include "cc/resources/transferable_resource.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "components/exo/compositor_frame_sink.h"
+#include "components/exo/surface_observer.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace exo {
+class Surface;
+
+// This class talks to MojoCompositorFrameSink and keeps track of references to
+// the contents of Buffers. It's keeped alive by references from
+// release_callbacks_. It's destroyed when its owning Surface is destroyed and
+// the last outstanding release callback is called.
+class CompositorFrameSinkHolder
+    : public base::RefCounted<CompositorFrameSinkHolder>,
+      public cc::ExternalBeginFrameSourceClient,
+      public cc::mojom::MojoCompositorFrameSinkClient,
+      public cc::BeginFrameObserver,
+      public SurfaceObserver {
+ public:
+  CompositorFrameSinkHolder(
+      Surface* surface,
+      std::unique_ptr<CompositorFrameSink> frame_sink,
+      cc::mojom::MojoCompositorFrameSinkClientRequest request);
+
+  bool HasReleaseCallbackForResource(cc::ResourceId id);
+  void AddResourceReleaseCallback(
+      cc::ResourceId id,
+      std::unique_ptr<cc::SingleReleaseCallback> callback);
+
+  CompositorFrameSink* GetCompositorFrameSink() { return frame_sink_.get(); }
+
+  base::WeakPtr<CompositorFrameSinkHolder> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
+
+  using FrameCallback = base::Callback<void(base::TimeTicks frame_time)>;
+  void ActivateFrameCallbacks(std::list<FrameCallback>* frame_callbacks);
+  void CancelFrameCallbacks();
+
+  void SetNeedsBeginFrame(bool needs_begin_frame);
+
+  void Satisfy(const cc::SurfaceSequence& sequence);
+  void Require(const cc::SurfaceId& id, const cc::SurfaceSequence& sequence);
+
+  // Overridden from cc::mojom::MojoCompositorFrameSinkClient:
+  void DidReceiveCompositorFrameAck() override;
+  void OnBeginFrame(const cc::BeginFrameArgs& args) override;
+  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void WillDrawSurface() override;
+
+  // Overridden from cc::BeginFrameObserver:
+  const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override;
+  void OnBeginFrameSourcePausedChanged(bool paused) override;
+
+  // Overridden from cc::ExternalBeginFrameSouceClient:
+  void OnNeedsBeginFrames(bool needs_begin_frames) override;
+
+  // Overridden from SurfaceObserver:
+  void OnSurfaceDestroying(Surface* surface) override;
+
+ private:
+  friend class base::RefCounted<CompositorFrameSinkHolder>;
+
+  ~CompositorFrameSinkHolder() override;
+
+  void UpdateNeedsBeginFrame();
+
+  // Each release callback holds a reference to the CompositorFrameSinkHolder
+  // itself to keep it alive. Running and erasing the callbacks might result in
+  // the instance being destroyed. Therefore, we should not access any member
+  // variables after running and erasing the callbacks.
+  using ResourceReleaseCallbackMap =
+      std::map<int,
+               std::pair<scoped_refptr<CompositorFrameSinkHolder>,
+                         std::unique_ptr<cc::SingleReleaseCallback>>>;
+  ResourceReleaseCallbackMap release_callbacks_;
+
+  Surface* surface_;
+  std::unique_ptr<CompositorFrameSink> frame_sink_;
+
+  std::list<FrameCallback> active_frame_callbacks_;
+  std::unique_ptr<cc::ExternalBeginFrameSource> begin_frame_source_;
+  bool needs_begin_frame_ = false;
+  cc::BeginFrameArgs last_begin_frame_args_;
+  mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> binding_;
+
+  base::WeakPtrFactory<CompositorFrameSinkHolder> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkHolder);
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_COMPOSITOR_FRAME_SINK_HOLDER_H_
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 8c5ed61..2c23fc3 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -18,9 +18,7 @@
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/resources/single_release_callback.h"
 #include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory.h"
 #include "cc/surfaces/surface_id_allocator.h"
-#include "cc/surfaces/surface_manager.h"
 #include "components/exo/buffer.h"
 #include "components/exo/surface_delegate.h"
 #include "components/exo/surface_observer.h"
@@ -141,73 +139,24 @@
   DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter);
 };
 
-void SatisfyCallback(cc::SurfaceManager* manager,
-                     const cc::SurfaceSequence& sequence) {
-  std::vector<uint32_t> sequences;
-  sequences.push_back(sequence.sequence);
-  manager->DidSatisfySequences(sequence.frame_sink_id, &sequences);
-}
-
-void RequireCallback(cc::SurfaceManager* manager,
-                     const cc::SurfaceId& id,
-                     const cc::SurfaceSequence& sequence) {
-  cc::Surface* surface = manager->GetSurfaceForId(id);
-  if (!surface) {
-    LOG(ERROR) << "Attempting to require callback on nonexistent surface";
-    return;
-  }
-  surface->AddDestructionDependency(sequence);
-}
-
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
-// SurfaceFactoryOwner, public:
-
-SurfaceFactoryOwner::SurfaceFactoryOwner() {}
-
-////////////////////////////////////////////////////////////////////////////////
-// cc::SurfaceFactoryClient overrides:
-
-void SurfaceFactoryOwner::ReturnResources(
-    const cc::ReturnedResourceArray& resources) {
-  scoped_refptr<SurfaceFactoryOwner> holder(this);
-  for (auto& resource : resources) {
-    auto it = release_callbacks_.find(resource.id);
-    DCHECK(it != release_callbacks_.end());
-    it->second.second->Run(resource.sync_token, resource.lost);
-    release_callbacks_.erase(it);
-  }
-}
-
-void SurfaceFactoryOwner::WillDrawSurface(const cc::LocalFrameId& id,
-                                          const gfx::Rect& damage_rect) {
-  if (surface_)
-    surface_->WillDraw();
-}
-
-void SurfaceFactoryOwner::SetBeginFrameSource(
-    cc::BeginFrameSource* begin_frame_source) {
-  if (surface_)
-    surface_->SetBeginFrameSource(begin_frame_source);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// SurfaceFactoryOwner, private:
-
-SurfaceFactoryOwner::~SurfaceFactoryOwner() {
-  if (surface_factory_->manager())
-    surface_factory_->manager()->InvalidateFrameSinkId(frame_sink_id_);
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // Surface, public:
 
 Surface::Surface()
     : window_(new aura::Window(new CustomWindowDelegate(this))),
-      surface_manager_(
-          aura::Env::GetInstance()->context_factory()->GetSurfaceManager()),
-      factory_owner_(new SurfaceFactoryOwner) {
+      frame_sink_id_(
+          aura::Env::GetInstance()->context_factory()->AllocateFrameSinkId()) {
+  cc::mojom::MojoCompositorFrameSinkClientPtr frame_sink_holder_ptr;
+  cc::mojom::MojoCompositorFrameSinkClientRequest frame_sink_client_request =
+      mojo::GetProxy(&frame_sink_holder_ptr);
+  std::unique_ptr<CompositorFrameSink> frame_sink(new CompositorFrameSink(
+      frame_sink_id_,
+      aura::Env::GetInstance()->context_factory()->GetSurfaceManager(),
+      std::move(frame_sink_holder_ptr)));
+  compositor_frame_sink_holder_ = new CompositorFrameSinkHolder(
+      this, std::move(frame_sink), std::move(frame_sink_client_request));
   window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
   window_->SetName("ExoSurface");
   window_->SetProperty(kSurfaceKey, this);
@@ -215,15 +164,6 @@
   window_->SetEventTargeter(base::WrapUnique(new CustomWindowTargeter));
   window_->set_owned_by_parent(false);
   window_->AddObserver(this);
-  factory_owner_->surface_ = this;
-  factory_owner_->frame_sink_id_ =
-      aura::Env::GetInstance()->context_factory()->AllocateFrameSinkId();
-  factory_owner_->id_allocator_.reset(new cc::SurfaceIdAllocator());
-  surface_manager_->RegisterFrameSinkId(factory_owner_->frame_sink_id_);
-  surface_manager_->RegisterSurfaceFactoryClient(factory_owner_->frame_sink_id_,
-                                                 factory_owner_.get());
-  factory_owner_->surface_factory_.reset(new cc::SurfaceFactory(
-      factory_owner_->frame_sink_id_, surface_manager_, factory_owner_.get()));
   aura::Env::GetInstance()->context_factory()->AddObserver(this);
 }
 
@@ -235,22 +175,11 @@
   window_->RemoveObserver(this);
   window_->layer()->SetShowSolidColorContent();
 
-  factory_owner_->surface_ = nullptr;
-
-  // Call pending frame callbacks with a null frame time to indicate that they
-  // have been cancelled.
   frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
-  active_frame_callbacks_.splice(active_frame_callbacks_.end(),
-                                 frame_callbacks_);
-  for (const auto& frame_callback : active_frame_callbacks_)
-    frame_callback.Run(base::TimeTicks());
-  if (begin_frame_source_ && needs_begin_frame_)
-    begin_frame_source_->RemoveObserver(this);
+  compositor_frame_sink_holder_->ActivateFrameCallbacks(&frame_callbacks_);
+  compositor_frame_sink_holder_->CancelFrameCallbacks();
 
-  factory_owner_->surface_factory_->EvictSurface();
-
-  surface_manager_->UnregisterSurfaceFactoryClient(
-      factory_owner_->frame_sink_id_);
+  compositor_frame_sink_holder_->GetCompositorFrameSink()->EvictFrame();
 }
 
 // static
@@ -259,7 +188,7 @@
 }
 
 cc::SurfaceId Surface::GetSurfaceId() const {
-  return cc::SurfaceId(factory_owner_->frame_sink_id_, local_frame_id_);
+  return cc::SurfaceId(frame_sink_id_, local_frame_id_);
 }
 
 void Surface::Attach(Buffer* buffer) {
@@ -476,7 +405,7 @@
   cc::LocalFrameId old_local_frame_id = local_frame_id_;
   if (needs_commit_to_new_surface_ || !local_frame_id_.is_valid()) {
     needs_commit_to_new_surface_ = false;
-    local_frame_id_ = factory_owner_->id_allocator_->GenerateId();
+    local_frame_id_ = id_allocator_.GenerateId();
   }
 
   UpdateSurface(true);
@@ -489,9 +418,11 @@
     window_->layer()->SetBounds(
         gfx::Rect(window_->layer()->bounds().origin(), content_size_));
     window_->layer()->SetShowSurface(
-        cc::SurfaceId(factory_owner_->frame_sink_id_, local_frame_id_),
-        base::Bind(&SatisfyCallback, base::Unretained(surface_manager_)),
-        base::Bind(&RequireCallback, base::Unretained(surface_manager_)),
+        cc::SurfaceId(frame_sink_id_, local_frame_id_),
+        base::Bind(&CompositorFrameSinkHolder::Satisfy,
+                   compositor_frame_sink_holder_),
+        base::Bind(&CompositorFrameSinkHolder::Require,
+                   compositor_frame_sink_holder_),
         content_size_, contents_surface_to_layer_scale, content_size_);
     window_->layer()->SetFillsBoundsOpaquely(
         state_.blend_mode == SkBlendMode::kSrc ||
@@ -503,7 +434,8 @@
   pending_damage_.setEmpty();
 
   DCHECK(!current_resource_.id ||
-         factory_owner_->release_callbacks_.count(current_resource_.id));
+         compositor_frame_sink_holder_->HasReleaseCallbackForResource(
+             current_resource_.id));
 
   // Move pending frame callbacks to the end of frame_callbacks_.
   frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
@@ -608,18 +540,7 @@
 }
 
 void Surface::WillDraw() {
-  active_frame_callbacks_.splice(active_frame_callbacks_.end(),
-                                 frame_callbacks_);
-  UpdateNeedsBeginFrame();
-}
-
-void Surface::SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) {
-  if (begin_frame_source_ && needs_begin_frame_) {
-    begin_frame_source_->RemoveObserver(this);
-    needs_begin_frame_ = false;
-  }
-  begin_frame_source_ = begin_frame_source;
-  UpdateNeedsBeginFrame();
+  compositor_frame_sink_holder_->ActivateFrameCallbacks(&frame_callbacks_);
 }
 
 void Surface::CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces() {
@@ -636,26 +557,12 @@
 }
 
 void Surface::OnWindowAddedToRootWindow(aura::Window* window) {
-  window->layer()->GetCompositor()->AddFrameSink(
-      factory_owner_->frame_sink_id_);
+  window->layer()->GetCompositor()->AddFrameSink(frame_sink_id_);
 }
 
 void Surface::OnWindowRemovingFromRootWindow(aura::Window* window,
                                              aura::Window* new_root) {
-  window->layer()->GetCompositor()->RemoveFrameSink(
-      factory_owner_->frame_sink_id_);
-}
-
-void Surface::OnBeginFrame(const cc::BeginFrameArgs& args) {
-  while (!active_frame_callbacks_.empty()) {
-    active_frame_callbacks_.front().Run(args.frame_time);
-    active_frame_callbacks_.pop_front();
-  }
-  last_begin_frame_args_ = args;
-}
-
-const cc::BeginFrameArgs& Surface::LastUsedBeginFrameArgs() const {
-  return last_begin_frame_args_;
+  window->layer()->GetCompositor()->RemoveFrameSink(frame_sink_id_);
 }
 
 Surface::State::State() : input_region(SkIRect::MakeLargest()) {}
@@ -743,8 +650,8 @@
                                                  texture_mailbox.target());
     resource.is_overlay_candidate = texture_mailbox.is_overlay_candidate();
 
-    factory_owner_->release_callbacks_[resource.id] = std::make_pair(
-        factory_owner_, std::move(texture_mailbox_release_callback));
+    compositor_frame_sink_holder_->AddResourceReleaseCallback(
+        resource.id, std::move(texture_mailbox_release_callback));
     current_resource_ = resource;
   } else {
     current_resource_.id = 0;
@@ -834,24 +741,8 @@
   }
 
   frame.render_pass_list.push_back(std::move(render_pass));
-
-  factory_owner_->surface_factory_->SubmitCompositorFrame(
-      local_frame_id_, std::move(frame), cc::SurfaceFactory::DrawCallback());
-}
-
-void Surface::UpdateNeedsBeginFrame() {
-  if (!begin_frame_source_)
-    return;
-
-  bool needs_begin_frame = !active_frame_callbacks_.empty();
-  if (needs_begin_frame == needs_begin_frame_)
-    return;
-
-  needs_begin_frame_ = needs_begin_frame;
-  if (needs_begin_frame)
-    begin_frame_source_->AddObserver(this);
-  else
-    begin_frame_source_->RemoveObserver(this);
+  compositor_frame_sink_holder_->GetCompositorFrameSink()
+      ->SubmitCompositorFrame(local_frame_id_, std::move(frame));
 }
 
 int64_t Surface::SetPropertyInternal(const void* key,
diff --git a/components/exo/surface.h b/components/exo/surface.h
index 032cd57f..c0dd787 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -17,7 +17,9 @@
 #include "base/observer_list.h"
 #include "cc/resources/transferable_resource.h"
 #include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "components/exo/compositor_frame_sink.h"
+#include "components/exo/compositor_frame_sink_holder.h"
 #include "third_party/skia/include/core/SkBlendMode.h"
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/aura/window.h"
@@ -31,7 +33,6 @@
 }
 
 namespace cc {
-class SurfaceFactory;
 class SurfaceIdAllocator;
 }
 
@@ -57,42 +58,9 @@
 // change in the future when better hardware cursor support is added.
 using CursorProvider = Pointer;
 
-// This class owns the SurfaceFactory and keeps track of references to the
-// contents of Buffers. It's keeped alive by references from
-// release_callbacks_. It's destroyed when its owning Surface is destroyed and
-// the last outstanding release callback is called.
-class SurfaceFactoryOwner : public base::RefCounted<SurfaceFactoryOwner>,
-                            public cc::SurfaceFactoryClient {
- public:
-  SurfaceFactoryOwner();
-
-  // Overridden from cc::SurfaceFactoryClient:
-  void ReturnResources(const cc::ReturnedResourceArray& resources) override;
-  void WillDrawSurface(const cc::LocalFrameId& id,
-                       const gfx::Rect& damage_rect) override;
-  void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
-
- private:
-  friend class base::RefCounted<SurfaceFactoryOwner>;
-  friend class Surface;
-
-  ~SurfaceFactoryOwner() override;
-
-  std::map<int,
-           std::pair<scoped_refptr<SurfaceFactoryOwner>,
-                     std::unique_ptr<cc::SingleReleaseCallback>>>
-      release_callbacks_;
-  cc::FrameSinkId frame_sink_id_;
-  std::unique_ptr<cc::SurfaceIdAllocator> id_allocator_;
-  std::unique_ptr<cc::SurfaceFactory> surface_factory_;
-  Surface* surface_ = nullptr;
-};
-
 // This class represents a rectangular area that is displayed on the screen.
 // It has a location, size and pixel contents.
-class Surface : public ui::ContextFactoryObserver,
-                public aura::WindowObserver,
-                public cc::BeginFrameObserver {
+class Surface : public ui::ContextFactoryObserver, public aura::WindowObserver {
  public:
   using PropertyDeallocator = void (*)(int64_t value);
 
@@ -104,9 +72,12 @@
 
   aura::Window* window() { return window_.get(); }
 
-  const cc::LocalFrameId& local_frame_id() const { return local_frame_id_; }
   cc::SurfaceId GetSurfaceId() const;
 
+  CompositorFrameSinkHolder* compositor_frame_sink_holder() {
+    return compositor_frame_sink_holder_.get();
+  }
+
   // Set a buffer as the content of this surface. A buffer can only be attached
   // to one surface at a time.
   void Attach(Buffer* buffer);
@@ -229,11 +200,6 @@
   void OnWindowRemovingFromRootWindow(aura::Window* window,
                                       aura::Window* new_root) override;
 
-  // Overridden from cc::BeginFrameObserver:
-  void OnBeginFrame(const cc::BeginFrameArgs& args) override;
-  const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override;
-  void OnBeginFrameSourcePausedChanged(bool paused) override {}
-
   // Sets the |value| of the given surface |property|. Setting to the default
   // value (e.g., NULL) removes the property. The caller is responsible for the
   // lifetime of any object set as a property on the Surface.
@@ -314,9 +280,6 @@
   // current_resource_.
   void UpdateSurface(bool full_damage);
 
-  // Adds/Removes begin frame observer based on state.
-  void UpdateNeedsBeginFrame();
-
   int64_t SetPropertyInternal(const void* key,
                               const char* name,
                               PropertyDeallocator deallocator,
@@ -350,13 +313,13 @@
   // The buffer that will become the content of surface when Commit() is called.
   BufferAttachment pending_buffer_;
 
-  cc::SurfaceManager* surface_manager_;
-
-  scoped_refptr<SurfaceFactoryOwner> factory_owner_;
-
-  // The Surface Id currently attached to the window.
+  const cc::FrameSinkId frame_sink_id_;
   cc::LocalFrameId local_frame_id_;
 
+  scoped_refptr<CompositorFrameSinkHolder> compositor_frame_sink_holder_;
+
+  cc::SurfaceIdAllocator id_allocator_;
+
   // The next resource id the buffer will be attached to.
   int next_resource_id_ = 1;
 
@@ -370,7 +333,6 @@
   // be drawn. They fire at the first begin frame notification after this.
   std::list<FrameCallback> pending_frame_callbacks_;
   std::list<FrameCallback> frame_callbacks_;
-  std::list<FrameCallback> active_frame_callbacks_;
 
   // This is the state that has yet to be committed.
   State pending_state_;
@@ -407,11 +369,6 @@
   // maintains.
   SurfaceDelegate* delegate_ = nullptr;
 
-  // The begin frame source being observed.
-  cc::BeginFrameSource* begin_frame_source_ = nullptr;
-  cc::BeginFrameArgs last_begin_frame_args_;
-  bool needs_begin_frame_ = false;
-
   struct Value {
     const char* name;
     int64_t value;
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index 570e4ac..2e82a57 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -50,6 +50,11 @@
   // attached buffer.
   surface->Attach(nullptr);
   surface->Commit();
+  // CompositorFrameSinkHolder::ReclaimResources() gets called via
+  // MojoCompositorFrameSinkClient interface. We need to wait here for the mojo
+  // call to finish so that the release callback finishes running before
+  // the assertion below.
+  RunAllPendingInMessageLoop();
   ASSERT_EQ(1, release_buffer_call_count);
 }
 
@@ -205,6 +210,7 @@
   surface->Attach(buffer.get());
   surface->SetBlendMode(SkBlendMode::kSrc);
   surface->Commit();
+  RunAllPendingInMessageLoop();
 
   const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
   ASSERT_EQ(1u, frame.render_pass_list.size());
@@ -222,6 +228,7 @@
 
   surface->Attach(buffer.get());
   surface->Commit();
+  RunAllPendingInMessageLoop();
 
   const cc::CompositorFrame& frame = GetFrameFromSurface(surface.get());
   ASSERT_EQ(1u, frame.render_pass_list.size());
diff --git a/components/exo/test/run_all_unittests.cc b/components/exo/test/run_all_unittests.cc
index e69d387..eedc4d93 100644
--- a/components/exo/test/run_all_unittests.cc
+++ b/components/exo/test/run_all_unittests.cc
@@ -6,9 +6,17 @@
 #include "base/bind.h"
 #include "base/test/launcher/unit_test_launcher.h"
 
+#if !defined(OS_IOS)
+#include "mojo/edk/embedder/embedder.h"
+#endif
+
 int main(int argc, char** argv) {
   ash::test::AuraShellTestSuite test_suite(argc, argv);
 
+#if !defined(OS_IOS)
+  mojo::edk::Init();
+#endif
+
   return base::LaunchUnitTestsSerially(
       argc, argv, base::Bind(&ash::test::AuraShellTestSuite::Run,
                              base::Unretained(&test_suite)));
diff --git a/components/sync/driver/glue/sync_backend_host_core.cc b/components/sync/driver/glue/sync_backend_host_core.cc
index 3fcbdbc..9fe765d 100644
--- a/components/sync/driver/glue/sync_backend_host_core.cc
+++ b/components/sync/driver/glue/sync_backend_host_core.cc
@@ -102,13 +102,6 @@
 
 DoInitializeOptions::~DoInitializeOptions() {}
 
-DoConfigureSyncerTypes::DoConfigureSyncerTypes() {}
-
-DoConfigureSyncerTypes::DoConfigureSyncerTypes(
-    const DoConfigureSyncerTypes& other) = default;
-
-DoConfigureSyncerTypes::~DoConfigureSyncerTypes() {}
-
 SyncBackendHostCore::SyncBackendHostCore(
     const std::string& name,
     const base::FilePath& sync_data_folder_path,
@@ -202,9 +195,10 @@
   ModelTypeSet types_to_purge =
       Difference(ModelTypeSet::All(), GetRoutingInfoTypes(routing_info));
 
+  sync_manager_->PurgeDisabledTypes(types_to_purge, ModelTypeSet(),
+                                    ModelTypeSet());
   sync_manager_->ConfigureSyncer(
-      reason, new_control_types, types_to_purge, ModelTypeSet(), ModelTypeSet(),
-      routing_info,
+      reason, new_control_types, routing_info,
       base::Bind(&SyncBackendHostCore::DoInitialProcessControlTypes,
                  weak_ptr_factory_.GetWeakPtr()),
       base::Closure());
@@ -554,24 +548,29 @@
   }
 }
 
+void SyncBackendHostCore::DoPurgeDisabledTypes(const ModelTypeSet& to_purge,
+                                               const ModelTypeSet& to_journal,
+                                               const ModelTypeSet& to_unapply) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  sync_manager_->PurgeDisabledTypes(to_purge, to_journal, to_unapply);
+}
+
 void SyncBackendHostCore::DoConfigureSyncer(
     ConfigureReason reason,
-    const DoConfigureSyncerTypes& config_types,
+    const ModelTypeSet& to_download,
     const ModelSafeRoutingInfo routing_info,
     const base::Callback<void(ModelTypeSet, ModelTypeSet)>& ready_task,
     const base::Closure& retry_callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!ready_task.is_null());
   DCHECK(!retry_callback.is_null());
-  base::Closure chained_ready_task(base::Bind(
-      &SyncBackendHostCore::DoFinishConfigureDataTypes,
-      weak_ptr_factory_.GetWeakPtr(), config_types.to_download, ready_task));
+  base::Closure chained_ready_task(
+      base::Bind(&SyncBackendHostCore::DoFinishConfigureDataTypes,
+                 weak_ptr_factory_.GetWeakPtr(), to_download, ready_task));
   base::Closure chained_retry_task(
       base::Bind(&SyncBackendHostCore::DoRetryConfiguration,
                  weak_ptr_factory_.GetWeakPtr(), retry_callback));
-  sync_manager_->ConfigureSyncer(reason, config_types.to_download,
-                                 config_types.to_purge, config_types.to_journal,
-                                 config_types.to_unapply, routing_info,
+  sync_manager_->ConfigureSyncer(reason, to_download, routing_info,
                                  chained_ready_task, chained_retry_task);
 }
 
diff --git a/components/sync/driver/glue/sync_backend_host_core.h b/components/sync/driver/glue/sync_backend_host_core.h
index 641fed6..55e5372 100644
--- a/components/sync/driver/glue/sync_backend_host_core.h
+++ b/components/sync/driver/glue/sync_backend_host_core.h
@@ -82,18 +82,6 @@
   const std::map<ModelType, int64_t> invalidation_versions;
 };
 
-// Helper struct to handle currying params to
-// SyncBackendHostCore::DoConfigureSyncer.
-struct DoConfigureSyncerTypes {
-  DoConfigureSyncerTypes();
-  DoConfigureSyncerTypes(const DoConfigureSyncerTypes& other);
-  ~DoConfigureSyncerTypes();
-  ModelTypeSet to_download;
-  ModelTypeSet to_purge;
-  ModelTypeSet to_journal;
-  ModelTypeSet to_unapply;
-};
-
 class SyncBackendHostCore
     : public base::RefCountedThreadSafe<SyncBackendHostCore>,
       public base::trace_event::MemoryDumpProvider,
@@ -205,9 +193,12 @@
   void DoDestroySyncManager(ShutdownReason reason);
 
   // Configuration methods that must execute on sync loop.
+  void DoPurgeDisabledTypes(const ModelTypeSet& to_purge,
+                            const ModelTypeSet& to_journal,
+                            const ModelTypeSet& to_unapply);
   void DoConfigureSyncer(
       ConfigureReason reason,
-      const DoConfigureSyncerTypes& config_types,
+      const ModelTypeSet& to_download,
       const ModelSafeRoutingInfo routing_info,
       const base::Callback<void(ModelTypeSet, ModelTypeSet)>& ready_task,
       const base::Closure& retry_callback);
diff --git a/components/sync/driver/glue/sync_backend_host_impl.cc b/components/sync/driver/glue/sync_backend_host_impl.cc
index 20d2462..1b135cb8 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.cc
+++ b/components/sync/driver/glue/sync_backend_host_impl.cc
@@ -366,9 +366,11 @@
   //   from the directory.
   // - Everything else (enabled types and already disabled types) is not
   //   touched.
-  RequestConfigureSyncer(reason, types_to_download, types_to_purge, fatal_types,
-                         unapply_types, inactive_types, routing_info,
-                         ready_task, retry_callback);
+  sync_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&SyncBackendHostCore::DoPurgeDisabledTypes, core_,
+                            types_to_purge, fatal_types, unapply_types));
+  RequestConfigureSyncer(reason, types_to_download, routing_info, ready_task,
+                         retry_callback);
 
   DCHECK(Intersection(active_types, types_to_purge).Empty());
   DCHECK(Intersection(active_types, fatal_types).Empty());
@@ -499,22 +501,13 @@
 void SyncBackendHostImpl::RequestConfigureSyncer(
     ConfigureReason reason,
     ModelTypeSet to_download,
-    ModelTypeSet to_purge,
-    ModelTypeSet to_journal,
-    ModelTypeSet to_unapply,
-    ModelTypeSet to_ignore,
     const ModelSafeRoutingInfo& routing_info,
     const base::Callback<void(ModelTypeSet, ModelTypeSet)>& ready_task,
     const base::Closure& retry_callback) {
-  DoConfigureSyncerTypes config_types;
-  config_types.to_download = to_download;
-  config_types.to_purge = to_purge;
-  config_types.to_journal = to_journal;
-  config_types.to_unapply = to_unapply;
   sync_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&SyncBackendHostCore::DoConfigureSyncer, core_, reason,
-                 config_types, routing_info, ready_task, retry_callback));
+                 to_download, routing_info, ready_task, retry_callback));
 }
 
 void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop(
diff --git a/components/sync/driver/glue/sync_backend_host_impl.h b/components/sync/driver/glue/sync_backend_host_impl.h
index e6735981..c344dcc 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.h
+++ b/components/sync/driver/glue/sync_backend_host_impl.h
@@ -139,10 +139,6 @@
   virtual void RequestConfigureSyncer(
       ConfigureReason reason,
       ModelTypeSet to_download,
-      ModelTypeSet to_purge,
-      ModelTypeSet to_journal,
-      ModelTypeSet to_unapply,
-      ModelTypeSet to_ignore,
       const ModelSafeRoutingInfo& routing_info,
       const base::Callback<void(ModelTypeSet, ModelTypeSet)>& ready_task,
       const base::Closure& retry_callback);
diff --git a/components/sync/engine/fake_sync_manager.cc b/components/sync/engine/fake_sync_manager.cc
index a9ebc31c..abda05a 100644
--- a/components/sync/engine/fake_sync_manager.cc
+++ b/components/sync/engine/fake_sync_manager.cc
@@ -106,7 +106,7 @@
   return empty_types;
 }
 
-bool FakeSyncManager::PurgePartiallySyncedTypes() {
+void FakeSyncManager::PurgePartiallySyncedTypes() {
   ModelTypeSet partial_types;
   for (ModelTypeSet::Iterator i = progress_marker_types_.First(); i.Good();
        i.Inc()) {
@@ -115,7 +115,20 @@
   }
   progress_marker_types_.RemoveAll(partial_types);
   cleaned_types_.PutAll(partial_types);
-  return true;
+}
+
+void FakeSyncManager::PurgeDisabledTypes(ModelTypeSet to_purge,
+                                         ModelTypeSet to_journal,
+                                         ModelTypeSet to_unapply) {
+  // Simulate cleaning up disabled types.
+  // TODO(sync): consider only cleaning those types that were recently disabled,
+  // if this isn't the first cleanup, which more accurately reflects the
+  // behavior of the real cleanup logic.
+  GetUserShare()->directory->PurgeEntriesWithTypeIn(to_purge, to_journal,
+                                                    to_unapply);
+  initial_sync_ended_types_.RemoveAll(to_purge);
+  progress_marker_types_.RemoveAll(to_purge);
+  cleaned_types_.PutAll(to_purge);
 }
 
 void FakeSyncManager::UpdateCredentials(const SyncCredentials& credentials) {
@@ -131,9 +144,6 @@
 void FakeSyncManager::ConfigureSyncer(
     ConfigureReason reason,
     ModelTypeSet to_download,
-    ModelTypeSet to_purge,
-    ModelTypeSet to_journal,
-    ModelTypeSet to_unapply,
     const ModelSafeRoutingInfo& new_routing_info,
     const base::Closure& ready_task,
     const base::Closure& retry_task) {
@@ -143,12 +153,10 @@
   success_types.RemoveAll(configure_fail_types_);
 
   DVLOG(1) << "Faking configuration. Downloading: "
-           << ModelTypeSetToString(success_types)
-           << ". Cleaning: " << ModelTypeSetToString(to_purge);
+           << ModelTypeSetToString(success_types);
 
   // Update our fake directory by clearing and fake-downloading as necessary.
   UserShare* share = GetUserShare();
-  share->directory->PurgeEntriesWithTypeIn(to_purge, to_journal, to_unapply);
   for (ModelTypeSet::Iterator it = success_types.First(); it.Good(); it.Inc()) {
     // We must be careful to not create the same root node twice.
     if (!initial_sync_ended_types_.Has(it.Get())) {
@@ -156,14 +164,6 @@
     }
   }
 
-  // Simulate cleaning up disabled types.
-  // TODO(sync): consider only cleaning those types that were recently disabled,
-  // if this isn't the first cleanup, which more accurately reflects the
-  // behavior of the real cleanup logic.
-  initial_sync_ended_types_.RemoveAll(to_purge);
-  progress_marker_types_.RemoveAll(to_purge);
-  cleaned_types_.PutAll(to_purge);
-
   // Now simulate the actual configuration for those types that successfully
   // download + apply.
   progress_marker_types_.PutAll(success_types);
diff --git a/components/sync/engine/fake_sync_manager.h b/components/sync/engine/fake_sync_manager.h
index 0c82ecf..42f0c26 100644
--- a/components/sync/engine/fake_sync_manager.h
+++ b/components/sync/engine/fake_sync_manager.h
@@ -76,15 +76,15 @@
   ModelTypeSet InitialSyncEndedTypes() override;
   ModelTypeSet GetTypesWithEmptyProgressMarkerToken(
       ModelTypeSet types) override;
-  bool PurgePartiallySyncedTypes() override;
+  void PurgePartiallySyncedTypes() override;
+  void PurgeDisabledTypes(ModelTypeSet to_purge,
+                          ModelTypeSet to_journal,
+                          ModelTypeSet to_unapply) override;
   void UpdateCredentials(const SyncCredentials& credentials) override;
   void StartSyncingNormally(const ModelSafeRoutingInfo& routing_info,
                             base::Time last_poll_time) override;
   void ConfigureSyncer(ConfigureReason reason,
                        ModelTypeSet to_download,
-                       ModelTypeSet to_purge,
-                       ModelTypeSet to_journal,
-                       ModelTypeSet to_unapply,
                        const ModelSafeRoutingInfo& new_routing_info,
                        const base::Closure& ready_task,
                        const base::Closure& retry_task) override;
diff --git a/components/sync/engine/sync_manager.h b/components/sync/engine/sync_manager.h
index dadfb4e..37e7de63 100644
--- a/components/sync/engine/sync_manager.h
+++ b/components/sync/engine/sync_manager.h
@@ -290,7 +290,15 @@
   // Purge from the directory those types with non-empty progress markers
   // but without initial synced ended set.
   // Returns false if an error occurred, true otherwise.
-  virtual bool PurgePartiallySyncedTypes() = 0;
+  virtual void PurgePartiallySyncedTypes() = 0;
+
+  // Purge those disabled types as specified by |to_purge|. |to_journal| and
+  // |to_unapply| specify subsets that require special handling. |to_journal|
+  // types are saved into the delete journal, while |to_unapply| have only
+  // their local data deleted, while their server data is preserved.
+  virtual void PurgeDisabledTypes(ModelTypeSet to_purge,
+                                  ModelTypeSet to_journal,
+                                  ModelTypeSet to_unapply) = 0;
 
   // Update tokens that we're using in Sync. Email must stay the same.
   virtual void UpdateCredentials(const SyncCredentials& credentials) = 0;
@@ -303,20 +311,12 @@
   // any configuration tasks needed as determined by the params. Once complete,
   // syncer will remain in CONFIGURATION_MODE until StartSyncingNormally is
   // called.
-  // Data whose types are not in |new_routing_info| are purged from sync
-  // directory, unless they're part of |to_ignore|, in which case they're left
-  // untouched. The purged data is backed up in delete journal for recovery in
-  // next session if its type is in |to_journal|. If in |to_unapply|
-  // only the local data is removed; the server data is preserved.
   // |ready_task| is invoked when the configuration completes.
   // |retry_task| is invoked if the configuration job could not immediately
   //              execute. |ready_task| will still be called when it eventually
   //              does finish.
   virtual void ConfigureSyncer(ConfigureReason reason,
                                ModelTypeSet to_download,
-                               ModelTypeSet to_purge,
-                               ModelTypeSet to_journal,
-                               ModelTypeSet to_unapply,
                                const ModelSafeRoutingInfo& new_routing_info,
                                const base::Closure& ready_task,
                                const base::Closure& retry_task) = 0;
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index a41eb56..87dd222 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -184,9 +184,6 @@
 void SyncManagerImpl::ConfigureSyncer(
     ConfigureReason reason,
     ModelTypeSet to_download,
-    ModelTypeSet to_purge,
-    ModelTypeSet to_journal,
-    ModelTypeSet to_unapply,
     const ModelSafeRoutingInfo& new_routing_info,
     const base::Closure& ready_task,
     const base::Closure& retry_task) {
@@ -203,19 +200,7 @@
            << "current types: "
            << ModelTypeSetToString(GetRoutingInfoTypes(new_routing_info))
            << "\n\t"
-           << "types to download: " << ModelTypeSetToString(to_download)
-           << "\n\t"
-           << "types to purge: " << ModelTypeSetToString(to_purge) << "\n\t"
-           << "types to journal: " << ModelTypeSetToString(to_journal) << "\n\t"
-           << "types to unapply: " << ModelTypeSetToString(to_unapply);
-  if (!PurgeDisabledTypes(to_purge, to_journal, to_unapply)) {
-    // We failed to cleanup the types. Invoke the ready task without actually
-    // configuring any types. The caller should detect this as a configuration
-    // failure and act appropriately.
-    ready_task.Run();
-    return;
-  }
-
+           << "types to download: " << ModelTypeSetToString(to_download);
   ConfigurationParams params(GetSourceFromReason(reason), to_download,
                              new_routing_info, ready_task, retry_task);
 
@@ -460,13 +445,11 @@
   // trigger the migration logic before the backend is initialized, resulting
   // in crashes. We therefore detect and purge any partially synced types as
   // part of initialization.
-  if (!PurgePartiallySyncedTypes())
-    return false;
-
+  PurgePartiallySyncedTypes();
   return true;
 }
 
-bool SyncManagerImpl::PurgePartiallySyncedTypes() {
+void SyncManagerImpl::PurgePartiallySyncedTypes() {
   ModelTypeSet partially_synced_types = ModelTypeSet::All();
   partially_synced_types.RemoveAll(directory()->InitialSyncEndedTypes());
   partially_synced_types.RemoveAll(
@@ -476,21 +459,22 @@
            << ModelTypeSetToString(partially_synced_types);
   UMA_HISTOGRAM_COUNTS("Sync.PartiallySyncedTypes",
                        partially_synced_types.Size());
-  if (partially_synced_types.Empty())
-    return true;
-  return directory()->PurgeEntriesWithTypeIn(partially_synced_types,
-                                             ModelTypeSet(), ModelTypeSet());
+  directory()->PurgeEntriesWithTypeIn(partially_synced_types, ModelTypeSet(),
+                                      ModelTypeSet());
 }
 
-bool SyncManagerImpl::PurgeDisabledTypes(ModelTypeSet to_purge,
+void SyncManagerImpl::PurgeDisabledTypes(ModelTypeSet to_purge,
                                          ModelTypeSet to_journal,
                                          ModelTypeSet to_unapply) {
-  if (to_purge.Empty())
-    return true;
-  DVLOG(1) << "Purging disabled types " << ModelTypeSetToString(to_purge);
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(initialized_);
+  DVLOG(1) << "Purging disabled types:\n\t"
+           << "types to purge: " << ModelTypeSetToString(to_purge) << "\n\t"
+           << "types to journal: " << ModelTypeSetToString(to_journal) << "\n\t"
+           << "types to unapply: " << ModelTypeSetToString(to_unapply);
   DCHECK(to_purge.HasAll(to_journal));
   DCHECK(to_purge.HasAll(to_unapply));
-  return directory()->PurgeEntriesWithTypeIn(to_purge, to_journal, to_unapply);
+  directory()->PurgeEntriesWithTypeIn(to_purge, to_journal, to_unapply);
 }
 
 void SyncManagerImpl::UpdateCredentials(const SyncCredentials& credentials) {
diff --git a/components/sync/engine_impl/sync_manager_impl.h b/components/sync/engine_impl/sync_manager_impl.h
index d448c4c1..4b396e9 100644
--- a/components/sync/engine_impl/sync_manager_impl.h
+++ b/components/sync/engine_impl/sync_manager_impl.h
@@ -67,15 +67,15 @@
   ModelTypeSet InitialSyncEndedTypes() override;
   ModelTypeSet GetTypesWithEmptyProgressMarkerToken(
       ModelTypeSet types) override;
-  bool PurgePartiallySyncedTypes() override;
+  void PurgePartiallySyncedTypes() override;
+  void PurgeDisabledTypes(ModelTypeSet to_purge,
+                          ModelTypeSet to_journal,
+                          ModelTypeSet to_unapply) override;
   void UpdateCredentials(const SyncCredentials& credentials) override;
   void StartSyncingNormally(const ModelSafeRoutingInfo& routing_info,
                             base::Time last_poll_time) override;
   void ConfigureSyncer(ConfigureReason reason,
                        ModelTypeSet to_download,
-                       ModelTypeSet to_purge,
-                       ModelTypeSet to_journal,
-                       ModelTypeSet to_unapply,
                        const ModelSafeRoutingInfo& new_routing_info,
                        const base::Closure& ready_task,
                        const base::Closure& retry_task) override;
@@ -219,14 +219,6 @@
   // Open the directory named with |username|.
   bool OpenDirectory(const std::string& username);
 
-  // Purge those disabled types as specified by |to_purge|. |to_journal| and
-  // |to_unapply| specify subsets that require special handling. |to_journal|
-  // types are saved into the delete journal, while |to_unapply| have only
-  // their local data deleted, while their server data is preserved.
-  bool PurgeDisabledTypes(ModelTypeSet to_purge,
-                          ModelTypeSet to_journal,
-                          ModelTypeSet to_unapply);
-
   void RequestNudgeForDataTypes(const tracked_objects::Location& nudge_location,
                                 ModelTypeSet type);
 
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index 8bc45bb..5f9db5d8 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -2767,11 +2767,13 @@
     SetProgressMarkerForType(iter.Get(), true);
   }
 
+  sync_manager_.PurgeDisabledTypes(disabled_types, ModelTypeSet(),
+                                   ModelTypeSet());
   CallbackCounter ready_task_counter, retry_task_counter;
   sync_manager_.ConfigureSyncer(
-      reason, types_to_download, disabled_types, ModelTypeSet(), ModelTypeSet(),
-      new_routing_info, base::Bind(&CallbackCounter::Callback,
-                                   base::Unretained(&ready_task_counter)),
+      reason, types_to_download, new_routing_info,
+      base::Bind(&CallbackCounter::Callback,
+                 base::Unretained(&ready_task_counter)),
       base::Bind(&CallbackCounter::Callback,
                  base::Unretained(&retry_task_counter)));
   EXPECT_EQ(0, ready_task_counter.times_called());
@@ -2822,10 +2824,12 @@
   cycle_context()->SetRoutingInfo(old_routing_info);
 
   CallbackCounter ready_task_counter, retry_task_counter;
+  sync_manager_.PurgeDisabledTypes(ModelTypeSet(), ModelTypeSet(),
+                                   ModelTypeSet());
   sync_manager_.ConfigureSyncer(
-      reason, types_to_download, ModelTypeSet(), ModelTypeSet(), ModelTypeSet(),
-      new_routing_info, base::Bind(&CallbackCounter::Callback,
-                                   base::Unretained(&ready_task_counter)),
+      reason, types_to_download, new_routing_info,
+      base::Bind(&CallbackCounter::Callback,
+                 base::Unretained(&ready_task_counter)),
       base::Bind(&CallbackCounter::Callback,
                  base::Unretained(&retry_task_counter)));
   EXPECT_EQ(0, ready_task_counter.times_called());
@@ -2908,7 +2912,7 @@
                                  pref_hashed_tag, pref_specifics);
 
   // And now, the purge.
-  EXPECT_TRUE(sync_manager_.PurgePartiallySyncedTypes());
+  sync_manager_.PurgePartiallySyncedTypes();
 
   // Ensure that autofill lost its progress marker, but preferences did not.
   ModelTypeSet empty_tokens =
diff --git a/components/sync/syncable/directory.cc b/components/sync/syncable/directory.cc
index ba417e7..42fd457b 100644
--- a/components/sync/syncable/directory.cc
+++ b/components/sync/syncable/directory.cc
@@ -729,81 +729,77 @@
   }
 }
 
-bool Directory::PurgeEntriesWithTypeIn(ModelTypeSet disabled_types,
+void Directory::PurgeEntriesWithTypeIn(ModelTypeSet disabled_types,
                                        ModelTypeSet types_to_journal,
                                        ModelTypeSet types_to_unapply) {
   disabled_types.RemoveAll(ProxyTypes());
-
   if (disabled_types.Empty())
-    return true;
+    return;
+
+  WriteTransaction trans(FROM_HERE, PURGE_ENTRIES, this);
+
+  OwnedEntryKernelSet entries_to_journal;
 
   {
-    WriteTransaction trans(FROM_HERE, PURGE_ENTRIES, this);
+    ScopedKernelLock lock(this);
 
-    OwnedEntryKernelSet entries_to_journal;
-
-    {
-      ScopedKernelLock lock(this);
-
-      bool found_progress = false;
-      for (ModelTypeSet::Iterator iter = disabled_types.First(); iter.Good();
-           iter.Inc()) {
-        if (!kernel_->persisted_info.HasEmptyDownloadProgress(iter.Get()))
-          found_progress = true;
-      }
-
-      // If none of the disabled types have progress markers, there's nothing to
-      // purge.
-      if (!found_progress)
-        return true;
-
-      for (MetahandlesMap::iterator it = kernel_->metahandles_map.begin();
-           it != kernel_->metahandles_map.end();) {
-        EntryKernel* entry = it->second.get();
-        const sync_pb::EntitySpecifics& local_specifics = entry->ref(SPECIFICS);
-        const sync_pb::EntitySpecifics& server_specifics =
-            entry->ref(SERVER_SPECIFICS);
-        ModelType local_type = GetModelTypeFromSpecifics(local_specifics);
-        ModelType server_type = GetModelTypeFromSpecifics(server_specifics);
-
-        // Increment the iterator before (potentially) calling DeleteEntry,
-        // otherwise our iterator may be invalidated.
-        ++it;
-
-        if ((IsRealDataType(local_type) && disabled_types.Has(local_type)) ||
-            (IsRealDataType(server_type) && disabled_types.Has(server_type))) {
-          if (types_to_unapply.Has(local_type) ||
-              types_to_unapply.Has(server_type)) {
-            UnapplyEntry(entry);
-          } else {
-            bool save_to_journal =
-                (types_to_journal.Has(local_type) ||
-                 types_to_journal.Has(server_type)) &&
-                (delete_journal_->IsDeleteJournalEnabled(local_type) ||
-                 delete_journal_->IsDeleteJournalEnabled(server_type));
-            DeleteEntry(lock, save_to_journal, entry, &entries_to_journal);
-          }
-        }
-      }
-
-      delete_journal_->AddJournalBatch(&trans, entries_to_journal);
-
-      // Ensure meta tracking for these data types reflects the purged state.
-      for (ModelTypeSet::Iterator it = disabled_types.First(); it.Good();
-           it.Inc()) {
-        kernel_->persisted_info.transaction_version[it.Get()] = 0;
-
-        // Don't discard progress markers or context for unapplied types.
-        if (!types_to_unapply.Has(it.Get())) {
-          kernel_->persisted_info.ResetDownloadProgress(it.Get());
-          kernel_->persisted_info.datatype_context[it.Get()].Clear();
-        }
-      }
-
-      kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
+    bool found_progress = false;
+    for (ModelTypeSet::Iterator iter = disabled_types.First(); iter.Good();
+         iter.Inc()) {
+      if (!kernel_->persisted_info.HasEmptyDownloadProgress(iter.Get()))
+        found_progress = true;
     }
+
+    // If none of the disabled types have progress markers, there's nothing to
+    // purge.
+    if (!found_progress)
+      return;
+
+    for (MetahandlesMap::iterator it = kernel_->metahandles_map.begin();
+         it != kernel_->metahandles_map.end();) {
+      EntryKernel* entry = it->second.get();
+      const sync_pb::EntitySpecifics& local_specifics = entry->ref(SPECIFICS);
+      const sync_pb::EntitySpecifics& server_specifics =
+          entry->ref(SERVER_SPECIFICS);
+      ModelType local_type = GetModelTypeFromSpecifics(local_specifics);
+      ModelType server_type = GetModelTypeFromSpecifics(server_specifics);
+
+      // Increment the iterator before (potentially) calling DeleteEntry,
+      // otherwise our iterator may be invalidated.
+      ++it;
+
+      if ((IsRealDataType(local_type) && disabled_types.Has(local_type)) ||
+          (IsRealDataType(server_type) && disabled_types.Has(server_type))) {
+        if (types_to_unapply.Has(local_type) ||
+            types_to_unapply.Has(server_type)) {
+          UnapplyEntry(entry);
+        } else {
+          bool save_to_journal =
+              (types_to_journal.Has(local_type) ||
+               types_to_journal.Has(server_type)) &&
+              (delete_journal_->IsDeleteJournalEnabled(local_type) ||
+               delete_journal_->IsDeleteJournalEnabled(server_type));
+          DeleteEntry(lock, save_to_journal, entry, &entries_to_journal);
+        }
+      }
+    }
+
+    delete_journal_->AddJournalBatch(&trans, entries_to_journal);
+
+    // Ensure meta tracking for these data types reflects the purged state.
+    for (ModelTypeSet::Iterator it = disabled_types.First(); it.Good();
+         it.Inc()) {
+      kernel_->persisted_info.transaction_version[it.Get()] = 0;
+
+      // Don't discard progress markers or context for unapplied types.
+      if (!types_to_unapply.Has(it.Get())) {
+        kernel_->persisted_info.ResetDownloadProgress(it.Get());
+        kernel_->persisted_info.datatype_context[it.Get()].Clear();
+      }
+    }
+
+    kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
   }
-  return true;
 }
 
 bool Directory::ResetVersionsForType(BaseWriteTransaction* trans,
diff --git a/components/sync/syncable/directory.h b/components/sync/syncable/directory.h
index 461892b..d3bd4293 100644
--- a/components/sync/syncable/directory.h
+++ b/components/sync/syncable/directory.h
@@ -464,11 +464,9 @@
   // Note: "Purge" is just meant to distinguish from "deleting" entries, which
   // means something different in the syncable namespace.
   // WARNING! This can be real slow, as it iterates over all entries.
-  // WARNING! Performs synchronous I/O.
-  // Returns: true on success, false if an error was encountered.
-  virtual bool PurgeEntriesWithTypeIn(ModelTypeSet disabled_types,
-                                      ModelTypeSet types_to_journal,
-                                      ModelTypeSet types_to_unapply);
+  void PurgeEntriesWithTypeIn(ModelTypeSet disabled_types,
+                              ModelTypeSet types_to_journal,
+                              ModelTypeSet types_to_unapply);
 
   // Resets the base_versions and server_versions of all synced entities
   // associated with |type| to 1.
diff --git a/components/test/data/web_database/version_69.sql b/components/test/data/web_database/version_69.sql
new file mode 100644
index 0000000..901d68f
--- /dev/null
+++ b/components/test/data/web_database/version_69.sql
@@ -0,0 +1,29 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
+INSERT INTO "meta" VALUES('mmap_status','-1');
+INSERT INTO "meta" VALUES('version','69');
+INSERT INTO "meta" VALUES('last_compatible_version','69');
+INSERT INTO "meta" VALUES('Builtin Keyword Version','96');
+CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
+CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,instant_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR, last_visited INTEGER DEFAULT 0);
+INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:iOSSearchLanguage}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}{google:contextualSearchVersion}ie={inputEncoding}',1,'',0,0,'UTF-8','{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&gs_ri={google:suggestRid}&xssi=t&q={searchTerms}&{google:inputType}{google:cursorPosition}{google:currentPageUrl}{google:pageClassification}{google:searchVersion}{google:sessionToken}{google:prefetchQuery}sugkey={google:suggestAPIKeyParameter}',1,0,'{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}ie={inputEncoding}',0,'3967f1bd-7913-440d-aab5-319ae178837a','["{google:baseURL}#q={searchTerms}","{google:baseURL}search#q={searchTerms}","{google:baseURL}webhp#q={searchTerms}","{google:baseURL}s#q={searchTerms}","{google:baseURL}s?q={searchTerms}"]','espv','{google:baseURL}searchbyimage/upload','','','','encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight}','{google:baseURL}_/chrome/newtab?{google:RLZ}{google:instantExtendedEnabledParameter}ie={inputEncoding}',0);
+INSERT INTO "keywords" VALUES(3,'Bing','bing.com','https://www.bing.com/s/a/bing_p.ico','https://www.bing.com/search?q={searchTerms}&PC=U316&FORM=CHROMN',1,'',0,0,'UTF-8','https://www.bing.com/osjson.aspx?query={searchTerms}&language={language}&PC=U316',3,0,'',0,'edf5b23b-f8c6-4235-80a2-c686b9de3e37','[]','','https://www.bing.com/images/detail/search?iss=sbi&FORM=CHROMI#enterInsights','','','','imgurl={google:imageURL}','https://www.bing.com/chrome/newtab',0);
+INSERT INTO "keywords" VALUES(4,'Yahoo!','yahoo.com','https://search.yahoo.com/favicon.ico','https://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,'',0,0,'UTF-8','https://search.yahoo.com/sugg/chrome?output=fxjson&appid=crmas&command={searchTerms}',2,0,'',0,'56b59942-da06-4f53-841b-a9ef28f50ac8','[]','','','','','','','',0);
+INSERT INTO "keywords" VALUES(5,'AOL','aol.com','http://search.aol.com/favicon.ico','http://search.aol.com/aol/search?q={searchTerms}',1,'',0,0,'UTF-8','http://autocomplete.search.aol.com/autocomplete/get?output=json&it=&q={searchTerms}',35,0,'',0,'1a485f3a-b545-4265-8515-d49914865ebd','[]','','','','','','','',0);
+INSERT INTO "keywords" VALUES(6,'Ask','ask.com','http://sp.ask.com/sh/i/a16/favicon/favicon.ico','http://www.ask.com/web?q={searchTerms}',1,'',0,0,'UTF-8','http://ss.ask.com/query?q={searchTerms}&li=ff',4,0,'',0,'6725c539-3c39-4518-b58a-2a0623007920','[]','','','','','','','',0);
+CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value));
+CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
+CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0);
+CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR);
+CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
+CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR);
+CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
+CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,type VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, billing_address_id VARCHAR);
+CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, unmask_date INTEGER NOT NULL DEFAULT 0);
+CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0);
+CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR);
+CREATE TABLE server_address_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0);
+CREATE INDEX autofill_name ON autofill (name);
+CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
+COMMIT;
diff --git a/components/webdata/common/BUILD.gn b/components/webdata/common/BUILD.gn
index f7dc236..bf67150 100644
--- a/components/webdata/common/BUILD.gn
+++ b/components/webdata/common/BUILD.gn
@@ -55,6 +55,7 @@
     "//components/test/data/web_database/version_66.sql",
     "//components/test/data/web_database/version_67.sql",
     "//components/test/data/web_database/version_68.sql",
+    "//components/test/data/web_database/version_69.sql",
   ]
   outputs = [
     "{{bundle_resources_dir}}/" +
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc
index 558f279..b7dc2818 100644
--- a/components/webdata/common/web_database.cc
+++ b/components/webdata/common/web_database.cc
@@ -13,13 +13,13 @@
 // corresponding changes must happen in the unit tests, and new migration test
 // added.  See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
 // static
-const int WebDatabase::kCurrentVersionNumber = 69;
+const int WebDatabase::kCurrentVersionNumber = 70;
 
 const int WebDatabase::kDeprecatedVersionNumber = 51;
 
 namespace {
 
-const int kCompatibleVersionNumber = 68;
+const int kCompatibleVersionNumber = 70;
 
 // Change the version number and possibly the compatibility version of
 // |meta_table_|.
diff --git a/components/webdata/common/web_database_migration_unittest.cc b/components/webdata/common/web_database_migration_unittest.cc
index 280890a..82aa0c61 100644
--- a/components/webdata/common/web_database_migration_unittest.cc
+++ b/components/webdata/common/web_database_migration_unittest.cc
@@ -130,7 +130,7 @@
   DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
 };
 
-const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 69;
+const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 70;
 
 void WebDatabaseMigrationTest::LoadDatabase(
     const base::FilePath::StringType& file) {
@@ -1134,3 +1134,35 @@
         connection.DoesColumnExist("keywords", "last_visited"));
   }
 }
+
+// Tests addition of sync metadata and model type state tables.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion69ToCurrent) {
+  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_69.sql")));
+
+  // Verify pre-conditions.
+  {
+    sql::Connection connection;
+    ASSERT_TRUE(connection.Open(GetDatabasePath()));
+    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+    sql::MetaTable meta_table;
+    ASSERT_TRUE(meta_table.Init(&connection, 69, 69));
+
+    EXPECT_FALSE(connection.DoesTableExist("autofill_sync_metadata"));
+    EXPECT_FALSE(connection.DoesTableExist("autofill_model_type_state"));
+  }
+
+  DoMigration();
+
+  // Verify post-conditions.
+  {
+    sql::Connection connection;
+    ASSERT_TRUE(connection.Open(GetDatabasePath()));
+    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+    EXPECT_TRUE(connection.DoesTableExist("autofill_sync_metadata"));
+    EXPECT_TRUE(connection.DoesTableExist("autofill_model_type_state"));
+  }
+}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 473fba72..6e24301e 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -70,7 +70,6 @@
     "//device/battery:mojo_bindings",
     "//device/bluetooth",
     "//device/gamepad",
-    "//device/gamepad/public/interfaces",
     "//device/generic_sensor",
     "//device/geolocation",
     "//device/geolocation/public/interfaces",
@@ -641,10 +640,6 @@
     "frame_host/render_widget_host_view_child_frame.h",
     "frame_host/render_widget_host_view_guest.cc",
     "frame_host/render_widget_host_view_guest.h",
-    "gamepad/gamepad_service.cc",
-    "gamepad/gamepad_service.h",
-    "gamepad/gamepad_shared_buffer_impl.cc",
-    "gamepad/gamepad_shared_buffer_impl.h",
     "gpu/browser_gpu_channel_host_factory.cc",
     "gpu/browser_gpu_channel_host_factory.h",
     "gpu/browser_gpu_memory_buffer_manager.cc",
@@ -1003,8 +998,6 @@
     "renderer_host/font_utils_linux.h",
     "renderer_host/frame_metadata_util.cc",
     "renderer_host/frame_metadata_util.h",
-    "renderer_host/gamepad_monitor.cc",
-    "renderer_host/gamepad_monitor.h",
     "renderer_host/input/gesture_event_queue.cc",
     "renderer_host/input/gesture_event_queue.h",
     "renderer_host/input/input_ack_handler.h",
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index cae028f..e76edcb 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -54,7 +54,6 @@
 #include "content/browser/dom_storage/dom_storage_area.h"
 #include "content/browser/download/download_resource_handler.h"
 #include "content/browser/download/save_file_manager.h"
-#include "content/browser/gamepad/gamepad_service.h"
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/gpu/compositor_util.h"
@@ -90,6 +89,7 @@
 #include "content/public/common/main_function_params.h"
 #include "content/public/common/result_codes.h"
 #include "device/battery/battery_status_service.h"
+#include "device/gamepad/gamepad_service.h"
 #include "device/time_zone_monitor/time_zone_monitor.h"
 #include "media/base/media.h"
 #include "media/base/user_input_monitor.h"
@@ -1272,7 +1272,7 @@
   // I/O thread and isn't threadsafe.
   {
     TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:GamepadService");
-    GamepadService::GetInstance()->Terminate();
+    device::GamepadService::GetInstance()->Terminate();
   }
   {
     TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:SensorService");
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index c6e228f..75a1d71 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -186,13 +186,16 @@
     agent_host_->DispatchProtocolMessage(this, json_command);
     // Some messages are dispatched synchronously.
     // Only run loop if we are not finished yet.
-    if (in_dispatch_ && wait) {
-      waiting_for_command_result_id_ = last_sent_id_;
-      base::RunLoop().Run();
-    }
+    if (in_dispatch_ && wait)
+      WaitForResponse();
     in_dispatch_ = false;
   }
 
+  void WaitForResponse() {
+    waiting_for_command_result_id_ = last_sent_id_;
+    base::RunLoop().Run();
+  }
+
   bool HasValue(const std::string& path) {
     base::Value* value = 0;
     return result_->Get(path, &value);
@@ -409,14 +412,26 @@
                     int modifier,
                     int windowsKeyCode,
                     int nativeKeyCode,
-                    const std::string& key) {
+                    const std::string& key,
+                    bool wait) {
     std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
     params->SetString("type", type);
     params->SetInteger("modifiers", modifier);
     params->SetInteger("windowsVirtualKeyCode", windowsKeyCode);
     params->SetInteger("nativeVirtualKeyCode", nativeKeyCode);
     params->SetString("key", key);
-    SendCommand("Input.dispatchKeyEvent", std::move(params));
+    SendCommand("Input.dispatchKeyEvent", std::move(params), wait);
+  }
+};
+
+class SyntheticMouseEventTest : public DevToolsProtocolTest {
+ protected:
+  void SendMouseEvent(const std::string& type, int x, int y, bool wait) {
+    std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+    params->SetString("type", type);
+    params->SetInteger("x", x);
+    params->SetInteger("y", y);
+    SendCommand("Input.dispatchMouseEvent", std::move(params), wait);
   }
 };
 
@@ -435,8 +450,8 @@
   DOMMessageQueue dom_message_queue;
 
   // Send enter (keycode 13).
-  SendKeyEvent("rawKeyDown", 0, 13, 13, "Enter");
-  SendKeyEvent("keyUp", 0, 13, 13, "Enter");
+  SendKeyEvent("rawKeyDown", 0, 13, 13, "Enter", true);
+  SendKeyEvent("keyUp", 0, 13, 13, "Enter", true);
 
   std::string key;
   ASSERT_TRUE(dom_message_queue.WaitForMessage(&key));
@@ -445,8 +460,8 @@
   EXPECT_EQ("\"Enter\"", key);
 
   // Send escape (keycode 27).
-  SendKeyEvent("rawKeyDown", 0, 27, 27, "Escape");
-  SendKeyEvent("keyUp", 0, 27, 27, "Escape");
+  SendKeyEvent("rawKeyDown", 0, 27, 27, "Escape", true);
+  SendKeyEvent("keyUp", 0, 27, 27, "Escape", true);
 
   ASSERT_TRUE(dom_message_queue.WaitForMessage(&key));
   EXPECT_EQ("\"Escape\"", key);
@@ -454,6 +469,59 @@
   EXPECT_EQ("\"Escape\"", key);
 }
 
+IN_PROC_BROWSER_TEST_F(SyntheticKeyEventTest, KeyboardEventAck) {
+  NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
+  Attach();
+  ASSERT_TRUE(content::ExecuteScript(
+      shell()->web_contents()->GetRenderViewHost(),
+      "document.body.addEventListener('keydown', () => console.log('x'));"));
+
+  scoped_refptr<InputMsgWatcher> filter = new InputMsgWatcher(
+      RenderWidgetHostImpl::From(
+          shell()->web_contents()->GetRenderViewHost()->GetWidget()),
+      blink::WebInputEvent::MouseMove);
+
+  SendCommand("Runtime.enable", nullptr);
+  SendKeyEvent("rawKeyDown", 0, 13, 13, "Enter", false);
+
+  // We expect that the console log message event arrives *before* the input
+  // event ack, and the subsequent command response for Input.dispatchKeyEvent.
+  WaitForNotification("Runtime.consoleAPICalled");
+  EXPECT_THAT(console_messages_, ElementsAre("x"));
+  EXPECT_FALSE(filter->HasReceivedAck());
+  EXPECT_EQ(1u, result_ids_.size());
+
+  WaitForResponse();
+  EXPECT_EQ(2u, result_ids_.size());
+}
+
+IN_PROC_BROWSER_TEST_F(SyntheticMouseEventTest, MouseEventAck) {
+  NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
+  Attach();
+  ASSERT_TRUE(content::ExecuteScript(
+      shell()->web_contents()->GetRenderViewHost(),
+      "document.body.addEventListener('mousemove', () => console.log('x'));"));
+
+  scoped_refptr<InputMsgWatcher> filter = new InputMsgWatcher(
+      RenderWidgetHostImpl::From(
+          shell()->web_contents()->GetRenderViewHost()->GetWidget()),
+      blink::WebInputEvent::MouseMove);
+
+  SendCommand("Runtime.enable", nullptr);
+  SendMouseEvent("mouseMoved", 15, 15, false);
+
+  // We expect that the console log message event arrives *before* the input
+  // event ack, and the subsequent command response for
+  // Input.dispatchMouseEvent.
+  WaitForNotification("Runtime.consoleAPICalled");
+  EXPECT_THAT(console_messages_, ElementsAre("x"));
+  EXPECT_FALSE(filter->HasReceivedAck());
+  EXPECT_EQ(1u, result_ids_.size());
+
+  WaitForResponse();
+  EXPECT_EQ(2u, result_ids_.size());
+}
+
 namespace {
 bool DecodePNG(std::string base64_data, SkBitmap* bitmap) {
   std::string png_data;
diff --git a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
index ca6f1ca8..45fc22d 100755
--- a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
+++ b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -663,6 +663,8 @@
     "Network.getCookies",
     "Network.deleteCookie",
     "Network.setCookie",
+    "Input.dispatchKeyEvent",
+    "Input.dispatchMouseEvent",
     "Input.synthesizePinchGesture",
     "Input.synthesizeScrollGesture",
     "Input.synthesizeTapGesture"]
diff --git a/content/browser/devtools/protocol/input_handler.cc b/content/browser/devtools/protocol/input_handler.cc
index b963044..1c0526f 100644
--- a/content/browser/devtools/protocol/input_handler.cc
+++ b/content/browser/devtools/protocol/input_handler.cc
@@ -130,6 +130,7 @@
 
 InputHandler::InputHandler()
     : host_(NULL),
+      input_queued_(false),
       page_scale_factor_(1.0),
       weak_factory_(this) {
 }
@@ -137,8 +138,30 @@
 InputHandler::~InputHandler() {
 }
 
+void InputHandler::OnInputEvent(const blink::WebInputEvent& event) {
+  input_queued_ = true;
+}
+
+void InputHandler::OnInputEventAck(const blink::WebInputEvent& event) {
+  if (blink::WebInputEvent::isKeyboardEventType(event.type) &&
+      !pending_key_command_ids_.empty()) {
+    SendDispatchKeyEventResponse(pending_key_command_ids_.front());
+    pending_key_command_ids_.pop_front();
+  } else if (blink::WebInputEvent::isMouseEventType(event.type) &&
+             !pending_mouse_command_ids_.empty()) {
+    SendDispatchMouseEventResponse(pending_mouse_command_ids_.front());
+    pending_mouse_command_ids_.pop_front();
+  }
+}
+
 void InputHandler::SetRenderWidgetHost(RenderWidgetHostImpl* host) {
+  ClearPendingKeyCommands();
+  ClearPendingMouseCommands();
+  if (host_)
+    host_->RemoveInputEventObserver(this);
   host_ = host;
+  if (host)
+    host->AddInputEventObserver(this);
 }
 
 void InputHandler::SetClient(std::unique_ptr<Client> client) {
@@ -151,7 +174,15 @@
   scrollable_viewport_size_ = frame_metadata.scrollable_viewport_size;
 }
 
+void InputHandler::Detached() {
+  ClearPendingKeyCommands();
+  ClearPendingMouseCommands();
+  if (host_)
+    host_->RemoveInputEventObserver(this);
+}
+
 Response InputHandler::DispatchKeyEvent(
+    DevToolsCommandId command_id,
     const std::string& type,
     const int* modifiers,
     const double* timestamp,
@@ -213,11 +244,17 @@
     return Response::ServerError("Could not connect to view");
 
   host_->Focus();
+  input_queued_ = false;
   host_->ForwardKeyboardEvent(event);
+  if (input_queued_)
+    pending_key_command_ids_.push_back(command_id);
+  else
+    SendDispatchKeyEventResponse(command_id);
   return Response::OK();
 }
 
 Response InputHandler::DispatchMouseEvent(
+    DevToolsCommandId command_id,
     const std::string& type,
     int x,
     int y,
@@ -249,7 +286,12 @@
     return Response::ServerError("Could not connect to view");
 
   host_->Focus();
+  input_queued_ = false;
   host_->ForwardMouseEvent(event);
+  if (input_queued_)
+    pending_mouse_command_ids_.push_back(command_id);
+  else
+    SendDispatchMouseEventResponse(command_id);
   return Response::OK();
 }
 
@@ -479,6 +521,17 @@
   return Response::FallThrough();
 }
 
+void InputHandler::SendDispatchKeyEventResponse(DevToolsCommandId command_id) {
+  client_->SendDispatchKeyEventResponse(
+      command_id, DispatchKeyEventResponse::Create());
+}
+
+void InputHandler::SendDispatchMouseEventResponse(
+    DevToolsCommandId command_id) {
+  client_->SendDispatchMouseEventResponse(
+      command_id, DispatchMouseEventResponse::Create());
+}
+
 void InputHandler::SendSynthesizePinchGestureResponse(
     DevToolsCommandId command_id,
     SyntheticGesture::Result result) {
@@ -521,6 +574,18 @@
   }
 }
 
+void InputHandler::ClearPendingKeyCommands() {
+  for (const DevToolsCommandId& command_id : pending_key_command_ids_)
+    SendDispatchKeyEventResponse(command_id);
+  pending_key_command_ids_.clear();
+}
+
+void InputHandler::ClearPendingMouseCommands() {
+  for (const DevToolsCommandId& command_id : pending_mouse_command_ids_)
+    SendDispatchMouseEventResponse(command_id);
+  pending_mouse_command_ids_.clear();
+}
+
 }  // namespace input
 }  // namespace devtools
 }  // namespace content
diff --git a/content/browser/devtools/protocol/input_handler.h b/content/browser/devtools/protocol/input_handler.h
index 691cad2..e98c527 100644
--- a/content/browser/devtools/protocol/input_handler.h
+++ b/content/browser/devtools/protocol/input_handler.h
@@ -10,6 +10,7 @@
 #include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h"
 #include "content/browser/renderer_host/input/synthetic_gesture.h"
 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
+#include "content/public/browser/render_widget_host.h"
 #include "ui/gfx/geometry/size_f.h"
 
 namespace cc {
@@ -23,18 +24,20 @@
 namespace devtools {
 namespace input {
 
-class InputHandler {
+class InputHandler : public RenderWidgetHost::InputEventObserver {
  public:
   typedef DevToolsProtocolClient::Response Response;
 
   InputHandler();
-  virtual ~InputHandler();
+  ~InputHandler() override;
 
   void SetRenderWidgetHost(RenderWidgetHostImpl* host);
   void SetClient(std::unique_ptr<Client> client);
   void OnSwapCompositorFrame(const cc::CompositorFrameMetadata& frame_metadata);
+  void Detached();
 
-  Response DispatchKeyEvent(const std::string& type,
+  Response DispatchKeyEvent(DevToolsCommandId command_id,
+                            const std::string& type,
                             const int* modifiers,
                             const double* timestamp,
                             const std::string* text,
@@ -48,7 +51,8 @@
                             const bool* is_keypad,
                             const bool* is_system_key);
 
-  Response DispatchMouseEvent(const std::string& type,
+  Response DispatchMouseEvent(DevToolsCommandId command_id,
+                              const std::string& type,
                               int x,
                               int y,
                               const int* modifiers,
@@ -101,6 +105,13 @@
       const double* timestamp);
 
  private:
+  // InputEventObserver
+  void OnInputEvent(const blink::WebInputEvent& event) override;
+  void OnInputEventAck(const blink::WebInputEvent& event) override;
+
+  void SendDispatchKeyEventResponse(DevToolsCommandId command_id);
+  void SendDispatchMouseEventResponse(DevToolsCommandId command_id);
+
   void SendSynthesizePinchGestureResponse(DevToolsCommandId command_id,
                                           SyntheticGesture::Result result);
 
@@ -125,8 +136,16 @@
                         DevToolsCommandId command_id,
                         SyntheticGesture::Result result);
 
+  void ClearPendingKeyCommands();
+  void ClearPendingMouseCommands();
+
   RenderWidgetHostImpl* host_;
   std::unique_ptr<Client> client_;
+  // DevToolsCommandIds for calls to Input.dispatchKey/MouseEvent that have been
+  // sent to the renderer, but that we haven't yet received an ack for.
+  bool input_queued_;
+  std::deque<DevToolsCommandId> pending_key_command_ids_;
+  std::deque<DevToolsCommandId> pending_mouse_command_ids_;
   float page_scale_factor_;
   gfx::SizeF scrollable_viewport_size_;
   base::WeakPtrFactory<InputHandler> weak_factory_;
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index dd1ee7ad..43253f6f9 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -584,6 +584,7 @@
     emulation_handler_->Detached();
   if (page_handler_)
     page_handler_->Detached();
+  input_handler_->Detached();
   service_worker_handler_->Detached();
   target_handler_->Detached();
   frame_trace_recorder_.reset();
diff --git a/content/browser/gamepad/OWNERS b/content/browser/gamepad/OWNERS
deleted file mode 100644
index 16c21dcb..0000000
--- a/content/browser/gamepad/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-scottmg@chromium.org
-bajones@chromium.org
diff --git a/content/browser/gamepad/gamepad_service_test_helpers.cc b/content/browser/gamepad/gamepad_service_test_helpers.cc
deleted file mode 100644
index 195dd8f..0000000
--- a/content/browser/gamepad/gamepad_service_test_helpers.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/gamepad/gamepad_service_test_helpers.h"
-
-#include "content/browser/gamepad/gamepad_service.h"
-
-namespace content {
-
-GamepadServiceTestConstructor::GamepadServiceTestConstructor(
-    const blink::WebGamepads& test_data) {
-  data_fetcher_ = new device::MockGamepadDataFetcher(test_data);
-  gamepad_service_ = new GamepadService(
-      std::unique_ptr<device::GamepadDataFetcher>(data_fetcher_));
-}
-
-GamepadServiceTestConstructor::~GamepadServiceTestConstructor() {
-  delete gamepad_service_;
-}
-
-}  // namespace content
diff --git a/content/browser/gamepad/gamepad_service_test_helpers.h b/content/browser/gamepad/gamepad_service_test_helpers.h
deleted file mode 100644
index 273a42d..0000000
--- a/content/browser/gamepad/gamepad_service_test_helpers.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_TEST_HELPERS_H_
-#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_TEST_HELPERS_H_
-
-#include "base/macros.h"
-#include "device/gamepad/gamepad_test_helpers.h"
-#include "third_party/WebKit/public/platform/WebGamepads.h"
-
-namespace content {
-
-class GamepadService;
-
-// Constructs a GamepadService with a mock data source. This bypasses the
-// global singleton for the gamepad service.
-class GamepadServiceTestConstructor : public device::GamepadTestHelper {
- public:
-  explicit GamepadServiceTestConstructor(const blink::WebGamepads& test_data);
-  ~GamepadServiceTestConstructor() override;
-
-  GamepadService* gamepad_service() { return gamepad_service_; }
-  device::MockGamepadDataFetcher* data_fetcher() { return data_fetcher_; }
-
- private:
-  // Owning pointer (can't be a scoped_ptr due to private destructor).
-  GamepadService* gamepad_service_;
-
-  // Pointer owned by the provider (which is owned by the gamepad service).
-  device::MockGamepadDataFetcher* data_fetcher_;
-
-  DISALLOW_COPY_AND_ASSIGN(GamepadServiceTestConstructor);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_TEST_HELPERS_H_
diff --git a/content/browser/gamepad/gamepad_shared_buffer_impl.cc b/content/browser/gamepad/gamepad_shared_buffer_impl.cc
deleted file mode 100644
index 03911cb..0000000
--- a/content/browser/gamepad/gamepad_shared_buffer_impl.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/gamepad/gamepad_shared_buffer_impl.h"
-
-#include "content/common/gamepad_hardware_buffer.h"
-
-namespace content {
-
-GamepadSharedBufferImpl::GamepadSharedBufferImpl() {
-  size_t data_size = sizeof(GamepadHardwareBuffer);
-  bool res = shared_memory_.CreateAndMapAnonymous(data_size);
-  CHECK(res);
-
-  void* mem = shared_memory_.memory();
-  DCHECK(mem);
-  new (mem) GamepadHardwareBuffer();
-}
-
-GamepadSharedBufferImpl::~GamepadSharedBufferImpl() {
-}
-
-base::SharedMemory* GamepadSharedBufferImpl::shared_memory() {
-  return &shared_memory_;
-}
-
-blink::WebGamepads* GamepadSharedBufferImpl::buffer() {
-  return &(hardware_buffer()->buffer);
-}
-
-GamepadHardwareBuffer* GamepadSharedBufferImpl::hardware_buffer() {
-  void* mem = shared_memory_.memory();
-  DCHECK(mem);
-  return static_cast<GamepadHardwareBuffer*>(mem);
-}
-
-void GamepadSharedBufferImpl::WriteBegin() {
-  hardware_buffer()->sequence.WriteBegin();
-}
-
-void GamepadSharedBufferImpl::WriteEnd() {
-  hardware_buffer()->sequence.WriteEnd();
-}
-
-}  // namespace content
diff --git a/content/browser/gamepad/gamepad_shared_buffer_impl.h b/content/browser/gamepad/gamepad_shared_buffer_impl.h
deleted file mode 100644
index fd2fa42..0000000
--- a/content/browser/gamepad/gamepad_shared_buffer_impl.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 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 CONTENT_BROWSER_GAMEPAD_GAMEPAD_SHARED_BUFFER_IMPL_H_
-#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_SHARED_BUFFER_IMPL_H_
-
-#include "device/gamepad/gamepad_shared_buffer.h"
-#include "third_party/WebKit/public/platform/WebGamepads.h"
-
-namespace content {
-
-struct GamepadHardwareBuffer;
-
-class GamepadSharedBufferImpl : public device::GamepadSharedBuffer {
- public:
-  GamepadSharedBufferImpl();
-  ~GamepadSharedBufferImpl() override;
-
-  base::SharedMemory* shared_memory() override;
-  blink::WebGamepads* buffer() override;
-  GamepadHardwareBuffer* hardware_buffer();
-
-  void WriteBegin() override;
-  void WriteEnd() override;
-
- private:
-  base::SharedMemory shared_memory_;
-
-  DISALLOW_COPY_AND_ASSIGN(GamepadSharedBufferImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_GAMEPAD_GAMEPAD_SHARED_BUFFER_IMPL_H_
diff --git a/content/browser/renderer_host/pepper/pepper_gamepad_host.cc b/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
index e7a0aa79..775b7bcd 100644
--- a/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_gamepad_host.cc
@@ -5,8 +5,8 @@
 #include "content/browser/renderer_host/pepper/pepper_gamepad_host.h"
 
 #include "base/bind.h"
-#include "content/browser/gamepad/gamepad_service.h"
 #include "content/public/browser/browser_ppapi_host.h"
+#include "device/gamepad/gamepad_service.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/host/dispatch_host_message.h"
 #include "ppapi/host/host_message_context.h"
@@ -21,11 +21,11 @@
                                      PP_Resource resource)
     : ResourceHost(host->GetPpapiHost(), instance, resource),
       browser_ppapi_host_(host),
-      gamepad_service_(GamepadService::GetInstance()),
+      gamepad_service_(device::GamepadService::GetInstance()),
       is_started_(false),
       weak_factory_(this) {}
 
-PepperGamepadHost::PepperGamepadHost(GamepadService* gamepad_service,
+PepperGamepadHost::PepperGamepadHost(device::GamepadService* gamepad_service,
                                      BrowserPpapiHost* host,
                                      PP_Instance instance,
                                      PP_Resource resource)
diff --git a/content/browser/renderer_host/pepper/pepper_gamepad_host.h b/content/browser/renderer_host/pepper/pepper_gamepad_host.h
index 0da28d9..6cc2422 100644
--- a/content/browser/renderer_host/pepper/pepper_gamepad_host.h
+++ b/content/browser/renderer_host/pepper/pepper_gamepad_host.h
@@ -14,6 +14,10 @@
 #include "device/gamepad/gamepad_consumer.h"
 #include "ppapi/host/resource_host.h"
 
+namespace device {
+class GamepadService;
+}
+
 namespace ppapi {
 namespace host {
 struct ReplyMessageContext;
@@ -23,7 +27,6 @@
 namespace content {
 
 class BrowserPpapiHost;
-class GamepadService;
 
 class CONTENT_EXPORT PepperGamepadHost :
     public ppapi::host::ResourceHost,
@@ -35,7 +38,7 @@
 
   // Allows tests to specify a gamepad service to use rather than the global
   // singleton. The caller owns the gamepad_service pointer.
-  PepperGamepadHost(GamepadService* gamepad_service,
+  PepperGamepadHost(device::GamepadService* gamepad_service,
                     BrowserPpapiHost* host,
                     PP_Instance instance,
                     PP_Resource resource);
@@ -59,7 +62,7 @@
 
   BrowserPpapiHost* browser_ppapi_host_;
 
-  GamepadService* gamepad_service_;
+  device::GamepadService* gamepad_service_;
 
   bool is_started_;
 
diff --git a/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc b/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc
index b79ba97..4075847 100644
--- a/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc
+++ b/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc
@@ -13,9 +13,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
-#include "content/browser/gamepad/gamepad_service_test_helpers.h"
 #include "content/browser/renderer_host/pepper/browser_ppapi_host_test.h"
-#include "content/common/gamepad_hardware_buffer.h"
+#include "device/gamepad/gamepad_shared_buffer.h"
 #include "device/gamepad/gamepad_test_helpers.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/host/host_message_context.h"
@@ -36,13 +35,15 @@
   ~PepperGamepadHostTest() override {}
 
   void ConstructService(const blink::WebGamepads& test_data) {
-    service_.reset(new GamepadServiceTestConstructor(test_data));
+    service_.reset(new device::GamepadServiceTestConstructor(test_data));
   }
 
-  GamepadService* gamepad_service() { return service_->gamepad_service(); }
+  device::GamepadService* gamepad_service() {
+    return service_->gamepad_service();
+  }
 
  protected:
-  std::unique_ptr<GamepadServiceTestConstructor> service_;
+  std::unique_ptr<device::GamepadServiceTestConstructor> service_;
 
   DISALLOW_COPY_AND_ASSIGN(PepperGamepadHostTest);
 };
@@ -59,13 +60,13 @@
 TEST_F(PepperGamepadHostTest, ValidateHardwareBuffersMatch) {
   // Hardware buffer.
   static_assert(sizeof(ppapi::ContentGamepadHardwareBuffer) ==
-                    sizeof(GamepadHardwareBuffer),
+                    sizeof(device::GamepadHardwareBuffer),
                 "gamepad hardware buffers must match");
   ppapi::ContentGamepadHardwareBuffer ppapi_buf;
-  GamepadHardwareBuffer content_buf;
-  EXPECT_EQ(AddressDiff(&content_buf.sequence, &content_buf),
+  device::GamepadHardwareBuffer content_buf;
+  EXPECT_EQ(AddressDiff(&content_buf.seqlock, &content_buf),
             AddressDiff(&ppapi_buf.sequence, &ppapi_buf));
-  EXPECT_EQ(AddressDiff(&content_buf.buffer, &content_buf),
+  EXPECT_EQ(AddressDiff(&content_buf.data, &content_buf),
             AddressDiff(&ppapi_buf.buffer, &ppapi_buf));
 }
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 87437a0bc..12fd4ea 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -99,7 +99,6 @@
 #include "content/browser/renderer_host/clipboard_message_filter.h"
 #include "content/browser/renderer_host/database_message_filter.h"
 #include "content/browser/renderer_host/file_utilities_message_filter.h"
-#include "content/browser/renderer_host/gamepad_monitor.h"
 #include "content/browser/renderer_host/media/audio_input_renderer_host.h"
 #include "content/browser/renderer_host/media/audio_renderer_host.h"
 #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
@@ -164,6 +163,7 @@
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
 #include "device/battery/battery_monitor_impl.h"
+#include "device/gamepad/gamepad_monitor.h"
 #include "device/power_monitor/power_monitor_message_broadcaster.h"
 #include "device/time_zone_monitor/time_zone_monitor.h"
 #include "gpu/GLES2/gl2extchromium.h"
@@ -1284,7 +1284,7 @@
   registry->AddInterface(base::Bind(&DeviceOrientationAbsoluteHost::Create));
 #endif  // defined(OS_ANDROID)
 
-  registry->AddInterface(base::Bind(&GamepadMonitor::Create));
+  registry->AddInterface(base::Bind(&device::GamepadMonitor::Create));
 
   registry->AddInterface(
       base::Bind(&VideoCaptureHost::Create,
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 6141da6d..dd33dfe 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2153,6 +2153,8 @@
       const NativeWebKeyboardEventWithLatencyInfo& event,
       InputEventAckState ack_result) {
   latency_tracker_.OnInputEventAck(event.event, &event.latency, ack_result);
+  for (auto& input_event_observer : input_event_observers_)
+    input_event_observer.OnInputEventAck(event.event);
 
   const bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result);
 
@@ -2173,6 +2175,8 @@
     InputEventAckState ack_result) {
   latency_tracker_.OnInputEventAck(mouse_event.event, &mouse_event.latency,
                                    ack_result);
+  for (auto& input_event_observer : input_event_observers_)
+    input_event_observer.OnInputEventAck(mouse_event.event);
 }
 
 void RenderWidgetHostImpl::OnWheelEventAck(
@@ -2180,6 +2184,8 @@
     InputEventAckState ack_result) {
   latency_tracker_.OnInputEventAck(wheel_event.event, &wheel_event.latency,
                                    ack_result);
+  for (auto& input_event_observer : input_event_observers_)
+    input_event_observer.OnInputEventAck(wheel_event.event);
 
   if (!is_hidden() && view_) {
     if (ack_result != INPUT_EVENT_ACK_STATE_CONSUMED &&
@@ -2194,6 +2200,8 @@
     const GestureEventWithLatencyInfo& event,
     InputEventAckState ack_result) {
   latency_tracker_.OnInputEventAck(event.event, &event.latency, ack_result);
+  for (auto& input_event_observer : input_event_observers_)
+    input_event_observer.OnInputEventAck(event.event);
 
   if (view_)
     view_->GestureEventAck(event.event, ack_result);
@@ -2203,6 +2211,8 @@
     const TouchEventWithLatencyInfo& event,
     InputEventAckState ack_result) {
   latency_tracker_.OnInputEventAck(event.event, &event.latency, ack_result);
+  for (auto& input_event_observer : input_event_observers_)
+    input_event_observer.OnInputEventAck(event.event);
 
   if (touch_emulator_ &&
       touch_emulator_->HandleTouchEventAck(event.event, ack_result)) {
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index 2b211b4..a76a59f98 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -37,7 +37,6 @@
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/interfaces/service.mojom.h"
 #include "services/service_manager/runner/common/client_util.h"
-#include "services/service_manager/runner/host/in_process_native_runner.h"
 #include "services/service_manager/service_manager.h"
 
 namespace content {
@@ -134,6 +133,22 @@
   DISALLOW_COPY_AND_ASSIGN(BuiltinManifestProvider);
 };
 
+class NullNativeRunnerFactory : public service_manager::NativeRunnerFactory {
+ public:
+  NullNativeRunnerFactory() {}
+  ~NullNativeRunnerFactory() override {}
+
+  std::unique_ptr<service_manager::NativeRunner> Create(
+      const base::FilePath& service_path) override {
+    LOG(ERROR) << "Attempting to run unsupported native service: "
+               << service_path.value();
+    return nullptr;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NullNativeRunnerFactory);
+};
+
 }  // namespace
 
 // State which lives on the IO thread and drives the ServiceManager.
@@ -174,12 +189,10 @@
     manifest_provider_ = std::move(manifest_provider);
 
     base::SequencedWorkerPool* blocking_pool = BrowserThread::GetBlockingPool();
-    std::unique_ptr<service_manager::NativeRunnerFactory> native_runner_factory(
-        new service_manager::InProcessNativeRunnerFactory(blocking_pool));
     catalog_.reset(
         new catalog::Catalog(blocking_pool, nullptr, manifest_provider_.get()));
     service_manager_.reset(new service_manager::ServiceManager(
-        std::move(native_runner_factory), catalog_->TakeService()));
+        base::MakeUnique<NullNativeRunnerFactory>(), catalog_->TakeService()));
 
     service_manager::mojom::ServiceRequest request =
         service_manager_->StartEmbedderService(mojom::kBrowserServiceName);
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 43eff18d..697de21 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -125,7 +125,6 @@
     "frame_owner_properties.h",
     "frame_replication_state.cc",
     "frame_replication_state.h",
-    "gamepad_hardware_buffer.h",
     "generic_shared_memory_id_generator.cc",
     "generic_shared_memory_id_generator.h",
     "gin_java_bridge_messages.h",
diff --git a/content/common/gamepad_hardware_buffer.h b/content/common/gamepad_hardware_buffer.h
deleted file mode 100644
index 5098cb1..0000000
--- a/content/common/gamepad_hardware_buffer.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_COMMON_GAMEPAD_HARDWARE_BUFFER_H_
-#define CONTENT_COMMON_GAMEPAD_HARDWARE_BUFFER_H_
-
-#include "device/base/synchronization/one_writer_seqlock.h"
-#include "third_party/WebKit/public/platform/WebGamepads.h"
-
-namespace content {
-
-/*
-
-This structure is stored in shared memory that's shared between the browser
-which does the hardware polling, and the various consumers of the gamepad
-state (renderers and NaCl plugins). The performance characteristics are that
-we want low latency (so would like to avoid explicit communication via IPC
-between producer and consumer) and relatively large data size.
-
-Writer and reader operate on the same buffer assuming contention is low, and
-contention is detected by using the associated SeqLock.
-
-*/
-
-struct GamepadHardwareBuffer {
-  // FIXME: Use the generic SharedMemorySeqLockBuffer<blink::WebGamepads>.
-  device::OneWriterSeqLock sequence;
-  blink::WebGamepads buffer;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_GAMEPAD_HARDWARE_BUFFER_H_
diff --git a/content/public/browser/render_widget_host.h b/content/public/browser/render_widget_host.h
index 0cda573d..7005ece92 100644
--- a/content/public/browser/render_widget_host.h
+++ b/content/public/browser/render_widget_host.h
@@ -243,12 +243,13 @@
   virtual void AddMouseEventCallback(const MouseEventCallback& callback) = 0;
   virtual void RemoveMouseEventCallback(const MouseEventCallback& callback) = 0;
 
-  // Observer for WebInputEvents (but not input event acks).
+  // Observer for WebInputEvents.
   class InputEventObserver {
    public:
     virtual ~InputEventObserver() {}
 
-    virtual void OnInputEvent(const blink::WebInputEvent&) = 0;
+    virtual void OnInputEvent(const blink::WebInputEvent&) {};
+    virtual void OnInputEventAck(const blink::WebInputEvent&) {};
   };
 
   // Add/remove an input event observer.
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 7d066fe1..a39b5f8b 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1327,7 +1327,11 @@
         new MessageLoopRunner(MessageLoopRunner::QuitMode::IMMEDIATE);
     message_loop_runner_->Run();
   }
-  // The queue should not be empty, unless we were quit because of a timeout.
+  return PopMessage(message);
+}
+
+bool DOMMessageQueue::PopMessage(std::string* message) {
+  DCHECK(message);
   if (message_queue_.empty())
     return false;
   *message = message_queue_.front();
@@ -1527,9 +1531,13 @@
   return false;
 }
 
+bool InputMsgWatcher::HasReceivedAck() const {
+  return ack_result_ != INPUT_EVENT_ACK_STATE_UNKNOWN;
+}
+
 uint32_t InputMsgWatcher::WaitForAck() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (ack_result_ != INPUT_EVENT_ACK_STATE_UNKNOWN)
+  if (HasReceivedAck())
     return ack_result_;
   base::RunLoop run_loop;
   base::AutoReset<base::Closure> reset_quit(&quit_, run_loop.QuitClosure());
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 1deed61..1d05389 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -442,6 +442,10 @@
   // message. Returns true on success.
   bool WaitForMessage(std::string* message) WARN_UNUSED_RESULT;
 
+  // If there is a message in the queue, then copies it to |message| and returns
+  // true.  Otherwise (if the queue is empty), returns false.
+  bool PopMessage(std::string* message) WARN_UNUSED_RESULT;
+
   // Overridden NotificationObserver methods.
   void Observe(int type,
                const NotificationSource& source,
@@ -552,6 +556,8 @@
   InputMsgWatcher(RenderWidgetHost* render_widget_host,
                   blink::WebInputEvent::Type type);
 
+  bool HasReceivedAck() const;
+
   // Wait until ack message occurs, returning the ack result from
   // the message.
   uint32_t WaitForAck();
diff --git a/content/renderer/gamepad_shared_memory_reader.cc b/content/renderer/gamepad_shared_memory_reader.cc
index f48a0fb2..f1eb932 100644
--- a/content/renderer/gamepad_shared_memory_reader.cc
+++ b/content/renderer/gamepad_shared_memory_reader.cc
@@ -6,7 +6,6 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
-#include "content/common/gamepad_hardware_buffer.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
 #include "ipc/ipc_sync_message_filter.h"
@@ -92,12 +91,12 @@
   int contention_count = -1;
   base::subtle::Atomic32 version;
   do {
-    version = gamepad_hardware_buffer_->sequence.ReadBegin();
-    memcpy(&read_into, &gamepad_hardware_buffer_->buffer, sizeof(read_into));
+    version = gamepad_hardware_buffer_->seqlock.ReadBegin();
+    memcpy(&read_into, &gamepad_hardware_buffer_->data, sizeof(read_into));
     ++contention_count;
     if (contention_count == kMaximumContentionCount)
       break;
-  } while (gamepad_hardware_buffer_->sequence.ReadRetry(version));
+  } while (gamepad_hardware_buffer_->seqlock.ReadRetry(version));
   UMA_HISTOGRAM_COUNTS("Gamepad.ReadContentionCount", contention_count);
 
   if (contention_count >= kMaximumContentionCount) {
diff --git a/content/renderer/gamepad_shared_memory_reader.h b/content/renderer/gamepad_shared_memory_reader.h
index 2eef9d22..af4530f3 100644
--- a/content/renderer/gamepad_shared_memory_reader.h
+++ b/content/renderer/gamepad_shared_memory_reader.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/shared_memory.h"
 #include "content/public/renderer/renderer_gamepad_provider.h"
+#include "device/base/synchronization/shared_memory_seqlock_buffer.h"
 #include "device/gamepad/public/interfaces/gamepad.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/platform_handle.h"
@@ -17,7 +18,8 @@
 
 namespace content {
 
-struct GamepadHardwareBuffer;
+typedef device::SharedMemorySeqLockBuffer<blink::WebGamepads>
+    GamepadHardwareBuffer;
 
 class GamepadSharedMemoryReader : public RendererGamepadProvider,
                                   public device::mojom::GamepadObserver {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 2a595d0..d63d0f6 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1072,9 +1072,6 @@
     "../browser/frame_host/render_frame_host_manager_unittest.cc",
     "../browser/frame_host/render_widget_host_view_child_frame_unittest.cc",
     "../browser/frame_host/render_widget_host_view_guest_unittest.cc",
-    "../browser/gamepad/gamepad_service_test_helpers.cc",
-    "../browser/gamepad/gamepad_service_test_helpers.h",
-    "../browser/gamepad/gamepad_service_unittest.cc",
     "../browser/gpu/gpu_data_manager_impl_private_unittest.cc",
     "../browser/gpu/shader_disk_cache_unittest.cc",
     "../browser/host_zoom_map_impl_unittest.cc",
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 44eddbe..3b7cd74d 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -62,6 +62,7 @@
     "bluetooth/test/test_bluetooth_local_gatt_service_delegate.cc",
     "bluetooth/test/test_bluetooth_local_gatt_service_delegate.h",
     "gamepad/gamepad_provider_unittest.cc",
+    "gamepad/gamepad_service_unittest.cc",
     "gamepad/public/interfaces/gamepad_struct_traits_unittest.cc",
     "generic_sensor/platform_sensor_and_provider_unittest_win.cc",
     "generic_sensor/platform_sensor_provider_unittest.cc",
diff --git a/device/gamepad/BUILD.gn b/device/gamepad/BUILD.gn
index 92cc1d3..2285dd93 100644
--- a/device/gamepad/BUILD.gn
+++ b/device/gamepad/BUILD.gn
@@ -23,6 +23,8 @@
     "gamepad_data_fetcher.h",
     "gamepad_data_fetcher_manager.cc",
     "gamepad_data_fetcher_manager.h",
+    "gamepad_monitor.cc",
+    "gamepad_monitor.h",
     "gamepad_pad_state_provider.cc",
     "gamepad_pad_state_provider.h",
     "gamepad_platform_data_fetcher.h",
@@ -36,6 +38,10 @@
     "gamepad_platform_data_fetcher_win.h",
     "gamepad_provider.cc",
     "gamepad_provider.h",
+    "gamepad_service.cc",
+    "gamepad_service.h",
+    "gamepad_shared_buffer.cc",
+    "gamepad_shared_buffer.h",
     "gamepad_standard_mappings.cc",
     "gamepad_standard_mappings.h",
     "gamepad_standard_mappings_linux.cc",
@@ -52,6 +58,9 @@
   deps = [
     "//base",
     "//base/third_party/dynamic_annotations",
+    "//device/base/synchronization",
+    "//device/gamepad/public/interfaces",
+    "//mojo/public/cpp/system",
     "//third_party/WebKit/public:blink_headers",
   ]
 
diff --git a/content/browser/renderer_host/gamepad_monitor.cc b/device/gamepad/gamepad_monitor.cc
similarity index 76%
rename from content/browser/renderer_host/gamepad_monitor.cc
rename to device/gamepad/gamepad_monitor.cc
index 4ac85f8..5bcf5f9 100644
--- a/content/browser/renderer_host/gamepad_monitor.cc
+++ b/device/gamepad/gamepad_monitor.cc
@@ -2,26 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/renderer_host/gamepad_monitor.h"
+#include "device/gamepad/gamepad_monitor.h"
 
 #include "base/memory/shared_memory.h"
-#include "content/browser/gamepad/gamepad_service.h"
-#include "content/common/gamepad_hardware_buffer.h"
-#include "content/public/browser/browser_thread.h"
+#include "device/gamepad/gamepad_service.h"
+#include "device/gamepad/gamepad_shared_buffer.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
-namespace content {
+namespace device {
 
 GamepadMonitor::GamepadMonitor() : is_started_(false) {}
 
 GamepadMonitor::~GamepadMonitor() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (is_started_)
     GamepadService::GetInstance()->RemoveConsumer(this);
 }
 
 // static
-void GamepadMonitor::Create(device::mojom::GamepadMonitorRequest request) {
+void GamepadMonitor::Create(mojom::GamepadMonitorRequest request) {
   mojo::MakeStrongBinding(base::MakeUnique<GamepadMonitor>(),
                           std::move(request));
 }
@@ -57,9 +55,8 @@
   callback.Run();
 }
 
-void GamepadMonitor::SetObserver(
-    device::mojom::GamepadObserverPtr gamepad_observer) {
+void GamepadMonitor::SetObserver(mojom::GamepadObserverPtr gamepad_observer) {
   gamepad_observer_ = std::move(gamepad_observer);
 }
 
-}  // namespace content
+}  // namespace device
diff --git a/content/browser/renderer_host/gamepad_monitor.h b/device/gamepad/gamepad_monitor.h
similarity index 60%
rename from content/browser/renderer_host/gamepad_monitor.h
rename to device/gamepad/gamepad_monitor.h
index 1503a240..fab371e 100644
--- a/content/browser/renderer_host/gamepad_monitor.h
+++ b/device/gamepad/gamepad_monitor.h
@@ -2,23 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_GAMEPAD_MONITOR_H_
-#define CONTENT_BROWSER_RENDERER_HOST_GAMEPAD_MONITOR_H_
+#ifndef DEVICE_GAMEPAD_GAMEPAD_MONITOR_H_
+#define DEVICE_GAMEPAD_GAMEPAD_MONITOR_H_
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "device/gamepad/gamepad_consumer.h"
+#include "device/gamepad/gamepad_export.h"
 #include "device/gamepad/public/interfaces/gamepad.mojom.h"
 
-namespace content {
+namespace device {
 
-class GamepadMonitor : public device::GamepadConsumer,
-                       public device::mojom::GamepadMonitor {
+class DEVICE_GAMEPAD_EXPORT GamepadMonitor
+    : public GamepadConsumer,
+      NON_EXPORTED_BASE(public mojom::GamepadMonitor) {
  public:
   GamepadMonitor();
   ~GamepadMonitor() override;
 
-  static void Create(device::mojom::GamepadMonitorRequest request);
+  static void Create(mojom::GamepadMonitorRequest request);
 
   // GamepadConsumer implementation.
   void OnGamepadConnected(unsigned index,
@@ -26,19 +28,19 @@
   void OnGamepadDisconnected(unsigned index,
                              const blink::WebGamepad& gamepad) override;
 
-  // device::mojom::GamepadMonitor implementation.
+  // mojom::GamepadMonitor implementation.
   void GamepadStartPolling(
       const GamepadStartPollingCallback& callback) override;
   void GamepadStopPolling(const GamepadStopPollingCallback& callback) override;
-  void SetObserver(device::mojom::GamepadObserverPtr gamepad_observer) override;
+  void SetObserver(mojom::GamepadObserverPtr gamepad_observer) override;
 
  private:
-  device::mojom::GamepadObserverPtr gamepad_observer_;
+  mojom::GamepadObserverPtr gamepad_observer_;
   bool is_started_;
 
   DISALLOW_COPY_AND_ASSIGN(GamepadMonitor);
 };
 
-}  // namespace content
+}  // namespace device
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_GAMEPAD_MONITOR_H_
+#endif  // DEVICE_GAMEPAD_GAMEPAD_MONITOR_H_
diff --git a/device/gamepad/gamepad_provider.cc b/device/gamepad/gamepad_provider.cc
index 024fdba3..ba10cd4c 100644
--- a/device/gamepad/gamepad_provider.cc
+++ b/device/gamepad/gamepad_provider.cc
@@ -39,20 +39,18 @@
 GamepadProvider::ClosureAndThread::~ClosureAndThread() {}
 
 GamepadProvider::GamepadProvider(
-    std::unique_ptr<GamepadSharedBuffer> buffer,
     GamepadConnectionChangeClient* connection_change_client)
     : is_paused_(true),
       have_scheduled_do_poll_(false),
       devices_changed_(true),
       ever_had_user_gesture_(false),
       sanitize_(true),
-      gamepad_shared_buffer_(std::move(buffer)),
+      gamepad_shared_buffer_(new GamepadSharedBuffer()),
       connection_change_client_(connection_change_client) {
   Initialize(std::unique_ptr<GamepadDataFetcher>());
 }
 
 GamepadProvider::GamepadProvider(
-    std::unique_ptr<GamepadSharedBuffer> buffer,
     GamepadConnectionChangeClient* connection_change_client,
     std::unique_ptr<GamepadDataFetcher> fetcher)
     : is_paused_(true),
@@ -60,7 +58,7 @@
       devices_changed_(true),
       ever_had_user_gesture_(false),
       sanitize_(true),
-      gamepad_shared_buffer_(std::move(buffer)),
+      gamepad_shared_buffer_(new GamepadSharedBuffer()),
       connection_change_client_(connection_change_client) {
   Initialize(std::move(fetcher));
 }
@@ -260,7 +258,7 @@
     base::AutoLock lock(shared_memory_lock_);
 
     // Acquire the SeqLock. There is only ever one writer to this data.
-    // See gamepad_hardware_buffer.h.
+    // See gamepad_shared_buffer.h.
     gamepad_shared_buffer_->WriteBegin();
     buffer->length = 0;
     for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
diff --git a/device/gamepad/gamepad_provider.h b/device/gamepad/gamepad_provider.h
index 6b24340..5cf4fdad 100644
--- a/device/gamepad/gamepad_provider.h
+++ b/device/gamepad/gamepad_provider.h
@@ -42,12 +42,10 @@
       public base::SystemMonitor::DevicesChangedObserver {
  public:
   explicit GamepadProvider(
-      std::unique_ptr<GamepadSharedBuffer> buffer,
       GamepadConnectionChangeClient* connection_change_client);
 
   // Manually specifies the data fetcher. Used for testing.
   explicit GamepadProvider(
-      std::unique_ptr<GamepadSharedBuffer> buffer,
       GamepadConnectionChangeClient* connection_change_client,
       std::unique_ptr<GamepadDataFetcher> fetcher);
 
diff --git a/device/gamepad/gamepad_provider_unittest.cc b/device/gamepad/gamepad_provider_unittest.cc
index 180a804..03b12638 100644
--- a/device/gamepad/gamepad_provider_unittest.cc
+++ b/device/gamepad/gamepad_provider_unittest.cc
@@ -45,11 +45,20 @@
   GamepadProvider* CreateProvider(const WebGamepads& test_data) {
     mock_data_fetcher_ = new MockGamepadDataFetcher(test_data);
     provider_.reset(new GamepadProvider(
-        std::unique_ptr<GamepadSharedBuffer>(new MockGamepadSharedBuffer()),
         nullptr, std::unique_ptr<GamepadDataFetcher>(mock_data_fetcher_)));
     return provider_.get();
   }
 
+  void ReadGamepadHardwareBuffer(GamepadHardwareBuffer* buffer,
+                                 WebGamepads* output) {
+    memset(output, 0, sizeof(WebGamepads));
+    base::subtle::Atomic32 version;
+    do {
+      version = buffer->seqlock.ReadBegin();
+      memcpy(output, &buffer->data, sizeof(WebGamepads));
+    } while (buffer->seqlock.ReadRetry(version));
+  }
+
  protected:
   GamepadProviderTest() {}
 
@@ -70,6 +79,7 @@
 #endif
 TEST_F(GamepadProviderTest, MAYBE_PollingAccess) {
   WebGamepads test_data;
+  memset(&test_data, 0, sizeof(WebGamepads));
   test_data.length = 1;
   test_data.items[0].connected = true;
   test_data.items[0].timestamp = 0;
@@ -93,18 +103,20 @@
       base::GetCurrentProcessHandle());
   std::unique_ptr<base::SharedMemory> shared_memory(
       new base::SharedMemory(handle, true));
-  EXPECT_TRUE(shared_memory->Map(sizeof(WebGamepads)));
-  void* mem = shared_memory->memory();
+  EXPECT_TRUE(shared_memory->Map(sizeof(GamepadHardwareBuffer)));
 
-  WebGamepads* output = static_cast<WebGamepads*>(mem);
+  GamepadHardwareBuffer* buffer =
+      static_cast<GamepadHardwareBuffer*>(shared_memory->memory());
+  WebGamepads output;
+  ReadGamepadHardwareBuffer(buffer, &output);
 
-  EXPECT_EQ(1u, output->length);
-  EXPECT_EQ(1u, output->items[0].buttonsLength);
-  EXPECT_EQ(1.f, output->items[0].buttons[0].value);
-  EXPECT_EQ(true, output->items[0].buttons[0].pressed);
-  EXPECT_EQ(2u, output->items[0].axesLength);
-  EXPECT_EQ(-1.f, output->items[0].axes[0]);
-  EXPECT_EQ(0.5f, output->items[0].axes[1]);
+  EXPECT_EQ(1u, output.length);
+  EXPECT_EQ(1u, output.items[0].buttonsLength);
+  EXPECT_EQ(1.f, output.items[0].buttons[0].value);
+  EXPECT_EQ(true, output.items[0].buttons[0].pressed);
+  EXPECT_EQ(2u, output.items[0].axesLength);
+  EXPECT_EQ(-1.f, output.items[0].axes[0]);
+  EXPECT_EQ(0.5f, output.items[0].axes[1]);
 }
 
 // Tests that waiting for a user gesture works properly.
@@ -191,43 +203,51 @@
       base::GetCurrentProcessHandle());
   std::unique_ptr<base::SharedMemory> shared_memory(
       new base::SharedMemory(handle, true));
-  EXPECT_TRUE(shared_memory->Map(sizeof(WebGamepads)));
-  void* mem = shared_memory->memory();
+  EXPECT_TRUE(shared_memory->Map(sizeof(GamepadHardwareBuffer)));
 
-  WebGamepads* output = static_cast<WebGamepads*>(mem);
+  GamepadHardwareBuffer* buffer =
+      static_cast<GamepadHardwareBuffer*>(shared_memory->memory());
+  WebGamepads output;
+  ReadGamepadHardwareBuffer(buffer, &output);
 
   // Initial data should all be zeroed out due to sanitization, even though the
   // gamepad reported input
-  EXPECT_EQ(1u, output->length);
-  EXPECT_EQ(1u, output->items[0].buttonsLength);
-  EXPECT_EQ(0.f, output->items[0].buttons[0].value);
-  EXPECT_FALSE(output->items[0].buttons[0].pressed);
-  EXPECT_EQ(1u, output->items[0].axesLength);
-  EXPECT_EQ(0.f, output->items[0].axes[0]);
+  EXPECT_EQ(1u, output.length);
+  EXPECT_EQ(1u, output.items[0].buttonsLength);
+  EXPECT_EQ(0.f, output.items[0].buttons[0].value);
+  EXPECT_FALSE(output.items[0].buttons[0].pressed);
+  EXPECT_EQ(1u, output.items[0].axesLength);
+  EXPECT_EQ(0.f, output.items[0].axes[0]);
 
   // Zero out the inputs
   mock_data_fetcher_->SetTestData(zero_data);
   mock_data_fetcher_->WaitForDataReadAndCallbacksIssued();
 
+  // Read updated data from shared memory
+  ReadGamepadHardwareBuffer(buffer, &output);
+
   // Should still read zero, which is now an accurate reflection of the data
-  EXPECT_EQ(1u, output->length);
-  EXPECT_EQ(1u, output->items[0].buttonsLength);
-  EXPECT_EQ(0.f, output->items[0].buttons[0].value);
-  EXPECT_FALSE(output->items[0].buttons[0].pressed);
-  EXPECT_EQ(1u, output->items[0].axesLength);
-  EXPECT_EQ(0.f, output->items[0].axes[0]);
+  EXPECT_EQ(1u, output.length);
+  EXPECT_EQ(1u, output.items[0].buttonsLength);
+  EXPECT_EQ(0.f, output.items[0].buttons[0].value);
+  EXPECT_FALSE(output.items[0].buttons[0].pressed);
+  EXPECT_EQ(1u, output.items[0].axesLength);
+  EXPECT_EQ(0.f, output.items[0].axes[0]);
 
   // Re-set the active inputs
   mock_data_fetcher_->SetTestData(active_data);
   mock_data_fetcher_->WaitForDataReadAndCallbacksIssued();
 
+  // Read updated data from shared memory
+  ReadGamepadHardwareBuffer(buffer, &output);
+
   // Should now accurately reflect the reported data.
-  EXPECT_EQ(1u, output->length);
-  EXPECT_EQ(1u, output->items[0].buttonsLength);
-  EXPECT_EQ(1.f, output->items[0].buttons[0].value);
-  EXPECT_TRUE(output->items[0].buttons[0].pressed);
-  EXPECT_EQ(1u, output->items[0].axesLength);
-  EXPECT_EQ(-1.f, output->items[0].axes[0]);
+  EXPECT_EQ(1u, output.length);
+  EXPECT_EQ(1u, output.items[0].buttonsLength);
+  EXPECT_EQ(1.f, output.items[0].buttons[0].value);
+  EXPECT_TRUE(output.items[0].buttons[0].pressed);
+  EXPECT_EQ(1u, output.items[0].axesLength);
+  EXPECT_EQ(-1.f, output.items[0].axes[0]);
 }
 
 }  // namespace
diff --git a/content/browser/gamepad/gamepad_service.cc b/device/gamepad/gamepad_service.cc
similarity index 67%
rename from content/browser/gamepad/gamepad_service.cc
rename to device/gamepad/gamepad_service.cc
index 8450fe7..2a30926 100644
--- a/content/browser/gamepad/gamepad_service.cc
+++ b/device/gamepad/gamepad_service.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/gamepad/gamepad_service.h"
+#include "device/gamepad/gamepad_service.h"
 
 #include <utility>
 
@@ -10,35 +10,33 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/singleton.h"
-#include "content/browser/gamepad/gamepad_shared_buffer_impl.h"
-#include "content/common/gamepad_hardware_buffer.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "device/gamepad/gamepad_consumer.h"
 #include "device/gamepad/gamepad_data_fetcher.h"
 #include "device/gamepad/gamepad_provider.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 
-namespace content {
+namespace device {
 
 namespace {
 GamepadService* g_gamepad_service = 0;
 }
 
 GamepadService::GamepadService()
-    : num_active_consumers_(0),
+    : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      num_active_consumers_(0),
       gesture_callback_pending_(false) {
   SetInstance(this);
 }
 
 GamepadService::GamepadService(
     std::unique_ptr<device::GamepadDataFetcher> fetcher)
-    : provider_(new device::GamepadProvider(
-        base::MakeUnique<GamepadSharedBufferImpl>(), this, std::move(fetcher))),
+    : provider_(new device::GamepadProvider(this, std::move(fetcher))),
+      main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       num_active_consumers_(0),
       gesture_callback_pending_(false) {
   SetInstance(this);
-  thread_checker_.DetachFromThread();
 }
 
 GamepadService::~GamepadService() {
@@ -60,11 +58,10 @@
 }
 
 void GamepadService::ConsumerBecameActive(device::GamepadConsumer* consumer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
   if (!provider_)
-    provider_.reset(new device::GamepadProvider(
-        base::MakeUnique<GamepadSharedBufferImpl>(), this));
+    provider_.reset(new device::GamepadProvider(this));
 
   std::pair<ConsumerSet::iterator, bool> insert_result =
       consumers_.insert(consumer);
@@ -73,8 +70,7 @@
       !gesture_callback_pending_) {
     gesture_callback_pending_ = true;
     provider_->RegisterForUserGesture(
-          base::Bind(&GamepadService::OnUserGesture,
-                     base::Unretained(this)));
+        base::Bind(&GamepadService::OnUserGesture, base::Unretained(this)));
   }
 
   if (num_active_consumers_++ == 0)
@@ -93,7 +89,7 @@
 }
 
 void GamepadService::RemoveConsumer(device::GamepadConsumer* consumer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
   ConsumerSet::iterator it = consumers_.find(consumer);
   if (it->is_active && --num_active_consumers_ == 0)
@@ -103,7 +99,7 @@
 
 void GamepadService::RegisterForUserGesture(const base::Closure& closure) {
   DCHECK(consumers_.size() > 0);
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
   provider_->RegisterForUserGesture(closure);
 }
 
@@ -115,35 +111,33 @@
                                                int index,
                                                const blink::WebGamepad& pad) {
   if (connected) {
-    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-                            base::Bind(&GamepadService::OnGamepadConnected,
-                                       base::Unretained(this), index, pad));
+    main_thread_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&GamepadService::OnGamepadConnected,
+                              base::Unretained(this), index, pad));
   } else {
-    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-                            base::Bind(&GamepadService::OnGamepadDisconnected,
-                                       base::Unretained(this), index, pad));
+    main_thread_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&GamepadService::OnGamepadDisconnected,
+                              base::Unretained(this), index, pad));
   }
 }
 
-void GamepadService::OnGamepadConnected(
-    int index,
-    const blink::WebGamepad& pad) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+void GamepadService::OnGamepadConnected(int index,
+                                        const blink::WebGamepad& pad) {
+  DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
-  for (ConsumerSet::iterator it = consumers_.begin();
-       it != consumers_.end(); ++it) {
+  for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end();
+       ++it) {
     if (it->did_observe_user_gesture && it->is_active)
       it->consumer->OnGamepadConnected(index, pad);
   }
 }
 
-void GamepadService::OnGamepadDisconnected(
-    int index,
-    const blink::WebGamepad& pad) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+void GamepadService::OnGamepadDisconnected(int index,
+                                           const blink::WebGamepad& pad) {
+  DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
-  for (ConsumerSet::iterator it = consumers_.begin();
-       it != consumers_.end(); ++it) {
+  for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end();
+       ++it) {
     if (it->did_observe_user_gesture && it->is_active)
       it->consumer->OnGamepadDisconnected(index, pad);
   }
@@ -151,12 +145,12 @@
 
 base::SharedMemoryHandle GamepadService::GetSharedMemoryHandleForProcess(
     base::ProcessHandle handle) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
   return provider_->GetSharedMemoryHandleForProcess(handle);
 }
 
 mojo::ScopedSharedBufferHandle GamepadService::GetSharedBufferHandle() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
   // TODO(heke): Use mojo::SharedBuffer rather than base::SharedMemory in
   // GamepadSharedBuffer. See crbug.com/670655 for details.
@@ -166,16 +160,15 @@
 }
 
 void GamepadService::OnUserGesture() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
   gesture_callback_pending_ = false;
 
-  if (!provider_ ||
-      num_active_consumers_ == 0)
+  if (!provider_ || num_active_consumers_ == 0)
     return;
 
-  for (ConsumerSet::iterator it = consumers_.begin();
-       it != consumers_.end(); ++it) {
+  for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end();
+       ++it) {
     if (!it->did_observe_user_gesture && it->is_active) {
       const ConsumerInfo& info = *it;
       info.did_observe_user_gesture = true;
@@ -194,4 +187,4 @@
   provider_->SetSanitizationEnabled(sanitize);
 }
 
-}  // namespace content
+}  // namespace device
diff --git a/content/browser/gamepad/gamepad_service.h b/device/gamepad/gamepad_service.h
similarity index 91%
rename from content/browser/gamepad/gamepad_service.h
rename to device/gamepad/gamepad_service.h
index a3604115..86130d85 100644
--- a/content/browser/gamepad/gamepad_service.h
+++ b/device/gamepad/gamepad_service.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 CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H_
-#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H_
+#ifndef DEVICE_GAMEPAD_GAMEPAD_SERVICE_H_
+#define DEVICE_GAMEPAD_GAMEPAD_SERVICE_H_
 
 #include <memory>
 #include <set>
@@ -12,29 +12,31 @@
 #include "base/macros.h"
 #include "base/memory/shared_memory.h"
 #include "base/memory/singleton.h"
-#include "base/threading/thread_checker.h"
-#include "content/common/content_export.h"
+#include "device/gamepad/gamepad_export.h"
 #include "device/gamepad/gamepad_provider.h"
 #include "mojo/public/cpp/system/buffer.h"
 
+namespace {
+class SingleThreadTaskRunner;
+}
+
 namespace blink {
 class WebGamepad;
 }
 
+namespace content {
+class GamepadServiceTestConstructor;
+}
+
 namespace device {
 class GamepadConsumer;
 class GamepadDataFetcher;
 class GamepadProvider;
-}
-
-namespace content {
-
-class GamepadServiceTestConstructor;
 
 // Owns the GamepadProvider (the background polling thread) and keeps track of
 // the number of consumers currently using the data (and pausing the provider
 // when not in use).
-class CONTENT_EXPORT GamepadService
+class DEVICE_GAMEPAD_EXPORT GamepadService
     : public device::GamepadConnectionChangeClient {
  public:
   // Returns the GamepadService singleton.
@@ -96,8 +98,7 @@
 
   // Constructor for testing. This specifies the data fetcher to use for a
   // provider, bypassing the default platform one.
-  GamepadService(
-      std::unique_ptr<device::GamepadDataFetcher> fetcher);
+  GamepadService(std::unique_ptr<device::GamepadDataFetcher> fetcher);
 
   virtual ~GamepadService();
 
@@ -126,7 +127,7 @@
 
   std::unique_ptr<device::GamepadProvider> provider_;
 
-  base::ThreadChecker thread_checker_;
+  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
 
   typedef std::set<ConsumerInfo> ConsumerSet;
   ConsumerSet consumers_;
@@ -140,4 +141,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H_
+#endif  // DEVICE_GAMEPAD_GAMEPAD_SERVICE_H_
diff --git a/content/browser/gamepad/gamepad_service_unittest.cc b/device/gamepad/gamepad_service_unittest.cc
similarity index 87%
rename from content/browser/gamepad/gamepad_service_unittest.cc
rename to device/gamepad/gamepad_service_unittest.cc
index ea5765d..cce028e 100644
--- a/content/browser/gamepad/gamepad_service_unittest.cc
+++ b/device/gamepad/gamepad_service_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/gamepad/gamepad_service.h"
+#include "device/gamepad/gamepad_service.h"
 
 #include <string.h>
 
@@ -10,12 +10,11 @@
 
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "device/gamepad/gamepad_consumer.h"
 #include "device/gamepad/gamepad_test_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace content {
+namespace device {
 
 namespace {
 static const int kNumberOfGamepads = blink::WebGamepads::itemsLengthCap;
@@ -25,9 +24,7 @@
 
 class ConnectionListener : public device::GamepadConsumer {
  public:
-  ConnectionListener() {
-    ClearCounters();
-  }
+  ConnectionListener() { ClearCounters(); }
 
   void OnGamepadConnected(unsigned index,
                           const blink::WebGamepad& gamepad) override {
@@ -69,17 +66,16 @@
   void SetUp() override;
 
  private:
+  base::MessageLoop message_loop_;
   device::MockGamepadDataFetcher* fetcher_;
   GamepadService* service_;
   std::unique_ptr<ConnectionListener> connection_listener_;
-  TestBrowserThreadBundle browser_thread_;
   WebGamepads test_data_;
 
   DISALLOW_COPY_AND_ASSIGN(GamepadServiceTest);
 };
 
-GamepadServiceTest::GamepadServiceTest()
-    : browser_thread_(TestBrowserThreadBundle::IO_MAINLOOP) {
+GamepadServiceTest::GamepadServiceTest() {
   memset(&test_data_, 0, sizeof(test_data_));
 
   // Set it so that we have user gesture.
@@ -94,8 +90,8 @@
 
 void GamepadServiceTest::SetUp() {
   fetcher_ = new device::MockGamepadDataFetcher(test_data_);
-  service_ = new GamepadService(
-      std::unique_ptr<device::GamepadDataFetcher>(fetcher_));
+  service_ =
+      new GamepadService(std::unique_ptr<device::GamepadDataFetcher>(fetcher_));
   connection_listener_.reset((new ConnectionListener));
   service_->SetSanitizationEnabled(false);
   service_->ConsumerBecameActive(connection_listener_.get());
@@ -134,4 +130,4 @@
   EXPECT_EQ(0, GetDisconnectedCounter());
 }
 
-}  // namespace content
+}  // namespace device
diff --git a/device/gamepad/gamepad_shared_buffer.cc b/device/gamepad/gamepad_shared_buffer.cc
new file mode 100644
index 0000000..66ada77
--- /dev/null
+++ b/device/gamepad/gamepad_shared_buffer.cc
@@ -0,0 +1,42 @@
+// 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 "device/gamepad/gamepad_shared_buffer.h"
+
+namespace device {
+
+GamepadSharedBuffer::GamepadSharedBuffer() {
+  size_t data_size = sizeof(GamepadHardwareBuffer);
+  bool res = shared_memory_.CreateAndMapAnonymous(data_size);
+  CHECK(res);
+
+  void* mem = shared_memory_.memory();
+  DCHECK(mem);
+  hardware_buffer_ = new (mem) GamepadHardwareBuffer();
+  memset(&(hardware_buffer_->data), 0, sizeof(blink::WebGamepads));
+}
+
+GamepadSharedBuffer::~GamepadSharedBuffer() {}
+
+base::SharedMemory* GamepadSharedBuffer::shared_memory() {
+  return &shared_memory_;
+}
+
+blink::WebGamepads* GamepadSharedBuffer::buffer() {
+  return &(hardware_buffer()->data);
+}
+
+GamepadHardwareBuffer* GamepadSharedBuffer::hardware_buffer() {
+  return hardware_buffer_;
+}
+
+void GamepadSharedBuffer::WriteBegin() {
+  hardware_buffer_->seqlock.WriteBegin();
+}
+
+void GamepadSharedBuffer::WriteEnd() {
+  hardware_buffer_->seqlock.WriteEnd();
+}
+
+}  // namespace device
diff --git a/device/gamepad/gamepad_shared_buffer.h b/device/gamepad/gamepad_shared_buffer.h
index 04cb911..b98e9616 100644
--- a/device/gamepad/gamepad_shared_buffer.h
+++ b/device/gamepad/gamepad_shared_buffer.h
@@ -6,20 +6,42 @@
 #define DEVICE_GAMEPAD_SHARED_BUFFER_H_
 
 #include "base/memory/shared_memory.h"
+#include "device/base/synchronization/shared_memory_seqlock_buffer.h"
 #include "device/gamepad/gamepad_export.h"
 #include "third_party/WebKit/public/platform/WebGamepads.h"
 
 namespace device {
 
+/*
+
+ GamepadHardwareBuffer is stored in shared memory that's shared between the
+ browser which does the hardware polling, and the various consumers of the
+ gamepad state (renderers and NaCl plugins). The performance characteristics are
+ that we want low latency (so would like to avoid explicit communication via IPC
+ between producer and consumer) and relatively large data size.
+
+ Writer and reader operate on the same buffer assuming contention is low, and
+ contention is detected by using the associated SeqLock.
+
+*/
+
+typedef SharedMemorySeqLockBuffer<blink::WebGamepads> GamepadHardwareBuffer;
+
 class DEVICE_GAMEPAD_EXPORT GamepadSharedBuffer {
  public:
-  virtual ~GamepadSharedBuffer() {}
+  GamepadSharedBuffer();
+  ~GamepadSharedBuffer();
 
-  virtual base::SharedMemory* shared_memory() = 0;
-  virtual blink::WebGamepads* buffer() = 0;
+  base::SharedMemory* shared_memory();
+  blink::WebGamepads* buffer();
+  GamepadHardwareBuffer* hardware_buffer();
 
-  virtual void WriteBegin() = 0;
-  virtual void WriteEnd() = 0;
+  void WriteBegin();
+  void WriteEnd();
+
+ private:
+  base::SharedMemory shared_memory_;
+  GamepadHardwareBuffer* hardware_buffer_;
 };
 
 }  // namespace device
diff --git a/device/gamepad/gamepad_test_helpers.cc b/device/gamepad/gamepad_test_helpers.cc
index b0aa221..e343b8a4 100644
--- a/device/gamepad/gamepad_test_helpers.cc
+++ b/device/gamepad/gamepad_test_helpers.cc
@@ -51,30 +51,19 @@
   test_data_ = new_data;
 }
 
-MockGamepadSharedBuffer::MockGamepadSharedBuffer() {
-  size_t data_size = sizeof(blink::WebGamepads);
-  bool res = shared_memory_.CreateAndMapAnonymous(data_size);
-  CHECK(res);
-  blink::WebGamepads* buf = buffer();
-  memset(buf, 0, sizeof(blink::WebGamepads));
-}
-
-base::SharedMemory* MockGamepadSharedBuffer::shared_memory() {
-  return &shared_memory_;
-}
-
-blink::WebGamepads* MockGamepadSharedBuffer::buffer() {
-  void* mem = shared_memory_.memory();
-  CHECK(mem);
-  return static_cast<blink::WebGamepads*>(mem);
-}
-
-void MockGamepadSharedBuffer::WriteBegin() {}
-
-void MockGamepadSharedBuffer::WriteEnd() {}
-
 GamepadTestHelper::GamepadTestHelper() {}
 
 GamepadTestHelper::~GamepadTestHelper() {}
 
+GamepadServiceTestConstructor::GamepadServiceTestConstructor(
+    const blink::WebGamepads& test_data) {
+  data_fetcher_ = new MockGamepadDataFetcher(test_data);
+  gamepad_service_ =
+      new GamepadService(std::unique_ptr<GamepadDataFetcher>(data_fetcher_));
+}
+
+GamepadServiceTestConstructor::~GamepadServiceTestConstructor() {
+  delete gamepad_service_;
+}
+
 }  // namespace device
diff --git a/device/gamepad/gamepad_test_helpers.h b/device/gamepad/gamepad_test_helpers.h
index 14eb1767..b4f8c93 100644
--- a/device/gamepad/gamepad_test_helpers.h
+++ b/device/gamepad/gamepad_test_helpers.h
@@ -12,6 +12,7 @@
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "device/gamepad/gamepad_data_fetcher.h"
+#include "device/gamepad/gamepad_service.h"
 #include "device/gamepad/gamepad_shared_buffer.h"
 #include "third_party/WebKit/public/platform/WebGamepads.h"
 
@@ -51,22 +52,6 @@
   DISALLOW_COPY_AND_ASSIGN(MockGamepadDataFetcher);
 };
 
-class MockGamepadSharedBuffer : public GamepadSharedBuffer {
- public:
-  MockGamepadSharedBuffer();
-
-  base::SharedMemory* shared_memory() override;
-  blink::WebGamepads* buffer() override;
-
-  void WriteBegin() override;
-  void WriteEnd() override;
-
- private:
-  base::SharedMemory shared_memory_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockGamepadSharedBuffer);
-};
-
 // Base class for the other test helpers. This just sets up the system monitor.
 class GamepadTestHelper {
  public:
@@ -82,6 +67,26 @@
   DISALLOW_COPY_AND_ASSIGN(GamepadTestHelper);
 };
 
+// Constructs a GamepadService with a mock data source. This bypasses the
+// global singleton for the gamepad service.
+class GamepadServiceTestConstructor : public GamepadTestHelper {
+ public:
+  explicit GamepadServiceTestConstructor(const blink::WebGamepads& test_data);
+  ~GamepadServiceTestConstructor() override;
+
+  GamepadService* gamepad_service() { return gamepad_service_; }
+  MockGamepadDataFetcher* data_fetcher() { return data_fetcher_; }
+
+ private:
+  // Owning pointer (can't be a scoped_ptr due to private destructor).
+  GamepadService* gamepad_service_;
+
+  // Pointer owned by the provider (which is owned by the gamepad service).
+  MockGamepadDataFetcher* data_fetcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(GamepadServiceTestConstructor);
+};
+
 }  // namespace device
 
 #endif  // DEVICE_GAMEPAD_GAMEPAD_TEST_HELPERS_H_
diff --git a/device/gamepad/public/interfaces/gamepad.mojom b/device/gamepad/public/interfaces/gamepad.mojom
index 58e2c6d6..1c670d5 100644
--- a/device/gamepad/public/interfaces/gamepad.mojom
+++ b/device/gamepad/public/interfaces/gamepad.mojom
@@ -57,7 +57,7 @@
 
 // Asks the browser process to start polling, and return a shared memory
 // handle that will hold the data from the hardware. See
-// gamepad_hardware_buffer.h for a description of how synchronization is
+// gamepad_shared_buffer.h for a description of how synchronization is
 // handled. The number of Starts should match the number of Stops.
 interface GamepadMonitor {
   [Sync]
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index 5e0b4d0..65d868fc 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -66,15 +66,9 @@
     buckets {
       name: "master.tryserver.chromium.mac"
       builders { name: "ios-device" }
-      builders {
-        name: "ios-device-xcode-clang"
-        experiment_percentage: 50
-      }
+      builders { name: "ios-device-xcode-clang" }
       builders { name: "ios-simulator" }
-      builders {
-        name: "ios-simulator-xcode-clang"
-        experiment_percentage: 50
-      }
+      builders { name: "ios-simulator-xcode-clang" }
       builders { name: "mac_chromium_compile_dbg_ng" }
       builders { name: "mac_chromium_rel_ng" }
       builders {
diff --git a/media/ffmpeg/ffmpeg_regression_tests.cc b/media/ffmpeg/ffmpeg_regression_tests.cc
index 5640823e..cab5d9f2 100644
--- a/media/ffmpeg/ffmpeg_regression_tests.cc
+++ b/media/ffmpeg/ffmpeg_regression_tests.cc
@@ -173,6 +173,20 @@
                  "security/599625.mp4",
                  PIPELINE_OK,
                  PIPELINE_ERROR_DECODE);
+FFMPEG_TEST_CASE(Cr635422,
+                 "security/635422.ogg",
+                 DEMUXER_ERROR_COULD_NOT_OPEN,
+                 DEMUXER_ERROR_COULD_NOT_OPEN);
+FFMPEG_TEST_CASE(Cr637428,
+                 "security/637428.ogg",
+                 PIPELINE_ERROR_DECODE,
+                 PIPELINE_ERROR_DECODE);
+FFMPEG_TEST_CASE(Cr639961,
+                 "security/639961.flac",
+                 PIPELINE_ERROR_INITIALIZATION_FAILED,
+                 PIPELINE_ERROR_INITIALIZATION_FAILED);
+FFMPEG_TEST_CASE(Cr640889, "security/640889.flac", PIPELINE_OK, PIPELINE_OK);
+FFMPEG_TEST_CASE(Cr640912, "security/640912.flac", PIPELINE_OK, PIPELINE_OK);
 // TODO(liberato): before crbug.com/658440 was fixed, this would fail if run
 // twice under ASAN.  If run once, then it doesn't.  However, it still catches
 // issues in crbug.com/662118, so it's included anyway.
@@ -191,6 +205,10 @@
                  DEMUXER_ERROR_COULD_NOT_OPEN,
                  DEMUXER_ERROR_COULD_NOT_OPEN);
 FFMPEG_TEST_CASE(Cr667063, "security/667063.mp4", PIPELINE_OK, PIPELINE_OK);
+FFMPEG_TEST_CASE(Cr668346,
+                 "security/668346.flac",
+                 PIPELINE_ERROR_INITIALIZATION_FAILED,
+                 PIPELINE_ERROR_INITIALIZATION_FAILED);
 
 // General MP4 test cases.
 FFMPEG_TEST_CASE(MP4_0,
diff --git a/net/cert/cert_verify_proc_win.cc b/net/cert/cert_verify_proc_win.cc
index a13117a7..b17fc0c 100644
--- a/net/cert/cert_verify_proc_win.cc
+++ b/net/cert/cert_verify_proc_win.cc
@@ -8,12 +8,16 @@
 #include <string>
 #include <vector>
 
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/memory/free_deleter.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/sha1.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_local.h"
+#include "base/time/time.h"
 #include "crypto/capi_util.h"
 #include "crypto/scoped_capi_types.h"
 #include "crypto/sha2.h"
@@ -895,6 +899,47 @@
   ~ScopedThreadLocalCRLSet() { g_revocation_injector.Get().SetCRLSet(nullptr); }
 };
 
+// Sends a crash dump (without actually crashing) when the system time
+// falls within the validity period of every certificate in
+// |verified_cert|'s chain. This is to investigate reports of odd
+// certificate errors that report ERR_CERT_DATE_INVALID when the
+// certificate chain's dates appear to be valid.
+//
+// TODO(estark): remove this after obtaining diagnostic data from
+// Canary. https://crbug.com/672906
+void MaybeDumpCertificateDateError(
+    const scoped_refptr<X509Certificate>& verified_cert,
+    DWORD error_status,
+    DWORD info_status) {
+  const base::Time now = base::Time::NowFromSystemTime();
+  // If the leaf certificate is expired or not yet valid, nothing is odd.
+  if (now >= verified_cert->valid_expiry() ||
+      now <= verified_cert->valid_start()) {
+    return;
+  }
+  // Repeat the check for the rest of the certificates in the chain; if
+  // any of them is expired or not yet valid, nothing is odd.
+  X509Certificate::OSCertHandles intermediates =
+      verified_cert->GetIntermediateCertificates();
+  for (const auto& intermediate : intermediates) {
+    base::Time valid_start =
+        base::Time::FromFileTime(intermediate->pCertInfo->NotBefore);
+    base::Time valid_expiry =
+        base::Time::FromFileTime(intermediate->pCertInfo->NotAfter);
+    if (now >= valid_expiry || now <= valid_start)
+      return;
+  }
+  // None of the certificates in the chain appear to be expired or
+  // not-yet-valid, so send a crash dump for diagnostics.
+  base::debug::ScopedCrashKey error_status_crash_key(
+      "cert_verify_proc_win_date_error_error_status",
+      base::IntToString(error_status));
+  base::debug::ScopedCrashKey info_status_crash_key(
+      "cert_verify_proc_win_date_error_info_status",
+      base::IntToString(info_status));
+  base::debug::DumpWithoutCrashing();
+}
+
 }  // namespace
 
 CertVerifyProcWin::CertVerifyProcWin() {}
@@ -1170,6 +1215,17 @@
   verify_result->cert_status |= MapCertChainErrorStatusToCertStatus(
       chain_context->TrustStatus.dwErrorStatus);
 
+  // Send some diagnostic data in the event of certificate date errors
+  // that occur on chains with validity periods that are valid according
+  // to the system clock.
+  // TODO(estark): remove this after obtaining diagnostic data from
+  // Canary. https://crbug.com/672906
+  if (verify_result->cert_status & CERT_STATUS_DATE_INVALID) {
+    MaybeDumpCertificateDateError(verify_result->verified_cert,
+                                  chain_context->TrustStatus.dwErrorStatus,
+                                  chain_context->TrustStatus.dwInfoStatus);
+  }
+
   // Flag certificates that have a Subject common name with a NULL character.
   if (CertSubjectCommonNameHasNull(cert_handle))
     verify_result->cert_status |= CERT_STATUS_INVALID;
diff --git a/net/net.gypi b/net/net.gypi
index d8292ea..bad038e5 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1215,12 +1215,16 @@
       'quic/platform/api/quic_ip_address_family.h',
       'quic/platform/api/quic_ip_address.cc',
       'quic/platform/api/quic_ip_address.h',
+      'quic/platform/api/quic_mutex.cc',
+      'quic/platform/api/quic_mutex.h',
       'quic/platform/api/quic_socket_address.cc',
       'quic/platform/api/quic_socket_address.h',
       'quic/platform/impl/quic_chromium_clock.cc',
       'quic/platform/impl/quic_chromium_clock.h',
       'quic/platform/impl/quic_ip_address_impl.cc',
       'quic/platform/impl/quic_ip_address_impl.h',
+      'quic/platform/impl/quic_mutex_impl.cc',
+      'quic/platform/impl/quic_mutex_impl.h',
       'quic/platform/impl/quic_socket_address_impl.cc',
       'quic/platform/impl/quic_socket_address_impl.h',
       'quic/quartc/quartc_alarm_factory.cc',
@@ -1910,7 +1914,7 @@
       'quic/core/crypto/quic_crypto_server_config_test.cc',
       'quic/core/crypto/quic_random_test.cc',
       'quic/core/crypto/strike_register_test.cc',
-      'quic/core/frames/quic_frame_test.cc',
+      'quic/core/frames/quic_frames_test.cc',
       'quic/core/interval_set_test.cc',
       'quic/core/interval_test.cc',
       'quic/core/quic_address_mismatch_test.cc',
diff --git a/net/quic/core/congestion_control/bbr_sender.cc b/net/quic/core/congestion_control/bbr_sender.cc
index af248b3..f3042847a 100644
--- a/net/quic/core/congestion_control/bbr_sender.cc
+++ b/net/quic/core/congestion_control/bbr_sender.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <sstream>
 
+#include "base/stl_util.h"
 #include "net/quic/core/congestion_control/rtt_stats.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_flags.h"
diff --git a/net/quic/core/congestion_control/bbr_sender.h b/net/quic/core/congestion_control/bbr_sender.h
index 89e5299a..152d5ec9 100644
--- a/net/quic/core/congestion_control/bbr_sender.h
+++ b/net/quic/core/congestion_control/bbr_sender.h
@@ -10,6 +10,7 @@
 #include <cstdint>
 #include <ostream>
 
+#include "base/macros.h"
 #include "net/quic/core/congestion_control/bandwidth_sampler.h"
 #include "net/quic/core/congestion_control/send_algorithm_interface.h"
 #include "net/quic/core/congestion_control/windowed_filter.h"
diff --git a/net/quic/core/congestion_control/bbr_sender_test.cc b/net/quic/core/congestion_control/bbr_sender_test.cc
index b4ffa58..c02fb71 100644
--- a/net/quic/core/congestion_control/bbr_sender_test.cc
+++ b/net/quic/core/congestion_control/bbr_sender_test.cc
@@ -95,7 +95,7 @@
 
     uint64_t seed = QuicRandom::GetInstance()->RandUint64();
     random_.set_seed(seed);
-    LOG(INFO) << "BbrSenderTest simulator set up.  Seed: " << seed;
+    VLOG(1) << "BbrSenderTest simulator set up.  Seed: " << seed;
   }
 
   simulator::Simulator simulator_;
@@ -146,7 +146,7 @@
     EXPECT_TRUE(simulator_result)
         << "Simple transfer failed.  Bytes remaining: "
         << bbr_sender_.bytes_to_transfer();
-    LOG(INFO) << "Simple transfer state: " << sender_->ExportDebugState();
+    VLOG(1) << "Simple transfer state: " << sender_->ExportDebugState();
   }
 
   // Drive the simulator by sending enough data to enter PROBE_BW.
diff --git a/net/quic/core/congestion_control/cubic.cc b/net/quic/core/congestion_control/cubic.cc
index 26ce0698..f0a1871 100644
--- a/net/quic/core/congestion_control/cubic.cc
+++ b/net/quic/core/congestion_control/cubic.cc
@@ -4,15 +4,13 @@
 
 #include "net/quic/core/congestion_control/cubic.h"
 
-#include <stdint.h>
 #include <algorithm>
 #include <cmath>
+#include <cstdint>
 
 #include "base/logging.h"
 #include "net/quic/core/quic_flags.h"
 #include "net/quic/core/quic_packets.h"
-#include "net/quic/core/quic_time.h"
-
 
 namespace net {
 
diff --git a/net/quic/core/congestion_control/cubic.h b/net/quic/core/congestion_control/cubic.h
index 29d42f03..e3a44be2 100644
--- a/net/quic/core/congestion_control/cubic.h
+++ b/net/quic/core/congestion_control/cubic.h
@@ -8,7 +8,7 @@
 #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_CUBIC_H_
 #define NET_QUIC_CORE_CONGESTION_CONTROL_CUBIC_H_
 
-#include <stdint.h>
+#include <cstdint>
 
 #include "base/macros.h"
 #include "net/quic/core/quic_bandwidth.h"
diff --git a/net/quic/core/congestion_control/cubic_bytes.cc b/net/quic/core/congestion_control/cubic_bytes.cc
index bbc9f696..7abe9209 100644
--- a/net/quic/core/congestion_control/cubic_bytes.cc
+++ b/net/quic/core/congestion_control/cubic_bytes.cc
@@ -4,15 +4,14 @@
 
 #include "net/quic/core/congestion_control/cubic_bytes.h"
 
-#include <stdint.h>
 #include <algorithm>
 #include <cmath>
+#include <cstdint>
 
 #include "base/logging.h"
 #include "net/quic/core/quic_flags.h"
 #include "net/quic/core/quic_packets.h"
 
-
 namespace net {
 
 namespace {
diff --git a/net/quic/core/congestion_control/cubic_bytes.h b/net/quic/core/congestion_control/cubic_bytes.h
index 4e70305a..481b012 100644
--- a/net/quic/core/congestion_control/cubic_bytes.h
+++ b/net/quic/core/congestion_control/cubic_bytes.h
@@ -8,7 +8,7 @@
 #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_CUBIC_BYTES_H_
 #define NET_QUIC_CORE_CONGESTION_CONTROL_CUBIC_BYTES_H_
 
-#include <stdint.h>
+#include <cstdint>
 
 #include "base/macros.h"
 #include "net/quic/core/quic_bandwidth.h"
diff --git a/net/quic/core/congestion_control/cubic_bytes_test.cc b/net/quic/core/congestion_control/cubic_bytes_test.cc
index 57c5ef1..0ee3b43c 100644
--- a/net/quic/core/congestion_control/cubic_bytes_test.cc
+++ b/net/quic/core/congestion_control/cubic_bytes_test.cc
@@ -4,6 +4,8 @@
 
 #include "net/quic/core/congestion_control/cubic_bytes.h"
 
+#include <cstdint>
+
 #include "base/logging.h"
 #include "net/quic/core/quic_flags.h"
 #include "net/quic/test_tools/mock_clock.h"
diff --git a/net/quic/core/congestion_control/cubic_test.cc b/net/quic/core/congestion_control/cubic_test.cc
index 578b94e7..c9342c0 100644
--- a/net/quic/core/congestion_control/cubic_test.cc
+++ b/net/quic/core/congestion_control/cubic_test.cc
@@ -4,8 +4,9 @@
 
 #include "net/quic/core/congestion_control/cubic.h"
 
+#include <cstdint>
+
 #include "base/logging.h"
-#include "net/quic/core/quic_flags.h"
 #include "net/quic/test_tools/mock_clock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/quic/core/congestion_control/general_loss_algorithm_test.cc b/net/quic/core/congestion_control/general_loss_algorithm_test.cc
index 826b4a34..02bf24f4 100644
--- a/net/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/net/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -5,8 +5,10 @@
 #include "net/quic/core/congestion_control/general_loss_algorithm.h"
 
 #include <algorithm>
+#include <cstdint>
 
 #include "base/logging.h"
+#include "base/stl_util.h"
 #include "net/quic/core/congestion_control/rtt_stats.h"
 #include "net/quic/core/quic_flags.h"
 #include "net/quic/core/quic_unacked_packet_map.h"
@@ -14,7 +16,6 @@
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-
 namespace net {
 namespace test {
 namespace {
diff --git a/net/quic/core/congestion_control/hybrid_slow_start.cc b/net/quic/core/congestion_control/hybrid_slow_start.cc
index 16b7dcf..7cac328 100644
--- a/net/quic/core/congestion_control/hybrid_slow_start.cc
+++ b/net/quic/core/congestion_control/hybrid_slow_start.cc
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 
-
 namespace net {
 
 // Note(pwestin): the magic clamping numbers come from the original code in
diff --git a/net/quic/core/congestion_control/hybrid_slow_start.h b/net/quic/core/congestion_control/hybrid_slow_start.h
index 73c564b..79561789 100644
--- a/net/quic/core/congestion_control/hybrid_slow_start.h
+++ b/net/quic/core/congestion_control/hybrid_slow_start.h
@@ -16,7 +16,7 @@
 #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_HYBRID_SLOW_START_H_
 #define NET_QUIC_CORE_CONGESTION_CONTROL_HYBRID_SLOW_START_H_
 
-#include <stdint.h>
+#include <cstdint>
 
 #include "base/macros.h"
 #include "net/quic/core/quic_packets.h"
diff --git a/net/quic/core/congestion_control/pacing_sender.cc b/net/quic/core/congestion_control/pacing_sender.cc
index 5cac490f..cce05b9f 100644
--- a/net/quic/core/congestion_control/pacing_sender.cc
+++ b/net/quic/core/congestion_control/pacing_sender.cc
@@ -4,11 +4,6 @@
 
 #include "net/quic/core/congestion_control/pacing_sender.h"
 
-#include <string>
-
-#include "net/quic/core/quic_flags.h"
-
-
 namespace net {
 namespace {
 
diff --git a/net/quic/core/congestion_control/pacing_sender.h b/net/quic/core/congestion_control/pacing_sender.h
index 2c01094..b297b8f8 100644
--- a/net/quic/core/congestion_control/pacing_sender.h
+++ b/net/quic/core/congestion_control/pacing_sender.h
@@ -11,8 +11,7 @@
 #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_PACING_SENDER_H_
 #define NET_QUIC_CORE_CONGESTION_CONTROL_PACING_SENDER_H_
 
-#include <stdint.h>
-
+#include <cstdint>
 #include <map>
 #include <memory>
 
diff --git a/net/quic/core/congestion_control/prr_sender.h b/net/quic/core/congestion_control/prr_sender.h
index e5efb97..2bc842a 100644
--- a/net/quic/core/congestion_control/prr_sender.h
+++ b/net/quic/core/congestion_control/prr_sender.h
@@ -7,8 +7,6 @@
 #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_PRR_SENDER_H_
 #define NET_QUIC_CORE_CONGESTION_CONTROL_PRR_SENDER_H_
 
-#include <stddef.h>
-
 #include "net/quic/core/quic_bandwidth.h"
 #include "net/quic/core/quic_time.h"
 #include "net/quic/platform/api/quic_export.h"
diff --git a/net/quic/core/congestion_control/prr_sender_test.cc b/net/quic/core/congestion_control/prr_sender_test.cc
index 77bf30c..673f554 100644
--- a/net/quic/core/congestion_control/prr_sender_test.cc
+++ b/net/quic/core/congestion_control/prr_sender_test.cc
@@ -8,9 +8,7 @@
 
 #include "base/logging.h"
 #include "net/quic/core/crypto/crypto_protocol.h"
-#include "net/quic/core/quic_bandwidth.h"
 #include "net/quic/core/quic_constants.h"
-#include "net/quic/core/quic_packets.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
diff --git a/net/quic/core/congestion_control/rtt_stats.cc b/net/quic/core/congestion_control/rtt_stats.cc
index e5da34a..da3c146 100644
--- a/net/quic/core/congestion_control/rtt_stats.cc
+++ b/net/quic/core/congestion_control/rtt_stats.cc
@@ -6,9 +6,6 @@
 
 #include <cstdlib>  // std::abs
 
-#include "net/quic/core/quic_flags.h"
-
-
 namespace net {
 
 namespace {
diff --git a/net/quic/core/congestion_control/rtt_stats.h b/net/quic/core/congestion_control/rtt_stats.h
index d04dd44..581ebf7 100644
--- a/net/quic/core/congestion_control/rtt_stats.h
+++ b/net/quic/core/congestion_control/rtt_stats.h
@@ -7,9 +7,8 @@
 #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_RTT_STATS_H_
 #define NET_QUIC_CORE_CONGESTION_CONTROL_RTT_STATS_H_
 
-#include <stdint.h>
-
 #include <algorithm>
+#include <cstdint>
 
 #include "base/macros.h"
 #include "net/quic/core/quic_bug_tracker.h"
diff --git a/net/quic/core/congestion_control/rtt_stats_test.cc b/net/quic/core/congestion_control/rtt_stats_test.cc
index 27b08d4..f4c99273 100644
--- a/net/quic/core/congestion_control/rtt_stats_test.cc
+++ b/net/quic/core/congestion_control/rtt_stats_test.cc
@@ -5,11 +5,9 @@
 #include "net/quic/core/congestion_control/rtt_stats.h"
 
 #include <cmath>
-#include <vector>
 
 #include "base/logging.h"
 #include "base/test/mock_log.h"
-#include "net/quic/core/quic_flags.h"
 #include "net/quic/test_tools/rtt_stats_peer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/quic/core/congestion_control/send_algorithm_interface.h b/net/quic/core/congestion_control/send_algorithm_interface.h
index 86465713..dacccba 100644
--- a/net/quic/core/congestion_control/send_algorithm_interface.h
+++ b/net/quic/core/congestion_control/send_algorithm_interface.h
@@ -29,7 +29,7 @@
 
 class QUIC_EXPORT_PRIVATE SendAlgorithmInterface {
  public:
-  // A sorted std::vector of packets.
+  // A sorted vector of packets.
   typedef std::vector<std::pair<QuicPacketNumber, QuicPacketLength>>
       CongestionVector;
 
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_base.cc b/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
index 3a74855e..069bb16 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
@@ -5,16 +5,12 @@
 #include "net/quic/core/congestion_control/tcp_cubic_sender_base.h"
 
 #include <algorithm>
-#include <string>
 
-#include "base/metrics/histogram_macros.h"
 #include "net/quic/core/congestion_control/prr_sender.h"
 #include "net/quic/core/congestion_control/rtt_stats.h"
 #include "net/quic/core/crypto/crypto_protocol.h"
 #include "net/quic/core/proto/cached_network_parameters.pb.h"
 #include "net/quic/core/quic_bug_tracker.h"
-#include "net/quic/core/quic_flags.h"
-
 
 namespace net {
 
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_base.h b/net/quic/core/congestion_control/tcp_cubic_sender_base.h
index ba7f8e9..f04eb74 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_base.h
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_base.h
@@ -7,7 +7,7 @@
 #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_
 #define NET_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_
 
-#include <stdint.h>
+#include <cstdint>
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
@@ -39,6 +39,7 @@
                      const RttStats* rtt_stats,
                      bool reno,
                      QuicConnectionStats* stats);
+
   ~TcpCubicSenderBase() override;
 
   // Start implementation of SendAlgorithmInterface.
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc b/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
index 269cfda..dab758a 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
@@ -5,15 +5,14 @@
 #include "net/quic/core/congestion_control/tcp_cubic_sender_bytes.h"
 
 #include <algorithm>
+#include <cstdint>
 
 #include "net/quic/core/congestion_control/prr_sender.h"
 #include "net/quic/core/congestion_control/rtt_stats.h"
 #include "net/quic/core/crypto/crypto_protocol.h"
-#include "net/quic/core/proto/cached_network_parameters.pb.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_flags.h"
 
-
 namespace net {
 
 namespace {
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h b/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h
index dde7782e..7813b2b 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h
@@ -7,7 +7,7 @@
 #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_
 #define NET_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_
 
-#include <stdint.h>
+#include <cstdint>
 
 #include "base/macros.h"
 #include "net/quic/core/congestion_control/cubic_bytes.h"
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
index 8f87a3fe..8c40012 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
@@ -13,12 +13,10 @@
 #include "net/quic/core/congestion_control/send_algorithm_interface.h"
 #include "net/quic/core/crypto/crypto_protocol.h"
 #include "net/quic/core/proto/cached_network_parameters.pb.h"
-#include "net/quic/core/quic_flags.h"
 #include "net/quic/core/quic_packets.h"
 #include "net/quic/core/quic_utils.h"
 #include "net/quic/test_tools/mock_clock.h"
 #include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc b/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc
index 600e379..aa99b9bf 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc
@@ -6,15 +6,12 @@
 
 #include <algorithm>
 
-#include "base/metrics/histogram_macros.h"
 #include "net/quic/core/congestion_control/prr_sender.h"
 #include "net/quic/core/congestion_control/rtt_stats.h"
 #include "net/quic/core/crypto/crypto_protocol.h"
-#include "net/quic/core/proto/cached_network_parameters.pb.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_flags.h"
 
-
 namespace net {
 
 namespace {
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_packets.h b/net/quic/core/congestion_control/tcp_cubic_sender_packets.h
index 759f93b..ff06a1d 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_packets.h
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_packets.h
@@ -7,7 +7,7 @@
 #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_PACKETS_H_
 #define NET_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_PACKETS_H_
 
-#include <stdint.h>
+#include <cstdint>
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc b/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc
index 4a4368d..26487b4 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc
@@ -12,15 +12,12 @@
 #include "net/quic/core/congestion_control/send_algorithm_interface.h"
 #include "net/quic/core/crypto/crypto_protocol.h"
 #include "net/quic/core/proto/cached_network_parameters.pb.h"
-#include "net/quic/core/quic_flags.h"
 #include "net/quic/core/quic_packets.h"
 #include "net/quic/core/quic_utils.h"
 #include "net/quic/test_tools/mock_clock.h"
 #include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-
 namespace net {
 namespace test {
 
@@ -134,7 +131,6 @@
     bytes_in_flight_ -= kDefaultTCPMSS;
   }
 
-  QuicFlagSaver flags_;  // Save/restore all QUIC flag values.
   const QuicTime::Delta one_ms_;
   MockClock clock_;
   std::unique_ptr<TcpCubicSenderPacketsPeer> sender_;
diff --git a/net/quic/core/congestion_control/windowed_filter_test.cc b/net/quic/core/congestion_control/windowed_filter_test.cc
index cd5399b..73ef09c 100644
--- a/net/quic/core/congestion_control/windowed_filter_test.cc
+++ b/net/quic/core/congestion_control/windowed_filter_test.cc
@@ -12,7 +12,6 @@
 
 namespace net {
 namespace test {
-namespace {
 
 class WindowedFilterTest : public ::testing::Test {
  public:
@@ -182,7 +181,6 @@
   // Latest sample was recorded at 100ms.
   QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
   windowed_min_rtt_.Update(rtt_sample, now);
-  windowed_min_rtt_.Update(rtt_sample, now);
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
             windowed_min_rtt_.GetSecondBest());
@@ -328,7 +326,6 @@
   // See crbug/616957
   ASSERT_LT(windowed_min_rtt_.GetThirdBest(),
             QuicTime::Delta::Infinite() - QuicTime::Delta::FromMilliseconds(5));
-
   // Third best min sample was recorded at 100ms, so expiry time is 199ms.
   QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(200);
   windowed_min_rtt_.Update(rtt_sample, now);
@@ -357,8 +354,8 @@
   WindowedFilter<uint64_t, MaxFilter<uint64_t>, uint64_t, uint64_t> max_filter(
       2, 0, 0);
 
-  // Insert 50000 at t = 1.
   const uint64_t kBest = 50000;
+  // Insert 50000 at t = 1.
   max_filter.Update(50000, 1);
   EXPECT_EQ(kBest, max_filter.GetBest());
   UpdateWithIrrelevantSamples(&max_filter, 20, 1);
@@ -387,6 +384,5 @@
   EXPECT_EQ(kNewBest, max_filter.GetBest());
 }
 
-}  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/core/crypto/crypto_secret_boxer.cc b/net/quic/core/crypto/crypto_secret_boxer.cc
index 6c5807c..986e34ab 100644
--- a/net/quic/core/crypto/crypto_secret_boxer.cc
+++ b/net/quic/core/crypto/crypto_secret_boxer.cc
@@ -50,14 +50,14 @@
   for (const string& key : keys) {
     DCHECK_EQ(kKeySize, key.size());
   }
-  base::AutoLock l(lock_);
+  QuicWriterMutexLock l(&lock_);
   keys_.swap(copy);
 }
 
 string CryptoSecretBoxer::Box(QuicRandom* rand, StringPiece plaintext) const {
   std::unique_ptr<Aes128Gcm12Encrypter> encrypter(new Aes128Gcm12Encrypter());
   {
-    base::AutoLock l(lock_);
+    QuicReaderMutexLock l(&lock_);
     DCHECK_EQ(kKeySize, keys_[0].size());
     if (!encrypter->SetKey(keys_[0])) {
       DLOG(DFATAL) << "CryptoSecretBoxer's encrypter->SetKey failed.";
@@ -104,7 +104,7 @@
   size_t plaintext_length = 0;
   bool ok = false;
   {
-    base::AutoLock l(lock_);
+    QuicReaderMutexLock l(&lock_);
     for (const string& key : keys_) {
       if (decrypter->SetKey(key)) {
         decrypter->SetNoncePrefix(nonce_prefix);
diff --git a/net/quic/core/crypto/crypto_secret_boxer.h b/net/quic/core/crypto/crypto_secret_boxer.h
index 07ab150..14737e0 100644
--- a/net/quic/core/crypto/crypto_secret_boxer.h
+++ b/net/quic/core/crypto/crypto_secret_boxer.h
@@ -12,8 +12,8 @@
 
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
-#include "base/synchronization/lock.h"
 #include "net/quic/platform/api/quic_export.h"
+#include "net/quic/platform/api/quic_mutex.h"
 
 namespace net {
 
@@ -51,9 +51,8 @@
              base::StringPiece* out) const;
 
  private:
-  mutable base::Lock lock_;
-  //  GUARDED_BY(lock_).mutable Mutex lock_;
-  std::vector<std::string> keys_;
+  mutable QuicMutex lock_;
+  std::vector<std::string> keys_ GUARDED_BY(lock_);
 
   DISALLOW_COPY_AND_ASSIGN(CryptoSecretBoxer);
 };
diff --git a/net/quic/core/crypto/local_strike_register_client.cc b/net/quic/core/crypto/local_strike_register_client.cc
index bd70e0b..1327818 100644
--- a/net/quic/core/crypto/local_strike_register_client.cc
+++ b/net/quic/core/crypto/local_strike_register_client.cc
@@ -24,7 +24,7 @@
                        startup) {}
 
 bool LocalStrikeRegisterClient::IsKnownOrbit(StringPiece orbit) const {
-  base::AutoLock lock(m_);
+  QuicWriterMutexLock lock(&m_);
   if (orbit.length() != kOrbitSize) {
     return false;
   }
@@ -39,7 +39,7 @@
   if (nonce.length() != kNonceSize) {
     nonce_error = NONCE_INVALID_FAILURE;
   } else {
-    base::AutoLock lock(m_);
+    QuicWriterMutexLock lock(&m_);
     nonce_error =
         strike_register_.Insert(reinterpret_cast<const uint8_t*>(nonce.data()),
                                 static_cast<uint32_t>(now.ToUNIXSeconds()));
diff --git a/net/quic/core/crypto/local_strike_register_client.h b/net/quic/core/crypto/local_strike_register_client.h
index 2af1fd9..7c00fce 100644
--- a/net/quic/core/crypto/local_strike_register_client.h
+++ b/net/quic/core/crypto/local_strike_register_client.h
@@ -9,11 +9,11 @@
 
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
-#include "base/synchronization/lock.h"
 #include "net/quic/core/crypto/strike_register.h"
 #include "net/quic/core/crypto/strike_register_client.h"
 #include "net/quic/core/quic_time.h"
 #include "net/quic/platform/api/quic_export.h"
+#include "net/quic/platform/api/quic_mutex.h"
 
 namespace net {
 
@@ -34,8 +34,8 @@
                                    ResultCallback* cb) override;
 
  private:
-  mutable base::Lock m_;
-  StrikeRegister strike_register_;
+  mutable QuicMutex m_;
+  StrikeRegister strike_register_ GUARDED_BY(m_);
 
   DISALLOW_COPY_AND_ASSIGN(LocalStrikeRegisterClient);
 };
diff --git a/net/quic/core/crypto/quic_crypto_server_config.cc b/net/quic/core/crypto/quic_crypto_server_config.cc
index fc4c8ad..8599b77 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.cc
+++ b/net/quic/core/crypto/quic_crypto_server_config.cc
@@ -311,7 +311,7 @@
   }
 
   {
-    base::AutoLock locked(configs_lock_);
+    QuicWriterMutexLock locked(&configs_lock_);
     if (configs_.find(config->id) != configs_.end()) {
       LOG(WARNING) << "Failed to add config because another with the same "
                       "server config id already exists: "
@@ -361,7 +361,7 @@
   } else {
     VLOG(1) << "Updating configs:";
 
-    base::AutoLock locked(configs_lock_);
+    QuicWriterMutexLock locked(&configs_lock_);
     ConfigMap new_configs;
 
     for (std::vector<scoped_refptr<Config>>::const_iterator i =
@@ -409,7 +409,7 @@
 }
 
 void QuicCryptoServerConfig::GetConfigIds(std::vector<string>* scids) const {
-  base::AutoLock locked(configs_lock_);
+  QuicReaderMutexLock locked(&configs_lock_);
   for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end();
        ++it) {
     scids->push_back(it->first);
@@ -436,7 +436,7 @@
   scoped_refptr<Config> requested_config;
   scoped_refptr<Config> primary_config;
   {
-    base::AutoLock locked(configs_lock_);
+    QuicReaderMutexLock locked(&configs_lock_);
 
     if (!primary_config_.get()) {
       result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
@@ -444,9 +444,13 @@
     } else {
       if (!next_config_promotion_time_.IsZero() &&
           next_config_promotion_time_.IsAfter(now)) {
+        configs_lock_.ReaderUnlock();
+        configs_lock_.WriterLock();
         SelectNewPrimaryConfig(now);
         DCHECK(primary_config_.get());
         DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
+        configs_lock_.WriterUnlock();
+        configs_lock_.ReaderLock();
       }
     }
 
@@ -629,16 +633,20 @@
   scoped_refptr<Config> primary_config;
   bool no_primary_config = false;
   {
-    base::AutoLock locked(configs_lock_);
+    QuicReaderMutexLock locked(&configs_lock_);
 
     if (!primary_config_) {
       no_primary_config = true;
     } else {
       if (!next_config_promotion_time_.IsZero() &&
           next_config_promotion_time_.IsAfter(now)) {
+        configs_lock_.ReaderUnlock();
+        configs_lock_.WriterLock();
         SelectNewPrimaryConfig(now);
         DCHECK(primary_config_.get());
         DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
+        configs_lock_.WriterUnlock();
+        configs_lock_.ReaderLock();
       }
 
       // Use the config that the client requested in order to do key-agreement.
@@ -995,9 +1003,7 @@
 
 scoped_refptr<QuicCryptoServerConfig::Config>
 QuicCryptoServerConfig::GetConfigWithScid(StringPiece requested_scid) const {
-  // In Chromium, we will dead lock if the lock is held by the current thread.
-  // Chromium doesn't have AssertReaderHeld API call.
-  // configs_lock_.AssertReaderHeld();
+  configs_lock_.AssertReaderHeld();
 
   if (!requested_scid.empty()) {
     ConfigMap::const_iterator it = configs_.find(requested_scid.as_string());
@@ -1346,7 +1352,7 @@
   QuicWallTime expiry_time = QuicWallTime::Zero();
   const CommonCertSets* common_cert_sets;
   {
-    base::AutoLock locked(configs_lock_);
+    QuicReaderMutexLock locked(&configs_lock_);
     serialized = primary_config_->serialized;
     common_cert_sets = primary_config_->common_cert_sets;
     expiry_time = primary_config_->expiry_time;
@@ -1403,7 +1409,7 @@
   string source_address_token;
   const CommonCertSets* common_cert_sets;
   {
-    base::AutoLock locked(configs_lock_);
+    QuicReaderMutexLock locked(&configs_lock_);
     serialized = primary_config_->serialized;
     common_cert_sets = primary_config_->common_cert_sets;
     source_address_token = NewSourceAddressToken(
@@ -1815,7 +1821,7 @@
 
 void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
     std::unique_ptr<PrimaryConfigChangedCallback> cb) {
-  base::AutoLock locked(configs_lock_);
+  QuicWriterMutexLock locked(&configs_lock_);
   primary_config_changed_cb_ = std::move(cb);
 }
 
@@ -1858,7 +1864,7 @@
 }
 
 int QuicCryptoServerConfig::NumberOfConfigs() const {
-  base::AutoLock locked(configs_lock_);
+  QuicReaderMutexLock locked(&configs_lock_);
   return configs_.size();
 }
 
diff --git a/net/quic/core/crypto/quic_crypto_server_config.h b/net/quic/core/crypto/quic_crypto_server_config.h
index f8f10ba..28f65f75 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.h
+++ b/net/quic/core/crypto/quic_crypto_server_config.h
@@ -16,7 +16,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_piece.h"
-#include "base/synchronization/lock.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/quic/core/crypto/crypto_handshake.h"
@@ -30,6 +29,7 @@
 #include "net/quic/core/proto/source_address_token.pb.h"
 #include "net/quic/core/quic_time.h"
 #include "net/quic/platform/api/quic_export.h"
+#include "net/quic/platform/api/quic_mutex.h"
 #include "net/quic/platform/api/quic_socket_address.h"
 
 namespace net {
@@ -739,18 +739,19 @@
   //   1) configs_.empty() <-> primary_config_ == nullptr
   //   2) primary_config_ != nullptr -> primary_config_->is_primary
   //   3) ∀ c∈configs_, c->is_primary <-> c == primary_config_
-  mutable base::Lock configs_lock_;
+  mutable QuicMutex configs_lock_;
   // configs_ contains all active server configs. It's expected that there are
   // about half-a-dozen configs active at any one time.
-  ConfigMap configs_;
+  ConfigMap configs_ GUARDED_BY(configs_lock_);
   // primary_config_ points to a Config (which is also in |configs_|) which is
   // the primary config - i.e. the one that we'll give out to new clients.
-  mutable scoped_refptr<Config> primary_config_;
+  mutable scoped_refptr<Config> primary_config_ GUARDED_BY(configs_lock_);
   // next_config_promotion_time_ contains the nearest, future time when an
   // active config will be promoted to primary.
-  mutable QuicWallTime next_config_promotion_time_;
+  mutable QuicWallTime next_config_promotion_time_ GUARDED_BY(configs_lock_);
   // Callback to invoke when the primary config changes.
-  std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_;
+  std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_
+      GUARDED_BY(configs_lock_);
 
   // Used to protect the source-address tokens that are given to clients.
   CryptoSecretBoxer source_address_token_boxer_;
diff --git a/net/quic/core/frames/quic_ack_frame.h b/net/quic/core/frames/quic_ack_frame.h
index 1875e42..9e76aee 100644
--- a/net/quic/core/frames/quic_ack_frame.h
+++ b/net/quic/core/frames/quic_ack_frame.h
@@ -5,6 +5,7 @@
 #ifndef NET_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_
 #define NET_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_
 
+#include <ostream>
 #include <string>
 
 #include "base/strings/string_piece.h"
diff --git a/net/quic/core/frames/quic_blocked_frame.h b/net/quic/core/frames/quic_blocked_frame.h
index bac2ce8..9409d7a 100644
--- a/net/quic/core/frames/quic_blocked_frame.h
+++ b/net/quic/core/frames/quic_blocked_frame.h
@@ -5,6 +5,8 @@
 #ifndef NET_QUIC_CORE_FRAMES_QUIC_BLOCKED_FRAME_H_
 #define NET_QUIC_CORE_FRAMES_QUIC_BLOCKED_FRAME_H_
 
+#include <ostream>
+
 #include "net/quic/core/quic_types.h"
 #include "net/quic/platform/api/quic_export.h"
 
diff --git a/net/quic/core/frames/quic_frame.h b/net/quic/core/frames/quic_frame.h
index c9171e0c..3ebe1cf 100644
--- a/net/quic/core/frames/quic_frame.h
+++ b/net/quic/core/frames/quic_frame.h
@@ -5,6 +5,7 @@
 #ifndef NET_QUIC_CORE_FRAMES_QUIC_FRAME_H_
 #define NET_QUIC_CORE_FRAMES_QUIC_FRAME_H_
 
+#include <ostream>
 #include <vector>
 
 #include "net/quic/core/frames/quic_ack_frame.h"
@@ -20,7 +21,6 @@
 #include "net/quic/core/frames/quic_stop_waiting_frame.h"
 #include "net/quic/core/frames/quic_stream_frame.h"
 #include "net/quic/core/frames/quic_window_update_frame.h"
-#include "net/quic/core/quic_constants.h"
 #include "net/quic/core/quic_types.h"
 #include "net/quic/platform/api/quic_export.h"
 
diff --git a/net/quic/core/frames/quic_frame_test.cc b/net/quic/core/frames/quic_frames_test.cc
similarity index 91%
rename from net/quic/core/frames/quic_frame_test.cc
rename to net/quic/core/frames/quic_frames_test.cc
index 3225d0e7..11f083ec 100644
--- a/net/quic/core/frames/quic_frame_test.cc
+++ b/net/quic/core/frames/quic_frames_test.cc
@@ -2,8 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "net/quic/core/frames/quic_ack_frame.h"
+#include "net/quic/core/frames/quic_blocked_frame.h"
+#include "net/quic/core/frames/quic_connection_close_frame.h"
 #include "net/quic/core/frames/quic_frame.h"
-
+#include "net/quic/core/frames/quic_goaway_frame.h"
+#include "net/quic/core/frames/quic_mtu_discovery_frame.h"
+#include "net/quic/core/frames/quic_padding_frame.h"
+#include "net/quic/core/frames/quic_path_close_frame.h"
+#include "net/quic/core/frames/quic_ping_frame.h"
+#include "net/quic/core/frames/quic_rst_stream_frame.h"
+#include "net/quic/core/frames/quic_stop_waiting_frame.h"
+#include "net/quic/core/frames/quic_stream_frame.h"
+#include "net/quic/core/frames/quic_window_update_frame.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/quic/core/frames/quic_goaway_frame.h b/net/quic/core/frames/quic_goaway_frame.h
index 6ae1530..5eafcff 100644
--- a/net/quic/core/frames/quic_goaway_frame.h
+++ b/net/quic/core/frames/quic_goaway_frame.h
@@ -5,6 +5,7 @@
 #ifndef NET_QUIC_CORE_FRAMES_QUIC_GOAWAY_FRAME_H_
 #define NET_QUIC_CORE_FRAMES_QUIC_GOAWAY_FRAME_H_
 
+#include <ostream>
 #include <string>
 
 #include "net/quic/core/quic_error_codes.h"
diff --git a/net/quic/core/frames/quic_path_close_frame.h b/net/quic/core/frames/quic_path_close_frame.h
index 64cccd2..55982a9 100644
--- a/net/quic/core/frames/quic_path_close_frame.h
+++ b/net/quic/core/frames/quic_path_close_frame.h
@@ -5,6 +5,8 @@
 #ifndef NET_QUIC_CORE_FRAMES_QUIC_PATH_CLOSE_FRAME_H_
 #define NET_QUIC_CORE_FRAMES_QUIC_PATH_CLOSE_FRAME_H_
 
+#include <ostream>
+
 #include "net/quic/core/quic_types.h"
 #include "net/quic/platform/api/quic_export.h"
 
diff --git a/net/quic/core/frames/quic_rst_stream_frame.h b/net/quic/core/frames/quic_rst_stream_frame.h
index bbb65762..896c66c3 100644
--- a/net/quic/core/frames/quic_rst_stream_frame.h
+++ b/net/quic/core/frames/quic_rst_stream_frame.h
@@ -5,6 +5,8 @@
 #ifndef NET_QUIC_CORE_FRAMES_QUIC_RST_STREAM_FRAME_H_
 #define NET_QUIC_CORE_FRAMES_QUIC_RST_STREAM_FRAME_H_
 
+#include <ostream>
+
 #include "net/quic/core/quic_error_codes.h"
 #include "net/quic/core/quic_types.h"
 #include "net/quic/platform/api/quic_export.h"
diff --git a/net/quic/core/frames/quic_stop_waiting_frame.h b/net/quic/core/frames/quic_stop_waiting_frame.h
index 9ca94fd2..1c02a77 100644
--- a/net/quic/core/frames/quic_stop_waiting_frame.h
+++ b/net/quic/core/frames/quic_stop_waiting_frame.h
@@ -5,6 +5,8 @@
 #ifndef NET_QUIC_CORE_FRAMES_QUIC_STOP_WAITING_FRAME_H_
 #define NET_QUIC_CORE_FRAMES_QUIC_STOP_WAITING_FRAME_H_
 
+#include <ostream>
+
 #include "net/quic/core/quic_types.h"
 #include "net/quic/platform/api/quic_export.h"
 
@@ -17,6 +19,7 @@
   friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
       std::ostream& os,
       const QuicStopWaitingFrame& s);
+
   // Path which this stop waiting frame belongs to.
   QuicPathId path_id;
   // The lowest packet we've sent which is unacked, and we expect an ack for.
diff --git a/net/quic/core/frames/quic_stream_frame.h b/net/quic/core/frames/quic_stream_frame.h
index 845698d9..99f2856 100644
--- a/net/quic/core/frames/quic_stream_frame.h
+++ b/net/quic/core/frames/quic_stream_frame.h
@@ -6,6 +6,7 @@
 #define NET_QUIC_CORE_FRAMES_QUIC_STREAM_FRAME_H_
 
 #include <memory>
+#include <ostream>
 
 #include "base/strings/string_piece.h"
 #include "net/quic/core/quic_buffer_allocator.h"
diff --git a/net/quic/core/frames/quic_window_update_frame.h b/net/quic/core/frames/quic_window_update_frame.h
index 3f04c870..0edf79ab 100644
--- a/net/quic/core/frames/quic_window_update_frame.h
+++ b/net/quic/core/frames/quic_window_update_frame.h
@@ -5,6 +5,8 @@
 #ifndef NET_QUIC_CORE_FRAMES_QUIC_WINDOW_UPDATE_FRAME_H_
 #define NET_QUIC_CORE_FRAMES_QUIC_WINDOW_UPDATE_FRAME_H_
 
+#include <ostream>
+
 #include "net/quic/core/quic_types.h"
 #include "net/quic/platform/api/quic_export.h"
 
diff --git a/net/quic/platform/api/quic_mutex.cc b/net/quic/platform/api/quic_mutex.cc
new file mode 100644
index 0000000..f0c8f099
--- /dev/null
+++ b/net/quic/platform/api/quic_mutex.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 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 "net/quic/platform/api/quic_mutex.h"
+
+namespace net {
+
+void QuicMutex::WriterLock() {
+  impl_.WriterLock();
+}
+
+void QuicMutex::WriterUnlock() {
+  impl_.WriterUnlock();
+}
+
+void QuicMutex::ReaderLock() {
+  impl_.ReaderLock();
+}
+
+void QuicMutex::ReaderUnlock() {
+  impl_.ReaderUnlock();
+}
+
+void QuicMutex::AssertReaderHeld() const {
+  impl_.AssertReaderHeld();
+}
+
+QuicReaderMutexLock::QuicReaderMutexLock(QuicMutex* lock) : lock_(lock) {
+  lock->ReaderLock();
+}
+
+QuicReaderMutexLock::~QuicReaderMutexLock() {
+  lock_->ReaderUnlock();
+}
+
+QuicWriterMutexLock::QuicWriterMutexLock(QuicMutex* lock) : lock_(lock) {
+  lock->WriterLock();
+}
+
+QuicWriterMutexLock::~QuicWriterMutexLock() {
+  lock_->WriterUnlock();
+}
+
+}  // namespace net
diff --git a/net/quic/platform/api/quic_mutex.h b/net/quic/platform/api/quic_mutex.h
new file mode 100644
index 0000000..cc51f30
--- /dev/null
+++ b/net/quic/platform/api/quic_mutex.h
@@ -0,0 +1,70 @@
+// Copyright (c) 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 NET_QUIC_PLATFORM_API_QUIC_MUTEX_H_
+#define NET_QUIC_PLATFORM_API_QUIC_MUTEX_H_
+
+#include "net/quic/platform/impl/quic_mutex_impl.h"
+
+namespace net {
+
+// A class representing a non-reentrant mutex in QUIC.
+class QUIC_EXPORT_PRIVATE LOCKABLE QuicMutex {
+ public:
+  QuicMutex() = default;
+
+  // Block until this Mutex is free, then acquire it exclusively.
+  void WriterLock() EXCLUSIVE_LOCK_FUNCTION();
+
+  // Release this Mutex. Caller must hold it exclusively.
+  void WriterUnlock() UNLOCK_FUNCTION();
+
+  // Block until this Mutex is free or shared, then acquire a share of it.
+  void ReaderLock() SHARED_LOCK_FUNCTION();
+
+  // Release this Mutex. Caller could hold it in shared mode.
+  void ReaderUnlock() UNLOCK_FUNCTION();
+
+  // Returns immediately if current thread holds the Mutex in at least shared
+  // mode.  Otherwise, may report an error (typically by crashing with a
+  // diagnostic), or may return immediately.
+  void AssertReaderHeld() const ASSERT_SHARED_LOCK();
+
+ private:
+  QuicLockImpl impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(QuicMutex);
+};
+
+// A helper class that acquires the given QuicMutex shared lock while the
+// QuicReaderMutexLock is in scope.
+class QUIC_EXPORT_PRIVATE SCOPED_LOCKABLE QuicReaderMutexLock {
+ public:
+  explicit QuicReaderMutexLock(QuicMutex* lock) SHARED_LOCK_FUNCTION(lock);
+
+  ~QuicReaderMutexLock() UNLOCK_FUNCTION();
+
+ private:
+  QuicMutex* const lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(QuicReaderMutexLock);
+};
+
+// A helper class that acquires the given QuicMutex exclusive lock while the
+// QuicWriterMutexLock is in scope.
+class QUIC_EXPORT_PRIVATE SCOPED_LOCKABLE QuicWriterMutexLock {
+ public:
+  explicit QuicWriterMutexLock(QuicMutex* lock) EXCLUSIVE_LOCK_FUNCTION(lock);
+
+  ~QuicWriterMutexLock() UNLOCK_FUNCTION();
+
+ private:
+  QuicMutex* const lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(QuicWriterMutexLock);
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_PLATFORM_API_QUIC_MUTEX_H_
diff --git a/net/quic/platform/impl/quic_mutex_impl.cc b/net/quic/platform/impl/quic_mutex_impl.cc
new file mode 100644
index 0000000..95e46c1
--- /dev/null
+++ b/net/quic/platform/impl/quic_mutex_impl.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 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 "net/quic/platform/impl/quic_mutex_impl.h"
+
+namespace net {
+
+void QuicLockImpl::WriterLock() {
+  lock_.Acquire();
+}
+
+void QuicLockImpl::WriterUnlock() {
+  lock_.Release();
+}
+
+void QuicLockImpl::ReaderLock() {
+  lock_.Acquire();
+}
+
+void QuicLockImpl::ReaderUnlock() {
+  lock_.Release();
+}
+
+}  // namespace net
diff --git a/net/quic/platform/impl/quic_mutex_impl.h b/net/quic/platform/impl/quic_mutex_impl.h
new file mode 100644
index 0000000..fae020a7
--- /dev/null
+++ b/net/quic/platform/impl/quic_mutex_impl.h
@@ -0,0 +1,69 @@
+// Copyright (c) 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 NET_QUIC_PLATFORM_IMPL_QUIC_MUTEX_IMPL_H_
+#define NET_QUIC_PLATFORM_IMPL_QUIC_MUTEX_IMPL_H_
+
+#include "base/synchronization/lock.h"
+#include "net/quic/platform/api/quic_export.h"
+
+#ifndef EXCLUSIVE_LOCK_FUNCTION
+#define EXCLUSIVE_LOCK_FUNCTION(...)
+#endif
+
+#ifndef UNLOCK_FUNCTION
+#define UNLOCK_FUNCTION(...)
+#endif
+
+#ifndef SHARED_LOCK_FUNCTION
+#define SHARED_LOCK_FUNCTION(...)
+#endif
+
+#ifndef ASSERT_SHARED_LOCK
+#define ASSERT_SHARED_LOCK(...)
+#endif
+
+#ifndef LOCKABLE
+#define LOCKABLE
+#endif
+
+#ifndef SCOPED_LOCKABLE
+#define SCOPED_LOCKABLE
+#endif
+
+#ifndef GUARDED_BY
+#define GUARDED_BY(x)
+#endif
+
+namespace net {
+
+// A class wrapping a non-reentrant mutex.
+class QUIC_EXPORT_PRIVATE QuicLockImpl {
+ public:
+  QuicLockImpl() = default;
+
+  // Block until lock_ is free, then acquire it exclusively.
+  void WriterLock() EXCLUSIVE_LOCK_FUNCTION();
+
+  // Release lock_. Caller must hold it exclusively.
+  void WriterUnlock() UNLOCK_FUNCTION();
+
+  // Block until lock_ is free or shared, then acquire a share of it.
+  void ReaderLock() SHARED_LOCK_FUNCTION();
+
+  // Release lock_. Caller could hold it in shared mode.
+  void ReaderUnlock() UNLOCK_FUNCTION();
+
+  // Not implemented.
+  void AssertReaderHeld() const ASSERT_SHARED_LOCK() {}
+
+ private:
+  base::Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(QuicLockImpl);
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_PLATFORM_IMPL_QUIC_MUTEX_IMPL_H_
diff --git a/net/quic/test_tools/quic_crypto_server_config_peer.cc b/net/quic/test_tools/quic_crypto_server_config_peer.cc
index 46d282e0e..95a3c1b2 100644
--- a/net/quic/test_tools/quic_crypto_server_config_peer.cc
+++ b/net/quic/test_tools/quic_crypto_server_config_peer.cc
@@ -22,14 +22,14 @@
 
 scoped_refptr<QuicCryptoServerConfig::Config>
 QuicCryptoServerConfigPeer::GetPrimaryConfig() {
-  base::AutoLock locked(server_config_->configs_lock_);
+  QuicReaderMutexLock locked(&server_config_->configs_lock_);
   return scoped_refptr<QuicCryptoServerConfig::Config>(
       server_config_->primary_config_);
 }
 
 scoped_refptr<QuicCryptoServerConfig::Config>
 QuicCryptoServerConfigPeer::GetConfig(string config_id) {
-  base::AutoLock locked(server_config_->configs_lock_);
+  QuicReaderMutexLock locked(&server_config_->configs_lock_);
   if (config_id == "<primary>") {
     return scoped_refptr<QuicCryptoServerConfig::Config>(
         server_config_->primary_config_);
@@ -120,7 +120,7 @@
 
   va_end(ap);
 
-  base::AutoLock locked(server_config_->configs_lock_);
+  QuicReaderMutexLock locked(&server_config_->configs_lock_);
 
   ASSERT_EQ(expected.size(), server_config_->configs_.size()) << ConfigsDebug();
 
@@ -166,7 +166,7 @@
 }
 
 void QuicCryptoServerConfigPeer::SelectNewPrimaryConfig(int seconds) {
-  base::AutoLock locked(server_config_->configs_lock_);
+  QuicWriterMutexLock locked(&server_config_->configs_lock_);
   server_config_->SelectNewPrimaryConfig(
       QuicWallTime::FromUNIXSeconds(seconds));
 }
diff --git a/net/tools/quic/quic_http_response_cache.cc b/net/tools/quic/quic_http_response_cache.cc
index 7057a2db..bc6c819 100644
--- a/net/tools/quic/quic_http_response_cache.cc
+++ b/net/tools/quic/quic_http_response_cache.cc
@@ -163,7 +163,7 @@
 const QuicHttpResponseCache::Response* QuicHttpResponseCache::GetResponse(
     StringPiece host,
     StringPiece path) const {
-  base::AutoLock lock(response_mutex_);
+  QuicWriterMutexLock lock(&response_mutex_);
 
   auto it = responses_.find(GetKey(host, path));
   if (it == responses_.end()) {
@@ -201,7 +201,7 @@
 }
 
 void QuicHttpResponseCache::AddDefaultResponse(Response* response) {
-  base::AutoLock lock(response_mutex_);
+  QuicWriterMutexLock lock(&response_mutex_);
   default_response_.reset(response);
 }
 
@@ -288,7 +288,7 @@
 
 std::list<ServerPushInfo> QuicHttpResponseCache::GetServerPushResources(
     string request_url) {
-  base::AutoLock lock(response_mutex_);
+  QuicWriterMutexLock lock(&response_mutex_);
 
   std::list<ServerPushInfo> resources;
   auto resource_range = server_push_resources_.equal_range(request_url);
@@ -302,7 +302,7 @@
 
 QuicHttpResponseCache::~QuicHttpResponseCache() {
   {
-    base::AutoLock lock(response_mutex_);
+    QuicWriterMutexLock lock(&response_mutex_);
     responses_.clear();
   }
 }
@@ -313,7 +313,7 @@
                                             SpdyHeaderBlock response_headers,
                                             StringPiece response_body,
                                             SpdyHeaderBlock response_trailers) {
-  base::AutoLock lock(response_mutex_);
+  QuicWriterMutexLock lock(&response_mutex_);
 
   DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\"";
   string key = GetKey(host, path);
@@ -349,7 +349,7 @@
              << " push url " << push_resource.request_url
              << " response headers " << push_resource.headers.DebugString();
     {
-      base::AutoLock lock(response_mutex_);
+      QuicWriterMutexLock lock(&response_mutex_);
       server_push_resources_.insert(std::make_pair(request_url, push_resource));
     }
     string host = push_resource.request_url.host();
@@ -359,7 +359,7 @@
     string path = push_resource.request_url.path();
     bool found_existing_response = false;
     {
-      base::AutoLock lock(response_mutex_);
+      QuicWriterMutexLock lock(&response_mutex_);
       found_existing_response =
           base::ContainsKey(responses_, GetKey(host, path));
     }
@@ -376,7 +376,7 @@
 bool QuicHttpResponseCache::PushResourceExistsInCache(
     string original_request_url,
     ServerPushInfo resource) {
-  base::AutoLock lock(response_mutex_);
+  QuicWriterMutexLock lock(&response_mutex_);
   auto resource_range =
       server_push_resources_.equal_range(original_request_url);
   for (auto it = resource_range.first; it != resource_range.second; ++it) {
diff --git a/net/tools/quic/quic_http_response_cache.h b/net/tools/quic/quic_http_response_cache.h
index 9ca5430..ad274bf 100644
--- a/net/tools/quic/quic_http_response_cache.h
+++ b/net/tools/quic/quic_http_response_cache.h
@@ -17,6 +17,7 @@
 #include "base/strings/string_piece.h"
 #include "net/http/http_response_headers.h"
 #include "net/quic/core/spdy_utils.h"
+#include "net/quic/platform/api/quic_mutex.h"
 #include "net/spdy/spdy_framer.h"
 #include "url/gurl.h"
 
@@ -201,17 +202,19 @@
                                  ServerPushInfo resource);
 
   // Cached responses.
-  std::unordered_map<std::string, std::unique_ptr<Response>> responses_;
+  std::unordered_map<std::string, std::unique_ptr<Response>> responses_
+      GUARDED_BY(response_mutex_);
 
   // The default response for cache misses, if set.
-  std::unique_ptr<Response> default_response_;
+  std::unique_ptr<Response> default_response_ GUARDED_BY(response_mutex_);
 
   // A map from request URL to associated server push responses (if any).
-  std::multimap<std::string, ServerPushInfo> server_push_resources_;
+  std::multimap<std::string, ServerPushInfo> server_push_resources_
+      GUARDED_BY(response_mutex_);
 
   // Protects against concurrent access from test threads setting responses, and
   // server threads accessing those responses.
-  mutable base::Lock response_mutex_;
+  mutable QuicMutex response_mutex_;
 
   DISALLOW_COPY_AND_ASSIGN(QuicHttpResponseCache);
 };
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
index 46c2a1a..df1057a 100644
--- a/net/tools/quic/test_tools/packet_dropping_test_writer.cc
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -84,7 +84,7 @@
   ++num_calls_to_write_;
   ReleaseOldPackets();
 
-  base::AutoLock locked(config_mutex_);
+  QuicReaderMutexLock lock(&config_mutex_);
   if (fake_drop_first_n_packets_ > 0 &&
       num_calls_to_write_ <=
           static_cast<uint64_t>(fake_drop_first_n_packets_)) {
@@ -168,7 +168,7 @@
   if (delayed_packets_.empty()) {
     return QuicTime::Zero();
   }
-  base::AutoLock locked(config_mutex_);
+  QuicReaderMutexLock lock(&config_mutex_);
   DelayedPacketList::iterator iter = delayed_packets_.begin();
   // Determine if we should re-order.
   if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 &&
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h
index a8a4ed2c..c4c28b6 100644
--- a/net/tools/quic/test_tools/packet_dropping_test_writer.h
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -71,14 +71,14 @@
 
   // The percent of time a packet is simulated as being lost.
   void set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage) {
-    base::AutoLock locked(config_mutex_);
+    QuicWriterMutexLock lock(&config_mutex_);
     fake_packet_loss_percentage_ = fake_packet_loss_percentage;
   }
 
   // Simulate dropping the first n packets unconditionally.
   // Subsequent packets will be lost at fake_packet_loss_percentage_ if set.
   void set_fake_drop_first_n_packets(int32_t fake_drop_first_n_packets) {
-    base::AutoLock locked(config_mutex_);
+    QuicWriterMutexLock lock(&config_mutex_);
     fake_drop_first_n_packets_ = fake_drop_first_n_packets;
   }
 
@@ -87,14 +87,14 @@
   void set_fake_blocked_socket_percentage(
       int32_t fake_blocked_socket_percentage) {
     DCHECK(clock_);
-    base::AutoLock locked(config_mutex_);
+    QuicWriterMutexLock lock(&config_mutex_);
     fake_blocked_socket_percentage_ = fake_blocked_socket_percentage;
   }
 
   // The percent of time a packet is simulated as being reordered.
   void set_fake_reorder_percentage(int32_t fake_packet_reorder_percentage) {
     DCHECK(clock_);
-    base::AutoLock locked(config_mutex_);
+    QuicWriterMutexLock lock(&config_mutex_);
     DCHECK(!fake_packet_delay_.IsZero());
     fake_packet_reorder_percentage_ = fake_packet_reorder_percentage;
   }
@@ -102,7 +102,7 @@
   // The delay before writing this packet.
   void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) {
     DCHECK(clock_);
-    base::AutoLock locked(config_mutex_);
+    QuicWriterMutexLock lock(&config_mutex_);
     fake_packet_delay_ = fake_packet_delay;
   }
 
@@ -113,7 +113,7 @@
   void set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth,
                                          QuicByteCount buffer_size) {
     DCHECK(clock_);
-    base::AutoLock locked(config_mutex_);
+    QuicWriterMutexLock lock(&config_mutex_);
     fake_bandwidth_ = fake_bandwidth;
     buffer_size_ = buffer_size;
   }
@@ -163,14 +163,14 @@
   QuicByteCount cur_buffer_size_;
   uint64_t num_calls_to_write_;
 
-  base::Lock config_mutex_;
-  int32_t fake_packet_loss_percentage_;
-  int32_t fake_drop_first_n_packets_;
-  int32_t fake_blocked_socket_percentage_;
-  int32_t fake_packet_reorder_percentage_;
-  QuicTime::Delta fake_packet_delay_;
-  QuicBandwidth fake_bandwidth_;
-  QuicByteCount buffer_size_;
+  QuicMutex config_mutex_;
+  int32_t fake_packet_loss_percentage_ GUARDED_BY(config_mutex_);
+  int32_t fake_drop_first_n_packets_ GUARDED_BY(config_mutex_);
+  int32_t fake_blocked_socket_percentage_ GUARDED_BY(config_mutex_);
+  int32_t fake_packet_reorder_percentage_ GUARDED_BY(config_mutex_);
+  QuicTime::Delta fake_packet_delay_ GUARDED_BY(config_mutex_);
+  QuicBandwidth fake_bandwidth_ GUARDED_BY(config_mutex_);
+  QuicByteCount buffer_size_ GUARDED_BY(config_mutex_);
 
   DISALLOW_COPY_AND_ASSIGN(PacketDroppingTestWriter);
 };
diff --git a/net/tools/quic/test_tools/quic_test_server.cc b/net/tools/quic/test_tools/quic_test_server.cc
index e5375ff..9d987b3 100644
--- a/net/tools/quic/test_tools/quic_test_server.cc
+++ b/net/tools/quic/test_tools/quic_test_server.cc
@@ -102,7 +102,7 @@
   QuicServerSessionBase* CreateQuicSession(
       QuicConnectionId id,
       const QuicSocketAddress& client) override {
-    base::AutoLock lock(factory_lock_);
+    QuicReaderMutexLock lock(&factory_lock_);
     if (session_factory_ == nullptr && stream_factory_ == nullptr &&
         crypto_stream_factory_ == nullptr) {
       return QuicSimpleDispatcher::CreateQuicSession(id, client);
@@ -128,7 +128,7 @@
   }
 
   void SetSessionFactory(QuicTestServer::SessionFactory* factory) {
-    base::AutoLock lock(factory_lock_);
+    QuicWriterMutexLock lock(&factory_lock_);
     DCHECK(session_factory_ == nullptr);
     DCHECK(stream_factory_ == nullptr);
     DCHECK(crypto_stream_factory_ == nullptr);
@@ -136,21 +136,21 @@
   }
 
   void SetStreamFactory(QuicTestServer::StreamFactory* factory) {
-    base::AutoLock lock(factory_lock_);
+    QuicWriterMutexLock lock(&factory_lock_);
     DCHECK(session_factory_ == nullptr);
     DCHECK(stream_factory_ == nullptr);
     stream_factory_ = factory;
   }
 
   void SetCryptoStreamFactory(QuicTestServer::CryptoStreamFactory* factory) {
-    base::AutoLock lock(factory_lock_);
+    QuicWriterMutexLock lock(&factory_lock_);
     DCHECK(session_factory_ == nullptr);
     DCHECK(crypto_stream_factory_ == nullptr);
     crypto_stream_factory_ = factory;
   }
 
  private:
-  base::Lock factory_lock_;
+  QuicMutex factory_lock_;
   QuicTestServer::SessionFactory* session_factory_;             // Not owned.
   QuicTestServer::StreamFactory* stream_factory_;               // Not owned.
   QuicTestServer::CryptoStreamFactory* crypto_stream_factory_;  // Not owned.
diff --git a/net/tools/quic/test_tools/server_thread.cc b/net/tools/quic/test_tools/server_thread.cc
index 35421d1..a04311e 100644
--- a/net/tools/quic/test_tools/server_thread.cc
+++ b/net/tools/quic/test_tools/server_thread.cc
@@ -71,7 +71,7 @@
 
 void ServerThread::Schedule(std::function<void()> action) {
   DCHECK(!quit_.IsSignaled());
-  base::AutoLock lock(scheduled_actions_lock_);
+  QuicWriterMutexLock lock(&scheduled_actions_lock_);
   scheduled_actions_.push_back(std::move(action));
 }
 
@@ -117,7 +117,7 @@
 void ServerThread::ExecuteScheduledActions() {
   std::deque<std::function<void()>> actions;
   {
-    base::AutoLock lock(scheduled_actions_lock_);
+    QuicWriterMutexLock lock(&scheduled_actions_lock_);
     actions.swap(scheduled_actions_);
   }
   while (!actions.empty()) {
diff --git a/net/tools/quic/test_tools/server_thread.h b/net/tools/quic/test_tools/server_thread.h
index 52cc24b8..77f0073 100644
--- a/net/tools/quic/test_tools/server_thread.h
+++ b/net/tools/quic/test_tools/server_thread.h
@@ -8,9 +8,9 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/synchronization/lock.h"
 #include "base/threading/simple_thread.h"
 #include "net/quic/core/quic_config.h"
+#include "net/quic/platform/api/quic_mutex.h"
 #include "net/quic/platform/api/quic_socket_address.h"
 #include "net/tools/quic/quic_server.h"
 
@@ -75,8 +75,9 @@
 
   bool initialized_;
 
-  base::Lock scheduled_actions_lock_;
-  std::deque<std::function<void()>> scheduled_actions_;
+  QuicMutex scheduled_actions_lock_;
+  std::deque<std::function<void()>> scheduled_actions_
+      GUARDED_BY(scheduled_actions_lock_);
 
   DISALLOW_COPY_AND_ASSIGN(ServerThread);
 };
diff --git a/ppapi/shared_impl/ppb_gamepad_shared.h b/ppapi/shared_impl/ppb_gamepad_shared.h
index 3a3d6802..4a71d964 100644
--- a/ppapi/shared_impl/ppb_gamepad_shared.h
+++ b/ppapi/shared_impl/ppb_gamepad_shared.h
@@ -109,7 +109,7 @@
 };
 
 // This is the structure store in shared memory. It must match
-// content/common/gamepad_hardware_buffer.h. The GamepadHost unit test has
+// device::GamepadHardwareBuffer. The GamepadHost unit test has
 // some compile asserts to validate this.
 struct ContentGamepadHardwareBuffer {
   base::subtle::Atomic32 sequence;
diff --git a/remoting/base/rate_counter.cc b/remoting/base/rate_counter.cc
index fdc7981..f676fc5 100644
--- a/remoting/base/rate_counter.cc
+++ b/remoting/base/rate_counter.cc
@@ -9,40 +9,31 @@
 namespace remoting {
 
 RateCounter::RateCounter(base::TimeDelta time_window)
-    : time_window_(time_window),
-      sum_(0) {
-  DCHECK_GT(time_window.InMilliseconds(), 0);
+    : time_window_(time_window), sum_(0) {
+  DCHECK_GT(time_window, base::TimeDelta());
 }
 
-RateCounter::~RateCounter() {
-}
+RateCounter::~RateCounter() {}
 
 void RateCounter::Record(int64_t value) {
   DCHECK(CalledOnValidThread());
 
-  base::Time current_time = CurrentTime();
-  EvictOldDataPoints(current_time);
+  base::TimeTicks now = tick_clock_->NowTicks();
+  EvictOldDataPoints(now);
   sum_ += value;
-  data_points_.push(std::make_pair(current_time, value));
+  data_points_.push(std::make_pair(now, value));
 }
 
 double RateCounter::Rate() {
   DCHECK(CalledOnValidThread());
 
-  EvictOldDataPoints(CurrentTime());
+  EvictOldDataPoints(tick_clock_->NowTicks());
   return sum_ / time_window_.InSecondsF();
 }
 
-void RateCounter::SetCurrentTimeForTest(base::Time current_time) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(current_time >= current_time_for_test_);
-
-  current_time_for_test_ = current_time;
-}
-
-void RateCounter::EvictOldDataPoints(base::Time current_time) {
+void RateCounter::EvictOldDataPoints(base::TimeTicks now) {
   // Remove data points outside of the window.
-  base::Time window_start = current_time - time_window_;
+  base::TimeTicks window_start = now - time_window_;
 
   while (!data_points_.empty()) {
     if (data_points_.front().first > window_start)
@@ -53,10 +44,4 @@
   }
 }
 
-base::Time RateCounter::CurrentTime() const {
-  if (current_time_for_test_ == base::Time())
-    return base::Time::Now();
-  return current_time_for_test_;
-}
-
 }  // namespace remoting
diff --git a/remoting/base/rate_counter.h b/remoting/base/rate_counter.h
index ee34edc0e..a7e0f35 100644
--- a/remoting/base/rate_counter.h
+++ b/remoting/base/rate_counter.h
@@ -12,6 +12,8 @@
 
 #include "base/macros.h"
 #include "base/threading/non_thread_safe.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/tick_clock.h"
 #include "base/time/time.h"
 
 namespace remoting {
@@ -32,18 +34,16 @@
   // Note that rates reported before |time_window| has elapsed are not accurate.
   double Rate();
 
-  // Overrides the current time for testing.
-  void SetCurrentTimeForTest(base::Time current_time);
+  void set_tick_clock_for_tests(base::TickClock* tick_clock) {
+    tick_clock_ = tick_clock;
+  }
 
  private:
   // Type used to store data points with timestamps.
-  typedef std::pair<base::Time, int64_t> DataPoint;
+  typedef std::pair<base::TimeTicks, int64_t> DataPoint;
 
   // Removes data points more than |time_window| older than |current_time|.
-  void EvictOldDataPoints(base::Time current_time);
-
-  // Returns the current time specified for test, if set, or base::Time::Now().
-  base::Time CurrentTime() const;
+  void EvictOldDataPoints(base::TimeTicks current_time);
 
   // Time window over which to calculate the rate.
   const base::TimeDelta time_window_;
@@ -54,8 +54,8 @@
   // Sum of values in |data_points_|.
   int64_t sum_;
 
-  // If set, used to calculate the running average, in place of Now().
-  base::Time current_time_for_test_;
+  base::DefaultTickClock default_tick_clock_;
+  base::TickClock* tick_clock_ = &default_tick_clock_;
 
   DISALLOW_COPY_AND_ASSIGN(RateCounter);
 };
diff --git a/remoting/base/rate_counter_unittest.cc b/remoting/base/rate_counter_unittest.cc
index 91b91c5..8d4188e 100644
--- a/remoting/base/rate_counter_unittest.cc
+++ b/remoting/base/rate_counter_unittest.cc
@@ -6,6 +6,7 @@
 #include <stdint.h>
 
 #include "base/macros.h"
+#include "base/test/simple_test_tick_clock.h"
 #include "remoting/base/rate_counter.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -18,10 +19,11 @@
   RateCounter rate_counter(base::TimeDelta::FromSeconds(1));
   EXPECT_EQ(0, rate_counter.Rate());
 
-  base::Time now = base::Time::Now();
+  base::SimpleTestTickClock tick_clock;
+  rate_counter.set_tick_clock_for_tests(&tick_clock);
+
   for (size_t i = 0; i < arraysize(kTestValues); ++i) {
-    now += base::TimeDelta::FromSeconds(1);
-    rate_counter.SetCurrentTimeForTest(now);
+    tick_clock.Advance(base::TimeDelta::FromSeconds(1));
     rate_counter.Record(kTestValues[i]);
     EXPECT_EQ(static_cast<double>(kTestValues[i]), rate_counter.Rate());
   }
@@ -32,7 +34,8 @@
   RateCounter rate_counter(base::TimeDelta::FromSeconds(1));
   EXPECT_EQ(0, rate_counter.Rate());
 
-  rate_counter.SetCurrentTimeForTest(base::Time::Now());
+  base::SimpleTestTickClock tick_clock;
+  rate_counter.set_tick_clock_for_tests(&tick_clock);
 
   double expected = 0.0;
   for (size_t i = 0; i < arraysize(kTestValues); ++i) {
@@ -50,10 +53,11 @@
   RateCounter rate_counter(base::TimeDelta::FromSeconds(2));
   EXPECT_EQ(0, rate_counter.Rate());
 
-  base::Time now = base::Time::Now();
+  base::SimpleTestTickClock tick_clock;
+  rate_counter.set_tick_clock_for_tests(&tick_clock);
+
   for (size_t i = 0; i < arraysize(kTestValues); ++i) {
-    now += base::TimeDelta::FromSeconds(1);
-    rate_counter.SetCurrentTimeForTest(now);
+    tick_clock.Advance(base::TimeDelta::FromSeconds(1));
     rate_counter.Record(kTestValues[i]);
     double expected = kTestValues[i];
     if (i > 0)
@@ -71,11 +75,12 @@
   RateCounter rate_counter(base::TimeDelta::FromSeconds(kWindowSeconds));
   EXPECT_EQ(0, rate_counter.Rate());
 
+  base::SimpleTestTickClock tick_clock;
+  rate_counter.set_tick_clock_for_tests(&tick_clock);
+
   double expected = 0.0;
-  base::Time now = base::Time::Now();
   for (size_t i = 0; i < arraysize(kTestValues); ++i) {
-    now += base::TimeDelta::FromSeconds(1);
-    rate_counter.SetCurrentTimeForTest(now);
+    tick_clock.Advance(base::TimeDelta::FromSeconds(1));
     rate_counter.Record(kTestValues[i]);
     if (i != 0)
       expected += kTestValues[i];
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc
index 604a3f1d..5477e718b 100644
--- a/remoting/protocol/webrtc_transport.cc
+++ b/remoting/protocol/webrtc_transport.cc
@@ -18,6 +18,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/task_runner_util.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "jingle/glue/thread_wrapper.h"
 #include "remoting/protocol/authenticator.h"
@@ -194,7 +195,13 @@
     peer_connection_ = peer_connection_factory_->CreatePeerConnection(
         rtc_config, &constraints, std::move(port_allocator), nullptr, this);
   }
-  virtual ~PeerConnectionWrapper() { peer_connection_->Close(); }
+  virtual ~PeerConnectionWrapper() {
+    // PeerConnection creates threads internally, which are stopped when the
+    // connection is closed. Thread.Stop() is a blocking operation.
+    // See crbug.com/660081.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    peer_connection_->Close();
+  }
 
   WebrtcAudioModule* audio_module() {
     return audio_module_.get();
diff --git a/services/catalog/reader.cc b/services/catalog/reader.cc
index ea93418..766aaf48 100644
--- a/services/catalog/reader.cc
+++ b/services/catalog/reader.cc
@@ -34,7 +34,7 @@
 
 base::FilePath GetExecutablePath(const base::FilePath& package_dir,
                                  const std::string& name) {
-  return package_dir.AppendASCII(name + "/" + name + ".library");
+  return package_dir.AppendASCII(name + "/" + name + ".service");
 }
 
 std::unique_ptr<Entry> ProcessManifest(
diff --git a/services/service_manager/background/background_service_manager_main.cc b/services/service_manager/background/background_service_manager_main.cc
index 4ef836f..6902ee4 100644
--- a/services/service_manager/background/background_service_manager_main.cc
+++ b/services/service_manager/background/background_service_manager_main.cc
@@ -9,33 +9,8 @@
 #include "base/debug/debugger.h"
 #include "base/process/launch.h"
 #include "services/service_manager/runner/common/switches.h"
-#include "services/service_manager/runner/host/child_process.h"
 #include "services/service_manager/runner/init.h"
 
-namespace service_manager {
-namespace {
-
-int RunChildProcess() {
-  base::AtExitManager at_exit;
-  InitializeLogging();
-  WaitForDebuggerIfNecessary();
-#if !defined(OFFICIAL_BUILD) && defined(OS_WIN)
-  base::RouteStdioToConsole(false);
-#endif
-  return ChildProcessMain();
-}
-
-}  // namespace
-}  // namespace service_manager
-
 int main(int argc, char** argv) {
-  base::CommandLine::Init(argc, argv);
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kChildProcess)) {
-    return service_manager::RunChildProcess();
-  }
-  // Reset CommandLine as most likely main() is going to use CommandLine too
-  // and expect to be able to initialize it.
-  base::CommandLine::Reset();
   return MasterProcessMain(argc, argv);
 }
diff --git a/services/service_manager/native_runner.h b/services/service_manager/native_runner.h
index 9d97c3c..505ed50 100644
--- a/services/service_manager/native_runner.h
+++ b/services/service_manager/native_runner.h
@@ -25,22 +25,21 @@
  public:
   virtual ~NativeRunner() {}
 
-  // Loads the app in the file at |app_path| and runs it on some other
+  // Loads the app in the file at |service_path| and runs it on some other
   // thread/process. Returns a Service handle the service manager can use to
   // connect to the the app.
   virtual mojom::ServicePtr Start(
-      const base::FilePath& app_path,
       const Identity& target,
       bool start_sandboxed,
       const base::Callback<void(base::ProcessId)>& pid_available_callback,
-      const base::Closure& app_completed_callback) = 0;
+      const base::Closure& service_completed_callback) = 0;
 };
 
 class NativeRunnerFactory {
  public:
   virtual ~NativeRunnerFactory() {}
   virtual std::unique_ptr<NativeRunner> Create(
-      const base::FilePath& app_path) = 0;
+      const base::FilePath& service_path) = 0;
 };
 
 }  // namespace service_manager
diff --git a/services/service_manager/public/cpp/lib/service_runner.cc b/services/service_manager/public/cpp/lib/service_runner.cc
index 2b8b388..ac333d2 100644
--- a/services/service_manager/public/cpp/lib/service_runner.cc
+++ b/services/service_manager/public/cpp/lib/service_runner.cc
@@ -71,12 +71,7 @@
 }
 
 MojoResult ServiceRunner::Run(MojoHandle service_request_handle) {
-  bool init_base = true;
-  if (base::CommandLine::InitializedForCurrentProcess()) {
-    init_base =
-        !base::CommandLine::ForCurrentProcess()->HasSwitch("single-process");
-  }
-  return Run(service_request_handle, init_base);
+  return Run(service_request_handle, false);
 }
 
 void ServiceRunner::Quit() {
diff --git a/services/service_manager/public/cpp/service.gni b/services/service_manager/public/cpp/service.gni
index 5faeb25..2fb9991 100644
--- a/services/service_manager/public/cpp/service.gni
+++ b/services/service_manager/public/cpp/service.gni
@@ -11,12 +11,13 @@
 }
 
 # Generates a Service "package", which includes:
-# . A self-named subdirectory
-# . A binary .library
-# . A resources subdirectory alongside .library that contains the contents of
-#   "resources"
 #
-# The parameters of this template are those of a shared library.
+#   - A self-named subdirectory
+#   - A binary .service executable
+#   - A resources subdirectory alongside the executable, which contains the
+#     contents of "resources"
+#
+# The parameters of this template are those of an executable
 template("service") {
   base_target_name = target_name
   if (defined(invoker.output_name)) {
@@ -25,12 +26,13 @@
 
   final_target_name = target_name
 
-  library_deps = []
+  service_deps = []
   if (defined(invoker.deps)) {
-    library_deps += invoker.deps
+    service_deps += invoker.deps
   }
 
-  library_data_deps = []
+  service_data_deps =
+      [ "//services/service_manager/public/cpp/standalone_service:main" ]
 
   if (defined(invoker.resources)) {
     copy_step_name = "${base_target_name}__copy_resources"
@@ -42,16 +44,22 @@
       if (defined(invoker.testonly)) {
         testonly = invoker.testonly
       }
-      deps = library_deps
+      deps = service_deps
     }
-    library_data_deps += [ ":$copy_step_name" ]
+    service_data_deps += [ ":$copy_step_name" ]
   }
 
-  output = base_target_name + ".library"
-  library_target_name = base_target_name + "_library"
-  library_name = "${shlib_prefix}${library_target_name}${shlib_extension}"
+  if (defined(invoker.data_deps)) {
+    service_data_deps += invoker.data_deps
+  }
 
-  shared_library(library_target_name) {
+  executable_target_name = base_target_name + "_executable"
+  executable_name = base_target_name + ".service"
+
+  executable(executable_target_name) {
+    output_name = base_target_name
+    output_extension = "service"
+
     if (defined(invoker.cflags)) {
       cflags = invoker.cflags
     }
@@ -83,22 +91,13 @@
       libs = invoker.libs
     }
 
-    data_deps = []
-    if (!defined(invoker.avoid_runner_cycle) || !invoker.avoid_runner_cycle) {
-      # Give the user an out; as some Services are depended on by the runner.
-      data_deps += [ "//services/service_manager/standalone" ]
-    }
-    if (defined(invoker.data_deps)) {
-      data_deps += invoker.data_deps
-    }
-    data_deps += library_data_deps
+    data_deps = service_data_deps
 
     deps = [
-      "//mojo/public/c/system:set_thunks_for_app",
-      "//services/service_manager/public/cpp:application_support",
+      "//services/service_manager/public/cpp/standalone_service:main",
     ]
 
-    deps += library_deps
+    deps += service_deps
     if (defined(invoker.public_deps)) {
       public_deps = invoker.public_deps
     }
@@ -138,14 +137,20 @@
                              "visibility",
                            ])
     deps = [
-      ":${library_target_name}",
+      ":${executable_target_name}",
     ]
 
+    # NOTE: We have to explicitly inherit the same data_deps as the executable
+    # target itself, rather than specifying a data depenedency on the executable
+    # target. This avoids needless duplication of service binary artifacts in
+    # test isolates, as the executable is unused in its original location.
+    data_deps = service_data_deps
+
     sources = [
-      "${root_shlib_dir}/${library_name}",
+      "${root_out_dir}/${executable_name}",
     ]
     outputs = [
-      "${root_out_dir}/${packages_directory}/${base_target_name}/${output}",
+      "${root_out_dir}/${packages_directory}/${base_target_name}/${executable_name}",
     ]
   }
 }
diff --git a/services/service_manager/public/cpp/service.h b/services/service_manager/public/cpp/service.h
index 2b8e780d..b3322b2 100644
--- a/services/service_manager/public/cpp/service.h
+++ b/services/service_manager/public/cpp/service.h
@@ -5,6 +5,8 @@
 #ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_SERVICE_H_
 #define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_SERVICE_H_
 
+#include "base/macros.h"
+
 namespace service_manager {
 
 class InterfaceRegistry;
@@ -65,6 +67,8 @@
   void set_context(ServiceContext* context) { service_context_ = context; }
 
   ServiceContext* service_context_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(Service);
 };
 
 // TODO(rockot): Remove this. It's here to satisfy a few remaining use cases
@@ -75,14 +79,16 @@
   explicit ForwardingService(Service* target);
   ~ForwardingService() override;
 
- private:
   // Service:
   void OnStart() override;
   bool OnConnect(const ServiceInfo& remote_info,
                  InterfaceRegistry* registry) override;
   bool OnStop() override;
 
+ private:
   Service* const target_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(ForwardingService);
 };
 
 }  // namespace service_manager
diff --git a/services/service_manager/public/cpp/standalone_service/BUILD.gn b/services/service_manager/public/cpp/standalone_service/BUILD.gn
new file mode 100644
index 0000000..433ddf68
--- /dev/null
+++ b/services/service_manager/public/cpp/standalone_service/BUILD.gn
@@ -0,0 +1,63 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("standalone_service") {
+  sources = [
+    "standalone_service.cc",
+    "standalone_service.h",
+    "switches.cc",
+    "switches.h",
+  ]
+
+  deps = [
+    "//mojo/edk/system",
+    "//mojo/public/cpp/system",
+    "//services/service_manager/public/cpp",
+    "//services/service_manager/runner:init",
+    "//services/service_manager/runner/common",
+  ]
+
+  public_deps = [
+    "//base",
+    "//services/service_manager/public/interfaces",
+  ]
+
+  if (is_linux && !is_android) {
+    sources += [
+      "linux_sandbox.cc",
+      "linux_sandbox.h",
+    ]
+
+    deps += [
+      "//sandbox/linux:sandbox",
+      "//sandbox/linux:sandbox_services",
+      "//sandbox/linux:seccomp_bpf",
+    ]
+  }
+
+  if (is_mac) {
+    sources += [
+      "mach_broker.cc",
+      "mach_broker.h",
+    ]
+  }
+}
+
+# Service executable targets should link against this to get a boilerplate entry
+# point which accepts canonical command-line arguments to establish a connection
+# to the Service Manager. In order to link properly, dependents must ensure that
+# they define a ServiceMain() symbol which matches the signature in
+# //services/service_manager/public/c/main.h.
+source_set("main") {
+  sources = [
+    "main.cc",
+  ]
+
+  deps = [
+    ":standalone_service",
+    "//base",
+    "//base:i18n",
+    "//services/service_manager/runner:init",
+  ]
+}
diff --git a/services/service_manager/public/cpp/standalone_service/DEPS b/services/service_manager/public/cpp/standalone_service/DEPS
new file mode 100644
index 0000000..ec69c8f
--- /dev/null
+++ b/services/service_manager/public/cpp/standalone_service/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+sandbox",
+]
diff --git a/services/service_manager/runner/host/linux_sandbox.cc b/services/service_manager/public/cpp/standalone_service/linux_sandbox.cc
similarity index 98%
rename from services/service_manager/runner/host/linux_sandbox.cc
rename to services/service_manager/public/cpp/standalone_service/linux_sandbox.cc
index 46fc62f..ae5b356 100644
--- a/services/service_manager/runner/host/linux_sandbox.cc
+++ b/services/service_manager/public/cpp/standalone_service/linux_sandbox.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "services/service_manager/runner/host/linux_sandbox.h"
+#include "services/service_manager/public/cpp/standalone_service/linux_sandbox.h"
 
 #include <fcntl.h>
 #include <sys/syscall.h>
diff --git a/services/service_manager/runner/host/linux_sandbox.h b/services/service_manager/public/cpp/standalone_service/linux_sandbox.h
similarity index 78%
rename from services/service_manager/runner/host/linux_sandbox.h
rename to services/service_manager/public/cpp/standalone_service/linux_sandbox.h
index a9e48045..df13dfd 100644
--- a/services/service_manager/runner/host/linux_sandbox.h
+++ b/services/service_manager/public/cpp/standalone_service/linux_sandbox.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SERVICES_SERVICE_MANAGER_RUNNER_HOST_LINUX_SANDBOX_H_
-#define SERVICES_SERVICE_MANAGER_RUNNER_HOST_LINUX_SANDBOX_H_
+#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_LINUX_SANDBOX_H_
+#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_LINUX_SANDBOX_H_
 
 #include <memory>
 
@@ -15,7 +15,8 @@
 
 namespace service_manager {
 
-// Encapsulates all tasks related to raising the sandbox for mojo runner.
+// Encapsulates all tasks related to raising the sandbox for a standalone
+// service.
 class LinuxSandbox {
  public:
   explicit LinuxSandbox(
@@ -48,4 +49,4 @@
 
 }  // namespace service_manager
 
-#endif  // SERVICES_SERVICE_MANAGER_RUNNER_HOST_LINUX_SANDBOX_H_
+#endif  // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_LINUX_SANDBOX_H_
diff --git a/services/service_manager/runner/host/mach_broker.cc b/services/service_manager/public/cpp/standalone_service/mach_broker.cc
similarity index 91%
rename from services/service_manager/runner/host/mach_broker.cc
rename to services/service_manager/public/cpp/standalone_service/mach_broker.cc
index 451a7fa..8f8c670 100644
--- a/services/service_manager/runner/host/mach_broker.cc
+++ b/services/service_manager/public/cpp/standalone_service/mach_broker.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "services/service_manager/runner/host/mach_broker.h"
+#include "services/service_manager/public/cpp/standalone_service/mach_broker.h"
 
 #include "base/logging.h"
 #include "base/memory/singleton.h"
diff --git a/services/service_manager/runner/host/mach_broker.h b/services/service_manager/public/cpp/standalone_service/mach_broker.h
similarity index 86%
rename from services/service_manager/runner/host/mach_broker.h
rename to services/service_manager/public/cpp/standalone_service/mach_broker.h
index 5d139da..bb96e9f 100644
--- a/services/service_manager/runner/host/mach_broker.h
+++ b/services/service_manager/public/cpp/standalone_service/mach_broker.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SERVICES_SERVICE_MANAGER_RUNNER_HOST_MACH_BROKER_H_
-#define SERVICES_SERVICE_MANAGER_RUNNER_HOST_MACH_BROKER_H_
+#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_MACH_BROKER_H_
+#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_MACH_BROKER_H_
 
 #include "base/mac/mach_port_broker.h"
 
@@ -50,4 +50,4 @@
 
 }  // namespace service_manager
 
-#endif  // SERVICES_SERVICE_MANAGER_RUNNER_HOST_MACH_BROKER_H_
+#endif  // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_MACH_BROKER_H_
diff --git a/services/service_manager/public/cpp/standalone_service/main.cc b/services/service_manager/public/cpp/standalone_service/main.cc
new file mode 100644
index 0000000..a505f8b
--- /dev/null
+++ b/services/service_manager/public/cpp/standalone_service/main.cc
@@ -0,0 +1,95 @@
+// 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 "base/at_exit.h"
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/debug/stack_trace.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/standalone_service/standalone_service.h"
+#include "services/service_manager/public/cpp/standalone_service/switches.h"
+#include "services/service_manager/public/interfaces/service.mojom.h"
+#include "services/service_manager/runner/init.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/bundle_locations.h"
+#endif
+
+namespace {
+
+// Cross-platform helper to override the necessary hard-coded path location
+// used to load ICU data.
+//
+// TODO(rockot): We should just parameterize InitializeICU so hacks like
+// this are unnecessary.
+class ScopedIcuDataDirOverride {
+ public:
+  ScopedIcuDataDirOverride(const base::FilePath& path) {
+#if defined(OS_WIN)
+    DCHECK(base::PathService::Get(base::DIR_MODULE, &original_path_));
+#elif defined(OS_MACOSX)
+    original_path_= base::mac::FrameworkBundlePath();
+#else
+    DCHECK(base::PathService::Get(base::DIR_EXE, &original_path_));
+#endif
+
+    if (!path.empty())
+      SetPathOverride(path);
+  }
+
+  ~ScopedIcuDataDirOverride() { SetPathOverride(original_path_); }
+
+ private:
+  static void SetPathOverride(const base::FilePath& path) {
+#if defined(OS_WIN)
+    DCHECK(base::PathService::Override(base::DIR_MODULE, path));
+#elif defined(OS_MACOSX)
+    base::mac::SetOverrideFrameworkBundlePath(path);
+#else
+    DCHECK(base::PathService::Override(base::DIR_EXE, path));
+#endif
+  }
+
+  base::FilePath original_path_;
+};
+
+// TODO(rockot): We should consider removing ServiceMain and instead allowing
+// service sources to define a CreateService method which returns a new instance
+// of service_manager::Service. This would reduce boilerplate in service sources
+// since they all effectively do the same thing via
+// service_manager::ServiceRunner.
+void RunServiceMain(service_manager::mojom::ServiceRequest request) {
+  MojoResult result = ServiceMain(request.PassMessagePipe().release().value());
+  DCHECK_EQ(result, MOJO_RESULT_OK);
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit;
+  base::CommandLine::Init(argc, argv);
+
+#if !defined(OFFICIAL_BIULD) && defined(OS_WIN)
+  base::RouteStdioToConsole(false);
+#endif
+
+  service_manager::InitializeLogging();
+
+  {
+    base::FilePath icu_data_dir = base::CommandLine::ForCurrentProcess()
+        ->GetSwitchValuePath(service_manager::switches::kIcuDataDir);
+    ScopedIcuDataDirOverride path_override(icu_data_dir);
+    base::i18n::InitializeICU();
+  }
+
+  service_manager::WaitForDebuggerIfNecessary();
+
+  service_manager::RunStandaloneService(base::Bind(&RunServiceMain));
+  return 0;
+}
diff --git a/services/service_manager/runner/host/child_process_base.cc b/services/service_manager/public/cpp/standalone_service/standalone_service.cc
similarity index 78%
rename from services/service_manager/runner/host/child_process_base.cc
rename to services/service_manager/public/cpp/standalone_service/standalone_service.cc
index 6341ecc..5e42b77 100644
--- a/services/service_manager/runner/host/child_process_base.cc
+++ b/services/service_manager/public/cpp/standalone_service/standalone_service.cc
@@ -1,35 +1,33 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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/service_manager/runner/host/child_process_base.h"
+#include "services/service_manager/public/cpp/standalone_service/standalone_service.h"
 
 #include "base/command_line.h"
 #include "base/debug/stack_trace.h"
 #include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
-#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/process_delegate.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/runner/common/client_util.h"
 #include "services/service_manager/runner/common/switches.h"
 
 #if defined(OS_LINUX)
 #include "base/rand_util.h"
 #include "base/sys_info.h"
-#include "services/service_manager/runner/host/linux_sandbox.h"
+#include "services/service_manager/public/cpp/standalone_service/linux_sandbox.h"
 #endif
 
 #if defined(OS_MACOSX)
-#include "services/service_manager/runner/host/mach_broker.h"
+#include "services/service_manager/public/cpp/standalone_service/mach_broker.h"
 #endif
 
 namespace service_manager {
-
 namespace {
 
 #if defined(OS_LINUX)
@@ -65,16 +63,10 @@
         wait_for_shutdown_event_(
             base::WaitableEvent::ResetPolicy::MANUAL,
             base::WaitableEvent::InitialState::NOT_SIGNALED) {
-    // Initialize Mojo before starting any threads.
     mojo::edk::Init();
-
-    // Create and start our I/O thread.
-    base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
-    CHECK(io_thread_.StartWithOptions(io_thread_options));
-    io_runner_ = io_thread_.task_runner().get();
-    CHECK(io_runner_.get());
-
-    mojo::edk::InitIPCSupport(this, io_runner_);
+    DCHECK(io_thread_.StartWithOptions(
+              base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
+    mojo::edk::InitIPCSupport(this, io_thread_.task_runner());
     mojo::edk::SetParentPipeHandleFromCommandLine();
   }
 
@@ -90,7 +82,6 @@
   }
 
   base::Thread io_thread_;
-  scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
 
   // Used to unblock the main thread on shutdown.
   base::WaitableEvent wait_for_shutdown_event_;
@@ -100,7 +91,7 @@
 
 }  // namespace
 
-void ChildProcessMainWithCallback(const RunCallback& callback) {
+void RunStandaloneService(const StandaloneServiceCallback& callback) {
   DCHECK(!base::MessageLoop::current());
 
 #if defined(OS_MACOSX)
diff --git a/services/service_manager/public/cpp/standalone_service/standalone_service.h b/services/service_manager/public/cpp/standalone_service/standalone_service.h
new file mode 100644
index 0000000..e7ea3a7
--- /dev/null
+++ b/services/service_manager/public/cpp/standalone_service/standalone_service.h
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+#include "services/service_manager/public/interfaces/service.mojom.h"
+
+namespace service_manager {
+
+using StandaloneServiceCallback = base::Callback<void(mojom::ServiceRequest)>;
+
+// Runs a standalone service in the current process. This takes care of setting
+// up a boilerplate environment, including initializing //base objects, Mojo
+// IPC, running a MessageLoop, and establishing a connection to the Service
+// Manager via canonical command-line arguments.
+//
+// Once a Service request is obtained, |callback| is invoked with it. This call
+// blocks until |callback| returns.
+//
+// NOTE: A typical service should also link against the main() defined in
+// main.cc (next to this header) and thus have no need to call this function
+// directly.
+void RunStandaloneService(const StandaloneServiceCallback& callback);
+
+}  // namespace service_manager
diff --git a/services/service_manager/public/cpp/standalone_service/switches.cc b/services/service_manager/public/cpp/standalone_service/switches.cc
new file mode 100644
index 0000000..58e07a0
--- /dev/null
+++ b/services/service_manager/public/cpp/standalone_service/switches.cc
@@ -0,0 +1,15 @@
+// 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/service_manager/public/cpp/standalone_service/switches.h"
+
+namespace service_manager {
+namespace switches {
+
+// The path where ICU initialization data can be found. If not provided, the
+// service binary's directory is assumed.
+const char kIcuDataDir[] = "icu-data-dir";
+
+}  // namespace switches
+}  // namespace service_manager
diff --git a/services/service_manager/public/cpp/standalone_service/switches.h b/services/service_manager/public/cpp/standalone_service/switches.h
new file mode 100644
index 0000000..b6f8508
--- /dev/null
+++ b/services/service_manager/public/cpp/standalone_service/switches.h
@@ -0,0 +1,11 @@
+// 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.
+
+namespace service_manager {
+namespace switches {
+
+extern const char kIcuDataDir[];
+
+}  // namespace switches
+}  // namespace service_manager
diff --git a/services/service_manager/runner/BUILD.gn b/services/service_manager/runner/BUILD.gn
index 83317470..0bf0e223c 100644
--- a/services/service_manager/runner/BUILD.gn
+++ b/services/service_manager/runner/BUILD.gn
@@ -5,7 +5,6 @@
 group("runner") {
   testonly = true
   deps = [
-    "//services/service_manager/runner/child",
     "//services/service_manager/runner/host",
   ]
 }
diff --git a/services/service_manager/runner/child/BUILD.gn b/services/service_manager/runner/child/BUILD.gn
deleted file mode 100644
index fc73aa6..0000000
--- a/services/service_manager/runner/child/BUILD.gn
+++ /dev/null
@@ -1,32 +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.
-
-import("//services/service_manager/public/cpp/service.gni")
-import("//services/service_manager/public/service_manifest.gni")
-import("//mojo/public/tools/bindings/mojom.gni")
-
-group("child") {
-  testonly = true
-  deps = [
-    ":test_native_main",
-  ]
-}
-
-source_set("test_native_main") {
-  sources = [
-    "test_native_main.cc",
-    "test_native_main.h",
-  ]
-
-  public_deps = [
-    "//services/service_manager/runner:init",
-  ]
-
-  deps = [
-    "//base",
-    "//mojo/edk/system",
-    "//services/service_manager/public/cpp",
-    "//services/service_manager/runner/common",
-  ]
-}
diff --git a/services/service_manager/runner/child/manifest.json b/services/service_manager/runner/child/manifest.json
deleted file mode 100644
index b49ff07..0000000
--- a/services/service_manager/runner/child/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "name": "mojo_runner_child_apptest",
-  "display_name": "Runner Child Apptest",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "requires": {
-        "*": [ "app" ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/runner/child/test_native_main.cc b/services/service_manager/runner/child/test_native_main.cc
deleted file mode 100644
index 75806cc..0000000
--- a/services/service_manager/runner/child/test_native_main.cc
+++ /dev/null
@@ -1,71 +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 "services/service_manager/runner/child/test_native_main.h"
-
-#include <utility>
-
-#include "base/debug/stack_trace.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/process/launch.h"
-#include "base/run_loop.h"
-#include "base/threading/thread.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/process_delegate.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_context.h"
-#include "services/service_manager/runner/common/client_util.h"
-#include "services/service_manager/runner/init.h"
-
-namespace service_manager {
-namespace {
-
-class ProcessDelegate : public mojo::edk::ProcessDelegate {
- public:
-  ProcessDelegate() {}
-  ~ProcessDelegate() override {}
-
- private:
-  void OnShutdownComplete() override {}
-
-  DISALLOW_COPY_AND_ASSIGN(ProcessDelegate);
-};
-
-}  // namespace
-
-int TestNativeMain(std::unique_ptr<service_manager::Service> service) {
-  service_manager::WaitForDebuggerIfNecessary();
-
-#if !defined(OFFICIAL_BUILD)
-  base::debug::EnableInProcessStackDumping();
-#if defined(OS_WIN)
-  base::RouteStdioToConsole(false);
-#endif
-#endif
-
-  {
-    mojo::edk::Init();
-
-    ProcessDelegate process_delegate;
-    base::Thread io_thread("io_thread");
-    base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
-    CHECK(io_thread.StartWithOptions(io_thread_options));
-
-    mojo::edk::InitIPCSupport(&process_delegate, io_thread.task_runner());
-    mojo::edk::SetParentPipeHandleFromCommandLine();
-
-    base::MessageLoop loop;
-    service_manager::ServiceContext context(
-        std::move(service),
-        service_manager::GetServiceRequestFromCommandLine());
-    base::RunLoop().Run();
-    mojo::edk::ShutdownIPCSupport();
-  }
-
-  return 0;
-}
-
-}  // namespace service_manager
diff --git a/services/service_manager/runner/child/test_native_main.h b/services/service_manager/runner/child/test_native_main.h
deleted file mode 100644
index 7148a96..0000000
--- a/services/service_manager/runner/child/test_native_main.h
+++ /dev/null
@@ -1,18 +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 SERVICES_SERVICE_MANAGER_RUNNER_CHILD_TEST_NATIVE_MAIN_H_
-#define SERVICES_SERVICE_MANAGER_RUNNER_CHILD_TEST_NATIVE_MAIN_H_
-
-#include <memory>
-
-namespace service_manager {
-
-class Service;
-
-int TestNativeMain(std::unique_ptr<Service> service);
-
-}  // namespace service_manager
-
-#endif  // SERVICES_SERVICE_MANAGER_RUNNER_CHILD_TEST_NATIVE_MAIN_H_
diff --git a/services/service_manager/runner/host/BUILD.gn b/services/service_manager/runner/host/BUILD.gn
index e110ccb236..f798dca8 100644
--- a/services/service_manager/runner/host/BUILD.gn
+++ b/services/service_manager/runner/host/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//testing/test.gni")
 
@@ -15,81 +16,19 @@
   ]
 }
 
-source_set("native_library_runner") {
-  sources = [
-    "native_library_runner.cc",
-    "native_library_runner.h",
-  ]
-
-  deps = [
-    "//base",
-    "//mojo/edk/system",
-    "//services/service_manager",
-  ]
-
-  # This target has to include the public thunk headers, which generally
-  # shouldn't be included without picking an implementation. We are providing
-  # the implementation but the thunk header target cannot declare that we are
-  # permitted to include it since it's in the public SDK and we are not.
-  # Suppress include checking so we can still check the rest of the targets in
-  # this file.
-  check_includes = false
-}
-
-source_set("child_process_base") {
-  sources = [
-    "child_process_base.cc",
-    "child_process_base.h",
-  ]
-
-  deps = [
-    "//base",
-    "//mojo/edk/system",
-    "//services/service_manager",
-    "//services/service_manager/public/interfaces",
-    "//services/service_manager/runner:init",
-    "//services/service_manager/runner/common",
-  ]
-
-  if (is_linux && !is_android) {
-    sources += [
-      "linux_sandbox.cc",
-      "linux_sandbox.h",
-    ]
-
-    deps += [
-      "//sandbox/linux:sandbox",
-      "//sandbox/linux:sandbox_services",
-      "//sandbox/linux:seccomp_bpf",
-    ]
-  }
-
-  if (is_mac) {
-    sources += [
-      "mach_broker.cc",
-      "mach_broker.h",
-    ]
-  }
-}
-
 source_set("lib") {
   sources = [
-    "child_process.cc",
-    "child_process.h",
     "child_process_host.cc",
     "child_process_host.h",
-    "in_process_native_runner.cc",
-    "in_process_native_runner.h",
     "out_of_process_native_runner.cc",
     "out_of_process_native_runner.h",
   ]
 
   deps = [
-    ":child_process_base",
-    ":native_library_runner",
     "//base:base_static",
     "//base:i18n",
     "//services/service_manager/public/cpp:sources",
+    "//services/service_manager/public/cpp/standalone_service",
     "//services/service_manager/runner:init",
     "//services/service_manager/runner/common",
   ]
@@ -111,7 +50,6 @@
   sources = [
     "child_process_host_unittest.cc",
     "host_unittests.cc",
-    "in_process_native_runner_unittest.cc",
   ]
 
   deps = [
@@ -124,4 +62,28 @@
     "//services/service_manager/runner/common",
     "//testing/gtest",
   ]
+
+  data_deps = [
+    ":host_test_service",
+  ]
+}
+
+service("host_test_service") {
+  sources = [
+    "host_test_service_main.cc",
+  ]
+
+  deps = [
+    "//mojo/public/cpp/system",
+    "//services/service_manager/public/cpp/standalone_service:main",
+  ]
+
+  data_deps = [
+    ":host_test_service_manifest",
+  ]
+}
+
+service_manifest("host_test_service_manifest") {
+  name = "host_test_service"
+  source = "host_test_service_manifest.json"
 }
diff --git a/services/service_manager/runner/host/child_process.cc b/services/service_manager/runner/host/child_process.cc
deleted file mode 100644
index 06a7339..0000000
--- a/services/service_manager/runner/host/child_process.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-
-#include "services/service_manager/runner/host/child_process.h"
-
-#include <stdint.h>
-
-#include <memory>
-#include <utility>
-
-#include "base/base_switches.h"
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/i18n/icu_util.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_checker.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/embedder/process_delegate.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/system/core.h"
-#include "services/service_manager/runner/common/switches.h"
-#include "services/service_manager/runner/host/child_process_base.h"
-#include "services/service_manager/runner/host/native_library_runner.h"
-#include "services/service_manager/runner/init.h"
-
-namespace service_manager {
-
-namespace {
-
-void RunNativeLibrary(base::NativeLibrary library,
-                      mojom::ServiceRequest service_request) {
-  if (!RunServiceInNativeLibrary(library, std::move(service_request))) {
-    LOG(ERROR) << "Failure to RunServiceInNativeLibrary()";
-  }
-}
-
-}  // namespace
-
-int ChildProcessMain() {
-  DVLOG(2) << "ChildProcessMain()";
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-
-  base::NativeLibrary library = 0;
-  // Load the application library before we engage the sandbox.
-  base::FilePath library_path =
-      command_line.GetSwitchValuePath(switches::kChildProcess);
-  if (!library_path.empty())
-    library = LoadNativeLibrary(library_path);
-  base::i18n::InitializeICU();
-  if (library)
-    CallLibraryEarlyInitialization(library);
-
-  ChildProcessMainWithCallback(base::Bind(&RunNativeLibrary, library));
-
-  return 0;
-}
-
-}  // namespace service_manager
diff --git a/services/service_manager/runner/host/child_process.h b/services/service_manager/runner/host/child_process.h
deleted file mode 100644
index 3f903d2..0000000
--- a/services/service_manager/runner/host/child_process.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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 SERVICES_SERVICE_MANAGER_RUNNER_HOST_CHILD_PROCESS_H_
-#define SERVICES_SERVICE_MANAGER_RUNNER_HOST_CHILD_PROCESS_H_
-
-namespace service_manager {
-
-// Main method for a child process.
-int ChildProcessMain();
-
-}  // namespace service_manager
-
-#endif  // SERVICES_SERVICE_MANAGER_RUNNER_HOST_CHILD_PROCESS_H_
diff --git a/services/service_manager/runner/host/child_process_base.h b/services/service_manager/runner/host/child_process_base.h
deleted file mode 100644
index 0d85adf..0000000
--- a/services/service_manager/runner/host/child_process_base.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_SERVICE_MANAGER_RUNNER_HOST_CHILD_PROCESS_BASE_H_
-#define SERVICES_SERVICE_MANAGER_RUNNER_HOST_CHILD_PROCESS_BASE_H_
-
-#include "base/callback.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
-
-namespace service_manager {
-
-// Child processes call this to establish the connection to the service manager
-// and obtain
-// the ServiceRequest. Once the connection has been established |callback|
-// is run. ChildProcessMainWithCallback() returns once the the callback
-// completes.
-using RunCallback = base::Callback<void(mojom::ServiceRequest)>;
-void ChildProcessMainWithCallback(const RunCallback& callback);
-
-}  // namespace service_manager
-
-#endif  // SERVICES_SERVICE_MANAGER_RUNNER_HOST_CHILD_PROCESS_BASE_H_
diff --git a/services/service_manager/runner/host/child_process_host.cc b/services/service_manager/runner/host/child_process_host.cc
index 4f1de53..067f432 100644
--- a/services/service_manager/runner/host/child_process_host.cc
+++ b/services/service_manager/runner/host/child_process_host.cc
@@ -8,12 +8,14 @@
 
 #include <utility>
 
+#include "base/base_paths.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/synchronization/lock.h"
@@ -23,6 +25,7 @@
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
 #include "mojo/public/cpp/system/core.h"
 #include "services/service_manager/native_runner_delegate.h"
+#include "services/service_manager/public/cpp/standalone_service/switches.h"
 #include "services/service_manager/runner/common/client_util.h"
 #include "services/service_manager/runner/common/switches.h"
 
@@ -35,7 +38,7 @@
 #endif
 
 #if defined(OS_MACOSX)
-#include "services/service_manager/runner/host/mach_broker.h"
+#include "services/service_manager/public/cpp/standalone_service/mach_broker.h"
 #endif
 
 namespace service_manager {
@@ -44,23 +47,24 @@
                                    NativeRunnerDelegate* delegate,
                                    bool start_sandboxed,
                                    const Identity& target,
-                                   const base::FilePath& app_path)
+                                   const base::FilePath& service_path)
     : launch_process_runner_(launch_process_runner),
       delegate_(delegate),
       start_sandboxed_(start_sandboxed),
       target_(target),
-      app_path_(app_path),
+      service_path_(service_path),
       child_token_(mojo::edk::GenerateRandomToken()),
       start_child_process_event_(
           base::WaitableEvent::ResetPolicy::AUTOMATIC,
           base::WaitableEvent::InitialState::NOT_SIGNALED),
-      weak_factory_(this) {}
+      weak_factory_(this) {
+  if (service_path_.empty())
+    service_path_ = base::CommandLine::ForCurrentProcess()->GetProgram();
+}
 
 ChildProcessHost::~ChildProcessHost() {
-  if (!app_path_.empty()) {
-    CHECK(!mojo_ipc_channel_)
-        << "Destroying ChildProcessHost before calling Join";
-  }
+  DCHECK(!mojo_ipc_channel_)
+      << "Destroying ChildProcessHost before calling Join";
 }
 
 mojom::ServicePtr ChildProcessHost::Start(
@@ -69,30 +73,21 @@
     const base::Closure& quit_closure) {
   DCHECK(!child_process_.IsValid());
 
-  const base::CommandLine* parent_command_line =
-      base::CommandLine::ForCurrentProcess();
-  base::FilePath target_path = parent_command_line->GetProgram();
-  // |app_path_| can be empty in tests.
-  if (!app_path_.MatchesExtension(FILE_PATH_LITERAL(".library")) &&
-      !app_path_.empty()) {
-    target_path = app_path_;
-  }
+  const base::CommandLine& parent_command_line =
+      *base::CommandLine::ForCurrentProcess();
 
   std::unique_ptr<base::CommandLine> child_command_line(
-      new base::CommandLine(target_path));
+      new base::CommandLine(service_path_));
 
-  child_command_line->AppendArguments(*parent_command_line, false);
+  child_command_line->AppendArguments(parent_command_line, false);
 
 #ifndef NDEBUG
   child_command_line->AppendSwitchASCII("n", target.name());
   child_command_line->AppendSwitchASCII("u", target.user_id());
 #endif
 
-  if (target_path != app_path_)
-    child_command_line->AppendSwitchPath(switches::kChildProcess, app_path_);
-
   if (start_sandboxed_)
-    child_command_line->AppendSwitch(switches::kEnableSandbox);
+    child_command_line->AppendSwitch(::switches::kEnableSandbox);
 
   mojo_ipc_channel_.reset(new mojo::edk::PlatformChannelPair);
   mojo_ipc_channel_->PrepareToPassClientHandleToChildProcess(
@@ -140,6 +135,24 @@
   }
 
   base::LaunchOptions options;
+
+  base::FilePath exe_dir;
+  DCHECK(base::PathService::Get(base::DIR_EXE, &exe_dir));
+  options.current_directory = exe_dir;
+
+  // The service should look for ICU data next to the service runner's
+  // executable rather than its own.
+  child_command_line->AppendSwitchPath(switches::kIcuDataDir, exe_dir);
+
+#if defined(OS_POSIX)
+  // We need the dynamic loader to be able to locate things like libbase.so
+  // in component builds, as well as some other dynamic runtime dependencies in
+  // other build environments (e.g. libosmesa.so). For this we set
+  // LD_LIBRARY_PATH to the service runner's executable path where such
+  // artifacts are typically expected to reside.
+  options.environ["LD_LIBRARY_PATH"] = exe_dir.value();
+#endif
+
 #if defined(OS_WIN)
   options.handles_to_inherit = &handle_passing_info_;
 #if defined(OFFICIAL_BUILD)
diff --git a/services/service_manager/runner/host/child_process_host.h b/services/service_manager/runner/host/child_process_host.h
index eb14adb..ab87d02 100644
--- a/services/service_manager/runner/host/child_process_host.h
+++ b/services/service_manager/runner/host/child_process_host.h
@@ -36,26 +36,25 @@
 
 // This class represents a "child process host". Handles launching and
 // connecting a platform-specific "pipe" to the child, and supports joining the
-// child process. Currently runs a single app (loaded from the file system).
+// child process. Currently runs a single service, loaded from a standalone
+// service executable on the file system.
 //
 // This class is not thread-safe. It should be created/used/destroyed on a
 // single thread.
 //
 // Note: Does not currently work on Windows before Vista.
-// Note: After |Start()|, |StartApp| must be called and this object must
-// remained alive until the |on_app_complete| callback is called.
 class ChildProcessHost {
  public:
   using ProcessReadyCallback = base::Callback<void(base::ProcessId)>;
 
   // |name| is just for debugging ease. We will spawn off a process so that it
-  // can be sandboxed if |start_sandboxed| is true. |app_path| is a path to the
-  // service we wish to start.
+  // can be sandboxed if |start_sandboxed| is true. |service_path| is a path to
+  // the service executable we wish to start.
   ChildProcessHost(base::TaskRunner* launch_process_runner,
                    NativeRunnerDelegate* delegate,
                    bool start_sandboxed,
                    const Identity& target,
-                   const base::FilePath& app_path);
+                   const base::FilePath& service_path);
   virtual ~ChildProcessHost();
 
   // |Start()|s the child process; calls |DidStart()| (on the thread on which
@@ -77,7 +76,7 @@
   NativeRunnerDelegate* delegate_ = nullptr;
   bool start_sandboxed_ = false;
   Identity target_;
-  const base::FilePath app_path_;
+  base::FilePath service_path_;
   base::Process child_process_;
 
   // Used to initialize the Mojo IPC channel between parent and child.
diff --git a/services/service_manager/runner/host/child_process_host_unittest.cc b/services/service_manager/runner/host/child_process_host_unittest.cc
index 4ccee538..a8804929 100644
--- a/services/service_manager/runner/host/child_process_host_unittest.cc
+++ b/services/service_manager/runner/host/child_process_host_unittest.cc
@@ -26,6 +26,12 @@
 namespace service_manager {
 namespace {
 
+const char kTestServiceName[] = "host_test_service";
+
+const base::FilePath::CharType kPackagesPath[] = FILE_PATH_LITERAL("Packages");
+const base::FilePath::CharType kServiceExtension[] =
+    FILE_PATH_LITERAL(".service");
+
 void ProcessReadyCallbackAdapater(const base::Closure& callback,
                                   base::ProcessId process_id) {
   callback.Run();
@@ -71,8 +77,6 @@
 #else
 #define MAYBE_StartJoin StartJoin
 #endif  // defined(OS_ANDROID)
-// Just tests starting the child process and joining it (without starting an
-// app).
 TEST(ChildProcessHostTest, MAYBE_StartJoin) {
   base::FilePath service_manager_dir;
   PathService::Get(base::DIR_MODULE, &service_manager_dir);
@@ -89,10 +93,14 @@
   ProcessDelegate delegate;
   mojo::edk::InitIPCSupport(&delegate, io_thread.task_runner());
 
+  base::FilePath test_service_path =
+      base::FilePath(kPackagesPath).AppendASCII(kTestServiceName)
+          .AppendASCII(kTestServiceName) .AddExtension(kServiceExtension);
+
   NativeRunnerDelegateImpl native_runner_delegate;
   ChildProcessHost child_process_host(blocking_pool.get(),
                                       &native_runner_delegate, false,
-                                      Identity(), base::FilePath());
+                                      Identity(), test_service_path);
   base::RunLoop run_loop;
   child_process_host.Start(
       Identity(),
diff --git a/services/service_manager/runner/host/host_test_service_main.cc b/services/service_manager/runner/host/host_test_service_main.cc
new file mode 100644
index 0000000..2ce8492f
--- /dev/null
+++ b/services/service_manager/runner/host/host_test_service_main.cc
@@ -0,0 +1,12 @@
+// 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 "mojo/public/cpp/system/message_pipe.h"
+#include "services/service_manager/public/c/main.h"
+
+MojoResult ServiceMain(MojoHandle service_request_handle) {
+  mojo::ScopedMessagePipeHandle service_request_pipe;
+  service_request_pipe.reset(mojo::MessagePipeHandle(service_request_handle));
+  return MOJO_RESULT_OK;
+}
diff --git a/services/service_manager/runner/host/host_test_service_manifest.json b/services/service_manager/runner/host/host_test_service_manifest.json
new file mode 100644
index 0000000..1307358
--- /dev/null
+++ b/services/service_manager/runner/host/host_test_service_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "host_test_service",
+  "display_name": "Service Host Test Service"
+}
diff --git a/services/service_manager/runner/host/host_unittests.cc b/services/service_manager/runner/host/host_unittests.cc
index 2e91efc..ed09c1c 100644
--- a/services/service_manager/runner/host/host_unittests.cc
+++ b/services/service_manager/runner/host/host_unittests.cc
@@ -10,23 +10,14 @@
 #include "base/test/test_suite.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "services/service_manager/runner/common/switches.h"
-#include "services/service_manager/runner/host/child_process.h"
 #include "services/service_manager/runner/init.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 int main(int argc, char** argv) {
   base::CommandLine::Init(argc, argv);
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
 
   service_manager::WaitForDebuggerIfNecessary();
 
-  if (command_line.HasSwitch(switches::kChildProcess)) {
-    base::AtExitManager at_exit;
-
-    return service_manager::ChildProcessMain();
-  }
-
   mojo::edk::Init();
 
   base::TestSuite test_suite(argc, argv);
diff --git a/services/service_manager/runner/host/in_process_native_runner.cc b/services/service_manager/runner/host/in_process_native_runner.cc
deleted file mode 100644
index 156c233c..0000000
--- a/services/service_manager/runner/host/in_process_native_runner.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.
-
-#include "services/service_manager/runner/host/in_process_native_runner.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/process/process.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task_runner.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/service_manager/runner/host/native_library_runner.h"
-#include "services/service_manager/runner/host/out_of_process_native_runner.h"
-#include "services/service_manager/runner/init.h"
-
-namespace service_manager {
-
-InProcessNativeRunner::InProcessNativeRunner() : library_(nullptr) {}
-
-InProcessNativeRunner::~InProcessNativeRunner() {
-  // It is important to let the thread exit before unloading the DSO (when
-  // library_ is destructed), because the library may have registered
-  // thread-local data and destructors to run on thread termination.
-  if (thread_) {
-    DCHECK(thread_->HasBeenStarted());
-    DCHECK(!thread_->HasBeenJoined());
-    thread_->Join();
-  }
-}
-
-mojom::ServicePtr InProcessNativeRunner::Start(
-    const base::FilePath& library_path,
-    const Identity& target,
-    bool start_sandboxed,
-    const base::Callback<void(base::ProcessId)>& pid_available_callback,
-    const base::Closure& service_completed_callback) {
-  library_path_ = library_path;
-
-  DCHECK(!request_.is_pending());
-  mojom::ServicePtr client;
-  request_ = GetProxy(&client);
-
-  DCHECK(service_completed_callback_runner_.is_null());
-  service_completed_callback_runner_ = base::Bind(
-      &base::TaskRunner::PostTask, base::ThreadTaskRunnerHandle::Get(),
-      FROM_HERE, service_completed_callback);
-
-  DCHECK(!thread_);
-  std::string thread_name = "Service Thread";
-#if defined(OS_WIN)
-  thread_name = base::WideToUTF8(library_path_.BaseName().value());
-#endif
-  thread_.reset(new base::DelegateSimpleThread(this, thread_name));
-  thread_->Start();
-  pid_available_callback.Run(base::Process::Current().Pid());
-
-  return client;
-}
-
-void InProcessNativeRunner::Run() {
-  DVLOG(2) << "Loading/running Service in process from library: "
-           << library_path_.value()
-           << " thread id=" << base::PlatformThread::CurrentId();
-
-  // TODO(vtl): ScopedNativeLibrary doesn't have a .get() method!
-  base::NativeLibrary library = LoadNativeLibrary(library_path_);
-  library_.Reset(library);
-  // This hangs on Windows in the component build, so skip it since it's
-  // unnecessary.
-#if !(defined(COMPONENT_BUILD) && defined(OS_WIN))
-  CallLibraryEarlyInitialization(library);
-#endif
-  RunServiceInNativeLibrary(library, std::move(request_));
-  service_completed_callback_runner_.Run();
-  service_completed_callback_runner_.Reset();
-}
-
-std::unique_ptr<NativeRunner> InProcessNativeRunnerFactory::Create(
-    const base::FilePath& library_path) {
-  // Executables are always run in a new process.
-  if (!library_path.MatchesExtension(FILE_PATH_LITERAL(".library"))) {
-    return base::MakeUnique<OutOfProcessNativeRunner>(launch_process_runner_,
-                                                      nullptr);
-  }
-  return base::WrapUnique(new InProcessNativeRunner);
-}
-
-}  // namespace service_manager
diff --git a/services/service_manager/runner/host/in_process_native_runner.h b/services/service_manager/runner/host/in_process_native_runner.h
deleted file mode 100644
index 9da7beca..0000000
--- a/services/service_manager/runner/host/in_process_native_runner.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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 SERVICES_SERVICE_MANAGER_RUNNER_HOST_IN_PROCESS_NATIVE_RUNNER_H_
-#define SERVICES_SERVICE_MANAGER_RUNNER_HOST_IN_PROCESS_NATIVE_RUNNER_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/scoped_native_library.h"
-#include "base/threading/simple_thread.h"
-#include "services/service_manager/native_runner.h"
-
-namespace base {
-class TaskRunner;
-}
-
-namespace service_manager {
-
-// An implementation of |NativeRunner| that loads/runs the given service (from
-// the file system) on a separate thread (in the current process).
-class InProcessNativeRunner : public NativeRunner,
-                              public base::DelegateSimpleThread::Delegate {
- public:
-  InProcessNativeRunner();
-  ~InProcessNativeRunner() override;
-
-  // NativeRunner:
-  mojom::ServicePtr Start(
-      const base::FilePath& library_path,
-      const Identity& target,
-      bool start_sandboxed,
-      const base::Callback<void(base::ProcessId)>& pid_available_callback,
-      const base::Closure& service_completed_callback) override;
-
- private:
-  // |base::DelegateSimpleThread::Delegate| method:
-  void Run() override;
-
-  base::FilePath library_path_;
-  mojom::ServiceRequest request_;
-  base::Callback<bool(void)> service_completed_callback_runner_;
-
-  base::ScopedNativeLibrary library_;
-  std::unique_ptr<base::DelegateSimpleThread> thread_;
-
-  DISALLOW_COPY_AND_ASSIGN(InProcessNativeRunner);
-};
-
-class InProcessNativeRunnerFactory : public NativeRunnerFactory {
- public:
-  explicit InProcessNativeRunnerFactory(base::TaskRunner* launch_process_runner)
-      : launch_process_runner_(launch_process_runner) {}
-  ~InProcessNativeRunnerFactory() override {}
-
-  std::unique_ptr<NativeRunner> Create(
-      const base::FilePath& library_path) override;
-
- private:
-  base::TaskRunner* const launch_process_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(InProcessNativeRunnerFactory);
-};
-
-}  // namespace service_manager
-
-#endif  // SERVICES_SERVICE_MANAGER_RUNNER_HOST_IN_PROCESS_NATIVE_RUNNER_H_
diff --git a/services/service_manager/runner/host/in_process_native_runner_unittest.cc b/services/service_manager/runner/host/in_process_native_runner_unittest.cc
deleted file mode 100644
index 76596fa..0000000
--- a/services/service_manager/runner/host/in_process_native_runner_unittest.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-
-#include "services/service_manager/runner/host/in_process_native_runner.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace service_manager {
-
-TEST(InProcessNativeRunnerTest, NotStarted) {
-  InProcessNativeRunner runner;
-  // Shouldn't crash or DCHECK on destruction.
-}
-
-}  // namespace service_manager
diff --git a/services/service_manager/runner/host/native_library_runner.cc b/services/service_manager/runner/host/native_library_runner.cc
deleted file mode 100644
index fbb86644..0000000
--- a/services/service_manager/runner/host/native_library_runner.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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.
-
-#include "services/service_manager/runner/host/native_library_runner.h"
-
-#include <stddef.h>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "mojo/edk/embedder/entrypoints.h"
-#include "mojo/public/c/system/thunks.h"
-
-namespace service_manager {
-
-namespace {
-
-template <typename Thunks>
-bool SetThunks(Thunks (*make_thunks)(),
-               const char* function_name,
-               base::NativeLibrary library) {
-  typedef size_t (*SetThunksFn)(const Thunks* thunks);
-  SetThunksFn set_thunks = reinterpret_cast<SetThunksFn>(
-      base::GetFunctionPointerFromNativeLibrary(library, function_name));
-  if (!set_thunks)
-    return false;
-  Thunks thunks = make_thunks();
-  size_t expected_size = set_thunks(&thunks);
-  if (expected_size > sizeof(Thunks)) {
-    LOG(ERROR) << "Invalid library: expected " << function_name
-               << " to return thunks of size: " << expected_size;
-    return false;
-  }
-  return true;
-}
-
-}  // namespace
-
-base::NativeLibrary LoadNativeLibrary(const base::FilePath& path) {
-  DVLOG(2) << "Loading Service in process from library: " << path.value();
-
-  base::NativeLibraryLoadError error;
-  base::NativeLibrary library = base::LoadNativeLibrary(path, &error);
-  LOG_IF(ERROR, !library)
-      << "Failed to load library (path: " << path.value()
-      << " reason: " << error.ToString() << ")";
-  return library;
-}
-
-bool RunServiceInNativeLibrary(base::NativeLibrary library,
-                               mojom::ServiceRequest request) {
-  // Tolerate |library| being null, to make life easier for callers.
-  if (!library)
-    return false;
-
-// Thunks aren't needed/used in component build, since the thunked methods
-// just live in their own dynamically loaded library.
-#if !defined(COMPONENT_BUILD)
-  if (!SetThunks(&mojo::edk::MakeSystemThunks, "MojoSetSystemThunks",
-                 library)) {
-    LOG(ERROR) << "MojoSetSystemThunks not found";
-    return false;
-  }
-
-#if !defined(OS_WIN)
-  // On Windows, initializing base::CommandLine with null parameters gets the
-  // process's command line from the OS. Other platforms need it to be passed
-  // in. This needs to be passed in before the service initializes the command
-  // line, which is done as soon as it loads.
-  typedef void (*InitCommandLineArgs)(int, const char* const*);
-  InitCommandLineArgs init_command_line_args =
-      reinterpret_cast<InitCommandLineArgs>(
-          base::GetFunctionPointerFromNativeLibrary(library,
-                                                    "InitCommandLineArgs"));
-  if (init_command_line_args) {
-    int argc = 0;
-    base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
-    const char** argv = new const char*[cmd_line->argv().size()];
-    for (auto& arg : cmd_line->argv())
-      argv[argc++] = arg.c_str();
-    init_command_line_args(argc, argv);
-  }
-#endif
-
-#endif  // !defined(COMPONENT_BUILD)
-
-  typedef MojoResult (*ServiceMainFunction)(MojoHandle);
-  ServiceMainFunction main_function = reinterpret_cast<ServiceMainFunction>(
-      base::GetFunctionPointerFromNativeLibrary(library, "ServiceMain"));
-  if (!main_function) {
-    LOG(ERROR) << "ServiceMain not found";
-    return false;
-  }
-  // |ServiceMain()| takes ownership of the service handle.
-  MojoHandle handle = request.PassMessagePipe().release().value();
-  MojoResult result = main_function(handle);
-  if (result != MOJO_RESULT_OK) {
-    LOG(ERROR) << "ServiceMain returned error (result: " << result << ")";
-  }
-  return true;
-}
-
-}  // namespace service_manager
diff --git a/services/service_manager/runner/host/native_library_runner.h b/services/service_manager/runner/host/native_library_runner.h
deleted file mode 100644
index 9e19caa..0000000
--- a/services/service_manager/runner/host/native_library_runner.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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 SERVICES_SERVICE_MANAGER_RUNNER_HOST_NATIVE_LIBRARY_RUNNER_H_
-#define SERVICES_SERVICE_MANAGER_RUNNER_HOST_NATIVE_LIBRARY_RUNNER_H_
-
-#include "base/native_library.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace service_manager {
-
-// Loads the native Service from the DSO specified by |app_path|.
-// Returns the |base::NativeLibrary| for the service on success (or null on
-// failure).
-//
-// Note: The caller may choose to eventually unload the returned DSO. If so,
-// this should be done only after the thread on which |LoadNativeLibrary()|
-// and |RunServiceInNativeLibrary()| were called has terminated, so that any
-// thread-local destructors have been executed.
-base::NativeLibrary LoadNativeLibrary(const base::FilePath& app_path);
-
-// Runs the native Service from the DSO that was loaded using
-// |LoadNativeLibrary()|; this tolerates |library| being null. This should be
-// called on the same thread as |LoadNativeLibrary()|. Returns true if
-// |ServiceMain()| was called (even if it returns an error), and false
-// otherwise.
-bool RunServiceInNativeLibrary(base::NativeLibrary library,
-                               mojom::ServiceRequest request);
-
-}  // namespace service_manager
-
-#endif  // SERVICES_SERVICE_MANAGER_RUNNER_HOST_NATIVE_LIBRARY_RUNNER_H_
diff --git a/services/service_manager/runner/host/out_of_process_native_runner.cc b/services/service_manager/runner/host/out_of_process_native_runner.cc
index 9edd59d..0df2edf 100644
--- a/services/service_manager/runner/host/out_of_process_native_runner.cc
+++ b/services/service_manager/runner/host/out_of_process_native_runner.cc
@@ -16,33 +16,33 @@
 #include "base/task_runner.h"
 #include "services/service_manager/runner/common/client_util.h"
 #include "services/service_manager/runner/host/child_process_host.h"
-#include "services/service_manager/runner/host/in_process_native_runner.h"
 
 namespace service_manager {
 
 OutOfProcessNativeRunner::OutOfProcessNativeRunner(
+    const base::FilePath& service_path,
     base::TaskRunner* launch_process_runner,
     NativeRunnerDelegate* delegate)
-    : launch_process_runner_(launch_process_runner), delegate_(delegate) {}
+    : launch_process_runner_(launch_process_runner),
+      delegate_(delegate),
+      service_path_(service_path) {}
 
 OutOfProcessNativeRunner::~OutOfProcessNativeRunner() {
-  if (child_process_host_ && !app_path_.empty())
+  if (child_process_host_ && !service_path_.empty())
     child_process_host_->Join();
 }
 
 mojom::ServicePtr OutOfProcessNativeRunner::Start(
-    const base::FilePath& app_path,
     const Identity& target,
     bool start_sandboxed,
     const base::Callback<void(base::ProcessId)>& pid_available_callback,
     const base::Closure& app_completed_callback) {
-  app_path_ = app_path;
-
   DCHECK(app_completed_callback_.is_null());
   app_completed_callback_ = app_completed_callback;
 
   child_process_host_.reset(new ChildProcessHost(
-      launch_process_runner_, delegate_, start_sandboxed, target, app_path));
+      launch_process_runner_, delegate_, start_sandboxed, target,
+      service_path_));
   return child_process_host_->Start(
       target, pid_available_callback,
       base::Bind(&OutOfProcessNativeRunner::AppCompleted,
@@ -64,12 +64,13 @@
     base::TaskRunner* launch_process_runner,
     NativeRunnerDelegate* delegate)
     : launch_process_runner_(launch_process_runner), delegate_(delegate) {}
+
 OutOfProcessNativeRunnerFactory::~OutOfProcessNativeRunnerFactory() {}
 
 std::unique_ptr<NativeRunner> OutOfProcessNativeRunnerFactory::Create(
-    const base::FilePath& app_path) {
-  return base::MakeUnique<OutOfProcessNativeRunner>(launch_process_runner_,
-                                                    delegate_);
+    const base::FilePath& service_path) {
+  return base::MakeUnique<OutOfProcessNativeRunner>(
+      service_path, launch_process_runner_, delegate_);
 }
 
 }  // namespace service_manager
diff --git a/services/service_manager/runner/host/out_of_process_native_runner.h b/services/service_manager/runner/host/out_of_process_native_runner.h
index df61565b..e2e8e4f4 100644
--- a/services/service_manager/runner/host/out_of_process_native_runner.h
+++ b/services/service_manager/runner/host/out_of_process_native_runner.h
@@ -24,17 +24,17 @@
 class ChildProcessHost;
 class NativeRunnerDelegate;
 
-// An implementation of |NativeRunner| that loads/runs the given app (from the
-// file system) in a separate process (of its own).
+// An implementation of |NativeRunner| that runs a given service executable
+// in a separate, dedicated process.
 class OutOfProcessNativeRunner : public NativeRunner {
  public:
-  OutOfProcessNativeRunner(base::TaskRunner* launch_process_runner,
+  OutOfProcessNativeRunner(const base::FilePath& service_path,
+                           base::TaskRunner* launch_process_runner,
                            NativeRunnerDelegate* delegate);
   ~OutOfProcessNativeRunner() override;
 
   // NativeRunner:
   mojom::ServicePtr Start(
-      const base::FilePath& app_path,
       const Identity& identity,
       bool start_sandboxed,
       const base::Callback<void(base::ProcessId)>& pid_available_callback,
@@ -46,7 +46,7 @@
   base::TaskRunner* const launch_process_runner_;
   NativeRunnerDelegate* delegate_;
 
-  base::FilePath app_path_;
+  const base::FilePath service_path_;
   base::Closure app_completed_callback_;
 
   std::unique_ptr<ChildProcessHost> child_process_host_;
@@ -60,7 +60,8 @@
                                   NativeRunnerDelegate* delegate);
   ~OutOfProcessNativeRunnerFactory() override;
 
-  std::unique_ptr<NativeRunner> Create(const base::FilePath& app_path) override;
+  std::unique_ptr<NativeRunner> Create(
+      const base::FilePath& service_path) override;
 
  private:
   base::TaskRunner* const launch_process_runner_;
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc
index dab2bd7..5f815c3 100644
--- a/services/service_manager/service_manager.cc
+++ b/services/service_manager/service_manager.cc
@@ -146,8 +146,8 @@
 
     std::unique_ptr<ConnectParams> params(std::move(*connect_params));
     if (!params->connect_callback().is_null()) {
-        params->connect_callback().Run(mojom::ConnectResult::SUCCEEDED,
-                                       identity_.user_id());
+      params->connect_callback().Run(mojom::ConnectResult::SUCCEEDED,
+                                     identity_.user_id());
     }
 
     InterfaceProviderSpecMap specs;
@@ -190,15 +190,19 @@
     StartWithService(std::move(service));
   }
 
-  void StartWithFilePath(const base::FilePath& path) {
-    CHECK(!service_);
+  bool StartWithFilePath(const base::FilePath& path) {
+    DCHECK(!service_);
+    DCHECK(!path.empty());
     runner_ = service_manager_->native_runner_factory_->Create(path);
+    if (!runner_)
+      return false;
     bool start_sandboxed = false;
     mojom::ServicePtr service = runner_->Start(
-        path, identity_, start_sandboxed,
+        identity_, start_sandboxed,
         base::Bind(&Instance::PIDAvailable, weak_factory_.GetWeakPtr()),
         base::Bind(&Instance::OnRunnerCompleted, weak_factory_.GetWeakPtr()));
     StartWithService(std::move(service));
+    return true;
   }
 
   mojom::RunningServiceInfoPtr CreateRunningServiceInfo() const {
@@ -637,9 +641,7 @@
   if (instance == service_manager_instance_)
     return;
 
-  const Identity identity = instance->identity();
-  identity_to_instance_.erase(identity);
-
+  EraseInstanceIdentity(instance);
   if (instance->parent()) {
     // Deletes |instance|.
     instance->parent()->RemoveChild(instance);
@@ -656,7 +658,7 @@
   // If an Instance becomes unreachable, new connection requests for this
   // identity will elicit a new Instance instantiation. The unreachable instance
   // remains alive.
-  identity_to_instance_.erase(instance->identity());
+  EraseInstanceIdentity(instance);
 }
 
 void ServiceManager::OnInstanceStopped(const Identity& identity) {
@@ -715,6 +717,28 @@
   return nullptr;
 }
 
+void ServiceManager::EraseInstanceIdentity(Instance* instance) {
+  const Identity& identity = instance->identity();
+
+  auto it = identity_to_instance_.find(identity);
+  if (it != identity_to_instance_.end()) {
+    identity_to_instance_.erase(it);
+    return;
+  }
+
+  if (singletons_.find(identity.name()) != singletons_.end()) {
+    singletons_.erase(identity.name());
+    for (auto it = identity_to_instance_.begin();
+         it != identity_to_instance_.end(); ++it) {
+      if (it->first.name() == identity.name() &&
+          it->first.instance() == identity.instance()) {
+        identity_to_instance_.erase(it);
+        return;
+      }
+    }
+  }
+}
+
 void ServiceManager::NotifyServiceStarted(const Identity& identity,
                                           base::ProcessId pid) {
   listeners_.ForAllPtrs(
@@ -927,9 +951,10 @@
         package_path = result->package_path;
       }
 
-      // TODO(rockot): Find a way to block this code path for content but allow
-      // it for chrome_mash.
-      instance->StartWithFilePath(package_path);
+      if (!instance->StartWithFilePath(package_path)) {
+        OnInstanceError(instance);
+        return;
+      }
     }
   }
 
diff --git a/services/service_manager/service_manager.h b/services/service_manager/service_manager.h
index ebfe8457..3711ca72 100644
--- a/services/service_manager/service_manager.h
+++ b/services/service_manager/service_manager.h
@@ -119,6 +119,10 @@
   // running as a different user if one is available that services all users.
   Instance* GetExistingInstance(const Identity& identity) const;
 
+  // Erases any identities mapping to |instance|. Following this call it is
+  // impossible for any call to GetExistingInstance() to return |instance|.
+  void EraseInstanceIdentity(Instance* instance);
+
   void NotifyServiceStarted(const Identity& identity, base::ProcessId pid);
   void NotifyServiceFailedToStart(const Identity& identity);
 
diff --git a/services/service_manager/standalone/BUILD.gn b/services/service_manager/standalone/BUILD.gn
index f7633aff..cf01f75 100644
--- a/services/service_manager/standalone/BUILD.gn
+++ b/services/service_manager/standalone/BUILD.gn
@@ -38,6 +38,7 @@
     "//services/catalog:lib",
     "//services/service_manager",
     "//services/service_manager/public/cpp",
+    "//services/service_manager/public/cpp/standalone_service",
     "//services/service_manager/runner/host:lib",
     "//services/tracing/public/cpp",
     "//services/tracing/public/interfaces",
diff --git a/services/service_manager/standalone/context.cc b/services/service_manager/standalone/context.cc
index 7af84b4..9800159 100644
--- a/services/service_manager/standalone/context.cc
+++ b/services/service_manager/standalone/context.cc
@@ -38,7 +38,6 @@
 #include "services/service_manager/connect_params.h"
 #include "services/service_manager/connect_util.h"
 #include "services/service_manager/runner/common/switches.h"
-#include "services/service_manager/runner/host/in_process_native_runner.h"
 #include "services/service_manager/runner/host/out_of_process_native_runner.h"
 #include "services/service_manager/standalone/tracer.h"
 #include "services/service_manager/switches.h"
@@ -48,7 +47,7 @@
 #include "services/tracing/public/interfaces/tracing.mojom.h"
 
 #if defined(OS_MACOSX)
-#include "services/service_manager/runner/host/mach_broker.h"
+#include "services/service_manager/public/cpp/standalone_service/mach_broker.h"
 #endif
 
 namespace service_manager {
@@ -137,21 +136,10 @@
 #endif
   }
 
-  std::unique_ptr<NativeRunnerFactory> runner_factory;
-  if (command_line.HasSwitch(switches::kSingleProcess)) {
-#if defined(COMPONENT_BUILD)
-    LOG(ERROR) << "Running Mojo in single process component build, which isn't "
-               << "supported because statics in apps interact. Use static build"
-               << " or don't pass --single-process.";
-#endif
-    runner_factory.reset(
-        new InProcessNativeRunnerFactory(blocking_pool_.get()));
-  } else {
-    NativeRunnerDelegate* native_runner_delegate = init_params ?
-        init_params->native_runner_delegate : nullptr;
-    runner_factory.reset(new OutOfProcessNativeRunnerFactory(
-        blocking_pool_.get(), native_runner_delegate));
-  }
+  std::unique_ptr<NativeRunnerFactory> runner_factory =
+      base::MakeUnique<OutOfProcessNativeRunnerFactory>(
+          blocking_pool_.get(),
+          init_params ? init_params->native_runner_delegate : nullptr);
   std::unique_ptr<catalog::Store> store;
   if (init_params)
     store = std::move(init_params->catalog_store);
diff --git a/services/service_manager/standalone/desktop/main_helper.cc b/services/service_manager/standalone/desktop/main_helper.cc
index d3f11c8..45d2f03 100644
--- a/services/service_manager/standalone/desktop/main_helper.cc
+++ b/services/service_manager/standalone/desktop/main_helper.cc
@@ -15,7 +15,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "services/service_manager/runner/common/switches.h"
-#include "services/service_manager/runner/host/child_process.h"
 #include "services/service_manager/runner/init.h"
 #include "services/service_manager/standalone/desktop/launcher_process.h"
 
@@ -29,8 +28,6 @@
 
 int StandaloneServiceManagerMain(int argc, char** argv) {
   base::CommandLine::Init(argc, argv);
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
 
   base::AtExitManager at_exit;
   InitializeLogging();
@@ -40,9 +37,6 @@
   base::RouteStdioToConsole(false);
 #endif
 
-  if (command_line.HasSwitch(switches::kChildProcess))
-    return ChildProcessMain();
-
   return LauncherProcessMain();
 }
 
diff --git a/services/service_manager/switches.cc b/services/service_manager/switches.cc
index 54221de..c8b9d2f 100644
--- a/services/service_manager/switches.cc
+++ b/services/service_manager/switches.cc
@@ -13,8 +13,5 @@
 // Disables the sandbox for debugging.
 const char kNoSandbox[] = "no-sandbox";
 
-// Load apps in a single processes.
-const char kSingleProcess[] = "single-process";
-
 }  // namespace switches
 }  // namespace service_manager
diff --git a/services/service_manager/switches.h b/services/service_manager/switches.h
index 35abc69..fc12923ee 100644
--- a/services/service_manager/switches.h
+++ b/services/service_manager/switches.h
@@ -12,7 +12,6 @@
 // alongside the definition of their values in the .cc file.
 extern const char kEnableTracing[];
 extern const char kNoSandbox[];
-extern const char kSingleProcess[];
 
 }  // namespace switches
 }  // namespace service_manager
diff --git a/services/service_manager/tests/connect/BUILD.gn b/services/service_manager/tests/connect/BUILD.gn
index ab9f411ff..10bc623 100644
--- a/services/service_manager/tests/connect/BUILD.gn
+++ b/services/service_manager/tests/connect/BUILD.gn
@@ -162,7 +162,7 @@
     "//base",
     "//build/win:default_exe_manifest",
     "//services/service_manager/public/cpp",
-    "//services/service_manager/runner/child:test_native_main",
+    "//services/service_manager/public/cpp/standalone_service:main",
   ]
 
   data_deps = [
diff --git a/services/service_manager/tests/connect/connect_test_exe.cc b/services/service_manager/tests/connect/connect_test_exe.cc
index 60de89e96..128eacd 100644
--- a/services/service_manager/tests/connect/connect_test_exe.cc
+++ b/services/service_manager/tests/connect/connect_test_exe.cc
@@ -2,19 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/at_exit.h"
-#include "base/command_line.h"
+#include <memory>
+
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/public/cpp/connection.h"
-#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/c/main.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
-#include "services/service_manager/runner/child/test_native_main.h"
-#include "services/service_manager/runner/init.h"
+#include "services/service_manager/public/cpp/service_runner.h"
 #include "services/service_manager/tests/connect/connect_test.mojom.h"
 
 using service_manager::test::mojom::ConnectTestService;
@@ -47,6 +45,7 @@
   void GetTitle(const GetTitleCallback& callback) override {
     callback.Run("connect_test_exe");
   }
+
   void GetInstance(const GetInstanceCallback& callback) override {
     callback.Run(context()->identity().instance());
   }
@@ -56,12 +55,9 @@
   DISALLOW_COPY_AND_ASSIGN(Target);
 };
 
-}  // namespace
+}  // namespac
 
-int main(int argc, char** argv) {
-  base::AtExitManager at_exit;
-  base::CommandLine::Init(argc, argv);
-
-  service_manager::InitializeLogging();
-  return service_manager::TestNativeMain(base::MakeUnique<Target>());
+MojoResult ServiceMain(MojoHandle service_request_handle) {
+  service_manager::ServiceRunner runner(new Target);
+  return runner.Run(service_request_handle);
 }
diff --git a/services/service_manager/tests/lifecycle/BUILD.gn b/services/service_manager/tests/lifecycle/BUILD.gn
index 0e65b67e..eb3bd461 100644
--- a/services/service_manager/tests/lifecycle/BUILD.gn
+++ b/services/service_manager/tests/lifecycle/BUILD.gn
@@ -149,7 +149,7 @@
     "//base",
     "//build/win:default_exe_manifest",
     "//services/service_manager/public/cpp:sources",
-    "//services/service_manager/runner/child:test_native_main",
+    "//services/service_manager/public/cpp/standalone_service:main",
   ]
 
   data_deps = [
diff --git a/services/service_manager/tests/lifecycle/lifecycle_exe.cc b/services/service_manager/tests/lifecycle/lifecycle_exe.cc
index a7ff9f9e..f5ab4cd 100644
--- a/services/service_manager/tests/lifecycle/lifecycle_exe.cc
+++ b/services/service_manager/tests/lifecycle/lifecycle_exe.cc
@@ -2,22 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/at_exit.h"
-#include "base/command_line.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "services/service_manager/public/cpp/connection.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/runner/child/test_native_main.h"
-#include "services/service_manager/runner/init.h"
+#include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/service_runner.h"
 #include "services/service_manager/tests/lifecycle/app_client.h"
 
-int main(int argc, char** argv) {
-  base::AtExitManager at_exit;
-  base::CommandLine::Init(argc, argv);
-
-  service_manager::InitializeLogging();
-  return service_manager::TestNativeMain(
-      base::MakeUnique<service_manager::test::AppClient>());
+MojoResult ServiceMain(MojoHandle service_request_handle) {
+  service_manager::ServiceRunner runner(new service_manager::test::AppClient);
+  return runner.Run(service_request_handle);
 }
diff --git a/services/service_manager/tests/lifecycle/package.cc b/services/service_manager/tests/lifecycle/package.cc
index 7287409..5dc4edce 100644
--- a/services/service_manager/tests/lifecycle/package.cc
+++ b/services/service_manager/tests/lifecycle/package.cc
@@ -97,22 +97,20 @@
   DISALLOW_COPY_AND_ASSIGN(PackagedApp);
 };
 
-class Package : public service_manager::Service,
+class Package : public service_manager::ForwardingService,
                 public service_manager::InterfaceFactory<
                     service_manager::mojom::ServiceFactory>,
                 public service_manager::mojom::ServiceFactory {
  public:
-  Package() {}
+  Package() : ForwardingService(&app_client_) {}
   ~Package() override {}
 
  private:
-  // service_manager::Service:
-  void OnStart() override { app_client_.OnStart(); }
-
+  // ForwardingService:
   bool OnConnect(const service_manager::ServiceInfo& remote_info,
                  service_manager::InterfaceRegistry* registry) override {
     registry->AddInterface<service_manager::mojom::ServiceFactory>(this);
-    return app_client_.OnConnect(remote_info, registry);
+    return ForwardingService::OnConnect(remote_info, registry);
   }
 
   // service_manager::InterfaceFactory<service_manager::mojom::ServiceFactory>:
diff --git a/services/service_manager/tests/service_manager/BUILD.gn b/services/service_manager/tests/service_manager/BUILD.gn
index e8960a5..d494b1b8 100644
--- a/services/service_manager/tests/service_manager/BUILD.gn
+++ b/services/service_manager/tests/service_manager/BUILD.gn
@@ -59,7 +59,7 @@
     "//base",
     "//build/win:default_exe_manifest",
     "//services/service_manager/public/cpp",
-    "//services/service_manager/runner/child:test_native_main",
+    "//services/service_manager/public/cpp/standalone_service:main",
   ]
 
   data_deps = [
@@ -99,9 +99,9 @@
     "//build/win:default_exe_manifest",
     "//mojo/edk/system",
     "//services/service_manager/public/cpp",
+    "//services/service_manager/public/cpp/standalone_service:main",
     "//services/service_manager/public/interfaces",
     "//services/service_manager/runner:init",
-    "//services/service_manager/runner/child:test_native_main",
     "//services/service_manager/runner/common",
   ]
 
diff --git a/services/service_manager/tests/service_manager/embedder.cc b/services/service_manager/tests/service_manager/embedder.cc
index af5ad9e6..9cabede 100644
--- a/services/service_manager/tests/service_manager/embedder.cc
+++ b/services/service_manager/tests/service_manager/embedder.cc
@@ -18,8 +18,6 @@
 #include "services/service_manager/public/cpp/service_runner.h"
 #include "services/service_manager/public/interfaces/service_factory.mojom.h"
 #include "services/service_manager/public/interfaces/service_manager.mojom.h"
-#include "services/service_manager/runner/child/test_native_main.h"
-#include "services/service_manager/runner/init.h"
 
 namespace {
 
diff --git a/services/service_manager/tests/service_manager/target.cc b/services/service_manager/tests/service_manager/target.cc
index 4efef83..02d12ec2 100644
--- a/services/service_manager/tests/service_manager/target.cc
+++ b/services/service_manager/tests/service_manager/target.cc
@@ -6,12 +6,12 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "services/service_manager/public/c/main.h"
 #include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
-#include "services/service_manager/runner/child/test_native_main.h"
-#include "services/service_manager/runner/init.h"
+#include "services/service_manager/public/cpp/service_runner.h"
 #include "services/service_manager/tests/service_manager/service_manager_unittest.mojom.h"
 
 using service_manager::test::mojom::CreateInstanceTestPtr;
@@ -42,10 +42,7 @@
 
 }  // namespace
 
-int main(int argc, char** argv) {
-  base::AtExitManager at_exit;
-  base::CommandLine::Init(argc, argv);
-
-  service_manager::InitializeLogging();
-  return service_manager::TestNativeMain(base::MakeUnique<Target>());
+MojoResult ServiceMain(MojoHandle service_request_handle) {
+  service_manager::ServiceRunner runner(new Target);
+  return runner.Run(service_request_handle);
 }
diff --git a/services/tracing/BUILD.gn b/services/tracing/BUILD.gn
index cb51c87..b384a93 100644
--- a/services/tracing/BUILD.gn
+++ b/services/tracing/BUILD.gn
@@ -10,8 +10,6 @@
     "main.cc",
   ]
 
-  avoid_runner_cycle = true
-
   deps = [
     ":lib",
     "//mojo/public/cpp/system",
diff --git a/services/ui/BUILD.gn b/services/ui/BUILD.gn
index 416f4750..f8d88227 100644
--- a/services/ui/BUILD.gn
+++ b/services/ui/BUILD.gn
@@ -24,6 +24,7 @@
   ]
 
   deps = [
+    ":copy_gl_libraries",
     ":lib",
     ":resources_100",
     ":resources_200",
@@ -32,11 +33,8 @@
     "//services/tracing/public/interfaces",
   ]
 
-  if (is_win) {
-    deps += [ ":copy_gl_libraries" ]
-  }
-
   data_deps = [
+    ":copy_gl_libraries",
     ":manifest",
     "//services/ui/ime/test_ime_driver",
   ]
@@ -53,9 +51,13 @@
   source = "manifest.json"
 }
 
-if (is_win) {
-  copy("copy_gl_libraries") {
-    deps = [
+copy("copy_gl_libraries") {
+  deps = [
+    "//third_party/mesa:osmesa",
+  ]
+
+  if (is_win) {
+    deps += [
       "//third_party/angle:libEGL",
       "//third_party/angle:libGLESv2",
     ]
@@ -63,12 +65,19 @@
     sources = [
       "$root_shlib_dir/libEGL.dll",
       "$root_shlib_dir/libGLESv2.dll",
+      "$root_shlib_dir/osmesa.dll",
     ]
-
-    outputs = [
-      "$root_out_dir/$packages_directory/ui/{{source_file_part}}",
+  } else if (is_android || is_linux) {
+    sources = [
+      "$root_shlib_dir/libosmesa.so",
     ]
+  } else {
+    sources = []
   }
+
+  outputs = [
+    "$root_out_dir/$packages_directory/ui/{{source_file_part}}",
+  ]
 }
 
 source_set("lib") {
diff --git a/services/ui/ws/window_manager_client_unittest.cc b/services/ui/ws/window_manager_client_unittest.cc
index 542c38c9..0697239c 100644
--- a/services/ui/ws/window_manager_client_unittest.cc
+++ b/services/ui/ws/window_manager_client_unittest.cc
@@ -703,6 +703,7 @@
   aura::WindowTreeClient second_client(connector(), this);
   second_client.ConnectViaWindowTreeFactory();
   aura::WindowTreeHostMus window_tree_host_in_second_client(&second_client);
+  window_tree_host_in_second_client.InitHost();
   ASSERT_TRUE(second_client.GetRoots().count(
                   window_tree_host_in_second_client.window()) > 0);
   // Wait for the window to appear in the wm.
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index c5066b8..5e303fe 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -866,38 +866,6 @@
         "test": "mojo_public_system_unittests"
       },
       {
-        "override_isolate_target": "mojo_runner_host_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:3ff24775a900b675866fbcacf2a8f98a18b2a16a"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "android_devices": "4",
-              "device_os": "MMB29Q",
-              "device_type": "bullhead"
-            }
-          ],
-          "hard_timeout": 60,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "mojo_runner_host_unittests"
-      },
-      {
         "override_isolate_target": "mojo_system_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter b/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter
index fd0562d..400f17bf 100644
--- a/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter
+++ b/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter
@@ -1,8 +1,5 @@
 -ChromeServiceWorkerTest.FallbackMainResourceRequestWhenJSDisabled
 -PDFExtensionTest.PdfAccessibilityInOOPIF
--PlatformAppUrlRedirectorBrowserTest.PrerenderedClickInTabIntercepted
--PredictorBrowserTest.RendererInitiatedNavigationPreconnect
--ThreatDOMDetailsTest.Everything
 
 # https://crbug.com/652767: NavigationHandle::GetResponseHeaders sometimes
 # returns null for browser-side navigations
diff --git a/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter b/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter
index 2c902e6..0b9bc16 100644
--- a/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter
+++ b/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter
@@ -1,3 +1,4 @@
 # List below tests to be excluded from running.
 
-# This list is currently empty. Hooray!
+# https://crbug.com/666858: No drag-and-drop events should fire...
+-*DragAndDropBrowserTest.CrossSiteDrag*
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index aa596cc3..a6b16ab 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1950,7 +1950,7 @@
                 {
                     "name": "Enabled",
                     "params": {
-                        "animation": "animate-all",
+                        "animation": "animate-nonsecure-only",
                         "visibility": "show-all"
                     },
                     "enable_features": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 163c789..f030191 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -108,8 +108,6 @@
 crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/clipping-should-not-repaint-composited-descendants.html [ Crash ]
 crbug.com/645667 virtual/spinvalidation/paint/invalidation/filter-repaint-on-accelerated-layer.html [ Crash ]
 
-crbug.com/672989 virtual/spinvalidation/fast/multicol/span/abspos-containing-block-outside-spanner.html [ Failure ]
-
 # --- End SlimmingPaintInvalidation Tests ---
 
 # Very slight rendering changes caused by Skia rect clipping change.
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-whitespace-parsing.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-whitespace-parsing.html
new file mode 100644
index 0000000..85bbab3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-whitespace-parsing.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Test whitespace parsing on canvas attributes that invoke the CSS parser</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+
+var ctx;
+function whiteSpaceTest(attribute, input, output) {
+    var canvas = document.createElement('canvas');
+    ctx = canvas.getContext('2d');
+    eval('ctx.' + attribute + ' = "' + input + '"');
+    assert_equals(eval('ctx.' + attribute), output);
+}
+
+generate_tests(whiteSpaceTest, [
+    ['', 'fillStyle', ' red', '#ff0000'],
+    ['', 'fillStyle', 'red ', '#ff0000'],
+    ['', 'fillStyle', '\tred', '#ff0000'],
+    ['', 'fillStyle', 'red\t', '#ff0000'],
+    ['', 'fillStyle', ' #f00', '#ff0000'],
+    ['', 'fillStyle', '#f00 ', '#ff0000'],
+    ['', 'fillStyle', '\t#f00', '#ff0000'],
+    ['', 'fillStyle', '#f00\t', '#ff0000'],
+    ['', 'fillStyle', ' rgb(255, 0, 0)', '#ff0000'],
+    ['', 'fillStyle', 'rgb(255,0,0) ', '#ff0000'],
+    ['', 'fillStyle', 'invalid', '#000000'], // Sanity check
+    ['', 'strokeStyle', ' red', '#ff0000'],
+    ['', 'strokeStyle', 'red ', '#ff0000'],
+    ['', 'strokeStyle', '\tred', '#ff0000'],
+    ['', 'strokeStyle', 'red\t', '#ff0000'],
+    ['', 'strokeStyle', 'invalid', '#000000'], // Sanity check
+// The filter attribute is different: it does not get re-serialized
+    ['', 'filter', ' blur(5px)', ' blur(5px)'],
+    ['', 'filter', 'blur(5px) ', 'blur(5px) '],
+    ['', 'filter', 'blur( 5px)', 'blur( 5px)'],
+    ['', 'filter', '\tblur(5px)', '\tblur(5px)'],
+    ['', 'filter', 'blur(5px)\t', 'blur(5px)\t'],
+    ['', 'filter', 'invalid', 'none'], // Sanity check
+  ]);
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/interstitial-sidebar-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/security/interstitial-sidebar-expected.txt
index 2fcc882..abcfb7b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/security/interstitial-sidebar-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/interstitial-sidebar-expected.txt
@@ -11,9 +11,11 @@
         </STYLE>
         <DIV class=tree-outline-disclosure >
             <OL class=tree-outline tabindex=0 >
-                <LI class=security-main-view-sidebar-tree-item selected >
+                <LI class=security-main-view-sidebar-tree-item selected force-white-icons >
                     <DIV class=selection fill >
                     </DIV>
+                    <SPAN class=tree-element-title >
+                    </SPAN>
                     <DIV class=icon lock-icon lock-icon-unknown >
                     </DIV>
                     <SPAN class=title >
@@ -60,6 +62,8 @@
                     <LI class=security-sidebar-tree-item >
                         <DIV class=selection fill >
                         </DIV>
+                        <SPAN class=tree-element-title >
+                        </SPAN>
                         <DIV class=icon security-property security-property-secure >
                         </DIV>
                         <SPAN class=title >
@@ -71,6 +75,8 @@
                     <LI class=security-sidebar-tree-item >
                         <DIV class=selection fill >
                         </DIV>
+                        <SPAN class=tree-element-title >
+                        </SPAN>
                         <DIV class=icon security-property security-property-secure >
                         </DIV>
                         <SPAN class=title >
@@ -108,9 +114,11 @@
         </STYLE>
         <DIV class=tree-outline-disclosure >
             <OL class=tree-outline tabindex=0 >
-                <LI class=security-main-view-sidebar-tree-item selected >
+                <LI class=security-main-view-sidebar-tree-item selected force-white-icons >
                     <DIV class=selection fill >
                     </DIV>
+                    <SPAN class=tree-element-title >
+                    </SPAN>
                     <DIV class=icon lock-icon lock-icon-unknown >
                     </DIV>
                     <SPAN class=title >
@@ -157,6 +165,8 @@
                     <LI class=security-sidebar-tree-item >
                         <DIV class=selection fill >
                         </DIV>
+                        <SPAN class=tree-element-title >
+                        </SPAN>
                         <DIV class=icon security-property security-property-secure >
                         </DIV>
                         <SPAN class=title >
@@ -168,6 +178,8 @@
                     <LI class=security-sidebar-tree-item >
                         <DIV class=selection fill >
                         </DIV>
+                        <SPAN class=tree-element-title >
+                        </SPAN>
                         <DIV class=icon security-property security-property-secure >
                         </DIV>
                         <SPAN class=title >
@@ -205,9 +217,11 @@
         </STYLE>
         <DIV class=tree-outline-disclosure >
             <OL class=tree-outline tabindex=0 >
-                <LI class=security-main-view-sidebar-tree-item selected >
+                <LI class=security-main-view-sidebar-tree-item selected force-white-icons >
                     <DIV class=selection fill >
                     </DIV>
+                    <SPAN class=tree-element-title >
+                    </SPAN>
                     <DIV class=icon lock-icon lock-icon-unknown >
                     </DIV>
                     <SPAN class=title >
@@ -254,6 +268,8 @@
                     <LI class=security-sidebar-tree-item >
                         <DIV class=selection fill >
                         </DIV>
+                        <SPAN class=tree-element-title >
+                        </SPAN>
                         <DIV class=icon security-property security-property-secure >
                         </DIV>
                         <SPAN class=title >
@@ -265,6 +281,8 @@
                     <LI class=security-sidebar-tree-item >
                         <DIV class=selection fill >
                         </DIV>
+                        <SPAN class=tree-element-title >
+                        </SPAN>
                         <DIV class=icon security-property security-property-secure >
                         </DIV>
                         <SPAN class=title >
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/breadcrumb-updates.html b/third_party/WebKit/LayoutTests/inspector/elements/breadcrumb-updates.html
index c13deac..5300a40 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/breadcrumb-updates.html
+++ b/third_party/WebKit/LayoutTests/inspector/elements/breadcrumb-updates.html
@@ -21,7 +21,8 @@
 
     function step0()
     {
-        InspectorTest.selectNodeWithId("target", step1);
+        InspectorTest.addSniffer(Elements.ElementsBreadcrumbs.prototype, "update", step1);
+        InspectorTest.selectNodeWithId("target");
     }
 
     function step1()
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/shadow/breadcrumb-shadow-roots.html b/third_party/WebKit/LayoutTests/inspector/elements/shadow/breadcrumb-shadow-roots.html
index ba26921..6cc5dbf3 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/shadow/breadcrumb-shadow-roots.html
+++ b/third_party/WebKit/LayoutTests/inspector/elements/shadow/breadcrumb-shadow-roots.html
@@ -48,7 +48,8 @@
         InspectorTest.findNode(matchFunction, callback);
         function callback(node)
         {
-            Common.Revealer.revealPromise(node).then(next);
+            InspectorTest.addSniffer(Elements.ElementsBreadcrumbs.prototype, "update", next);
+            Common.Revealer.revealPromise(node);
         }
     }
 
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_union.py b/third_party/WebKit/Source/bindings/scripts/v8_union.py
index 407d2c1..84dd56b 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_union.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_union.py
@@ -121,7 +121,7 @@
         cpp_includes.update(interface_info.get(
             'dependencies_include_paths', []))
         # We need complete types for IDL dictionaries in union containers.
-        if member.is_dictionary:
+        if member.is_dictionary or member.is_typed_array:
             header_includes.update(member.includes_for_type())
         else:
             cpp_includes.update(member.includes_for_type())
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.cpp b/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.cpp
index 67d6319..a5be16e 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.cpp
@@ -9,10 +9,7 @@
 #include "TestInterface2OrUint8Array.h"
 
 #include "bindings/core/v8/ToV8.h"
-#include "bindings/core/v8/V8ArrayBufferView.h"
 #include "bindings/core/v8/V8TestInterface2.h"
-#include "bindings/core/v8/V8Uint8Array.h"
-#include "core/dom/FlexibleArrayBufferView.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.h b/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.h
index a6eeeef7..41891949 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.h
@@ -11,13 +11,15 @@
 
 #include "bindings/core/v8/Dictionary.h"
 #include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/V8ArrayBufferView.h"
 #include "bindings/core/v8/V8Binding.h"
+#include "bindings/core/v8/V8Uint8Array.h"
 #include "core/CoreExport.h"
+#include "core/dom/FlexibleArrayBufferView.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
 
-class DOMUint8Array;
 class TestInterface2;
 
 class CORE_EXPORT TestInterface2OrUint8Array final {
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index 2ff00ca41..1424270 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -480,9 +480,10 @@
   if (!layoutObject)
     return nullptr;
 
-  if (layoutObject->isCanvas())
-    return toHTMLCanvasElement(node).copiedImage(FrontBuffer,
-                                                 PreferNoAcceleration);
+  if (layoutObject->isCanvas()) {
+    return toHTMLCanvasElement(node).copiedImage(
+        FrontBuffer, PreferNoAcceleration, SnapshotReasonCopyToClipboard);
+  }
 
   if (layoutObject->isImage()) {
     LayoutImage* layoutImage = toLayoutImage(layoutObject);
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
index 64d6a684..24d47d34 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
+++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
@@ -475,10 +475,12 @@
                          const ImageBitmapOptions& options) {
   ASSERT(canvas->isPaintable());
   RefPtr<Image> input;
-  if (canvas->placeholderFrame())
+  if (canvas->placeholderFrame()) {
     input = canvas->placeholderFrame();
-  else
-    input = canvas->copiedImage(BackBuffer, PreferAcceleration);
+  } else {
+    input = canvas->copiedImage(BackBuffer, PreferAcceleration,
+                                SnapshotReasonCreateImageBitmap);
+  }
   ParsedOptions parsedOptions =
       parseOptions(options, cropRect, IntSize(input->width(), input->height()));
   if (dstBufferSizeHasOverflow(parsedOptions))
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 97e8f79d..b90acdd 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -1123,7 +1123,8 @@
 
 PassRefPtr<Image> HTMLCanvasElement::copiedImage(
     SourceDrawingBuffer sourceBuffer,
-    AccelerationHint hint) const {
+    AccelerationHint hint,
+    SnapshotReason snapshotReason) const {
   if (!isPaintable())
     return nullptr;
   if (!m_context)
@@ -1131,10 +1132,9 @@
 
   if (m_context->getContextType() ==
       CanvasRenderingContext::ContextImageBitmap) {
-    RefPtr<Image> image =
-        m_context->getImage(hint, SnapshotReasonGetCopiedImage);
+    RefPtr<Image> image = m_context->getImage(hint, snapshotReason);
     if (image)
-      return m_context->getImage(hint, SnapshotReasonGetCopiedImage);
+      return m_context->getImage(hint, snapshotReason);
     // Special case: transferFromImageBitmap is not yet called.
     sk_sp<SkSurface> surface =
         SkSurface::MakeRasterN32Premul(width(), height());
@@ -1146,8 +1146,7 @@
   if (m_context->is3d())
     needToUpdate |= m_context->paintRenderingResultsToCanvas(sourceBuffer);
   if (needToUpdate && buffer()) {
-    m_copiedImage =
-        buffer()->newImageSnapshot(hint, SnapshotReasonGetCopiedImage);
+    m_copiedImage = buffer()->newImageSnapshot(hint, snapshotReason);
     updateExternallyAllocatedMemory();
   }
   return m_copiedImage;
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index aed02126..41dedd92 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -143,7 +143,9 @@
 
   void ensureUnacceleratedImageBuffer();
   ImageBuffer* buffer() const;
-  PassRefPtr<Image> copiedImage(SourceDrawingBuffer, AccelerationHint) const;
+  PassRefPtr<Image> copiedImage(SourceDrawingBuffer,
+                                AccelerationHint,
+                                SnapshotReason) const;
   void clearCopiedImage();
 
   SecurityOrigin* getSecurityOrigin() const;
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
index 7d8b58d..0e17679 100644
--- a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
@@ -886,8 +886,7 @@
   SourceImageStatus status;
   FloatSize defaultObjectSize(width(), height());
   RefPtr<Image> image = getSourceImageForCanvas(
-      &status, PreferNoAcceleration, SnapshotReasonCopyToWebGLTexture,
-      defaultObjectSize);
+      &status, PreferNoAcceleration, SnapshotReasonUnknown, defaultObjectSize);
   return image->width();
 }
 
@@ -895,8 +894,7 @@
   SourceImageStatus status;
   FloatSize defaultObjectSize(width(), height());
   RefPtr<Image> image = getSourceImageForCanvas(
-      &status, PreferNoAcceleration, SnapshotReasonCopyToWebGLTexture,
-      defaultObjectSize);
+      &status, PreferNoAcceleration, SnapshotReasonUnknown, defaultObjectSize);
   return image->height();
 }
 
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
index 16d3f4c..47ef71c7 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
@@ -328,9 +328,13 @@
   // TODO(crbug.com/637313): This is temporary before we support filters in
   // paint property tree.
   // TODO(crbug.com/648274): This is a workaround for multi-column contents.
-  if (object.hasFilterInducingProperty() || object.isLayoutFlowThread())
+  // TODO(crbug.com/672989): This is a workaround for out-of-flow positioned
+  // objects in multi-column spanner.
+  if (object.hasFilterInducingProperty() || object.isLayoutFlowThread() ||
+      object.isColumnSpanAll()) {
     context.forcedSubtreeInvalidationFlags |=
         PaintInvalidatorContext::ForcedSubtreeSlowPathRect;
+  }
 
   ObjectPaintInvalidator objectPaintInvalidator(object);
   context.oldVisualRect = object.previousVisualRect();
diff --git a/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js b/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js
index f56fdaa..6f50e90 100644
--- a/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js
+++ b/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js
@@ -176,6 +176,11 @@
    */
   setInspected(inspected) {
     this._inspected = inspected;
+    if (this._inspected)
+      this.setTrailingIcons([UI.Icon.create('smallicon-thick-left-arrow')]);
+    else
+      this.setTrailingIcons([]);
+
     this.listItemElement.classList.toggle('inspected', this._inspected);
   }
 
@@ -211,28 +216,28 @@
   }
 
   _update() {
-    this.listItemElement.removeChildren();
+    this.titleElement().removeChildren();
 
     if (this._axNode.ignored()) {
       this._appendIgnoredNodeElement();
     } else {
       this._appendRoleElement(this._axNode.role());
       if (this._axNode.name().value) {
-        this.listItemElement.createChild('span', 'separator').textContent = '\u00A0';
+        this.titleElement().createChild('span', 'separator').textContent = '\u00A0';
         this._appendNameElement(/** @type {string} */ (this._axNode.name().value));
       }
     }
 
     if (this._axNode.hasOnlyUnloadedChildren()) {
-      this.listItemElement.classList.add('children-unloaded');
+      this.titleElement().classList.add('children-unloaded');
       this.setExpandable(true);
     } else {
       this.setExpandable(!!this._axNode.numChildren());
     }
 
     if (!this._axNode.isDOMNode())
-      this.listItemElement.classList.add('no-dom-node');
-    this.listItemElement.appendChild(this._inspectNodeButton.element);
+      this.titleElement().classList.add('no-dom-node');
+    this.titleElement().appendChild(this._inspectNodeButton.element);
   }
 
   /**
@@ -265,7 +270,7 @@
     var nameElement = createElement('span');
     nameElement.textContent = '"' + name + '"';
     nameElement.classList.add('ax-readable-string');
-    this.listItemElement.appendChild(nameElement);
+    this.titleElement().appendChild(nameElement);
   }
 
   /**
@@ -279,14 +284,14 @@
     roleElement.classList.add(Accessibility.AXNodeTreeElement.RoleStyles[role.type]);
     roleElement.setTextContentTruncatedIfNeeded(role.value || '');
 
-    this.listItemElement.appendChild(roleElement);
+    this.titleElement().appendChild(roleElement);
   }
 
   _appendIgnoredNodeElement() {
     var ignoredNodeElement = createElementWithClass('span', 'monospace');
     ignoredNodeElement.textContent = Common.UIString('Ignored');
     ignoredNodeElement.classList.add('ax-tree-ignored-node');
-    this.listItemElement.appendChild(ignoredNodeElement);
+    this.titleElement().appendChild(ignoredNodeElement);
   }
 
   /**
@@ -359,7 +364,7 @@
     if (this._treePane.isExpanded(this._axNode.backendDOMNodeId()))
       this.listItemElement.classList.add('siblings-expanded');
     if (this._axNode.numChildren() > 1)
-      this.listItemElement.insertBefore(this._expandSiblingsButton.element, this._inspectNodeButton.element);
+      this.titleElement().insertBefore(this._expandSiblingsButton.element, this._inspectNodeButton.element);
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/accessibility/accessibilityNode.css b/third_party/WebKit/Source/devtools/front_end/accessibility/accessibilityNode.css
index 55782db6..b70d60e 100644
--- a/third_party/WebKit/Source/devtools/front_end/accessibility/accessibilityNode.css
+++ b/third_party/WebKit/Source/devtools/front_end/accessibility/accessibilityNode.css
@@ -80,24 +80,6 @@
     left: -2px;
 }
 
-.tree-outline li.inspected::after {
-    -webkit-mask-image: url(Images/smallIcons.png);
-    -webkit-mask-size: 190px 30px;
-    -webkit-mask-position: -180px 0;
-    background-color: rgb(74, 139, 238);
-    content: "";
-    position: relative;
-    left: 4px;
-    top: 1px;
-    width: 10px;
-    height: 10px;
-    transform: rotate(180deg);
-}
-
-.tree-outline:focus li.inspected.selected::after {
-    background-color: white;
-}
-
 .tree-outline li.selected .selection {
     background-color: inherit;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js b/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js
index a2a3152..4926fac 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js
@@ -326,7 +326,7 @@
       return;
     if (!Components.Linkifier._decorator || !info.uiLocation)
       return;
-    if (info.icon)
+    if (info.icon && info.icon.parentElement)
       anchor.removeChild(info.icon);
     var icon = Components.Linkifier._decorator.linkIcon(info.uiLocation.uiSourceCode);
     if (icon) {
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsBreadcrumbs.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsBreadcrumbs.js
index 5bc9f28..67bca2f 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsBreadcrumbs.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsBreadcrumbs.js
@@ -43,7 +43,7 @@
    */
   setSelectedNode(node) {
     this._currentDOMNode = node;
-    this.update();
+    this.crumbsElement.window().requestAnimationFrame(() => this.update());
   }
 
   _mouseMovedInCrumbs(event) {
@@ -59,6 +59,60 @@
       SDK.DOMModel.hideDOMNodeHighlight();
   }
 
+
+  /**
+   * @param {!Event} event
+   * @this {Elements.ElementsBreadcrumbs}
+   */
+  _onClickCrumb(event) {
+    event.preventDefault();
+    var crumb = /** @type {!Element} */ (event.currentTarget);
+    if (!crumb.classList.contains('collapsed')) {
+      this.dispatchEventToListeners(Elements.ElementsBreadcrumbs.Events.NodeSelected, crumb[this._nodeSymbol]);
+      return;
+    }
+
+    // Clicking a collapsed crumb will expose the hidden crumbs.
+    if (crumb === this.crumbsElement.firstChild) {
+      // If the clicked crumb is the first child, pick the farthest crumb
+      // that is still hidden. This allows the user to expose every crumb.
+      var currentCrumb = crumb;
+      while (currentCrumb) {
+        var hidden = currentCrumb.classList.contains('hidden');
+        var collapsed = currentCrumb.classList.contains('collapsed');
+        if (!hidden && !collapsed)
+          break;
+        crumb = currentCrumb;
+        currentCrumb = currentCrumb.nextSiblingElement;
+      }
+    }
+
+    this.updateSizes(crumb);
+  }
+
+  /**
+   * @param {!SDK.DOMNode} domNode
+   * @return {?string}
+   */
+  _determineElementTitle(domNode) {
+    switch (domNode.nodeType()) {
+      case Node.ELEMENT_NODE:
+        if (domNode.pseudoType())
+          return '::' + domNode.pseudoType();
+        return null;
+      case Node.TEXT_NODE:
+        return Common.UIString('(text)');
+      case Node.COMMENT_NODE:
+        return '<!-->';
+      case Node.DOCUMENT_TYPE_NODE:
+        return '<!DOCTYPE>';
+      case Node.DOCUMENT_FRAGMENT_NODE:
+        return domNode.shadowRootType() ? '#shadow-root' : domNode.nodeNameInCorrectCase();
+      default:
+        return domNode.nodeNameInCorrectCase();
+    }
+  }
+
   /**
    * @param {boolean=} force
    */
@@ -91,81 +145,22 @@
 
     crumbs.removeChildren();
 
-    var panel = this;
-
-    /**
-     * @param {!Event} event
-     * @this {Elements.ElementsBreadcrumbs}
-     */
-    function selectCrumb(event) {
-      event.preventDefault();
-      var crumb = /** @type {!Element} */ (event.currentTarget);
-      if (!crumb.classList.contains('collapsed')) {
-        this.dispatchEventToListeners(Elements.ElementsBreadcrumbs.Events.NodeSelected, crumb[this._nodeSymbol]);
-        return;
-      }
-
-      // Clicking a collapsed crumb will expose the hidden crumbs.
-      if (crumb === panel.crumbsElement.firstChild) {
-        // If the focused crumb is the first child, pick the farthest crumb
-        // that is still hidden. This allows the user to expose every crumb.
-        var currentCrumb = crumb;
-        while (currentCrumb) {
-          var hidden = currentCrumb.classList.contains('hidden');
-          var collapsed = currentCrumb.classList.contains('collapsed');
-          if (!hidden && !collapsed)
-            break;
-          crumb = currentCrumb;
-          currentCrumb = currentCrumb.nextSiblingElement;
-        }
-      }
-
-      this.updateSizes(crumb);
-    }
-
-    var boundSelectCrumb = selectCrumb.bind(this);
     for (var current = currentDOMNode; current; current = current.parentNode) {
       if (current.nodeType() === Node.DOCUMENT_NODE)
         continue;
 
       crumb = createElementWithClass('span', 'crumb');
       crumb[this._nodeSymbol] = current;
-      crumb.addEventListener('mousedown', boundSelectCrumb, false);
+      crumb.addEventListener('mousedown', this._onClickCrumb.bind(this), false);
 
-      var crumbTitle = '';
-      switch (current.nodeType()) {
-        case Node.ELEMENT_NODE:
-          if (current.pseudoType())
-            crumbTitle = '::' + current.pseudoType();
-          else
-            Components.DOMPresentationUtils.decorateNodeLabel(current, crumb);
-          break;
-
-        case Node.TEXT_NODE:
-          crumbTitle = Common.UIString('(text)');
-          break;
-
-        case Node.COMMENT_NODE:
-          crumbTitle = '<!-->';
-          break;
-
-        case Node.DOCUMENT_TYPE_NODE:
-          crumbTitle = '<!DOCTYPE>';
-          break;
-
-        case Node.DOCUMENT_FRAGMENT_NODE:
-          crumbTitle = current.shadowRootType() ? '#shadow-root' : current.nodeNameInCorrectCase();
-          break;
-
-        default:
-          crumbTitle = current.nodeNameInCorrectCase();
-      }
-
-      if (!crumb.childNodes.length) {
+      var crumbTitle = this._determineElementTitle(current);
+      if (crumbTitle) {
         var nameElement = createElement('span');
         nameElement.textContent = crumbTitle;
         crumb.appendChild(nameElement);
         crumb.title = crumbTitle;
+      } else {
+        Components.DOMPresentationUtils.decorateNodeLabel(current, crumb);
       }
 
       if (current === currentDOMNode)
@@ -178,18 +173,13 @@
 
   /**
    * @param {!Element=} focusedCrumb
+   * @return {{selectedIndex: number, focusedIndex: number, selectedCrumb: ?Element}}
    */
-  updateSizes(focusedCrumb) {
-    if (!this.isShowing())
-      return;
-
+  _resetCrumbStylesAndFindSelections(focusedCrumb) {
     var crumbs = this.crumbsElement;
-    if (!crumbs.firstChild)
-      return;
-
     var selectedIndex = 0;
     var focusedIndex = 0;
-    var selectedCrumb;
+    var selectedCrumb = null;
 
     // Reset crumb styles.
     for (var i = 0; i < crumbs.childNodes.length; ++i) {
@@ -207,14 +197,31 @@
       crumb.classList.remove('compact', 'collapsed', 'hidden');
     }
 
-    // Layout 1: Measure total and normal crumb sizes
-    var contentElementWidth = this.contentElement.offsetWidth;
+    return {selectedIndex: selectedIndex, focusedIndex: focusedIndex, selectedCrumb: selectedCrumb};
+  }
+
+  /**
+   * @return {{normal: !Array.<number>, compact: !Array.<number>, collapsed: number, available: number}}
+   */
+  _measureElementSizes() {
+    var crumbs = this.crumbsElement;
+
+    // Layout 1: Measure total and normal crumb sizes at the same time as a
+    // dummy element for the collapsed size.
+    var collapsedElement = createElementWithClass('span', 'crumb collapsed');
+    crumbs.insertBefore(collapsedElement, crumbs.firstChild);
+
+    var available = crumbs.offsetWidth;
+    var collapsed = collapsedElement.offsetWidth;
+
     var normalSizes = [];
-    for (var i = 0; i < crumbs.childNodes.length; ++i) {
+    for (var i = 1; i < crumbs.childNodes.length; ++i) {
       var crumb = crumbs.childNodes[i];
-      normalSizes[i] = crumb.offsetWidth;
+      normalSizes[i - 1] = crumb.offsetWidth;
     }
 
+    crumbs.removeChild(collapsedElement);
+
     // Layout 2: Measure collapsed crumb sizes
     var compactSizes = [];
     for (var i = 0; i < crumbs.childNodes.length; ++i) {
@@ -226,16 +233,32 @@
       compactSizes[i] = crumb.offsetWidth;
     }
 
-    // Layout 3: Measure collapsed crumb size
-    crumbs.firstChild.classList.add('collapsed');
-    var collapsedSize = crumbs.firstChild.offsetWidth;
-
     // Clean up.
     for (var i = 0; i < crumbs.childNodes.length; ++i) {
       var crumb = crumbs.childNodes[i];
       crumb.classList.remove('compact', 'collapsed');
     }
 
+    return {normal: normalSizes, compact: compactSizes, collapsed: collapsed, available: available};
+  }
+
+  /**
+   * @param {!Element=} focusedCrumb
+   */
+  updateSizes(focusedCrumb) {
+    if (!this.isShowing())
+      return;
+
+    var crumbs = this.crumbsElement;
+    if (!crumbs.firstChild)
+      return;
+
+    var selections = this._resetCrumbStylesAndFindSelections(focusedCrumb);
+    var sizes = this._measureElementSizes();
+    var selectedIndex = selections.selectedIndex;
+    var focusedIndex = selections.focusedIndex;
+    var selectedCrumb = selections.selectedCrumb;
+
     function crumbsAreSmallerThanContainer() {
       var totalSize = 0;
       for (var i = 0; i < crumbs.childNodes.length; ++i) {
@@ -243,13 +266,13 @@
         if (crumb.classList.contains('hidden'))
           continue;
         if (crumb.classList.contains('collapsed')) {
-          totalSize += collapsedSize;
+          totalSize += sizes.collapsed;
           continue;
         }
-        totalSize += crumb.classList.contains('compact') ? compactSizes[i] : normalSizes[i];
+        totalSize += crumb.classList.contains('compact') ? sizes.compact[i] : sizes.normal[i];
       }
       const rightPadding = 10;
-      return totalSize + rightPadding < contentElementWidth;
+      return totalSize + rightPadding < sizes.available;
     }
 
     if (crumbsAreSmallerThanContainer())
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js b/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js
index 739d9bdb..d30c0f9 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js
@@ -431,6 +431,9 @@
     this.clearResultsButton = new UI.ToolbarButton(Common.UIString('Clear all profiles'), 'largeicon-clear');
     this.clearResultsButton.addEventListener('click', this._reset, this);
     toolbar.appendToolbarItem(this.clearResultsButton);
+    toolbar.appendSeparator();
+    toolbar.appendToolbarItem(
+        /** @type {!UI.ToolbarItem} */ (UI.Toolbar.createActionButtonForId('profiler.collect-garbage')));
 
     this._profileTypeToolbar = new UI.Toolbar('', this._toolbarElement);
     this._profileViewToolbar = new UI.Toolbar('', this._toolbarElement);
@@ -1260,3 +1263,21 @@
     return true;
   }
 };
+
+/**
+ * @implements {UI.ActionDelegate}
+ * @unrestricted
+ */
+Profiler.ProfilesPanel.GCActionDelegate = class {
+  /**
+   * @override
+   * @param {!UI.Context} context
+   * @param {string} actionId
+   * @return {boolean}
+   */
+  handleAction(context, actionId) {
+    for (var target of SDK.targetManager.targets())
+      target.heapProfilerAgent().collectGarbage();
+    return true;
+  }
+};
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/module.json b/third_party/WebKit/Source/devtools/front_end/profiler/module.json
index 81a4bee..4853542 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/module.json
@@ -65,6 +65,13 @@
                     "shortcut": "Meta+E"
                 }
             ]
+        },
+        {
+            "type": "@UI.ActionDelegate",
+            "actionId": "profiler.collect-garbage",
+            "title": "Collect garbage",
+            "iconClass": "largeicon-trash-bin",
+            "className": "Profiler.ProfilesPanel.GCActionDelegate"
         }
     ],
     "dependencies": [
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
index 61fe3f93..3b0192f 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -384,11 +384,6 @@
     }
 
     this._panelToolbar.appendSeparator();
-    var garbageCollectButton = new UI.ToolbarButton(Common.UIString('Collect garbage'), 'largeicon-trash-bin');
-    garbageCollectButton.addEventListener('click', this._garbageCollectButtonClicked, this);
-    this._panelToolbar.appendToolbarItem(garbageCollectButton);
-
-    this._panelToolbar.appendSeparator();
     this._cpuThrottlingCombobox = new UI.ToolbarComboBox(this._onCPUThrottlingChanged.bind(this));
     this._panelToolbar.appendToolbarItem(this._createNetworkConditionsSelect());
     this._panelToolbar.appendToolbarItem(this._cpuThrottlingCombobox);
@@ -424,10 +419,8 @@
       hasSelection = true;
     }
     var predefinedRates = new Map([
-      [1, Common.UIString('No CPU throttling')],
-      [2, Common.UIString('2\xD7 slowdown')],
-      [5, Common.UIString('5\xD7 slowdown')],
-      [10, Common.UIString('10\xD7 slowdown')],
+      [1, Common.UIString('No CPU throttling')], [2, Common.UIString('2\xD7 slowdown')],
+      [5, Common.UIString('5\xD7 slowdown')], [10, Common.UIString('10\xD7 slowdown')],
       [20, Common.UIString('20\xD7 slowdown')]
     ]);
     for (var rate of predefinedRates)
@@ -639,12 +632,6 @@
       this._stopRecording();
   }
 
-  _garbageCollectButtonClicked() {
-    var targets = SDK.targetManager.targets();
-    for (var i = 0; i < targets.length; ++i)
-      targets[i].heapProfilerAgent().collectGarbage();
-  }
-
   _clear() {
     if (Runtime.experiments.isEnabled('timelineRuleUsageRecording') && this._markUnusedCSS.get())
       Components.CoverageProfile.instance().reset();
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Icon.js b/third_party/WebKit/Source/devtools/front_end/ui/Icon.js
index e45c108..41232ae 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Icon.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Icon.js
@@ -100,6 +100,8 @@
   'smallicon-green-ball': {x: -140, y: 0, width: 10, height: 10, spritesheet: 'smallicons'},
   'smallicon-orange-ball': {x: -160, y: 0, width: 10, height: 10, spritesheet: 'smallicons'},
   'smallicon-thick-right-arrow': {x: -180, y: 0, width: 10, height: 10, spritesheet: 'smallicons'},
+  'smallicon-thick-left-arrow':
+      {x: -180, y: 0, width: 10, height: 10, spritesheet: 'smallicons', transform: 'rotate(180deg)'},
   'smallicon-user-command': {x: 0, y: -20, width: 10, height: 10, spritesheet: 'smallicons'},
   'smallicon-text-prompt': {x: -20, y: -20, width: 10, height: 10, spritesheet: 'smallicons'},
   'smallicon-command-result': {x: -40, y: -20, width: 10, height: 10, spritesheet: 'smallicons'},
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
index 42a899db..4d7c9b8 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
@@ -88,6 +88,11 @@
     color: inherit;
 }
 
+.tree-outline li .icons-container {
+    margin-left: 4px;
+    align-self: center;
+}
+
 .tree-outline li::before {
     -webkit-user-select: none;
     -webkit-mask-image: url(Images/toolbarButtonGlyphs.png);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
index 55b61a27..8755e425 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
@@ -44,10 +44,22 @@
 
     this.contentElement = this._rootElement._childrenListNode;
     this.contentElement.addEventListener('keydown', this._treeKeyDown.bind(this), true);
+    this.contentElement.addEventListener('focus', setFocused.bind(this, true), false);
+    this.contentElement.addEventListener('blur', setFocused.bind(this, false), false);
 
     this.setFocusable(!nonFocusable);
 
     this.element = this.contentElement;
+
+    /**
+     * @param {boolean} isFocused
+     * @this {TreeOutline}
+     */
+    function setFocused(isFocused) {
+      this._focused = isFocused;
+      if (this.selectedTreeElement)
+        this.selectedTreeElement._setFocused(this._focused);
+    }
   }
 
   _createRootElement() {
@@ -308,6 +320,7 @@
     this.nextSibling = null;
 
     this._listItemNode = createElement('li');
+    this._titleElement = this._listItemNode.createChild('span', 'tree-element-title');
     this._listItemNode.treeElement = this;
     if (title)
       this.title = title;
@@ -552,6 +565,13 @@
     return this._listItemNode;
   }
 
+  /**
+   * @return {!Element}
+   */
+  titleElement() {
+    return this._titleElement;
+  }
+
   get childrenListElement() {
     return this._childrenListNode;
   }
@@ -572,7 +592,6 @@
     this._title = x;
 
     if (typeof x === 'string') {
-      this._titleElement = createElementWithClass('span', 'tree-element-title');
       this._titleElement.textContent = x;
       this.tooltip = x;
     } else {
@@ -585,6 +604,8 @@
       this._listItemNode.appendChild(this._iconElement);
 
     this._listItemNode.appendChild(this._titleElement);
+    if (this._trailingIconsElement)
+      this._listItemNode.appendChild(this._trailingIconsElement);
     this._ensureSelection();
   }
 
@@ -616,6 +637,30 @@
   }
 
   /**
+   * @param {!Array<!UI.Icon>} icons
+   */
+  setTrailingIcons(icons) {
+    if (!this._trailingIconsElement && !icons.length)
+      return;
+    if (!this._trailingIconsElement) {
+      this._trailingIconsElement = createElementWithClass('div', 'icons-container');
+      this._listItemNode.appendChild(this._trailingIconsElement);
+      this._ensureSelection();
+    }
+    this._trailingIconsElement.removeChildren();
+    for (var icon of icons)
+      this._trailingIconsElement.appendChild(icon);
+  }
+
+  /**
+   * @param {boolean} focused
+   */
+  _setFocused(focused) {
+    this._focused = focused;
+    this._listItemNode.classList.toggle('force-white-icons', focused);
+  }
+
+  /**
    * @return {string}
    */
   get tooltip() {
@@ -945,6 +990,7 @@
       return false;
     this.treeOutline.selectedTreeElement = this;
     this._listItemNode.classList.add('selected');
+    this._setFocused(this.treeOutline._focused);
     this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementSelected, this);
     return this.onselect(selectedByUser);
   }
@@ -967,6 +1013,7 @@
     this.selected = false;
     this.treeOutline.selectedTreeElement = null;
     this._listItemNode.classList.remove('selected');
+    this._setFocused(false);
   }
 
   _populateIfNeeded() {
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasStyle.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasStyle.cpp
index 3f8b189..0c24f22e2 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasStyle.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasStyle.cpp
@@ -32,6 +32,7 @@
 #include "core/css/StylePropertySet.h"
 #include "core/css/parser/CSSParser.h"
 #include "core/html/HTMLCanvasElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
 #include "modules/canvas2d/CanvasGradient.h"
 #include "modules/canvas2d/CanvasPattern.h"
 #include "platform/graphics/skia/SkiaUtils.h"
@@ -71,7 +72,8 @@
 bool parseColorOrCurrentColor(Color& parsedColor,
                               const String& colorString,
                               HTMLCanvasElement* canvas) {
-  ColorParseResult parseResult = parseColor(parsedColor, colorString);
+  ColorParseResult parseResult =
+      parseColor(parsedColor, colorString.stripWhiteSpace(isHTMLSpace<UChar>));
   switch (parseResult) {
     case ParsedRGBA:
     case ParsedSystemColor:
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index ce833cad..3ba9722d 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -4868,7 +4868,24 @@
   return true;
 }
 
+SnapshotReason WebGLRenderingContextBase::functionIDToSnapshotReason(
+    TexImageFunctionID id) {
+  switch (id) {
+    case TexImage2D:
+      return SnapshotReasonWebGLTexImage2D;
+    case TexSubImage2D:
+      return SnapshotReasonWebGLTexSubImage2D;
+    case TexImage3D:
+      return SnapshotReasonWebGLTexImage3D;
+    case TexSubImage3D:
+      return SnapshotReasonWebGLTexSubImage3D;
+  }
+  NOTREACHED();
+  return SnapshotReasonUnknown;
+}
+
 void WebGLRenderingContextBase::texImageCanvasByGPU(
+    TexImageFunctionID functionID,
     HTMLCanvasElement* canvas,
     GLuint targetTexture,
     GLenum targetInternalformat,
@@ -4881,9 +4898,10 @@
     ImageBuffer* buffer = canvas->buffer();
     if (buffer &&
         !buffer->copyToPlatformTexture(
-            contextGL(), targetTexture, targetInternalformat, targetType,
-            targetLevel, m_unpackPremultiplyAlpha, m_unpackFlipY,
-            IntPoint(xoffset, yoffset), sourceSubRectangle)) {
+            functionIDToSnapshotReason(functionID), contextGL(), targetTexture,
+            targetInternalformat, targetType, targetLevel,
+            m_unpackPremultiplyAlpha, m_unpackFlipY, IntPoint(xoffset, yoffset),
+            sourceSubRectangle)) {
       NOTREACHED();
     }
   } else {
@@ -4900,7 +4918,7 @@
 }
 
 void WebGLRenderingContextBase::texImageByGPU(
-    TexImageByGPUType functionType,
+    TexImageFunctionID functionID,
     WebGLTexture* texture,
     GLenum target,
     GLint level,
@@ -4922,7 +4940,7 @@
   GLenum targetInternalformat = internalformat;
   GLint targetLevel = level;
   bool possibleDirectCopy = false;
-  if (functionType == TexImage2DByGPU) {
+  if (functionID == TexImage2D) {
     possibleDirectCopy = Extensions3DUtil::canUseCopyTextureCHROMIUM(
         target, internalformat, type, level);
   }
@@ -4953,9 +4971,10 @@
   }
 
   if (image->isCanvasElement()) {
-    texImageCanvasByGPU(static_cast<HTMLCanvasElement*>(image), targetTexture,
-                        targetInternalformat, targetType, targetLevel,
-                        copyXOffset, copyYOffset, sourceSubRectangle);
+    texImageCanvasByGPU(functionID, static_cast<HTMLCanvasElement*>(image),
+                        targetTexture, targetInternalformat, targetType,
+                        targetLevel, copyXOffset, copyYOffset,
+                        sourceSubRectangle);
   } else {
     texImageBitmapByGPU(static_cast<ImageBitmap*>(image), targetTexture,
                         targetInternalformat, targetType, targetLevel,
@@ -4969,12 +4988,12 @@
     contextGL()->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                       GL_TEXTURE_2D, targetTexture, 0);
     contextGL()->BindTexture(texture->getTarget(), texture->object());
-    if (functionType == TexImage2DByGPU) {
+    if (functionID == TexImage2D) {
       contextGL()->CopyTexSubImage2D(target, level, 0, 0, 0, 0, width, height);
-    } else if (functionType == TexSubImage2DByGPU) {
+    } else if (functionID == TexSubImage2D) {
       contextGL()->CopyTexSubImage2D(target, level, xoffset, yoffset, 0, 0,
                                      width, height);
-    } else if (functionType == TexSubImage3DByGPU) {
+    } else if (functionID == TexSubImage3D) {
       contextGL()->CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset,
                                      0, 0, width, height);
     }
@@ -5040,7 +5059,10 @@
       // 2D canvas has only FrontBuffer.
       texImageImpl(functionID, target, level, internalformat, xoffset, yoffset,
                    zoffset, format, type,
-                   canvas->copiedImage(FrontBuffer, PreferAcceleration).get(),
+                   canvas
+                       ->copiedImage(FrontBuffer, PreferAcceleration,
+                                     functionIDToSnapshotReason(functionID))
+                       .get(),
                    WebGLImageConversion::HtmlDomCanvas, m_unpackFlipY,
                    m_unpackPremultiplyAlpha, sourceSubRectangle, 1, 0);
       return;
@@ -5056,11 +5078,11 @@
     if (functionID == TexImage2D) {
       texImage2DBase(target, level, internalformat, sourceSubRectangle.width(),
                      sourceSubRectangle.height(), 0, format, type, 0);
-      texImageByGPU(TexImage2DByGPU, texture, target, level, internalformat,
-                    type, 0, 0, 0, canvas, adjustedSourceSubRectangle);
+      texImageByGPU(functionID, texture, target, level, internalformat, type, 0,
+                    0, 0, canvas, adjustedSourceSubRectangle);
     } else {
-      texImageByGPU(TexSubImage2DByGPU, texture, target, level, GL_RGBA, type,
-                    xoffset, yoffset, 0, canvas, adjustedSourceSubRectangle);
+      texImageByGPU(functionID, texture, target, level, GL_RGBA, type, xoffset,
+                    yoffset, 0, canvas, adjustedSourceSubRectangle);
     }
   } else {
     // 3D functions.
@@ -5068,12 +5090,14 @@
     // TODO(zmo): Implement GPU-to-GPU copy path (crbug.com/612542).
     // Note that code will also be needed to copy to layers of 3D
     // textures, and elements of 2D texture arrays.
-    texImageImpl(functionID, target, level, internalformat, xoffset, yoffset,
-                 zoffset, format, type,
-                 canvas->copiedImage(FrontBuffer, PreferAcceleration).get(),
-                 WebGLImageConversion::HtmlDomCanvas, m_unpackFlipY,
-                 m_unpackPremultiplyAlpha, sourceSubRectangle, depth,
-                 unpackImageHeight);
+    texImageImpl(
+        functionID, target, level, internalformat, xoffset, yoffset, zoffset,
+        format, type, canvas
+                          ->copiedImage(FrontBuffer, PreferAcceleration,
+                                        functionIDToSnapshotReason(functionID))
+                          .get(),
+        WebGLImageConversion::HtmlDomCanvas, m_unpackFlipY,
+        m_unpackPremultiplyAlpha, sourceSubRectangle, depth, unpackImageHeight);
   }
 }
 
@@ -5181,7 +5205,8 @@
                        video->videoHeight(), 0, format, type, nullptr);
 
         if (imageBuffer->copyToPlatformTexture(
-                contextGL(), texture->object(), internalformat, type, level,
+                functionIDToSnapshotReason(functionID), contextGL(),
+                texture->object(), internalformat, type, level,
                 m_unpackPremultiplyAlpha, m_unpackFlipY, IntPoint(0, 0),
                 IntRect(0, 0, video->videoWidth(), video->videoHeight()))) {
           return;
@@ -5290,11 +5315,11 @@
     if (functionID == TexImage2D) {
       texImage2DBase(target, level, internalformat, width, height, 0, format,
                      type, 0);
-      texImageByGPU(TexImage2DByGPU, texture, target, level, internalformat,
-                    type, 0, 0, 0, bitmap, sourceSubRect);
+      texImageByGPU(functionID, texture, target, level, internalformat, type, 0,
+                    0, 0, bitmap, sourceSubRect);
     } else if (functionID == TexSubImage2D) {
-      texImageByGPU(TexSubImage2DByGPU, texture, target, level, GL_RGBA, type,
-                    xoffset, yoffset, 0, bitmap, sourceSubRect);
+      texImageByGPU(functionID, texture, target, level, GL_RGBA, type, xoffset,
+                    yoffset, 0, bitmap, sourceSubRect);
     }
     return;
   }
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index b604fb2c..18f00f5 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -987,11 +987,9 @@
     TexImage3D,
     TexSubImage3D
   };
-  enum TexImageByGPUType {
-    TexImage2DByGPU,
-    TexSubImage2DByGPU,
-    TexSubImage3DByGPU
-  };
+
+  static SnapshotReason functionIDToSnapshotReason(TexImageFunctionID);
+
   enum TexImageDimension { Tex2D, Tex3D };
   void texImage2DBase(GLenum target,
                       GLint level,
@@ -1102,7 +1100,7 @@
 
   // Copy from the source directly to the texture via the gpu, without a
   // read-back to system memory.  Source could be canvas or imageBitmap.
-  void texImageByGPU(TexImageByGPUType,
+  void texImageByGPU(TexImageFunctionID,
                      WebGLTexture*,
                      GLenum target,
                      GLint level,
@@ -1646,7 +1644,8 @@
                                 ScriptState*,
                                 const CanvasContextCreationAttributes&,
                                 unsigned);
-  void texImageCanvasByGPU(HTMLCanvasElement*,
+  void texImageCanvasByGPU(TexImageFunctionID,
+                           HTMLCanvasElement*,
                            GLuint,
                            GLenum,
                            GLenum,
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h b/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
index 7b92d47..b011f6f 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
@@ -88,7 +88,10 @@
 enum SnapshotReason {
   SnapshotReasonUnknown,
   SnapshotReasonGetImageData,
-  SnapshotReasonCopyToWebGLTexture,
+  SnapshotReasonWebGLTexImage2D,
+  SnapshotReasonWebGLTexSubImage2D,
+  SnapshotReasonWebGLTexImage3D,
+  SnapshotReasonWebGLTexSubImage3D,
   SnapshotReasonPaint,
   SnapshotReasonToDataURL,
   SnapshotReasonToBlob,
@@ -99,6 +102,8 @@
   SnapshotReasonUnitTests,
   SnapshotReasonGetCopiedImage,
   SnapshotReasonWebGLDrawImageIntoBuffer,
+  SnapshotReasonCopyToClipboard,
+  SnapshotReasonCreateImageBitmap,
 };
 
 // Note: enum used directly for histogram, values must not change
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
index 1bf8610..84cbb6f8 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -208,7 +208,8 @@
   return m_surface->layer();
 }
 
-bool ImageBuffer::copyToPlatformTexture(gpu::gles2::GLES2Interface* gl,
+bool ImageBuffer::copyToPlatformTexture(SnapshotReason reason,
+                                        gpu::gles2::GLES2Interface* gl,
                                         GLuint texture,
                                         GLenum internalFormat,
                                         GLenum destType,
@@ -224,8 +225,8 @@
   if (!isSurfaceValid())
     return false;
 
-  sk_sp<const SkImage> textureImage = m_surface->newImageSnapshot(
-      PreferAcceleration, SnapshotReasonCopyToWebGLTexture);
+  sk_sp<const SkImage> textureImage =
+      m_surface->newImageSnapshot(PreferAcceleration, reason);
   if (!textureImage)
     return false;
 
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
index ba8e471..435e534 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
@@ -145,7 +145,8 @@
   // FIXME: Current implementations of this method only work with textures that
   // are RGB or RGBA format, UNSIGNED_BYTE type and level 0, as specified in
   // Extensions3D::canUseCopyTextureCHROMIUM().
-  bool copyToPlatformTexture(gpu::gles2::GLES2Interface*,
+  bool copyToPlatformTexture(SnapshotReason,
+                             gpu::gles2::GLES2Interface*,
                              GLuint texture,
                              GLenum internalFormat,
                              GLenum destType,
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
index 0a111a00..f67d5eb9c 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
@@ -125,9 +125,6 @@
       return RecordingImageBufferSurface::FallbackReasonUnknown;
     case SnapshotReasonGetImageData:
       return RecordingImageBufferSurface::FallbackReasonSnapshotForGetImageData;
-    case SnapshotReasonCopyToWebGLTexture:
-      return RecordingImageBufferSurface::
-          FallbackReasonSnapshotForCopyToWebGLTexture;
     case SnapshotReasonPaint:
       return RecordingImageBufferSurface::FallbackReasonSnapshotForPaint;
     case SnapshotReasonToDataURL:
@@ -152,8 +149,26 @@
     case SnapshotReasonWebGLDrawImageIntoBuffer:
       return RecordingImageBufferSurface::
           FallbackReasonSnapshotWebGLDrawImageIntoBuffer;
+    case SnapshotReasonWebGLTexImage2D:
+      return RecordingImageBufferSurface::
+          FallbackReasonSnapshotForWebGLTexImage2D;
+    case SnapshotReasonWebGLTexSubImage2D:
+      return RecordingImageBufferSurface::
+          FallbackReasonSnapshotForWebGLTexSubImage2D;
+    case SnapshotReasonWebGLTexImage3D:
+      return RecordingImageBufferSurface::
+          FallbackReasonSnapshotForWebGLTexImage3D;
+    case SnapshotReasonWebGLTexSubImage3D:
+      return RecordingImageBufferSurface::
+          FallbackReasonSnapshotForWebGLTexSubImage3D;
+    case SnapshotReasonCopyToClipboard:
+      return RecordingImageBufferSurface::
+          FallbackReasonSnapshotForCopyToClipboard;
+    case SnapshotReasonCreateImageBitmap:
+      return RecordingImageBufferSurface::
+          FallbackReasonSnapshotForCreateImageBitmap;
   }
-  ASSERT_NOT_REACHED();
+  NOTREACHED();
   return RecordingImageBufferSurface::FallbackReasonUnknown;
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h
index 6148e2b..93034d3 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h
@@ -95,7 +95,6 @@
     FallbackReasonFlushInitialClear = 4,
     FallbackReasonFlushForDrawImageOfWebGL = 5,
     FallbackReasonSnapshotForGetImageData = 6,
-    FallbackReasonSnapshotForCopyToWebGLTexture = 7,
     FallbackReasonSnapshotForPaint = 8,
     FallbackReasonSnapshotForToDataURL = 9,
     FallbackReasonSnapshotForToBlob = 10,
@@ -113,6 +112,12 @@
         21,  // This value should never appear in production histograms
     FallbackReasonSnapshotGetCopiedImage = 22,
     FallbackReasonSnapshotWebGLDrawImageIntoBuffer = 23,
+    FallbackReasonSnapshotForWebGLTexImage2D = 24,
+    FallbackReasonSnapshotForWebGLTexSubImage2D = 25,
+    FallbackReasonSnapshotForWebGLTexImage3D = 26,
+    FallbackReasonSnapshotForWebGLTexSubImage3D = 27,
+    FallbackReasonSnapshotForCopyToClipboard = 28,
+    FallbackReasonSnapshotForCreateImageBitmap = 29,
     FallbackReasonCount,
   };
 
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 821a187..bfdf0fc 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -484,9 +484,11 @@
       'base/timer/elapsed_timer.cc',
       'base/timer/timer.cc',
       'base/trace_event/category_registry.cc',
+      'base/trace_event/event_name_filter.cc',
       'base/trace_event/heap_profiler_allocation_context.cc',
       'base/trace_event/heap_profiler_allocation_context_tracker.cc',
       'base/trace_event/heap_profiler_allocation_register.cc',
+      'base/trace_event/heap_profiler_event_filter.cc',
       'base/trace_event/heap_profiler_heap_dump_writer.cc',
       'base/trace_event/heap_profiler_stack_frame_deduplicator.cc',
       'base/trace_event/heap_profiler_type_name_deduplicator.cc',
@@ -502,6 +504,7 @@
       'base/trace_event/trace_buffer.cc',
       'base/trace_event/trace_config.cc',
       'base/trace_event/trace_event_argument.cc',
+      'base/trace_event/trace_event_filter.cc',
       'base/trace_event/trace_event_impl.cc',
       'base/trace_event/trace_event_memory_overhead.cc',
       'base/trace_event/trace_event_synthetic_delay.cc',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index d4e86e14..a5fee149 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -77881,7 +77881,8 @@
   <int value="4" label="Flush for initial clear."/>
   <int value="5" label="Flush after drawing from a WebGL canvas."/>
   <int value="6" label="Acquiring snapshot for getImageData()."/>
-  <int value="7" label="Acquiring snapshot for WebGL texture upload."/>
+  <int value="7"
+      label="Acquiring snapshot for WebGL texture upload. (obsolete)"/>
   <int value="8"
       label="Acquiring snapshot for direct painting of canvas contents."/>
   <int value="9" label="Acquiring snapshot for toDataURL()"/>
@@ -77903,6 +77904,12 @@
              production)."/>
   <int value="22" label="Acquiring snapshot for copiedImage()."/>
   <int value="23" label="Acquiring snapshot for drawImageIntoBuffer()."/>
+  <int value="24" label="Acquiring snapshot for WebGL texImage2D()."/>
+  <int value="25" label="Acquiring snapshot for WebGL texSubImage2D()."/>
+  <int value="26" label="Acquiring snapshot for WebGL texImage3D()."/>
+  <int value="27" label="Acquiring snapshot for WebGL texSubImage3D()."/>
+  <int value="28" label="Acquiring snapshot for copy to clipboard."/>
+  <int value="29" label="Acquiring snapshot for createImageBitmap()."/>
 </enum>
 
 <enum name="CanvasGPUAccelerated2DCanvasDisableDeferralReason" type="int">
diff --git a/tools/win/linker_verbose_tracking.py b/tools/win/linker_verbose_tracking.py
new file mode 100644
index 0000000..506a86a
--- /dev/null
+++ b/tools/win/linker_verbose_tracking.py
@@ -0,0 +1,151 @@
+# Copyright (c) 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.
+
+"""
+This script parses the /verbose output from the VC++ linker and uses it to
+explain why a particular object file is being linked in. It parses records
+like these:
+
+      Found "public: static void * __cdecl SkTLS::Get(void * (__cdecl*)(void)...
+        Referenced in chrome_crash_reporter_client_win.obj
+        Referenced in skia.lib(SkError.obj)
+        Loaded skia.lib(SkTLS.obj)
+
+and then uses the information to answer questions such as "why is SkTLS.obj
+being linked in. In this case it was requested by SkError.obj, and the process
+is then repeated for SkError.obj. It traces the dependency tree back to a file
+that was specified on the command line. Typically that file is part of a
+source_set, and if that source_set is causing unnecessary code and data to be
+pulled in then changing it to a static_library may reduce the binary size. See
+crrev.com/2556603002 for an example of a ~900 KB savings from such a change.
+
+In other cases the source_set to static_library fix does not work because some
+of the symbols are required, while others are pulling in unwanted object files.
+In these cases it can be necessary to see what symbol is causing one object file
+to reference another. Removing or moving the problematic symbol can fix the
+problem. See crrev.com/2559063002 for an example of such a change.
+
+One complication is that there are sometimes multiple source files with the
+same name, such as crc.c, which can make analysis more difficult or
+ambiguous. If this becomes a blocking issue they it may be necessary to
+temporarily rename the source file.
+
+Object file name matching is case sensitive.
+
+Typical output when run on chrome.dll verbose link output is:
+
+>python tools\win\linker_verbose_tracking.py chrome_verbose_02.txt flac_crc
+Database loaded - 11277 xrefs found
+flac_crc.obj pulled in for symbol "_FLAC__crc8" by
+        stream_decoder.obj
+        bitwriter.obj
+
+stream_decoder.obj pulled in for symbol "_FLAC__stream_decoder_new" by
+        stream_encoder.obj
+bitwriter.obj pulled in for symbol "_FLAC__bitwriter_new" by
+        stream_encoder.obj
+
+stream_encoder.obj pulled in for symbol "_FLAC__stream_encoder_new" by
+        Command-line obj file: audio_encoder.obj
+"""
+
+import pdb
+import re
+import sys
+
+def ParseVerbose(input_file):
+  # This matches line like this:
+  #   Referenced in skia.lib(SkError.obj)
+  # with the groups()[0] referring to the object file name without the file
+  # extension.
+  obj_match = re.compile('.*\((.*)\.obj\)')
+  # Prefix used for symbols that are referenced:
+  found_prefix = '      Found'
+
+  cross_refs = {}
+  cross_refed_symbols = {}
+
+  references = None
+  for line in open(input_file):
+    if line.startswith(found_prefix):
+      references = []
+      # Grab the symbol name
+      symbol = line[len(found_prefix):].strip()
+      if symbol[0] == '"':
+        # Strip off leading and trailing quotes if present.
+        symbol = symbol[1:-1]
+      continue
+    if type(references) == type([]):
+      sub_line = line.strip()
+      match = obj_match.match(sub_line)
+      # See if the line is part of the list of places where this symbol was
+      # referenced
+      if sub_line.count('Referenced ') > 0:
+        if match:
+          # This indicates a match that is xxx.lib(yyy.obj), so a referencing
+          # .obj file that was itself inside of a library. We discard the
+          # library name.
+          reference = match.groups()[0]
+        else:
+          # This indicates a match that is just a pure .obj file name
+          # I think this means that the .obj file was specified on the linker
+          # command line.
+          reference = ('Command-line obj file: ' +
+                       sub_line[len('Referenced in '): -len('.obj')])
+        references.append(reference)
+      elif sub_line.count('Loaded ') > 0:
+        if match:
+          loaded = match.groups()[0]
+          cross_refs[loaded] = references
+          cross_refed_symbols[loaded] = symbol
+        references = None
+    if line.startswith('Finished pass 1'):
+      # Stop now because the remaining 90% of the verbose output is
+      # not of interest. Could probably use /VERBOSE:REF to trim out
+      # boring information.
+      break
+  return cross_refs, cross_refed_symbols
+
+
+def TrackObj(cross_refs, cross_refed_symbols, obj_name):
+  if obj_name.lower().endswith('.obj'):
+    obj_name = obj_name[:-len('.obj')]
+
+  # Keep track of which references we've already followed.
+  tracked = {}
+
+  # Initial set of object files that we are tracking.
+  targets = [obj_name]
+  printed = False
+  for i in range(100):
+    new_targets = {}
+    for target in targets:
+      if not target in tracked:
+        tracked[target] = True
+        if target in cross_refs.keys():
+          symbol = cross_refed_symbols[target]
+          printed = True
+          print '%s.obj pulled in for symbol "%s" by' % (target, symbol)
+          for ref in cross_refs[target]:
+            print '\t%s.obj' % ref
+            new_targets[ref] = True
+    if len(new_targets) == 0:
+      break
+    print
+    targets = new_targets.keys()
+  if not printed:
+    print 'No references to %s.obj found.' % obj_name
+
+
+def main():
+  if len(sys.argv) < 3:
+    print r'Usage: %s <verbose_output_file> <objfile>' % sys.argv[0]
+    print r'Sample: %s chrome_dll_verbose.txt SkTLS' % sys.argv[0]
+    return 0
+  cross_refs, cross_refed_symbols = ParseVerbose(sys.argv[1])
+  print 'Database loaded - %d xrefs found' % len(cross_refs)
+  TrackObj(cross_refs, cross_refed_symbols, sys.argv[2])
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index e8a7f7fd..6f6c3509 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -399,6 +399,7 @@
   std::unique_ptr<WindowTreeHostMus> window_tree_host =
       base::MakeUnique<WindowTreeHostMus>(std::move(window_port), this,
                                           display_id);
+  window_tree_host->InitHost();
   SetLocalPropertiesFromServerProperties(
       WindowMus::Get(window_tree_host->window()), window_data);
   if (window_data.visible) {
diff --git a/ui/aura/mus/window_tree_client_unittest.cc b/ui/aura/mus/window_tree_client_unittest.cc
index a83763d..2315b37 100644
--- a/ui/aura/mus/window_tree_client_unittest.cc
+++ b/ui/aura/mus/window_tree_client_unittest.cc
@@ -477,6 +477,7 @@
   Window* top_level = window_tree_host.window();
   const gfx::Rect bounds(0, 0, 100, 100);
   window_tree_host.SetBoundsInPixels(bounds);
+  window_tree_host.InitHost();
   window_tree_host.Show();
   EXPECT_EQ(bounds, top_level->bounds());
   EXPECT_EQ(bounds, window_tree_host.GetBoundsInPixels());
@@ -713,6 +714,7 @@
       window_tree_client_impl()->GetRoots().size();
   std::unique_ptr<WindowTreeHostMus> window_tree_host =
       base::MakeUnique<WindowTreeHostMus>(window_tree_client_impl());
+  window_tree_host->InitHost();
   aura::Window* top_level = window_tree_host->window();
   // TODO: need to check WindowTreeHost visibility.
   // EXPECT_TRUE(WindowPrivate(root2).parent_drawn());
@@ -757,6 +759,10 @@
   EXPECT_FALSE(IsWindowHostVisible(top_level));
   EXPECT_FALSE(top_level->TargetVisibility());
 
+  // TODO(mfomitchev): crbug.com/672150 InitHost() currently makes the host
+  // visible, which shouldn't be the case.
+  window_tree_host.InitHost();
+
   // Ack the request to the windowtree to create the new window.
   EXPECT_EQ(window_tree()->window_id(), server_id(top_level));
 
@@ -770,13 +776,15 @@
       WindowTreeChangeType::NEW_TOP_LEVEL, &change_id));
   window_tree_client()->OnTopLevelCreated(change_id, std::move(data),
                                           display_id, true);
-  EXPECT_EQ(
-      0u, window_tree()->GetChangeCountForType(WindowTreeChangeType::VISIBLE));
+  // TODO(mfomitchev): Uncomment while crbug.com/crbug.com/672150 is fixed
+  //  EXPECT_EQ(
+  //      0u,
+  //      window_tree()->GetChangeCountForType(WindowTreeChangeType::VISIBLE));
 
   // Make sure all the properties took.
-  EXPECT_TRUE(IsWindowHostVisible(top_level));
+  // TODO(mfomitchev): Uncomment while crbug.com/crbug.com/672150 is fixed
+  //  EXPECT_TRUE(IsWindowHostVisible(top_level));
   EXPECT_TRUE(top_level->TargetVisibility());
-  // TODO: check display_id.
   EXPECT_EQ(display_id, window_tree_host.display_id());
   EXPECT_EQ(gfx::Rect(0, 0, 3, 4), top_level->bounds());
   EXPECT_EQ(gfx::Rect(1, 2, 3, 4), top_level->GetHost()->GetBoundsInPixels());
@@ -787,9 +795,10 @@
 
   WindowTreeHostMus window_tree_host(window_tree_client_impl());
   Window* top_level = window_tree_host.window();
-
   EXPECT_FALSE(top_level->TargetVisibility());
 
+  window_tree_host.InitHost();
+
   // Make visibility go from false->true->false. Don't ack immediately.
   top_level->Show();
   top_level->Hide();
@@ -1024,6 +1033,7 @@
       window_tree_client_impl()->GetRoots().size();
   std::unique_ptr<WindowTreeHostMus> window_tree_host =
       base::MakeUnique<WindowTreeHostMus>(window_tree_client_impl());
+  window_tree_host->InitHost();
   EXPECT_EQ(initial_root_count + 1,
             window_tree_client_impl()->GetRoots().size());
 
@@ -1060,6 +1070,7 @@
   std::unique_ptr<WindowTreeHostMus> window_tree_host =
       base::MakeUnique<WindowTreeHostMus>(window_tree_client_impl(),
                                           &properties);
+  window_tree_host->InitHost();
   // Verify the property made it to the window.
   EXPECT_EQ(property_value,
             window_tree_host->window()->GetProperty(kTestPropertyKey1));
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 87fac84..a1bac9be 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -209,8 +209,11 @@
 }
 
 void WindowTreeHost::Show() {
-  if (compositor())
-    compositor()->SetVisible(true);
+  // Ensure that compositor has been properly initialized, see InitCompositor()
+  // and InitHost().
+  DCHECK(compositor());
+  DCHECK_EQ(compositor()->root_layer(), window()->layer());
+  compositor()->SetVisible(true);
   ShowImpl();
 }