diff --git a/DEPS b/DEPS
index 21f82be..5cd7626 100644
--- a/DEPS
+++ b/DEPS
@@ -86,7 +86,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '7e9556c898af6803a4a1239d44d62fd2a19a24e9',
+  'v8_revision': '5e02fa850d27e25cc96a7e708506fd9642b4bcf0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -110,7 +110,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
-  'openmax_dl_revision': '63d8cf4708c94c9c8931c389ce333954541a96f2',
+  'openmax_dl_revision': '59265e0e9105ec94e473b59c5c7ca1941e4dbd83',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -142,7 +142,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '883d59ef70276b408240bc48e9b615787a224188',
+  'catapult_revision': '7b821dff598416556b5942edbf400216ced4034b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -411,7 +411,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8c177b33bdde9246e05f8edf4e95521ca0916b91',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '46d83879919cc77d6dbcfb07b8aa8cd95af2f0ef',
       'condition': 'checkout_linux',
   },
 
@@ -471,7 +471,7 @@
   },
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'dee930847568b85e25ef6db3e87a563057731e32',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'f34a90b2109007f1dace5824e26108b19d11cb81',
 
   'src/third_party/flac':
     Var('chromium_git') + '/chromium/deps/flac.git' + '@' + '7d0f5b3a173ffe98db08057d1f52b7787569e0a6',
diff --git a/android_webview/support_library/boundary_interfaces/BUILD.gn b/android_webview/support_library/boundary_interfaces/BUILD.gn
index 00acb4e1..2f475ab 100644
--- a/android_webview/support_library/boundary_interfaces/BUILD.gn
+++ b/android_webview/support_library/boundary_interfaces/BUILD.gn
@@ -13,7 +13,6 @@
     "src/org/chromium/support_lib_boundary/ServiceWorkerControllerBoundaryInterface.java",
     "src/org/chromium/support_lib_boundary/ServiceWorkerWebSettingsBoundaryInterface.java",
     "src/org/chromium/support_lib_boundary/StaticsBoundaryInterface.java",
-    "src/org/chromium/support_lib_boundary/SupportLibraryInfoBoundaryInterface.java",
     "src/org/chromium/support_lib_boundary/VisualStateCallbackBoundaryInterface.java",
     "src/org/chromium/support_lib_boundary/WebResourceErrorBoundaryInterface.java",
     "src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java",
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/SupportLibraryInfoBoundaryInterface.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/SupportLibraryInfoBoundaryInterface.java
deleted file mode 100644
index 11a141f..0000000
--- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/SupportLibraryInfoBoundaryInterface.java
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.support_lib_boundary;
-
-/**
- * Contains information about the WebView support library side, e.g. which features are supported on
- * that side.
- * This is passed to the WebView APK code on support library initialization.
- */
-public interface SupportLibraryInfoBoundaryInterface { String[] getSupportedFeatures(); }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibReflectionUtil.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibReflectionUtil.java
index 84b9304..6eeaeed 100644
--- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibReflectionUtil.java
+++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibReflectionUtil.java
@@ -20,10 +20,8 @@
      * Changing the signature of this method will break existing WebView Support Library versions!
      */
     @UsedByReflection("WebView Support Library")
-    public static InvocationHandler createWebViewProviderFactory(
-            /* SupportLibraryInfo */ InvocationHandler supportLibraryInfo) {
-        final SupportLibWebViewChromiumFactory factory =
-                new SupportLibWebViewChromiumFactory(supportLibraryInfo);
-        return BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(factory);
+    public static InvocationHandler createWebViewProviderFactory() {
+        return BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
+                new SupportLibWebViewChromiumFactory());
     }
 }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
index 760ee297..e8db97b1 100644
--- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
+++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
@@ -15,7 +15,6 @@
 import com.android.webview.chromium.WebkitToSharedGlueConverter;
 
 import org.chromium.support_lib_boundary.StaticsBoundaryInterface;
-import org.chromium.support_lib_boundary.SupportLibraryInfoBoundaryInterface;
 import org.chromium.support_lib_boundary.WebViewProviderFactoryBoundaryInterface;
 import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
 import org.chromium.support_lib_boundary.util.Features;
@@ -30,7 +29,6 @@
     // SupportLibWebkitToCompatConverterAdapter
     private final InvocationHandler mCompatConverterAdapter;
     private final WebViewChromiumAwInit mAwInit;
-    private final String[] mSupportLibrarySupportedFeatures;
     private final String[] mWebViewSupportedFeatures =
             new String[] {Features.VISUAL_STATE_CALLBACK};
 
@@ -38,16 +36,10 @@
     private InvocationHandler mStatics;
     private InvocationHandler mServiceWorkerController;
 
-    public SupportLibWebViewChromiumFactory(
-            /* SupportLibraryInfo */ InvocationHandler supportLibraryInfo) {
+    public SupportLibWebViewChromiumFactory() {
         mCompatConverterAdapter = BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
                 new SupportLibWebkitToCompatConverterAdapter());
         mAwInit = WebkitToSharedGlueConverter.getGlobalAwInit();
-        mSupportLibrarySupportedFeatures =
-                BoundaryInterfaceReflectionUtil
-                        .castToSuppLibClass(
-                                SupportLibraryInfoBoundaryInterface.class, supportLibraryInfo)
-                        .getSupportedFeatures();
     }
 
     @Override
diff --git a/base/sampling_heap_profiler/sampling_heap_profiler.cc b/base/sampling_heap_profiler/sampling_heap_profiler.cc
index 529d562..65e858fb 100644
--- a/base/sampling_heap_profiler/sampling_heap_profiler.cc
+++ b/base/sampling_heap_profiler/sampling_heap_profiler.cc
@@ -279,6 +279,8 @@
                                        uint32_t skip_frames) {
   if (UNLIKELY(!base::subtle::NoBarrier_Load(&g_running)))
     return;
+  if (UNLIKELY(base::ThreadLocalStorage::HasBeenDestroyed()))
+    return;
 
   // TODO(alph): On MacOS it may call the hook several times for a single
   // allocation. Handle the case.
@@ -363,6 +365,8 @@
 }
 
 void SamplingHeapProfiler::DoRecordFree(void* address) {
+  if (UNLIKELY(base::ThreadLocalStorage::HasBeenDestroyed()))
+    return;
   if (entered_.Get())
     return;
   base::AutoLock lock(mutex_);
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
index df6eb065..13ec694b 100644
--- a/base/threading/thread_local_storage.h
+++ b/base/threading/thread_local_storage.h
@@ -24,6 +24,8 @@
 
 namespace base {
 
+class SamplingHeapProfiler;
+
 namespace trace_event {
 class MallocDumpProvider;
 }  // namespace trace_event
@@ -151,6 +153,7 @@
   // thread destruction. Attempting to call Slot::Get() during destruction is
   // disallowed and will hit a DCHECK. Any code that relies on TLS during thread
   // destruction must first check this method before calling Slot::Get().
+  friend class base::SamplingHeapProfiler;
   friend class base::internal::ThreadLocalStorageTestInternal;
   friend class base::trace_event::MallocDumpProvider;
   friend class profiling::MemlogAllocatorShimInternal;
diff --git a/base/trace_event/cfi_backtrace_android.cc b/base/trace_event/cfi_backtrace_android.cc
index 04faf13361..3859eb1 100644
--- a/base/trace_event/cfi_backtrace_android.cc
+++ b/base/trace_event/cfi_backtrace_android.cc
@@ -8,7 +8,6 @@
 #include <sys/types.h>
 
 #include "base/android/apk_assets.h"
-#include "base/debug/stack_trace.h"
 
 #if !defined(ARCH_CPU_ARMEL)
 #error This file should not be built for this architecture.
@@ -120,7 +119,9 @@
   return instance;
 }
 
-CFIBacktraceAndroid::CFIBacktraceAndroid() {
+CFIBacktraceAndroid::CFIBacktraceAndroid()
+    : thread_local_cfi_cache_(
+          [](void* ptr) { delete static_cast<CFICache*>(ptr); }) {
   Initialize();
 }
 
@@ -171,8 +172,7 @@
   unw_data_start_addr_ = unw_index_indices_col_ + unw_index_row_count_;
 }
 
-size_t CFIBacktraceAndroid::Unwind(const void** out_trace,
-                                   size_t max_depth) const {
+size_t CFIBacktraceAndroid::Unwind(const void** out_trace, size_t max_depth) {
   // This function walks the stack using the call frame information to find the
   // return addresses of all the functions that belong to current binary in call
   // stack. For each function the CFI table defines the offset of the previous
@@ -209,9 +209,13 @@
   return depth;
 }
 
-bool CFIBacktraceAndroid::FindCFIRowForPC(
-    uintptr_t func_addr,
-    CFIBacktraceAndroid::CFIRow* cfi) const {
+bool CFIBacktraceAndroid::FindCFIRowForPC(uintptr_t func_addr,
+                                          CFIBacktraceAndroid::CFIRow* cfi) {
+  auto* cache = GetThreadLocalCFICache();
+  *cfi = {0};
+  if (cache->Find(func_addr, cfi))
+    return true;
+
   // Consider each column of UNW_INDEX table as arrays of uintptr_t (function
   // addresses) and uint16_t (indices). Define start and end iterator on the
   // first column array (addresses) and use std::lower_bound() to binary search
@@ -220,7 +224,6 @@
       unw_index_function_col_ + unw_index_row_count_;
   const uintptr_t* found =
       std::lower_bound(unw_index_function_col_, unw_index_fn_end, func_addr);
-  *cfi = {0};
 
   // If found is start, then the given function is not in the table. If the
   // given pc is start of a function then we cannot unwind.
@@ -280,8 +283,32 @@
   *cfi = {cfi_row.cfa_offset(), ra_offset};
   DCHECK(cfi->cfa_offset);
   DCHECK(cfi->ra_offset);
+
+  // safe to update since the cache is thread local.
+  cache->Add(func_addr, *cfi);
   return true;
 }
 
+CFIBacktraceAndroid::CFICache* CFIBacktraceAndroid::GetThreadLocalCFICache() {
+  auto* cache = static_cast<CFICache*>(thread_local_cfi_cache_.Get());
+  if (!cache) {
+    cache = new CFICache();
+    thread_local_cfi_cache_.Set(cache);
+  }
+  return cache;
+}
+
+void CFIBacktraceAndroid::CFICache::Add(uintptr_t address, CFIRow cfi) {
+  cache_[address % kLimit] = {address, cfi};
+}
+
+bool CFIBacktraceAndroid::CFICache::Find(uintptr_t address, CFIRow* cfi) {
+  if (cache_[address % kLimit].address == address) {
+    *cfi = cache_[address % kLimit].cfi;
+    return true;
+  }
+  return false;
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/cfi_backtrace_android.h b/base/trace_event/cfi_backtrace_android.h
index 1b7369df..5e969787 100644
--- a/base/trace_event/cfi_backtrace_android.h
+++ b/base/trace_event/cfi_backtrace_android.h
@@ -14,6 +14,7 @@
 #include "base/debug/debugging_buildflags.h"
 #include "base/files/memory_mapped_file.h"
 #include "base/gtest_prod_util.h"
+#include "base/threading/thread_local_storage.h"
 
 namespace base {
 namespace trace_event {
@@ -40,16 +41,17 @@
 
   // Returns the program counters by unwinding stack in the current thread in
   // order of latest call frame first. Unwinding works only if
-  // can_unwind_stack_frames() returns true. This function does not allocate
-  // memory from heap. For each stack frame, this method searches through the
+  // can_unwind_stack_frames() returns true. This function allocates memory from
+  // heap for caches. For each stack frame, this method searches through the
   // unwind table mapped in memory to find the unwind information for function
   // and walks the stack to find all the return address. This only works until
   // the last function call from the chrome.so. We do not have unwind
   // information to unwind beyond any frame outside of chrome.so. Calls to
   // Unwind() are thread safe and lock free, once Initialize() returns success.
-  size_t Unwind(const void** out_trace, size_t max_depth) const;
+  size_t Unwind(const void** out_trace, size_t max_depth);
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(CFIBacktraceAndroidTest, TestCFICache);
   FRIEND_TEST_ALL_PREFIXES(CFIBacktraceAndroidTest, TestFindCFIRow);
   FRIEND_TEST_ALL_PREFIXES(CFIBacktraceAndroidTest, TestUnwinding);
 
@@ -62,12 +64,43 @@
     // The offset of the call frame address of previous function from the
     // current stack pointer. Rule for unwinding SP: SP_prev = SP_cur +
     // cfa_offset.
-    size_t cfa_offset = 0;
+    uint16_t cfa_offset = 0;
     // The offset of location of return address from the previous call frame
     // address. Rule for unwinding PC: PC_prev = * (SP_prev - ra_offset).
-    size_t ra_offset = 0;
+    uint16_t ra_offset = 0;
   };
 
+  // A simple cache that stores entries in table using prime modulo hashing.
+  // This cache with 500 entries already gives us 95% hit rate, and fits in a
+  // single system page (usually 4KiB). Using a thread local cache for each
+  // thread gives us 30% improvements on performance of heap profiling.
+  class CFICache {
+   public:
+    // Add new item to the cache. It replaces an existing item with same hash.
+    // Constant time operation.
+    void Add(uintptr_t address, CFIRow cfi);
+
+    // Finds the given address and fills |cfi| with the info for the address.
+    // returns true if found, otherwise false. Assumes |address| is never 0.
+    bool Find(uintptr_t address, CFIRow* cfi);
+
+   private:
+    FRIEND_TEST_ALL_PREFIXES(CFIBacktraceAndroidTest, TestCFICache);
+
+    // Size is the highest prime which fits the cache in a single system page,
+    // usually 4KiB. A prime is chosen to make sure addresses are hashed evenly.
+    static const int kLimit = 509;
+
+    struct AddrAndCFI {
+      uintptr_t address;
+      CFIRow cfi;
+    };
+    AddrAndCFI cache_[kLimit] = {};
+  };
+
+  static_assert(sizeof(CFIBacktraceAndroid::CFICache) < 4096,
+                "The cache does not fit in a single page.");
+
   CFIBacktraceAndroid();
   ~CFIBacktraceAndroid();
 
@@ -86,7 +119,9 @@
 
   // Finds the CFI row for the given |func_addr| in terms of offset from
   // the start of the current binary.
-  bool FindCFIRowForPC(uintptr_t func_addr, CFIRow* out) const;
+  bool FindCFIRowForPC(uintptr_t func_addr, CFIRow* out);
+
+  CFICache* GetThreadLocalCFICache();
 
   // Details about the memory mapped region which contains the libchrome.so
   // library file.
@@ -111,6 +146,8 @@
   const uint16_t* unw_data_start_addr_ = nullptr;
 
   bool can_unwind_stack_frames_ = false;
+
+  ThreadLocalStorage::Slot thread_local_cfi_cache_;
 };
 
 }  // namespace trace_event
diff --git a/base/trace_event/cfi_backtrace_android_unittest.cc b/base/trace_event/cfi_backtrace_android_unittest.cc
index 05e0ac2..365749a 100644
--- a/base/trace_event/cfi_backtrace_android_unittest.cc
+++ b/base/trace_event/cfi_backtrace_android_unittest.cc
@@ -91,7 +91,7 @@
   unwinder->ParseCFITables();
 
   CFIBacktraceAndroid::CFIRow cfi_row = {0};
-  EXPECT_FALSE(unwinder->FindCFIRowForPC(0x00, &cfi_row));
+  EXPECT_FALSE(unwinder->FindCFIRowForPC(0x01, &cfi_row));
   EXPECT_FALSE(unwinder->FindCFIRowForPC(0x100, &cfi_row));
   EXPECT_FALSE(unwinder->FindCFIRowForPC(0x1502, &cfi_row));
   EXPECT_FALSE(unwinder->FindCFIRowForPC(0x3000, &cfi_row));
@@ -123,6 +123,73 @@
   EXPECT_EQ(kRow5, cfi_row);
   EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2210, &cfi_row));
   EXPECT_EQ(kRow5, cfi_row);
+
+  // Test if cache is used on the future calls to Find, all addresses should
+  // have different hash. Resetting the memory map to make sure it is never
+  // accessed in Find().
+  unwinder->cfi_mmap_.reset(new MemoryMappedFile());
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1002, &cfi_row));
+  EXPECT_EQ(kRow1, cfi_row);
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1003, &cfi_row));
+  EXPECT_EQ(kRow1, cfi_row);
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1008, &cfi_row));
+  EXPECT_EQ(kRow2, cfi_row);
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1009, &cfi_row));
+  EXPECT_EQ(kRow2, cfi_row);
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1039, &cfi_row));
+  EXPECT_EQ(kRow2, cfi_row);
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1080, &cfi_row));
+  EXPECT_EQ(kRow3, cfi_row);
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x1100, &cfi_row));
+  EXPECT_EQ(kRow3, cfi_row);
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2050, &cfi_row));
+  EXPECT_EQ(kRow4, cfi_row);
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2208, &cfi_row));
+  EXPECT_EQ(kRow5, cfi_row);
+  EXPECT_TRUE(unwinder->FindCFIRowForPC(0x2210, &cfi_row));
+  EXPECT_EQ(kRow5, cfi_row);
+}
+
+TEST(CFIBacktraceAndroidTest, TestCFICache) {
+  // Use ASSERT macros in this function since they are in loop and using EXPECT
+  // prints too many failures.
+  CFIBacktraceAndroid::CFICache cache;
+  CFIBacktraceAndroid::CFIRow cfi;
+
+  // Empty cache should not find anything.
+  EXPECT_FALSE(cache.Find(1, &cfi));
+
+  // Insert 1 - 2*kLimit
+  for (size_t i = 1; i <= 2 * cache.kLimit; ++i) {
+    CFIBacktraceAndroid::CFIRow val = {4 * i, 2 * i};
+    cache.Add(i, val);
+    ASSERT_TRUE(cache.Find(i, &cfi));
+    ASSERT_EQ(cfi, val);
+
+    // Inserting more than kLimit items evicts |i - cache.kLimit| from cache.
+    if (i >= cache.kLimit)
+      ASSERT_FALSE(cache.Find(i - cache.kLimit, &cfi));
+  }
+  // Cache contains kLimit+1 - 2*kLimit.
+
+  // Check that 1 - kLimit cannot be found.
+  for (size_t i = 1; i <= cache.kLimit; ++i) {
+    ASSERT_FALSE(cache.Find(i, &cfi));
+  }
+
+  // Check if kLimit+1 - 2*kLimit still exists in cache.
+  for (size_t i = cache.kLimit + 1; i <= 2 * cache.kLimit; ++i) {
+    CFIBacktraceAndroid::CFIRow val = {4 * i, 2 * i};
+    ASSERT_TRUE(cache.Find(i, &cfi));
+    ASSERT_EQ(cfi, val);
+  }
+
+  // Insert 2*kLimit+1, will evict kLimit.
+  cfi = {1, 1};
+  cache.Add(2 * cache.kLimit + 1, cfi);
+  EXPECT_TRUE(cache.Find(2 * cache.kLimit + 1, &cfi));
+  EXPECT_FALSE(cache.Find(cache.kLimit + 1, &cfi));
+  // Cache contains kLimit+1 - 2*kLimit.
 }
 
 }  // namespace trace_event
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 60f05de..ddcd327 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -143,11 +143,8 @@
 
 # Unwinding with CFI table is only possible on static library builds and
 # requried only when frame pointers are not enabled.
-# Builds with use_thin_lto use link registers to store offsets, and this is
-# not supported yet.
-can_unwind_with_cfi_table =
-    is_android && !is_component_build && !can_unwind_with_frame_pointers &&
-    current_cpu == "arm" && !use_thin_lto
+can_unwind_with_cfi_table = is_android && !is_component_build &&
+                            !enable_frame_pointers && current_cpu == "arm"
 
 declare_args() {
   # Whether or not the official builds should be built with full WPO. Enabled by
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 427e8a39..0b86ac6e 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -366,13 +366,7 @@
   # turned on either.
   # CFG seems to lead to random corruption with incremental linking so turn off
   # CFG in component builds. https://crbug.com/812421
-  # CFG, ThinLTO and RTTI don't currently work together, so turn off
-  # CFG for that combination. We detect RTTI by looking for
-  # use_cfi_diag || is_ubsan_vptr || is_ubsan_security, as per
-  # //build/config/compiler/BUILD.gn.
-  # TODO(inglorion): Re-enable once figured out, bug https://crbug.com/818086
-  if (!is_debug && !is_component_build &&
-      !(use_thin_lto && (use_cfi_diag || is_ubsan_vptr || is_ubsan_security))) {
+  if (!is_debug && !is_component_build) {
     # Turn on CFG in msvc linker, regardless of compiler used. Turn off CFG for
     # longjmp (new in VS 2017) because it relies on compiler support which we do
     # not have enabled.
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1
index 37b316d6..8e9e92d 100644
--- a/build/fuchsia/sdk.sha1
+++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@
-20cc9f09319aef5699fc39b9adcc09265c81205e
+836b86e410e052129d3f1ded023f63ca79d3290e
diff --git a/build/install-build-deps-android.sh b/build/install-build-deps-android.sh
index 860f8f5b..69838d6f 100755
--- a/build/install-build-deps-android.sh
+++ b/build/install-build-deps-android.sh
@@ -38,7 +38,7 @@
 sudo apt-get -y install bsdiff
 
 # Needed to unpack the profiles we pull with `gclient runhooks`
-sudo apt-get -y install bzip2
+sudo apt-get -y install bzip2 xz-utils
 
 # Do our own error handling for java.
 set +e
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index dc076cb..19828e33 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -638,6 +638,7 @@
     "raster/synchronous_task_graph_runner_unittest.cc",
     "raster/task_graph_work_queue_unittest.cc",
     "raster/texture_compressor_etc1_unittest.cc",
+    "resources/display_resource_provider_unittest.cc",
     "resources/layer_tree_resource_provider_unittest.cc",
     "resources/resource_pool_unittest.cc",
     "resources/resource_provider_unittest.cc",
diff --git a/cc/benchmarks/rasterize_and_record_benchmark.cc b/cc/benchmarks/rasterize_and_record_benchmark.cc
index 66017c06..5d1afd1 100644
--- a/cc/benchmarks/rasterize_and_record_benchmark.cc
+++ b/cc/benchmarks/rasterize_and_record_benchmark.cc
@@ -170,10 +170,10 @@
         if (paint_op_memory_usage) {
           // Verify we are recording the same thing each time.
           DCHECK_EQ(paint_op_memory_usage, display_list->BytesUsed());
-          DCHECK_EQ(paint_op_count, display_list->op_count());
+          DCHECK_EQ(paint_op_count, display_list->TotalOpCount());
         } else {
           paint_op_memory_usage = display_list->BytesUsed();
-          paint_op_count = display_list->op_count();
+          paint_op_count = display_list->TotalOpCount();
         }
 
         timer.NextLap();
diff --git a/cc/layers/recording_source.cc b/cc/layers/recording_source.cc
index 80648d3..66c44cc0 100644
--- a/cc/layers/recording_source.cc
+++ b/cc/layers/recording_source.cc
@@ -141,11 +141,11 @@
   is_solid_color_ = false;
   solid_color_ = SK_ColorTRANSPARENT;
 
-  if (display_list_->op_count() > kMaxOpsToAnalyzeForLayer)
+  if (display_list_->TotalOpCount() > kMaxOpsToAnalyzeForLayer)
     return;
 
   TRACE_EVENT1("cc", "RecordingSource::DetermineIfSolidColor", "opcount",
-               display_list_->op_count());
+               display_list_->TotalOpCount());
   is_solid_color_ = display_list_->GetColorIfSolidInRect(
       gfx::ScaleToRoundedRect(gfx::Rect(GetSize()), recording_scale_factor_),
       &solid_color_, kMaxOpsToAnalyzeForLayer);
diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h
index 935f643..0ade2b1 100644
--- a/cc/paint/display_item_list.h
+++ b/cc/paint/display_item_list.h
@@ -162,7 +162,7 @@
   bool HasNonAAPaint() const { return paint_op_buffer_.HasNonAAPaint(); }
 
   // This gives the total number of PaintOps.
-  size_t op_count() const { return paint_op_buffer_.size(); }
+  size_t TotalOpCount() const { return paint_op_buffer_.total_op_count(); }
   size_t BytesUsed() const;
 
   const DiscardableImageMap& discardable_image_map() const {
diff --git a/cc/paint/display_item_list_unittest.cc b/cc/paint/display_item_list_unittest.cc
index ee69227..98f4e2b 100644
--- a/cc/paint/display_item_list_unittest.cc
+++ b/cc/paint/display_item_list_unittest.cc
@@ -128,7 +128,7 @@
     list->EndPaintOfUnpaired(layer_rect);
   }
   // No ops.
-  EXPECT_EQ(0u, list->op_count());
+  EXPECT_EQ(0u, list->TotalOpCount());
 
   {
     list->StartPaint();
@@ -137,7 +137,7 @@
     list->EndPaintOfUnpaired(layer_rect);
   }
   // Two ops.
-  EXPECT_EQ(2u, list->op_count());
+  EXPECT_EQ(2u, list->TotalOpCount());
 }
 
 TEST(DisplayItemListTest, ClipPairedRange) {
@@ -552,7 +552,7 @@
 
 TEST(DisplayItemListTest, SizeEmpty) {
   auto list = base::MakeRefCounted<DisplayItemList>();
-  EXPECT_EQ(0u, list->op_count());
+  EXPECT_EQ(0u, list->TotalOpCount());
 }
 
 TEST(DisplayItemListTest, SizeOne) {
@@ -563,7 +563,7 @@
     list->push<DrawRectOp>(gfx::RectToSkRect(drawing_bounds), PaintFlags());
     list->EndPaintOfUnpaired(drawing_bounds);
   }
-  EXPECT_EQ(1u, list->op_count());
+  EXPECT_EQ(1u, list->TotalOpCount());
 }
 
 TEST(DisplayItemListTest, SizeMultiple) {
@@ -581,7 +581,7 @@
     list->push<RestoreOp>();
     list->EndPaintOfPairedEnd();
   }
-  EXPECT_EQ(3u, list->op_count());
+  EXPECT_EQ(3u, list->TotalOpCount());
 }
 
 TEST(DisplayItemListTest, AppendVisualRectSimple) {
@@ -596,7 +596,7 @@
     list->EndPaintOfUnpaired(drawing_bounds);
   }
 
-  EXPECT_EQ(1u, list->op_count());
+  EXPECT_EQ(1u, list->TotalOpCount());
   EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
 }
 
@@ -619,7 +619,7 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(3u, list->op_count());
+  EXPECT_EQ(3u, list->TotalOpCount());
   EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(0));
   EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(1));
   EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(2));
@@ -656,7 +656,7 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(5u, list->op_count());
+  EXPECT_EQ(5u, list->TotalOpCount());
   EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(0));
   EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(1));
   EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(2));
@@ -691,7 +691,7 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(4u, list->op_count());
+  EXPECT_EQ(4u, list->TotalOpCount());
   EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
   EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(1));
   EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(2));
@@ -725,7 +725,7 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(4u, list->op_count());
+  EXPECT_EQ(4u, list->TotalOpCount());
   EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
   EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(1));
   EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(2));
@@ -768,7 +768,7 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(5u, list->op_count());
+  EXPECT_EQ(5u, list->TotalOpCount());
   EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(0));
   EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(1));
   EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(2));
@@ -824,7 +824,7 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(8u, list->op_count());
+  EXPECT_EQ(8u, list->TotalOpCount());
   gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
   merged_drawing_bounds.Union(drawing_b_bounds);
   EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
@@ -887,7 +887,7 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(8u, list->op_count());
+  EXPECT_EQ(8u, list->TotalOpCount());
   gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
   merged_drawing_bounds.Union(drawing_b_bounds);
   EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
@@ -950,7 +950,7 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(8u, list->op_count());
+  EXPECT_EQ(8u, list->TotalOpCount());
   gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
   merged_drawing_bounds.Union(drawing_b_bounds);
   EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
@@ -1013,7 +1013,7 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(8u, list->op_count());
+  EXPECT_EQ(8u, list->TotalOpCount());
   gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
   merged_drawing_bounds.Union(drawing_b_bounds);
   EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
@@ -1051,10 +1051,31 @@
     list->EndPaintOfPairedEnd();
   }
 
-  EXPECT_EQ(3u, list->op_count());
+  EXPECT_EQ(3u, list->TotalOpCount());
   EXPECT_RECT_EQ(visual_rect, list->VisualRectForTesting(0));
   EXPECT_RECT_EQ(visual_rect, list->VisualRectForTesting(1));
   EXPECT_RECT_EQ(visual_rect, list->VisualRectForTesting(2));
 }
 
+TEST(DisplayItemListTest, TotalOpCount) {
+  auto list = base::MakeRefCounted<DisplayItemList>();
+  auto sub_list = base::MakeRefCounted<DisplayItemList>();
+
+  sub_list->StartPaint();
+  sub_list->push<SaveOp>();
+  sub_list->push<TranslateOp>(10.f, 20.f);
+  sub_list->push<DrawRectOp>(SkRect::MakeWH(10, 20), PaintFlags());
+  sub_list->push<RestoreOp>();
+  sub_list->EndPaintOfUnpaired(gfx::Rect());
+  EXPECT_EQ(4u, sub_list->TotalOpCount());
+
+  list->StartPaint();
+  list->push<SaveOp>();
+  list->push<TranslateOp>(10.f, 20.f);
+  list->push<DrawRecordOp>(sub_list->ReleaseAsRecord());
+  list->push<RestoreOp>();
+  list->EndPaintOfUnpaired(gfx::Rect());
+  EXPECT_EQ(8u, list->TotalOpCount());
+}
+
 }  // namespace cc
diff --git a/cc/paint/paint_flags.cc b/cc/paint/paint_flags.cc
index d6298749..41b561f 100644
--- a/cc/paint/paint_flags.cc
+++ b/cc/paint/paint_flags.cc
@@ -40,7 +40,7 @@
   // TODO(enne): non-default dtor to investigate http://crbug.com/790915
 
   // Sanity check accessing this object doesn't crash.
-  CHECK_NE(blend_mode_, static_cast<uint32_t>(SkBlendMode::kLastMode) + 100);
+  blend_mode_ = static_cast<uint32_t>(SkBlendMode::kLastMode);
 
   // Free refcounted objects one by one.
   typeface_.reset();
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index ba18221..626b0b7 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -2055,6 +2055,10 @@
   return record->bytes_used();
 }
 
+size_t DrawRecordOp::AdditionalOpCount() const {
+  return record->total_op_count();
+}
+
 bool DrawRecordOp::HasDiscardableImages() const {
   return record->HasDiscardableImages();
 }
@@ -2102,6 +2106,7 @@
   op_count_ = other.op_count_;
   num_slow_paths_ = other.num_slow_paths_;
   subrecord_bytes_used_ = other.subrecord_bytes_used_;
+  subrecord_op_count_ = other.subrecord_op_count_;
   has_non_aa_paint_ = other.has_non_aa_paint_;
   has_discardable_images_ = other.has_discardable_images_;
 
@@ -2122,6 +2127,7 @@
   num_slow_paths_ = 0;
   has_non_aa_paint_ = false;
   subrecord_bytes_used_ = 0;
+  subrecord_op_count_ = 0;
   has_discardable_images_ = false;
 }
 
@@ -2379,6 +2385,8 @@
     return false;
   if (subrecord_bytes_used_ != other.subrecord_bytes_used_)
     return false;
+  if (subrecord_op_count_ != other.subrecord_op_count_)
+    return false;
   if (has_non_aa_paint_ != other.has_non_aa_paint_)
     return false;
   if (has_discardable_images_ != other.has_discardable_images_)
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h
index 0b3951a..2228e487 100644
--- a/cc/paint/paint_op_buffer.h
+++ b/cc/paint/paint_op_buffer.h
@@ -210,6 +210,9 @@
   // and display lists.  This doesn't count other objects like paths or blobs.
   size_t AdditionalBytesUsed() const { return 0; }
 
+  // Returns the number of ops in referenced sub records and display lists.
+  size_t AdditionalOpCount() const { return 0; }
+
   // Run the destructor for the derived op type.  Ops are usually contained in
   // memory buffers and so don't have their destructors run automatically.
   void DestroyThis();
@@ -601,6 +604,7 @@
   bool IsValid() const { return true; }
   static bool AreEqual(const PaintOp* left, const PaintOp* right);
   size_t AdditionalBytesUsed() const;
+  size_t AdditionalOpCount() const;
   bool HasDiscardableImages() const;
   int CountSlowPaths() const;
   bool HasNonAAPaint() const;
@@ -863,6 +867,9 @@
   size_t bytes_used() const {
     return sizeof(*this) + reserved_ + subrecord_bytes_used_;
   }
+  // Returns the total number of ops including sub-records.
+  size_t total_op_count() const { return op_count_ + subrecord_op_count_; }
+
   size_t next_op_offset() const { return used_; }
   int numSlowPaths() const { return num_slow_paths_; }
   bool HasNonAAPaint() const { return has_non_aa_paint_; }
@@ -927,6 +934,7 @@
     has_discardable_images_ |= op->HasDiscardableImagesFromFlags();
 
     subrecord_bytes_used_ += op->AdditionalBytesUsed();
+    subrecord_op_count_ += op->AdditionalOpCount();
   }
 
   template <typename T>
@@ -1140,6 +1148,8 @@
   int num_slow_paths_ = 0;
   // Record additional bytes used by referenced sub-records and display lists.
   size_t subrecord_bytes_used_ = 0;
+  // Record total op count of referenced sub-record and display lists.
+  size_t subrecord_op_count_ = 0;
 
   bool has_non_aa_paint_ : 1;
   bool has_discardable_images_ : 1;
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index 7c6ce78..3b0e5d0 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -1955,7 +1955,7 @@
     PaintOp* written = PaintOp::Deserialize(
         output_.get(), bytes_written, deserialized.get(), deserialized_size,
         &bytes_read, options_provider.deserialize_options());
-    ASSERT_TRUE(written);
+    ASSERT_TRUE(written) << PaintOpTypeToString(GetParamType());
     EXPECT_EQ(*op, *written);
     written->DestroyThis();
     written = nullptr;
@@ -3124,4 +3124,20 @@
   EXPECT_EQ(scale.height(), 0.8f);
 }
 
+TEST(PaintOpBufferTest, TotalOpCount) {
+  auto record_buffer = sk_make_sp<PaintOpBuffer>();
+  auto sub_record_buffer = sk_make_sp<PaintOpBuffer>();
+  auto sub_sub_record_buffer = sk_make_sp<PaintOpBuffer>();
+  PushDrawRectOps(sub_sub_record_buffer.get());
+  PushDrawRectOps(sub_record_buffer.get());
+  PushDrawRectOps(record_buffer.get());
+  sub_record_buffer->push<DrawRecordOp>(sub_sub_record_buffer);
+  record_buffer->push<DrawRecordOp>(sub_record_buffer);
+
+  size_t len = std::min(test_rects.size(), test_flags.size());
+  EXPECT_EQ(len, sub_sub_record_buffer->total_op_count());
+  EXPECT_EQ(2 * len + 1, sub_record_buffer->total_op_count());
+  EXPECT_EQ(3 * len + 2, record_buffer->total_op_count());
+}
+
 }  // namespace cc
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index bf51dc8e..2e7dbe0 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -17,6 +17,7 @@
 #include "cc/paint/transfer_cache_deserialize_helper.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "third_party/skia/include/core/SkRRect.h"
+#include "third_party/skia/include/core/SkSerialProcs.h"
 #include "third_party/skia/include/core/SkTextBlob.h"
 
 namespace cc {
@@ -33,8 +34,15 @@
   bool had_null = false;
 };
 
-sk_sp<SkTypeface> ResolveTypeface(uint32_t id, void* ctx) {
+sk_sp<SkTypeface> ResolveTypeface(const void* data, size_t length, void* ctx) {
   TypefacesCatalog* catalog = static_cast<TypefacesCatalog*>(ctx);
+  if (length != 4) {
+    catalog->had_null = true;
+    return nullptr;
+  }
+
+  uint32_t id;
+  memcpy(&id, data, length);
   auto* entry = catalog->transfer_cache
                     ->GetEntryAs<ServicePaintTypefaceTransferCacheEntry>(id);
   // TODO(vmpstr): The !entry->typeface() check is here because not all
@@ -386,24 +394,19 @@
 void PaintOpReader::Read(scoped_refptr<PaintTextBlob>* paint_blob) {
   size_t data_bytes = 0u;
   ReadSimple(&data_bytes);
-  // Skia expects aligned data size, make sure we don't pass it incorrect data.
-  if (remaining_bytes_ < data_bytes || data_bytes == 0u ||
-      !SkIsAlign4(data_bytes)) {
+  if (remaining_bytes_ < data_bytes || data_bytes == 0u)
     SetInvalid();
-  }
-
   if (!valid_)
     return;
 
-  sk_sp<SkData> data =
-      SkData::MakeWithoutCopy(const_cast<const char*>(memory_), data_bytes);
-  memory_ += data_bytes;
-  remaining_bytes_ -= data_bytes;
-
   TypefacesCatalog catalog;
   catalog.transfer_cache = transfer_cache_;
-  sk_sp<SkTextBlob> blob = SkTextBlob::Deserialize(data->data(), data->size(),
-                                                   &ResolveTypeface, &catalog);
+
+  SkDeserialProcs procs;
+  procs.fTypefaceProc = &ResolveTypeface;
+  procs.fTypefaceCtx = &catalog;
+  sk_sp<SkTextBlob> blob = SkTextBlob::Deserialize(
+      const_cast<const char*>(memory_), data_bytes, procs);
   // TODO(vmpstr): If we couldn't serialize |blob|, we should make |paint_blob|
   // nullptr. However, this causes GL errors right now, because not all
   // typefaces are serialized. Fix this once we serialize everything. For now
@@ -414,6 +417,8 @@
     blob = nullptr;
   *paint_blob = base::MakeRefCounted<PaintTextBlob>(
       std::move(blob), std::vector<PaintTypeface>());
+  memory_ += data_bytes;
+  remaining_bytes_ -= data_bytes;
 }
 
 void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
diff --git a/cc/paint/paint_op_writer.cc b/cc/paint/paint_op_writer.cc
index 68b3a2f6..697a9ea 100644
--- a/cc/paint/paint_op_writer.cc
+++ b/cc/paint/paint_op_writer.cc
@@ -12,16 +12,27 @@
 #include "cc/paint/paint_shader.h"
 #include "cc/paint/paint_typeface_transfer_cache_entry.h"
 #include "cc/paint/transfer_cache_serialize_helper.h"
+#include "third_party/skia/include/core/SkSerialProcs.h"
 #include "third_party/skia/include/core/SkTextBlob.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/skia_util.h"
 
 namespace cc {
 namespace {
-void TypefaceCataloger(SkTypeface* typeface, void* ctx) {
+const size_t kSkiaAlignment = 4u;
+
+sk_sp<SkData> TypefaceCataloger(SkTypeface* typeface, void* ctx) {
   static_cast<TransferCacheSerializeHelper*>(ctx)->AssertLocked(
       TransferCacheEntryType::kPaintTypeface, typeface->uniqueID());
+
+  uint32_t id = typeface->uniqueID();
+  return SkData::MakeWithCopy(&id, sizeof(uint32_t));
 }
+
+size_t RoundDownToAlignment(size_t bytes, size_t alignment) {
+  return bytes - (bytes & (alignment - 1));
+}
+
 }  // namespace
 
 // static
@@ -97,16 +108,28 @@
 void PaintOpWriter::WriteFlattenable(const SkFlattenable* val) {
   DCHECK(SkIsAlign4(reinterpret_cast<uintptr_t>(memory_)))
       << "Flattenable must start writing at 4 byte alignment.";
-
   if (!val) {
     WriteSize(static_cast<size_t>(0u));
     return;
   }
 
-  sk_sp<SkData> data = val->serialize();
-  WriteSize(data->size());
-  if (!data->isEmpty())
-    WriteData(data->size(), data->data());
+  size_t size_offset = sizeof(size_t);
+  EnsureBytes(size_offset);
+  if (!valid_)
+    return;
+  char* size_memory = memory_;
+  memory_ += size_offset;
+  remaining_bytes_ -= size_offset;
+
+  size_t bytes_written = val->serialize(
+      memory_, RoundDownToAlignment(remaining_bytes_, kSkiaAlignment));
+  if (bytes_written == 0u) {
+    valid_ = false;
+    return;
+  }
+  reinterpret_cast<size_t*>(size_memory)[0] = bytes_written;
+  memory_ += bytes_written;
+  remaining_bytes_ -= bytes_written;
 }
 
 void PaintOpWriter::WriteSize(size_t size) {
@@ -250,13 +273,28 @@
 }
 
 void PaintOpWriter::Write(const sk_sp<SkTextBlob>& blob) {
-  // TODO(khushalsagar): Change skia API to serialize directly into shared mem.
-  auto data = blob->serialize(&TypefaceCataloger, transfer_cache_);
-  DCHECK(data);
-  DCHECK_GT(data->size(), 0u);
+  DCHECK(blob);
 
-  WriteSize(data->size());
-  WriteData(data->size(), data->data());
+  size_t size_offset = sizeof(size_t);
+  EnsureBytes(size_offset);
+  if (!valid_)
+    return;
+
+  char* size_memory = memory_;
+  memory_ += size_offset;
+  remaining_bytes_ -= size_offset;
+  SkSerialProcs procs;
+  procs.fTypefaceProc = &TypefaceCataloger;
+  procs.fTypefaceCtx = transfer_cache_;
+  size_t bytes_written = blob->serialize(
+      procs, memory_, RoundDownToAlignment(remaining_bytes_, kSkiaAlignment));
+  if (bytes_written == 0u) {
+    valid_ = false;
+    return;
+  }
+  reinterpret_cast<size_t*>(size_memory)[0] = bytes_written;
+  memory_ += bytes_written;
+  remaining_bytes_ -= bytes_written;
 }
 
 void PaintOpWriter::Write(const scoped_refptr<PaintTextBlob>& blob) {
diff --git a/cc/resources/display_resource_provider.cc b/cc/resources/display_resource_provider.cc
index 8fc95b2..c48d3ff 100644
--- a/cc/resources/display_resource_provider.cc
+++ b/cc/resources/display_resource_provider.cc
@@ -268,7 +268,8 @@
 
     bool is_lost = resource.lost ||
                    (resource.is_gpu_resource_type() && lost_context_provider_);
-    if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
+    if (resource.exported_count > 0 || resource.lock_for_read_count > 0 ||
+        resource.locked_for_external_use) {
       if (style != FOR_SHUTDOWN) {
         // Defer this resource deletion.
         resource.marked_for_deletion = true;
@@ -512,49 +513,8 @@
 
 bool DisplayResourceProvider::InUse(viz::ResourceId id) {
   viz::internal::Resource* resource = GetResource(id);
-  return resource->lock_for_read_count > 0 || resource->lost;
-}
-
-viz::ResourceMetadata
-DisplayResourceProvider::GetResourceMetadataForExternalUse(
-    viz::ResourceId id,
-    const gpu::SyncToken& release_sync_token) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  ResourceMap::iterator it = resources_.find(id);
-  DCHECK(it != resources_.end());
-
-  viz::internal::Resource* resource = &it->second;
-  viz::ResourceMetadata metadata;
-  // TODO(xing.xu): remove locked_for_write.
-  DCHECK(!resource->locked_for_write)
-      << "locked for write: " << resource->locked_for_write;
-  DCHECK_EQ(resource->exported_count, 0);
-  // Uninitialized! Call SetPixels or LockForWrite first.
-  DCHECK(resource->allocated);
-  // TODO(penghuang): support software resource.
-  DCHECK(resource->is_gpu_resource_type());
-
-  metadata.mailbox = resource->mailbox;
-  metadata.backend_format = GrBackendFormat::MakeGL(
-      TextureStorageFormat(resource->format), resource->target);
-  metadata.size = resource->size;
-  metadata.mip_mapped = GrMipMapped::kNo;
-  metadata.origin = kTopLeft_GrSurfaceOrigin;
-  metadata.color_type = ResourceFormatToClosestSkColorType(resource->format);
-  metadata.alpha_type = kPremul_SkAlphaType;
-  metadata.color_space = nullptr;
-  metadata.sync_token = resource->sync_token();
-
-  // Update the resource sync token to |release_sync_token|. When the next frame
-  // is being composited, the DeclareUsedResourcesFromChild() will be called
-  // with resources belong to every child for the next frame. If the resource
-  // is not used by the next frame, the resource will be returned to a child
-  // which owns it with the |release_sync_token|. The child is responsible for
-  // issuing a WaitSyncToken GL command with the |release_sync_token| before
-  // reusing it.
-  resource->UpdateSyncToken(release_sync_token);
-
-  return metadata;
+  return resource->lock_for_read_count > 0 || resource->lost ||
+         resource->locked_for_external_use;
 }
 
 DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
@@ -641,7 +601,74 @@
   DCHECK_GT(resource->lock_for_read_count, 0);
   DCHECK_EQ(resource->exported_count, 0);
   resource->lock_for_read_count--;
-  if (resource->marked_for_deletion && !resource->lock_for_read_count) {
+  TryReleaseResource(it);
+}
+
+viz::ResourceMetadata DisplayResourceProvider::LockForExternalUse(
+    viz::ResourceId id) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  ResourceMap::iterator it = resources_.find(id);
+  DCHECK(it != resources_.end());
+
+  viz::internal::Resource* resource = &it->second;
+  viz::ResourceMetadata metadata;
+  // TODO(xing.xu): remove locked_for_write.
+  DCHECK(!resource->locked_for_write)
+      << "locked for write: " << resource->locked_for_write;
+  DCHECK_EQ(resource->exported_count, 0);
+  // Uninitialized! Call SetPixels or LockForWrite first.
+  DCHECK(resource->allocated);
+  // Make sure there is no outstanding LockForExternalUse without calling
+  // UnlockForExternalUse.
+  DCHECK(!resource->locked_for_external_use);
+  // TODO(penghuang): support software resource.
+  DCHECK(resource->is_gpu_resource_type());
+
+  metadata.mailbox = resource->mailbox;
+  metadata.backend_format = GrBackendFormat::MakeGL(
+      TextureStorageFormat(resource->format), resource->target);
+  metadata.size = resource->size;
+  metadata.mip_mapped = GrMipMapped::kNo;
+  metadata.origin = kTopLeft_GrSurfaceOrigin;
+  metadata.color_type = ResourceFormatToClosestSkColorType(resource->format);
+  metadata.alpha_type = kPremul_SkAlphaType;
+  metadata.color_space = nullptr;
+  metadata.sync_token = resource->sync_token();
+
+  resource->locked_for_external_use = true;
+  return metadata;
+}
+
+void DisplayResourceProvider::UnlockForExternalUse(
+    viz::ResourceId id,
+    const gpu::SyncToken& sync_token) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  ResourceMap::iterator it = resources_.find(id);
+  DCHECK(it != resources_.end());
+  DCHECK(sync_token.verified_flush());
+
+  viz::internal::Resource* resource = &it->second;
+  DCHECK(resource->locked_for_external_use);
+  // TODO(penghuang): support software resource.
+  DCHECK(resource->is_gpu_resource_type());
+
+  // Update the resource sync token to |sync_token|. When the next frame is
+  // being composited, the DeclareUsedResourcesFromChild() will be called with
+  // resources belong to every child for the next frame. If the resource is not
+  // used by the next frame, the resource will be returned to a child which
+  // owns it with the |sync_token|. The child is responsible for issuing a
+  // WaitSyncToken GL command with the |sync_token| before reusing it.
+  resource->UpdateSyncToken(sync_token);
+  resource->locked_for_external_use = false;
+
+  TryReleaseResource(it);
+}
+
+void DisplayResourceProvider::TryReleaseResource(ResourceMap::iterator it) {
+  viz::ResourceId id = it->first;
+  viz::internal::Resource* resource = &it->second;
+  if (resource->marked_for_deletion && !resource->lock_for_read_count &&
+      !resource->locked_for_external_use) {
     if (!resource->child_id) {
       // The resource belongs to this ResourceProvider, so it can be destroyed.
 #if defined(OS_ANDROID)
@@ -748,6 +775,30 @@
   resource_provider_->UnlockForRead(resource_id_);
 }
 
+DisplayResourceProvider::LockSetForExternalUse::LockSetForExternalUse(
+    DisplayResourceProvider* resource_provider)
+    : resource_provider_(resource_provider) {}
+
+DisplayResourceProvider::LockSetForExternalUse::~LockSetForExternalUse() {
+  DCHECK(resources_.empty());
+}
+
+viz::ResourceMetadata
+DisplayResourceProvider::LockSetForExternalUse::LockResource(
+    viz::ResourceId id) {
+  DCHECK(std::find(resources_.begin(), resources_.end(), id) ==
+         resources_.end());
+  resources_.push_back(id);
+  return resource_provider_->LockForExternalUse(id);
+}
+
+void DisplayResourceProvider::LockSetForExternalUse::UnlockResources(
+    const gpu::SyncToken& sync_token) {
+  for (const auto& id : resources_)
+    resource_provider_->UnlockForExternalUse(id, sync_token);
+  resources_.clear();
+}
+
 DisplayResourceProvider::SynchronousFence::SynchronousFence(
     gpu::gles2::GLES2Interface* gl)
     : gl_(gl), has_synchronized_(true) {}
diff --git a/cc/resources/display_resource_provider.h b/cc/resources/display_resource_provider.h
index 25e9463c..5c6baef7 100644
--- a/cc/resources/display_resource_provider.h
+++ b/cc/resources/display_resource_provider.h
@@ -57,14 +57,6 @@
   // Checks whether a resource is in use.
   bool InUse(viz::ResourceId id);
 
-  // Get the resource metadata for external use.
-  // The |release_sync_token| should be one that can be waited on in a command
-  // buffer to ensure that any external use of it is completed, before reusing
-  // the resource's backing.
-  viz::ResourceMetadata GetResourceMetadataForExternalUse(
-      viz::ResourceId id,
-      const gpu::SyncToken& release_sync_token);
-
   // The following lock classes are part of the DisplayResourceProvider API and
   // are needed to read the resource contents. The user must ensure that they
   // only use GL locks on GL resources, etc, and this is enforced by assertions.
@@ -155,6 +147,27 @@
     DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSoftware);
   };
 
+  // Maintains set of lock for external use.
+  class CC_EXPORT LockSetForExternalUse {
+   public:
+    explicit LockSetForExternalUse(DisplayResourceProvider* resource_provider);
+    ~LockSetForExternalUse();
+
+    // Lock a resource for external use.
+    viz::ResourceMetadata LockResource(viz::ResourceId resource_id);
+
+    // Unlock all locked resources with a |sync_token|.
+    // See UnlockForExternalUse for the detail. All resources must be unlocked
+    // before destroying this class.
+    void UnlockResources(const gpu::SyncToken& sync_token);
+
+   private:
+    DisplayResourceProvider* const resource_provider_;
+    std::vector<viz::ResourceId> resources_;
+
+    DISALLOW_COPY_AND_ASSIGN(LockSetForExternalUse);
+  };
+
   // All resources that are returned to children while an instance of this
   // class exists will be stored and returned when the instance is destroyed.
   class CC_EXPORT ScopedBatchReturnResources {
@@ -233,10 +246,20 @@
       const viz::ResourceIdSet& resources_from_child);
 
  private:
-  friend class ScopedBatchReturnResources;
-
   const viz::internal::Resource* LockForRead(viz::ResourceId id);
   void UnlockForRead(viz::ResourceId id);
+
+  // Lock a resource for external use.
+  viz::ResourceMetadata LockForExternalUse(viz::ResourceId id);
+
+  // Unlock a resource which locked by LockForExternalUse.
+  // The |sync_token| should be waited on before reusing the resouce's backing
+  // to ensure that any external use of it is completed. This |sync_token|
+  // should have been verified.
+  void UnlockForExternalUse(viz::ResourceId id,
+                            const gpu::SyncToken& sync_token);
+
+  void TryReleaseResource(ResourceMap::iterator it);
   // Binds the given GL resource to a texture target for sampling using the
   // specified filter for both minification and magnification. Returns the
   // texture target used. The resource must be locked for reading.
diff --git a/cc/resources/display_resource_provider_unittest.cc b/cc/resources/display_resource_provider_unittest.cc
new file mode 100644
index 0000000..b8e3e56
--- /dev/null
+++ b/cc/resources/display_resource_provider_unittest.cc
@@ -0,0 +1,548 @@
+// Copyright 2018 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 "cc/resources/display_resource_provider.h"
+#include "cc/resources/layer_tree_resource_provider.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "cc/test/render_pass_test_utils.h"
+#include "cc/test/resource_provider_test_utils.h"
+#include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/common/resources/returned_resource.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/single_release_callback.h"
+#include "components/viz/test/test_context_provider.h"
+#include "components/viz/test/test_gpu_memory_buffer_manager.h"
+#include "components/viz/test/test_shared_bitmap_manager.h"
+#include "components/viz/test/test_texture.h"
+#include "components/viz/test/test_web_graphics_context_3d.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace cc {
+namespace {
+
+static const bool kUseGpuMemoryBufferResources = false;
+
+MATCHER_P(MatchesSyncToken, sync_token, "") {
+  gpu::SyncToken other;
+  memcpy(&other, arg, sizeof(other));
+  return other == sync_token;
+}
+
+static void ReleaseSharedBitmapCallback(
+    std::unique_ptr<viz::SharedBitmap> shared_bitmap,
+    bool* release_called,
+    gpu::SyncToken* release_sync_token,
+    bool* lost_resource_result,
+    const gpu::SyncToken& sync_token,
+    bool lost_resource) {
+  *release_called = true;
+  *release_sync_token = sync_token;
+  *lost_resource_result = lost_resource;
+}
+
+static std::unique_ptr<viz::SharedBitmap> CreateAndFillSharedBitmap(
+    viz::SharedBitmapManager* manager,
+    const gfx::Size& size,
+    viz::ResourceFormat format,
+    uint32_t value) {
+  std::unique_ptr<viz::SharedBitmap> shared_bitmap =
+      manager->AllocateSharedBitmap(size, format);
+  CHECK(shared_bitmap);
+  uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_bitmap->pixels());
+  CHECK(pixels);
+  std::fill_n(pixels, size.GetArea(), value);
+  return shared_bitmap;
+}
+
+static viz::ResourceSettings CreateResourceSettings() {
+  viz::ResourceSettings resource_settings;
+  resource_settings.use_gpu_memory_buffer_resources =
+      kUseGpuMemoryBufferResources;
+  return resource_settings;
+}
+
+// Shared data between multiple ResourceProviderContext. This contains mailbox
+// contents as well as information about sync points.
+class ContextSharedData {
+ public:
+  static std::unique_ptr<ContextSharedData> Create() {
+    return base::WrapUnique(new ContextSharedData());
+  }
+
+  uint32_t InsertFenceSync() { return next_fence_sync_++; }
+
+  void GenMailbox(GLbyte* mailbox) {
+    memset(mailbox, 0, GL_MAILBOX_SIZE_CHROMIUM);
+    memcpy(mailbox, &next_mailbox_, sizeof(next_mailbox_));
+    ++next_mailbox_;
+  }
+
+  void ProduceTexture(const GLbyte* mailbox_name,
+                      const gpu::SyncToken& sync_token,
+                      scoped_refptr<viz::TestTexture> texture) {
+    uint32_t sync_point = static_cast<uint32_t>(sync_token.release_count());
+
+    unsigned mailbox = 0;
+    memcpy(&mailbox, mailbox_name, sizeof(mailbox));
+    ASSERT_TRUE(mailbox && mailbox < next_mailbox_);
+    textures_[mailbox] = texture;
+    ASSERT_LT(sync_point_for_mailbox_[mailbox], sync_point);
+    sync_point_for_mailbox_[mailbox] = sync_point;
+  }
+
+  scoped_refptr<viz::TestTexture> ConsumeTexture(
+      const GLbyte* mailbox_name,
+      const gpu::SyncToken& sync_token) {
+    unsigned mailbox = 0;
+    memcpy(&mailbox, mailbox_name, sizeof(mailbox));
+    DCHECK(mailbox && mailbox < next_mailbox_);
+
+    // If the latest sync point the context has waited on is before the sync
+    // point for when the mailbox was set, pretend we never saw that
+    // ProduceTexture.
+    if (sync_point_for_mailbox_[mailbox] > sync_token.release_count()) {
+      NOTREACHED();
+      return scoped_refptr<viz::TestTexture>();
+    }
+    return textures_[mailbox];
+  }
+
+ private:
+  ContextSharedData() : next_fence_sync_(1), next_mailbox_(1) {}
+
+  uint64_t next_fence_sync_;
+  unsigned next_mailbox_;
+  using TextureMap =
+      std::unordered_map<unsigned, scoped_refptr<viz::TestTexture>>;
+  TextureMap textures_;
+  std::unordered_map<unsigned, uint32_t> sync_point_for_mailbox_;
+};
+
+class ResourceProviderContext : public viz::TestWebGraphicsContext3D {
+ public:
+  static std::unique_ptr<ResourceProviderContext> Create(
+      ContextSharedData* shared_data) {
+    return base::WrapUnique(new ResourceProviderContext(shared_data));
+  }
+
+  void genSyncToken(GLbyte* sync_token) override {
+    uint64_t fence_sync = shared_data_->InsertFenceSync();
+    gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO,
+                                   gpu::CommandBufferId::FromUnsafeValue(0x123),
+                                   fence_sync);
+    sync_token_data.SetVerifyFlush();
+    // Commit the ProduceTextureDirectCHROMIUM calls at this point, so that
+    // they're associated with the sync point.
+    for (const std::unique_ptr<PendingProduceTexture>& pending_texture :
+         pending_produce_textures_) {
+      shared_data_->ProduceTexture(pending_texture->mailbox, sync_token_data,
+                                   pending_texture->texture);
+    }
+    pending_produce_textures_.clear();
+    memcpy(sync_token, &sync_token_data, sizeof(sync_token_data));
+  }
+
+  void waitSyncToken(const GLbyte* sync_token) override {
+    gpu::SyncToken sync_token_data;
+    if (sync_token)
+      memcpy(&sync_token_data, sync_token, sizeof(sync_token_data));
+
+    if (sync_token_data.release_count() >
+        last_waited_sync_token_.release_count()) {
+      last_waited_sync_token_ = sync_token_data;
+    }
+  }
+
+  const gpu::SyncToken& last_waited_sync_token() const {
+    return last_waited_sync_token_;
+  }
+
+  void texStorage2DEXT(GLenum target,
+                       GLint levels,
+                       GLuint internalformat,
+                       GLint width,
+                       GLint height) override {
+    CheckTextureIsBound(target);
+    ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
+    ASSERT_EQ(1, levels);
+    GLenum format = GL_RGBA;
+    switch (internalformat) {
+      case GL_RGBA8_OES:
+        break;
+      case GL_BGRA8_EXT:
+        format = GL_BGRA_EXT;
+        break;
+      default:
+        NOTREACHED();
+    }
+    AllocateTexture(gfx::Size(width, height), format);
+  }
+
+  void texImage2D(GLenum target,
+                  GLint level,
+                  GLenum internalformat,
+                  GLsizei width,
+                  GLsizei height,
+                  GLint border,
+                  GLenum format,
+                  GLenum type,
+                  const void* pixels) override {
+    CheckTextureIsBound(target);
+    ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
+    ASSERT_FALSE(level);
+    ASSERT_EQ(internalformat, format);
+    ASSERT_FALSE(border);
+    ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+    AllocateTexture(gfx::Size(width, height), format);
+    if (pixels)
+      SetPixels(0, 0, width, height, pixels);
+  }
+
+  void texSubImage2D(GLenum target,
+                     GLint level,
+                     GLint xoffset,
+                     GLint yoffset,
+                     GLsizei width,
+                     GLsizei height,
+                     GLenum format,
+                     GLenum type,
+                     const void* pixels) override {
+    CheckTextureIsBound(target);
+    ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
+    ASSERT_FALSE(level);
+    ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+    {
+      base::AutoLock lock_for_texture_access(namespace_->lock);
+      ASSERT_EQ(GLDataFormat(BoundTexture(target)->format), format);
+    }
+    ASSERT_TRUE(pixels);
+    SetPixels(xoffset, yoffset, width, height, pixels);
+  }
+
+  void genMailboxCHROMIUM(GLbyte* mailbox) override {
+    return shared_data_->GenMailbox(mailbox);
+  }
+
+  void produceTextureDirectCHROMIUM(GLuint texture,
+                                    const GLbyte* mailbox) override {
+    // Delay moving the texture into the mailbox until the next
+    // sync token, so that it is not visible to other contexts that
+    // haven't waited on that sync point.
+    std::unique_ptr<PendingProduceTexture> pending(new PendingProduceTexture);
+    memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox));
+    base::AutoLock lock_for_texture_access(namespace_->lock);
+    pending->texture = UnboundTexture(texture);
+    pending_produce_textures_.push_back(std::move(pending));
+  }
+
+  GLuint createAndConsumeTextureCHROMIUM(const GLbyte* mailbox) override {
+    GLuint texture_id = createTexture();
+    base::AutoLock lock_for_texture_access(namespace_->lock);
+    scoped_refptr<viz::TestTexture> texture =
+        shared_data_->ConsumeTexture(mailbox, last_waited_sync_token_);
+    namespace_->textures.Replace(texture_id, texture);
+    return texture_id;
+  }
+
+  void GetPixels(const gfx::Size& size,
+                 viz::ResourceFormat format,
+                 uint8_t* pixels) {
+    CheckTextureIsBound(GL_TEXTURE_2D);
+    base::AutoLock lock_for_texture_access(namespace_->lock);
+    scoped_refptr<viz::TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
+    ASSERT_EQ(texture->size, size);
+    ASSERT_EQ(texture->format, format);
+    memcpy(pixels, texture->data.get(), TextureSizeBytes(size, format));
+  }
+
+ protected:
+  explicit ResourceProviderContext(ContextSharedData* shared_data)
+      : shared_data_(shared_data) {}
+
+ private:
+  void AllocateTexture(const gfx::Size& size, GLenum format) {
+    CheckTextureIsBound(GL_TEXTURE_2D);
+    viz::ResourceFormat texture_format = viz::RGBA_8888;
+    switch (format) {
+      case GL_RGBA:
+        texture_format = viz::RGBA_8888;
+        break;
+      case GL_BGRA_EXT:
+        texture_format = viz::BGRA_8888;
+        break;
+    }
+    base::AutoLock lock_for_texture_access(namespace_->lock);
+    BoundTexture(GL_TEXTURE_2D)->Reallocate(size, texture_format);
+  }
+
+  void SetPixels(int xoffset,
+                 int yoffset,
+                 int width,
+                 int height,
+                 const void* pixels) {
+    CheckTextureIsBound(GL_TEXTURE_2D);
+    base::AutoLock lock_for_texture_access(namespace_->lock);
+    scoped_refptr<viz::TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
+    ASSERT_TRUE(texture->data.get());
+    ASSERT_TRUE(xoffset >= 0 && xoffset + width <= texture->size.width());
+    ASSERT_TRUE(yoffset >= 0 && yoffset + height <= texture->size.height());
+    ASSERT_TRUE(pixels);
+    size_t in_pitch = TextureSizeBytes(gfx::Size(width, 1), texture->format);
+    size_t out_pitch =
+        TextureSizeBytes(gfx::Size(texture->size.width(), 1), texture->format);
+    uint8_t* dest = texture->data.get() + yoffset * out_pitch +
+                    TextureSizeBytes(gfx::Size(xoffset, 1), texture->format);
+    const uint8_t* src = static_cast<const uint8_t*>(pixels);
+    for (int i = 0; i < height; ++i) {
+      memcpy(dest, src, in_pitch);
+      dest += out_pitch;
+      src += in_pitch;
+    }
+  }
+
+  struct PendingProduceTexture {
+    GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
+    scoped_refptr<viz::TestTexture> texture;
+  };
+  ContextSharedData* shared_data_;
+  gpu::SyncToken last_waited_sync_token_;
+  std::vector<std::unique_ptr<PendingProduceTexture>> pending_produce_textures_;
+};
+
+class DisplayResourceProviderTest : public testing::TestWithParam<bool> {
+ public:
+  explicit DisplayResourceProviderTest(bool child_needs_sync_token)
+      : use_gpu_(GetParam()),
+        child_needs_sync_token_(child_needs_sync_token),
+        shared_data_(ContextSharedData::Create()) {
+    if (use_gpu_) {
+      auto context3d(ResourceProviderContext::Create(shared_data_.get()));
+      context3d_ = context3d.get();
+      context_provider_ =
+          viz::TestContextProvider::Create(std::move(context3d));
+      context_provider_->UnboundTestContext3d()
+          ->set_support_texture_format_bgra8888(true);
+      context_provider_->BindToCurrentThread();
+
+      auto child_context_owned =
+          ResourceProviderContext::Create(shared_data_.get());
+      child_context_ = child_context_owned.get();
+      child_context_provider_ =
+          viz::TestContextProvider::Create(std::move(child_context_owned));
+      child_context_provider_->UnboundTestContext3d()
+          ->set_support_texture_format_bgra8888(true);
+      child_context_provider_->BindToCurrentThread();
+      gpu_memory_buffer_manager_ =
+          std::make_unique<viz::TestGpuMemoryBufferManager>();
+      child_gpu_memory_buffer_manager_ =
+          gpu_memory_buffer_manager_->CreateClientGpuMemoryBufferManager();
+    } else {
+      shared_bitmap_manager_ = std::make_unique<viz::TestSharedBitmapManager>();
+    }
+
+    resource_provider_ = std::make_unique<DisplayResourceProvider>(
+        context_provider_.get(), shared_bitmap_manager_.get());
+
+    MakeChildResourceProvider();
+  }
+
+  DisplayResourceProviderTest() : DisplayResourceProviderTest(true) {}
+
+  bool use_gpu() const { return use_gpu_; }
+
+  void MakeChildResourceProvider() {
+    child_resource_provider_ = std::make_unique<LayerTreeResourceProvider>(
+        child_context_provider_.get(), shared_bitmap_manager_.get(),
+        child_gpu_memory_buffer_manager_.get(), child_needs_sync_token_,
+        CreateResourceSettings());
+  }
+
+  static void CollectResources(
+      std::vector<viz::ReturnedResource>* array,
+      const std::vector<viz::ReturnedResource>& returned) {
+    array->insert(array->end(), returned.begin(), returned.end());
+  }
+
+  static ReturnCallback GetReturnCallback(
+      std::vector<viz::ReturnedResource>* array) {
+    return base::BindRepeating(&DisplayResourceProviderTest::CollectResources,
+                               array);
+  }
+
+  static void SetResourceFilter(DisplayResourceProvider* resource_provider,
+                                viz::ResourceId id,
+                                GLenum filter) {
+    DisplayResourceProvider::ScopedSamplerGL sampler(resource_provider, id,
+                                                     GL_TEXTURE_2D, filter);
+  }
+
+  ResourceProviderContext* context() { return context3d_; }
+
+  viz::ResourceId CreateChildMailbox(gpu::SyncToken* release_sync_token,
+                                     bool* lost_resource,
+                                     bool* release_called,
+                                     gpu::SyncToken* sync_token,
+                                     viz::ResourceFormat format) {
+    if (use_gpu()) {
+      unsigned texture = child_context_->createTexture();
+      gpu::Mailbox gpu_mailbox;
+      child_context_->genMailboxCHROMIUM(gpu_mailbox.name);
+      child_context_->produceTextureDirectCHROMIUM(texture, gpu_mailbox.name);
+      child_context_->genSyncToken(sync_token->GetData());
+      EXPECT_TRUE(sync_token->HasData());
+
+      std::unique_ptr<viz::SharedBitmap> shared_bitmap;
+      std::unique_ptr<viz::SingleReleaseCallback> callback =
+          viz::SingleReleaseCallback::Create(base::BindRepeating(
+              ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
+              release_called, release_sync_token, lost_resource));
+      viz::TransferableResource gl_resource = viz::TransferableResource::MakeGL(
+          gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, *sync_token);
+      gl_resource.format = format;
+      return child_resource_provider_->ImportResource(gl_resource,
+                                                      std::move(callback));
+    } else {
+      gfx::Size size(64, 64);
+      std::unique_ptr<viz::SharedBitmap> shared_bitmap(
+          CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, format,
+                                    0));
+
+      viz::SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
+      std::unique_ptr<viz::SingleReleaseCallback> callback =
+          viz::SingleReleaseCallback::Create(base::BindRepeating(
+              ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
+              release_called, release_sync_token, lost_resource));
+      return child_resource_provider_->ImportResource(
+          viz::TransferableResource::MakeSoftware(
+              shared_bitmap_ptr->id(), shared_bitmap_ptr->sequence_number(),
+              size, format),
+          std::move(callback));
+    }
+  }
+
+  viz::ResourceId MakeGpuResourceAndSendToDisplay(
+      char c,
+      GLuint filter,
+      GLuint target,
+      const gpu::SyncToken& sync_token,
+      DisplayResourceProvider* resource_provider) {
+    ReturnCallback return_callback = base::DoNothing();
+
+    int child = resource_provider->CreateChild(return_callback);
+
+    gpu::Mailbox gpu_mailbox;
+    gpu_mailbox.name[0] = c;
+    gpu_mailbox.name[1] = 0;
+    auto resource = viz::TransferableResource::MakeGL(gpu_mailbox, GL_LINEAR,
+                                                      target, sync_token);
+    resource.id = 11;
+    resource_provider->ReceiveFromChild(child, {resource});
+    auto& map = resource_provider->GetChildToParentMap(child);
+    return map.find(resource.id)->second;
+  }
+
+ protected:
+  const bool use_gpu_;
+  const bool child_needs_sync_token_;
+  const std::unique_ptr<ContextSharedData> shared_data_;
+  ResourceProviderContext* context3d_ = nullptr;
+  ResourceProviderContext* child_context_ = nullptr;
+  scoped_refptr<viz::TestContextProvider> context_provider_;
+  scoped_refptr<viz::TestContextProvider> child_context_provider_;
+  std::unique_ptr<viz::TestGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+  std::unique_ptr<DisplayResourceProvider> resource_provider_;
+  std::unique_ptr<viz::TestGpuMemoryBufferManager>
+      child_gpu_memory_buffer_manager_;
+  std::unique_ptr<LayerTreeResourceProvider> child_resource_provider_;
+  std::unique_ptr<viz::TestSharedBitmapManager> shared_bitmap_manager_;
+};
+
+INSTANTIATE_TEST_CASE_P(DisplayResourceProviderTests,
+                        DisplayResourceProviderTest,
+                        ::testing::Values(false, true));
+
+TEST_P(DisplayResourceProviderTest, LockForExternalUse) {
+  // TODO(penghuang): consider supporting SW mode.
+  if (!use_gpu())
+    return;
+
+  gfx::Size size(1, 1);
+  viz::ResourceFormat format = viz::RGBA_8888;
+
+  viz::ResourceId id1 = child_resource_provider_->CreateGpuTextureResource(
+      size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
+  uint8_t data1[4] = {1, 2, 3, 4};
+  child_resource_provider_->CopyToResource(id1, data1, size);
+  std::vector<viz::ReturnedResource> returned_to_child;
+  int child_id =
+      resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+
+  // Transfer some resources to the parent.
+  ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+  resource_ids_to_transfer.push_back(id1);
+
+  std::vector<viz::TransferableResource> list;
+  child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+                                                &list);
+  ASSERT_EQ(1u, list.size());
+  EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+
+  resource_provider_->ReceiveFromChild(child_id, list);
+
+  // In DisplayResourceProvider's namespace, use the mapped resource id.
+  ResourceProvider::ResourceIdMap resource_map =
+      resource_provider_->GetChildToParentMap(child_id);
+
+  unsigned parent_id = resource_map[list.front().id];
+
+  DisplayResourceProvider::LockSetForExternalUse lock_set(
+      resource_provider_.get());
+
+  viz::ResourceMetadata metadata = lock_set.LockResource(parent_id);
+  ASSERT_EQ(size, metadata.size);
+  ASSERT_FALSE(metadata.mailbox.IsZero());
+  ASSERT_TRUE(metadata.sync_token.HasData());
+
+  resource_provider_->DeclareUsedResourcesFromChild(child_id,
+                                                    viz::ResourceIdSet());
+  // The resource should not be returned due to the external use lock.
+  EXPECT_EQ(0u, returned_to_child.size());
+
+  gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
+                            gpu::CommandBufferId::FromUnsafeValue(0x234),
+                            0x456);
+  sync_token.SetVerifyFlush();
+  lock_set.UnlockResources(sync_token);
+  resource_provider_->DeclareUsedResourcesFromChild(child_id,
+                                                    viz::ResourceIdSet());
+  // The resource should be returned after the lock is released.
+  EXPECT_EQ(1u, returned_to_child.size());
+  EXPECT_EQ(sync_token, returned_to_child[0].sync_token);
+  child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+  child_resource_provider_->DeleteResource(id1);
+  EXPECT_EQ(0u, child_resource_provider_->num_resources());
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/chrome/VERSION b/chrome/VERSION
index 7100c6d..0aaa3566 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=67
 MINOR=0
-BUILD=3390
+BUILD=3391
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BasicNativePage.java b/chrome/android/java/src/org/chromium/chrome/browser/BasicNativePage.java
index 61b810ff..77fc769 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BasicNativePage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BasicNativePage.java
@@ -10,19 +10,23 @@
 import android.widget.FrameLayout.LayoutParams;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.common.BrowserControlsState;
 
 /**
  * A basic implementation of a white {@link NativePage} that docks below the toolbar.
  */
-public abstract class BasicNativePage implements NativePage {
-
+public abstract class BasicNativePage extends EmptyTabObserver implements NativePage {
     private final Activity mActivity;
     private final NativePageHost mHost;
     private final int mBackgroundColor;
     private final int mThemeColor;
+    private int mTopMargin;
+    private int mBottomMargin;
 
     private String mUrl;
 
@@ -37,20 +41,23 @@
 
         Resources res = mActivity.getResources();
 
-        int topMargin = 0;
-        int bottomMargin = 0;
+        mTopMargin = 0;
+        mBottomMargin = 0;
         if (activity instanceof ChromeActivity
                 && ((ChromeActivity) activity).getBottomSheet() != null) {
-            bottomMargin = res.getDimensionPixelSize(R.dimen.bottom_control_container_peek_height);
+            mBottomMargin = res.getDimensionPixelSize(R.dimen.bottom_control_container_peek_height);
         } else {
-            topMargin = res.getDimensionPixelSize(R.dimen.tab_strip_height)
+            mTopMargin = res.getDimensionPixelSize(R.dimen.tab_strip_height)
                     + res.getDimensionPixelSize(R.dimen.toolbar_height_no_shadow);
         }
 
-        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT);
-        layoutParams.setMargins(0, topMargin, 0, bottomMargin);
-        getView().setLayoutParams(layoutParams);
+        if (host.getActiveTab() != null) {
+            host.getActiveTab().addObserver(this);
+        }
+
+        updateMargins(host.getActiveTab() != null
+                        ? host.getActiveTab().getBrowserControlsStateConstraints()
+                        : BrowserControlsState.SHOWN);
     }
 
     /**
@@ -59,6 +66,12 @@
     protected abstract void initialize(Activity activity, NativePageHost host);
 
     @Override
+    public void onBrowserControlsConstraintsUpdated(
+            Tab tab, @BrowserControlsState int constraints) {
+        updateMargins(constraints);
+    }
+
+    @Override
     public abstract View getView();
 
     @Override
@@ -87,7 +100,10 @@
     }
 
     @Override
-    public void destroy() { }
+    public void destroy() {
+        if (mHost.getActiveTab() == null) return;
+        mHost.getActiveTab().removeObserver(this);
+    }
 
     /**
      * Tells the native page framework that the url should be changed.
@@ -96,4 +112,21 @@
         if (url.equals(mUrl)) return;
         mHost.loadUrl(new LoadUrlParams(url), /* incognito = */ false);
     }
+
+    /**
+     * Updates the top and bottom margin depending on wether the browser controls are shown or
+     * hidden.
+     */
+    private void updateMargins(@BrowserControlsState int constraints) {
+        int topMargin = mTopMargin;
+        int bottomMargin = mBottomMargin;
+        if (constraints == BrowserControlsState.HIDDEN) {
+            topMargin = 0;
+            bottomMargin = 0;
+        }
+        LayoutParams layoutParams =
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+        layoutParams.setMargins(0, topMargin, 0, bottomMargin);
+        getView().setLayoutParams(layoutParams);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBridge.java
index 110b2c91..788f91c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBridge.java
@@ -94,9 +94,9 @@
      * Reports an event happening in the context of the current URL.
      *
      * @param webContents Web contents with the document for which event is reported.
-     * @param eventId Id of the reported event.
+     * @param eventId The Id of the reported event as a {@link ContextualSuggestionsEvent} integer.
      */
-    void reportEvent(WebContents webContents, int eventId) {
+    void reportEvent(WebContents webContents, @ContextualSuggestionsEvent int eventId) {
         assert mNativeContextualSuggestionsBridge != 0;
         assert webContents != null && !webContents.isDestroyed();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java
index c6e4cea..2ab3bab3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsModel.java
@@ -12,7 +12,17 @@
 import java.util.Collections;
 
 /** A model for the contextual suggestions UI component. */
-class ContextualSuggestionsModel extends PropertyObservable<PropertyKey> {
+class ContextualSuggestionsModel
+        extends PropertyObservable<ContextualSuggestionsModel.PropertyKey> {
+    /** Keys uniquely identifying model properties. */
+    static class PropertyKey {
+        static final PropertyKey CLOSE_BUTTON_ON_CLICK_LISTENER = new PropertyKey();
+        static final PropertyKey TITLE = new PropertyKey();
+        static final PropertyKey TOOLBAR_SHADOW_VISIBILITY = new PropertyKey();
+
+        private PropertyKey() {}
+    }
+
     /** A {@link ListObservable} containing the current cluster list. */
     class ClusterListObservable extends ListObservable {
         ClusterList mClusterList = new ClusterList(Collections.emptyList());
@@ -51,7 +61,7 @@
     /** @param listener The {@link OnClickListener} for the close button. */
     void setCloseButtonOnClickListener(OnClickListener listener) {
         mCloseButtonOnClickListener = listener;
-        notifyPropertyChanged(new PropertyKey(PropertyKey.CLOSE_BUTTON_ON_CLICK_LISTENER));
+        notifyPropertyChanged(PropertyKey.CLOSE_BUTTON_ON_CLICK_LISTENER);
     }
 
     /** @return The {@link OnClickListener} for the close button. */
@@ -62,7 +72,7 @@
     /** @param title The title to display in the toolbar. */
     void setTitle(String title) {
         mTitle = title;
-        notifyPropertyChanged(new PropertyKey(PropertyKey.TITLE));
+        notifyPropertyChanged(PropertyKey.TITLE);
     }
 
     /** @return title The title to display in the toolbar. */
@@ -80,7 +90,7 @@
     /** @param visible Whether the toolbar shadow should be visible. */
     void setToolbarShadowVisibility(boolean visible) {
         mToolbarShadowVisibility = visible;
-        notifyPropertyChanged(new PropertyKey(PropertyKey.TOOLBAR_SHADOW_VISIBILITY));
+        notifyPropertyChanged(PropertyKey.TOOLBAR_SHADOW_VISIBILITY);
     }
 
     /** @return Whether the toolbar shadow should be visible. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/PropertyKey.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/PropertyKey.java
deleted file mode 100644
index 1d91af3..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/PropertyKey.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.contextual_suggestions;
-
-import android.support.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Contains a key uniquely identifying properties held in the {@link ContextualSuggestionsModel}.
- */
-class PropertyKey {
-    /** The unique identifiers for properties held in the model. */
-    @IntDef({CLOSE_BUTTON_ON_CLICK_LISTENER, TITLE, TOOLBAR_SHADOW_VISIBILITY})
-    @Retention(RetentionPolicy.SOURCE)
-    @interface Key {}
-    static final int CLOSE_BUTTON_ON_CLICK_LISTENER = 0;
-    static final int TITLE = 1;
-    static final int TOOLBAR_SHADOW_VISIBILITY = 2;
-
-    @Key
-    Integer mKey;
-
-    PropertyKey(@Key Integer key) {
-        mKey = key;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarCoordinator.java
index d8ace1b..a69fb79 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarCoordinator.java
@@ -10,6 +10,8 @@
 import android.view.ViewGroup;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsModel.PropertyKey;
+import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
 
 /**
  * Coordinator for the toolbar sub-component. Responsible for communication with the parent
@@ -18,7 +20,8 @@
 class ToolbarCoordinator {
     private final ContextualSuggestionsModel mModel;
     private ToolbarView mToolbarView;
-    private ToolbarModelChangeProcessor mModelChangeProcessor;
+    private PropertyModelChangeProcessor<ContextualSuggestionsModel, ToolbarView, PropertyKey>
+            mModelChangeProcessor;
 
     /**
      * Construct a new {@link ToolbarCoordinator}.
@@ -32,8 +35,14 @@
         mToolbarView = (ToolbarView) LayoutInflater.from(context).inflate(
                 R.layout.contextual_suggestions_toolbar, parentView, false);
 
-        mModelChangeProcessor = new ToolbarModelChangeProcessor(mToolbarView, mModel);
+        mModelChangeProcessor =
+                new PropertyModelChangeProcessor<>(mModel, mToolbarView, new ToolbarViewBinder());
         mModel.addObserver(mModelChangeProcessor);
+
+        // The ToolbarCoordinator is created dynamically as needed, so the initial model state
+        // needs to be bound on creation.
+        mModelChangeProcessor.onPropertyChanged(mModel, PropertyKey.CLOSE_BUTTON_ON_CLICK_LISTENER);
+        mModelChangeProcessor.onPropertyChanged(mModel, PropertyKey.TITLE);
     }
 
     /** @return The content {@link View}. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarModelChangeProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarModelChangeProcessor.java
deleted file mode 100644
index 7fc4760..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarModelChangeProcessor.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.contextual_suggestions;
-
-import org.chromium.chrome.browser.modelutil.PropertyObservable;
-import org.chromium.chrome.browser.modelutil.PropertyObservable.PropertyObserver;
-
-/**
- * A model change processor for use with a {@link ToolbarView}. The
- * {@link ToolbarModelChangeProcessor} should be registered as a property observer of
- * {@link ContextualSuggestionsModel}. Internally uses a view binder to bind model
- * properties to the toolbar view.
- */
-class ToolbarModelChangeProcessor implements PropertyObserver<PropertyKey> {
-    private static class ViewBinder {
-        /**
-         * Bind the changed property to the toolbar view.
-         * @param view The {@link ToolbarView} to which data will be bound.
-         * @param model The {@link ContextualSuggestionsModel} containing the data to be bound.
-         * @param propertyKey The {@link PropertyKey} of the property that has changed.
-         */
-        private static void bindProperty(
-                ToolbarView view, ContextualSuggestionsModel model, PropertyKey propertyKey) {
-            switch (propertyKey.mKey) {
-                case PropertyKey.CLOSE_BUTTON_ON_CLICK_LISTENER:
-                    view.setCloseButtonOnClickListener(model.getCloseButtonOnClickListener());
-                    break;
-                case PropertyKey.TITLE:
-                    view.setTitle(model.getTitle());
-                    break;
-                case PropertyKey.TOOLBAR_SHADOW_VISIBILITY:
-                    view.setShadowVisibility(model.getToolbarShadowVisibility());
-                    break;
-                default:
-                    assert false;
-            }
-        }
-    }
-
-    private final ToolbarView mToolbarView;
-    private final ContextualSuggestionsModel mModel;
-
-    /**
-     * Construct a new ToolbarModelChangeProcessor.
-     * @param view The {@link ToolbarView} to which data will be bound.
-     * @param model The {@link ContextualSuggestionsModel} containing the data to be bound.
-     */
-    ToolbarModelChangeProcessor(ToolbarView view, ContextualSuggestionsModel model) {
-        mToolbarView = view;
-        mModel = model;
-
-        // The ToolbarCoordinator is created dynamically as needed, so the initial model state
-        // needs to be bound on creation.
-        ViewBinder.bindProperty(
-                mToolbarView, mModel, new PropertyKey(PropertyKey.CLOSE_BUTTON_ON_CLICK_LISTENER));
-        ViewBinder.bindProperty(mToolbarView, mModel, new PropertyKey(PropertyKey.TITLE));
-    }
-
-    @Override
-    public void onPropertyChanged(PropertyObservable<PropertyKey> source, PropertyKey propertyKey) {
-        ViewBinder.bindProperty(mToolbarView, mModel, propertyKey);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarViewBinder.java
new file mode 100644
index 0000000..a5800b1
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarViewBinder.java
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.contextual_suggestions;
+
+import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsModel.PropertyKey;
+import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
+
+/**
+ * A view binder for use with a {@link ToolbarView}.
+ */
+class ToolbarViewBinder
+        implements PropertyModelChangeProcessor
+                           .ViewBinder<ContextualSuggestionsModel, ToolbarView, PropertyKey> {
+    @Override
+    public void bind(ContextualSuggestionsModel model, ToolbarView view, PropertyKey propertyKey) {
+        if (propertyKey == PropertyKey.CLOSE_BUTTON_ON_CLICK_LISTENER) {
+            view.setCloseButtonOnClickListener(model.getCloseButtonOnClickListener());
+        } else if (propertyKey == PropertyKey.TITLE) {
+            view.setTitle(model.getTitle());
+        } else if (propertyKey == PropertyKey.TOOLBAR_SHADOW_VISIBILITY) {
+            view.setShadowVisibility(model.getToolbarShadowVisibility());
+        } else {
+            assert false : "Unhandled property detected.";
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
index 3ea2fed4..dbf0a76 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -17,6 +17,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ApplicationStatus;
+import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.FileUtils;
 import org.chromium.base.Log;
@@ -33,6 +34,7 @@
 import org.chromium.chrome.browser.download.ui.BackendProvider.DownloadDelegate;
 import org.chromium.chrome.browser.download.ui.DownloadFilter;
 import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper;
+import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.OfflineItemWrapper;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.media.MediaViewerUtils;
 import org.chromium.chrome.browser.offlinepages.DownloadUiActionFlags;
@@ -67,8 +69,10 @@
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -306,13 +310,16 @@
     /**
      * Creates an Intent to share {@code items} with another app by firing an Intent to Android.
      *
-     * Sharing a DownloadItem shares the file itself, while sharing an OfflinePageItem shares the
-     * URL.
+     * Sharing a DownloadItem shares the file itself. Sharing an OfflinePageItem shares the archive
+     * file if the sharing is enabled. Otherwise, the URL is shared.
      *
      * @param items Items to share.
+     * @param newOfflineFilePathMap Map of id to new file path for those offline pages that are
+     *        published before sharing.
      * @return      Intent that can be used to share the items.
      */
-    public static Intent createShareIntent(List<DownloadHistoryItemWrapper> items) {
+    public static Intent createShareIntent(
+            List<DownloadHistoryItemWrapper> items, Map<String, String> newOfflineFilePathMap) {
         Intent shareIntent = new Intent();
         String intentAction;
         ArrayList<Uri> itemUris = new ArrayList<Uri>();
@@ -326,13 +333,34 @@
         for (int i = 0; i < items.size(); i++) {
             DownloadHistoryItemWrapper wrappedItem  = items.get(i);
 
-            if (wrappedItem.isOfflinePage() && !OfflinePageBridge.isPageSharingEnabled()) {
+            boolean shareUrl = false;
+            File file = null;
+            if (wrappedItem.isOfflinePage()) {
+                if (OfflinePageBridge.isPageSharingEnabled()) {
+                    if (newOfflineFilePathMap != null) {
+                        OfflineItemWrapper wrappedOfflineItem = (OfflineItemWrapper) wrappedItem;
+                        String newFilePath = newOfflineFilePathMap.get(wrappedOfflineItem.getId());
+                        if (newFilePath != null) {
+                            file = new File(newFilePath);
+                        }
+                    }
+                } else {
+                    // Share the URL, instead of the file, when the offline page sharing is
+                    // disabled.
+                    shareUrl = true;
+                }
+            }
+
+            if (shareUrl) {
                 if (offlinePagesString.length() != 0) {
                     offlinePagesString.append("\n");
                 }
                 offlinePagesString.append(wrappedItem.getUrl());
             } else {
-                itemUris.add(getUriForItem(wrappedItem.getFile()));
+                if (file == null) {
+                    file = wrappedItem.getFile();
+                }
+                itemUris.add(getUriForItem(file));
             }
 
             if (selectedItemsFilterType != wrappedItem.getFilterType()) {
@@ -391,7 +419,7 @@
 
         if (itemUris.size() == 1 && offlinePagesString.length() == 0) {
             // Sharing a downloaded item or an offline page.
-            shareIntent.putExtra(Intent.EXTRA_STREAM, getUriForItem(items.get(0).getFile()));
+            shareIntent.putExtra(Intent.EXTRA_STREAM, itemUris.get(0));
         } else {
             shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, itemUris);
         }
@@ -410,6 +438,72 @@
     }
 
     /**
+     * Performs all the necessary work needed to share download items. For offline pages, we may
+     * need to publish the internal archive file to public location first.
+     *
+     * @param items Items to share.
+     * @return True if the work is done or not needed and the sharing can start immediately.
+     *         False if the asynchronous work is in progress. After it is done, |callback| will be
+     *         invoked to inform the result.
+     */
+    public static boolean prepareForSharing(
+            List<DownloadHistoryItemWrapper> items, Callback<Map<String, String>> callback) {
+        if (!OfflinePageBridge.isPageSharingEnabled()) return true;
+
+        OfflinePageBridge offlinePageBridge =
+                OfflinePageBridge.getForProfile(Profile.getLastUsedProfile().getOriginalProfile());
+
+        // If the sharing of offline pages is enabled, we need to publish the archive files if they
+        // are still located in the internal directory.
+        List<OfflineItemWrapper> offlinePagesToPublish = new ArrayList<OfflineItemWrapper>();
+        for (int i = 0; i < items.size(); i++) {
+            DownloadHistoryItemWrapper wrappedItem = items.get(i);
+            if (wrappedItem.isOfflinePage()) {
+                OfflineItemWrapper wrappedOfflineItem = (OfflineItemWrapper) wrappedItem;
+                if (offlinePageBridge.isInPrivateDirectory(wrappedOfflineItem.getFilePath())) {
+                    offlinePagesToPublish.add(wrappedOfflineItem);
+                }
+            }
+        }
+
+        if (offlinePagesToPublish.isEmpty()) return true;
+
+        publishOfflinePagesForSharing(offlinePageBridge, offlinePagesToPublish, callback);
+        return false;
+    }
+
+    static void publishOfflinePagesForSharing(OfflinePageBridge offlinePageBridge,
+            List<OfflineItemWrapper> offlinePages, Callback<Map<String, String>> callback) {
+        // TODO(jianli): Check and request permission.
+        publishOfflinePageForSharing(
+                offlinePageBridge, offlinePages, 0, new HashMap<String, String>(), callback);
+    }
+
+    static void publishOfflinePageForSharing(OfflinePageBridge offlinePageBridge,
+            final List<OfflineItemWrapper> offlinePages, final int index,
+            final Map<String, String> newFilePathMap, Callback<Map<String, String>> callback) {
+        assert index < offlinePages.size();
+
+        final OfflineItemWrapper wrappedItem = offlinePages.get(index);
+        assert wrappedItem.isOfflinePage();
+
+        offlinePageBridge.publishInternalPageByGuid(wrappedItem.getId(), (newFilePath) -> {
+            if (!newFilePath.isEmpty()) {
+                newFilePathMap.put(wrappedItem.getId(), newFilePath);
+            }
+
+            int nextIndex = index + 1;
+            if (nextIndex >= offlinePages.size()) {
+                callback.onResult(newFilePathMap);
+                return;
+            }
+
+            publishOfflinePageForSharing(
+                    offlinePageBridge, offlinePages, nextIndex, newFilePathMap, callback);
+        });
+    }
+
+    /**
      * Returns a URI that points at the file.
      * @param file File to get a URI for.
      * @return URI that points at that file, either as a content:// URI or a file:// URI.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
index fc881af..1542a2d8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
@@ -283,7 +283,7 @@
 
     @Override
     public void shareItem(DownloadHistoryItemWrapper item) {
-        startShareIntent(DownloadUtils.createShareIntent(CollectionUtil.newArrayList(item)));
+        shareItems(CollectionUtil.newArrayList(item));
     }
 
     /**
@@ -369,7 +369,7 @@
             RecordHistogram.recordCount100Histogram(
                     "Android.DownloadManager.Menu.Share.SelectedCount", items.size());
 
-            startShareIntent(DownloadUtils.createShareIntent(items));
+            shareItems(items);
             return true;
         } else if (item.getItemId() == R.id.info_menu_id) {
             boolean showInfo = !mHistoryAdapter.shouldShowStorageInfoHeader();
@@ -543,4 +543,12 @@
         RecordHistogram.recordEnumeratedHistogram(
                 "Android.DownloadManager.Menu.Action", action, MENU_ACTION_BOUNDARY);
     }
+
+    private void shareItems(final List<DownloadHistoryItemWrapper> items) {
+        boolean done = DownloadUtils.prepareForSharing(items, (newFilePathMap) -> {
+            startShareIntent(DownloadUtils.createShareIntent(items, newFilePathMap));
+        });
+
+        if (done) startShareIntent(DownloadUtils.createShareIntent(items, null));
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index 374cb55..c3a4b24 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -562,19 +562,22 @@
 
     /**
      * Ask the native code to publish the internal page asychronously.
-     * @param profile Profile for current user.
      * @param offlineId ID of the offline page to publish.
-     * @param title Title of the offline page.
-     * @param url Url of the offline page.
-     * @param filePath Path to the file for the offline page.
-     * @param size Length of the offline page file.
      * @param publishedCallback Function to call when publishing is done.  This will be called
      *        with the new path of the file.
      */
-    public void publishInternalPage(Profile profile, long offlineId, String title, String url,
-            String filePath, long size, Callback<String> publishedCallback) {
-        nativePublishInternalPage(mNativeOfflinePageBridge, profile, offlineId, title, url,
-                filePath, size, publishedCallback);
+    public void publishInternalPageByOfflineId(long offlineId, Callback<String> publishedCallback) {
+        nativePublishInternalPageByOfflineId(
+                mNativeOfflinePageBridge, offlineId, publishedCallback);
+    }
+
+    /**
+     * Ask the native code to publish the internal page asychronously.
+     * @param guid Client ID of the offline page to publish.
+     * @param publishedCallback Function to call when publishing is done.
+     */
+    public void publishInternalPageByGuid(String guid, Callback<String> publishedCallback) {
+        nativePublishInternalPageByGuid(mNativeOfflinePageBridge, guid, publishedCallback);
     }
 
     /**
@@ -857,9 +860,11 @@
     native void nativeDeletePagesByOfflineId(
             long nativeOfflinePageBridge, long[] offlineIds, Callback<Integer> callback);
     @VisibleForTesting
-    private native void nativePublishInternalPage(long nativeOfflinePageBridge, Profile profile,
-            long offlineId, String title, String url, String filePath, long size,
-            Callback<String> publishedCallback);
+    private native void nativePublishInternalPageByOfflineId(
+            long nativeOfflinePageBridge, long offlineId, Callback<String> publishedCallback);
+    @VisibleForTesting
+    private native void nativePublishInternalPageByGuid(
+            long nativeOfflinePageBridge, String guid, Callback<String> publishedCallback);
 
     private native void nativeSelectPageForOnlineUrl(
             long nativeOfflinePageBridge, String onlineUrl, int tabId,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
index 022c51e..93005c1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -386,7 +386,7 @@
             // If the page is not in a public location, we must publish it before sharing it.
             if (offlinePageBridge.isInPrivateDirectory(offlinePath)) {
                 publishThenShareInternalPage(
-                        activity, tab.getProfile(), offlinePageBridge, offlinePage, shareCallback);
+                        activity, offlinePageBridge, offlinePage, shareCallback);
                 return;
             }
 
@@ -447,14 +447,13 @@
      * @param offlinePage Page to publish and share.
      * @param shareCallback The callback to be used to send the ShareParams.
      */
-    public static void publishThenShareInternalPage(final Activity activity, Profile profile,
+    public static void publishThenShareInternalPage(final Activity activity,
             OfflinePageBridge offlinePageBridge, OfflinePageItem offlinePage,
             final Callback<ShareParams> shareCallback) {
         Callback<String> publishPageCallback =
                 new PublishPageCallback(activity, offlinePage, shareCallback);
-        offlinePageBridge.publishInternalPage(profile, offlinePage.getOfflineId(),
-                offlinePage.getTitle(), offlinePage.getUrl(), offlinePage.getFilePath(),
-                offlinePage.getFileSize(), publishPageCallback);
+        offlinePageBridge.publishInternalPageByOfflineId(
+                offlinePage.getOfflineId(), publishPageCallback);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
index 48805a135..9072ef6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
@@ -9,6 +9,7 @@
 
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.BrowserControlsState;
 
 /**
  * An implementation of the {@link TabObserver} which has empty implementations of all methods.
@@ -123,4 +124,8 @@
 
     @Override
     public void onNavigationEntriesDeleted(Tab tab) {}
+
+    @Override
+    public void onBrowserControlsConstraintsUpdated(
+            Tab tab, @BrowserControlsState int constraints) {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 683d8fe..380ef2f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -424,6 +424,9 @@
      */
     private @Nullable String mTrustedCdnPublisherUrl;
 
+    /** The current browser controls constraints. -1 if not set. */
+    private @BrowserControlsState int mBrowserConstrolsConstraints = -1;
+
     private GestureStateListener createGestureStateListener() {
         return new GestureStateListener() {
             @Override
@@ -2832,6 +2835,12 @@
             @BrowserControlsState int current, boolean animate) {
         if (mNativeTabAndroid == 0) return;
         nativeUpdateBrowserControlsState(mNativeTabAndroid, constraints, current, animate);
+
+        if (constraints == mBrowserConstrolsConstraints) return;
+        mBrowserConstrolsConstraints = constraints;
+        for (TabObserver observer : mObservers) {
+            observer.onBrowserControlsConstraintsUpdated(this, constraints);
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java
index 8a8a4c5..07d6156f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java
@@ -12,6 +12,7 @@
 import org.chromium.content_public.browser.ContentViewCore;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.BrowserControlsState;
 
 /**
  * An observer that is notified of changes to a {@link Tab} object.
@@ -303,4 +304,11 @@
      * @param tab The notifying {@link Tab}.
      */
     public void onNavigationEntriesDeleted(Tab tab);
+
+    /**
+     * Called when the tab's browser controls constraints has been updated.
+     * @param tab The notifying {@link Tab}.
+     * @param constraints The updated browser controls constraints.
+     */
+    public void onBrowserControlsConstraintsUpdated(Tab tab, @BrowserControlsState int constraints);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index 913844f..a7518086 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -244,6 +244,12 @@
         return (intent == null) ? WebappInfo.createEmpty() : WebappInfo.create(intent);
     }
 
+    @Override
+    public void initializeState() {
+        super.initializeState();
+        initializeUI(getSavedInstanceState());
+    }
+
     protected void initializeUI(Bundle savedInstanceState) {
         // We do not load URL when restoring from saved instance states.
         if (savedInstanceState == null) {
@@ -324,12 +330,6 @@
 
     @Override
     public void finishNativeInitialization() {
-        if (!mWebappInfo.isInitialized()) {
-            ApiCompatibilityUtils.finishAndRemoveTask(this);
-            return;
-        }
-
-        initializeUI(getSavedInstanceState());
         LayoutManager layoutDriver = new LayoutManager(getCompositorViewHolder());
         initializeCompositorContent(layoutDriver, findViewById(R.id.url_bar),
                 (ViewGroup) findViewById(android.R.id.content),
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_am.xtb b/chrome/android/java/strings/translations/android_chrome_strings_am.xtb
index 8b131300..49ddd75 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_am.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_am.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">ወደ <ph name="SCREEN_NAME" /> በመውሰድ ላይ</translation>
 <translation id="7375125077091615385">ዓይነት፦</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">ስለ<ph name="TOPIC" /> ተጨማሪ</translation>
 <translation id="7403691278183511381">Chrome የመጀመሪያ አሂድ ተሞክሮ</translation>
 <translation id="7423098979219808738">መጀመሪያ ጠይቅ</translation>
 <translation id="7423538860840206698">ቅንጥብ ሰሌዳን ከማንበብ ታግዷል</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb
index ae3c2b5..74f5d01 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb
@@ -686,7 +686,6 @@
 <translation id="7366340029385295517">جارٍ الإرسال إلى <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">النوع:</translation>
 <translation id="7400418766976504921">‏عنوان URL</translation>
-<translation id="7400730245189251663">مزيد من الاقتراحات حول <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">‏أول تجربة تشغيل لمتصفح Chrome</translation>
 <translation id="7423098979219808738">السؤال أولاً</translation>
 <translation id="7423538860840206698">تم الحظر من قراءة الحافظة</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb b/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb
index 93f2a7f..36a05f8 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Предава се към „<ph name="SCREEN_NAME" />“</translation>
 <translation id="7375125077091615385">Тип:</translation>
 <translation id="7400418766976504921">URL адрес</translation>
-<translation id="7400730245189251663">Още за <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Представяне при първо стартиране на Chrome</translation>
 <translation id="7423098979219808738">Първо ще се извежда запитване</translation>
 <translation id="7423538860840206698">Достъпът за четене до буферната памет е блокиран</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
index 5b628c8f..e4da978 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">S'està emetent a <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Tipus:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Més contingut sobre <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Experiència de primera execució de Chrome</translation>
 <translation id="7423098979219808738">Pregunta-m'ho abans</translation>
 <translation id="7423538860840206698">L'accés de lectura al porta-retalls està bloquejat</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb b/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb
index 334cae0..8192e185 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb
@@ -241,7 +241,7 @@
 <translation id="3259831549858767975">Zmenšit veškerý obsah stránky</translation>
 <translation id="3269093882174072735">Načíst obrázek</translation>
 <translation id="3269956123044984603">Chcete-li získat přístup ke kartám ze svých ostatních zařízení, zapněte v nastavení účtu Android možnost Automatická synchronizace dat.</translation>
-<translation id="3282568296779691940">Přihlášení do Chrome</translation>
+<translation id="3282568296779691940">Přihlásit se do Chromu</translation>
 <translation id="32895400574683172">Oznámení jsou povolena</translation>
 <translation id="3295602654194328831">Skrýt informace</translation>
 <translation id="3303414029551471755">Chcete pokračovat ke stažení obsahu?</translation>
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Odesílání do zařízení <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Typ:</translation>
 <translation id="7400418766976504921">Adresa URL</translation>
-<translation id="7400730245189251663">Více o tématu <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">První spuštění Chromu</translation>
 <translation id="7423098979219808738">Nejprve se dotázat</translation>
 <translation id="7423538860840206698">Čtení schránky je blokováno</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_da.xtb b/chrome/android/java/strings/translations/android_chrome_strings_da.xtb
index a20d05e5..796656f 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_da.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_da.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Caster til <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Type:</translation>
 <translation id="7400418766976504921">Webadresse</translation>
-<translation id="7400730245189251663">Mere om <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Førstegangsoplevelse af Chrome</translation>
 <translation id="7423098979219808738">Spørg først</translation>
 <translation id="7423538860840206698">Blokeret fra at læse udklipsholderen</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_de.xtb b/chrome/android/java/strings/translations/android_chrome_strings_de.xtb
index e488d78f..f83e7f5e 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_de.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_de.xtb
@@ -247,7 +247,7 @@
 <translation id="3303414029551471755">Inhalt herunterladen?</translation>
 <translation id="3328801116991980348">Websiteinformationen</translation>
 <translation id="3341058695485821946">Sie können sich ansehen, wie viel Datenvolumen Sie einsparen</translation>
-<translation id="3350687908700087792">Alle Inkognitotabs schließen</translation>
+<translation id="3350687908700087792">Alle Inkognito-Tabs schließen</translation>
 <translation id="3365671512111106261">Nicht verfügbar, wenn der Datensparmodus aktiviert ist</translation>
 <translation id="3367813778245106622">Melden Sie sich nochmals an, um die Synchronisierung zu starten</translation>
 <translation id="3384347053049321195">Bild teilen</translation>
@@ -686,7 +686,6 @@
 <translation id="7366340029385295517">Übertragung an <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Typ:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Weitere Informationen zu <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Eindruck beim ersten Ausführen von Chrome</translation>
 <translation id="7423098979219808738">Zuerst fragen</translation>
 <translation id="7423538860840206698">Es dürfen keine Dateien aus der Zwischenablage abgerufen werden</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_el.xtb b/chrome/android/java/strings/translations/android_chrome_strings_el.xtb
index 01e67244..fb85c8f 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_el.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_el.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Μετάδοση στη συσκευή <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Τύπος:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Περισσότερα σχετικά με <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Εμπειρία πρώτης εκτέλεσης Chrome</translation>
 <translation id="7423098979219808738">Να γίνεται ερώτηση πρώτα</translation>
 <translation id="7423538860840206698">Αποκλεισμός από ανάγνωση πρόχειρου</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb b/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb
index 360c6cc..43593d73 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Casting to <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Type:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">More about <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Chrome First Run Experience</translation>
 <translation id="7423098979219808738">Ask first</translation>
 <translation id="7423538860840206698">Blocked from reading clipboard</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb b/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
index bb3a3c4..b86a3c97 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Transmitiendo a <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Tipo:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Más información sobre <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Primera experiencia de ejecución de Chrome</translation>
 <translation id="7423098979219808738">Preguntar primero</translation>
 <translation id="7423538860840206698">Se impidió la lectura del portapapeles</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_es.xtb b/chrome/android/java/strings/translations/android_chrome_strings_es.xtb
index d2c17f0c..8b04ade37 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_es.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_es.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Enviando contenido a <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Tipo:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Más información sobre <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Primera experiencia de ejecución de Chrome</translation>
 <translation id="7423098979219808738">Preguntar antes</translation>
 <translation id="7423538860840206698">Se ha bloqueado la lectura del portapapeles</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb
index dec35e0..ea9648c 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb
@@ -684,7 +684,6 @@
 <translation id="7366340029385295517">درحال فرستادن به <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">نوع:</translation>
 <translation id="7400418766976504921">نشانی وب</translation>
-<translation id="7400730245189251663">اطلاعات بیشتر درباره <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">‏اولین تجربه اجرا Chrome</translation>
 <translation id="7423098979219808738">ابتدا سؤال شود</translation>
 <translation id="7423538860840206698">خواندن محتوای بریده‌دان مسدود شد</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb
index bd1781d..5d647b7 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Suoratoistetaan näytöllä <ph name="SCREEN_NAME" />.</translation>
 <translation id="7375125077091615385">Tyyppi:</translation>
 <translation id="7400418766976504921">URL-osoite</translation>
-<translation id="7400730245189251663">Lisätietoja aiheesta <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Chromen ensimmäinen käyttökerta</translation>
 <translation id="7423098979219808738">Kysy ensin</translation>
 <translation id="7423538860840206698">Leikepöydältä lukeminen estetty</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb
index c6ec871..4136b50 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Nagka-cast sa <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Uri:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Higit pa tungkol sa <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Unang Karanasan sa Pagtakbo ng Chrome</translation>
 <translation id="7423098979219808738">Magtanong muna</translation>
 <translation id="7423538860840206698">Na-block sa pag-read ng clipboard</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb
index 7a6f874..007c252 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Diffusion sur "<ph name="SCREEN_NAME" />" en cours…</translation>
 <translation id="7375125077091615385">Type :</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">En savoir plus sur <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Expérience de première utilisation de Chrome</translation>
 <translation id="7423098979219808738">Demander d'abord</translation>
 <translation id="7423538860840206698">Accès en lecture au presse-papiers bloqué</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb b/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb
index ef9b290..6c26a4e 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517"><ph name="SCREEN_NAME" /> पर कास्ट किया जा रहा है</translation>
 <translation id="7375125077091615385">प्रकार:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663"><ph name="TOPIC" /> के बारे में और सुझाव</translation>
 <translation id="7403691278183511381">Chrome पहली बार चलाने का अनुभव</translation>
 <translation id="7423098979219808738">पहले पूछें</translation>
 <translation id="7423538860840206698">क्लिपबोर्ड पढ़ने से ब्लॉक किया गया है</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb
index 457fc2c4..58d07c9 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Emitiranje na uređaj <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Vrsta:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Više o temi <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Chromeov doživljaj prvog pokretanja</translation>
 <translation id="7423098979219808738">Prvo pitaj</translation>
 <translation id="7423538860840206698">Blokirano je čitanje međuspremnika</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb b/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb
index 43001b00..9fa6d35 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Átküldés a következőre: <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Típus:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">További információ a következőről: <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Chrome – Első futtatási élmény</translation>
 <translation id="7423098979219808738">Kérdezzen rá</translation>
 <translation id="7423538860840206698">Le van tiltva a vágólap megtekintése</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_id.xtb b/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
index 8ee8b24..7dd3a38 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Mentransmisikan ke <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Jenis:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Selengkapnya tentang <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Pengalaman Penggunaan Pertama Chrome</translation>
 <translation id="7423098979219808738">Tanyakan terlebih dahulu</translation>
 <translation id="7423538860840206698">Diblokir agar tidak membaca papan klip</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_it.xtb b/chrome/android/java/strings/translations/android_chrome_strings_it.xtb
index 970236be..a18a1b8 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_it.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_it.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Trasmissione su <ph name="SCREEN_NAME" /> in corso</translation>
 <translation id="7375125077091615385">Tipo:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Altro su <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Esperienza prima esecuzione di Chrome</translation>
 <translation id="7423098979219808738">Chiedi prima</translation>
 <translation id="7423538860840206698">Lettura degli appunti non consentita</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb b/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb
index 313505d..8b49e72 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">מעביר אל <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">סוג:</translation>
 <translation id="7400418766976504921">כתובת אתר</translation>
-<translation id="7400730245189251663">מידע נוסף על <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">‏חוויית ההפעלה הראשונה של Chrome</translation>
 <translation id="7423098979219808738">בקש אישור</translation>
 <translation id="7423538860840206698">הגישה לקריאה מלוח העריכה נחסמה</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb
index 36281880..cbcf864 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517"><ph name="SCREEN_NAME" />にキャストしています</translation>
 <translation id="7375125077091615385">タイプ:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">「<ph name="TOPIC" />」の詳細</translation>
 <translation id="7403691278183511381">Chrome 初回起動時の操作</translation>
 <translation id="7423098979219808738">最初に確認する</translation>
 <translation id="7423538860840206698">クリップボードの読み取りがブロックされています</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb
index fd2599781..d1e7670 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517"><ph name="SCREEN_NAME" />(으)로 전송 중</translation>
 <translation id="7375125077091615385">유형:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663"><ph name="TOPIC" />에 관해 자세히 알아보기</translation>
 <translation id="7403691278183511381">Chrome 첫 실행</translation>
 <translation id="7423098979219808738">우선 확인</translation>
 <translation id="7423538860840206698">클립보드 액세스가 차단됨</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb b/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb
index 3560623..3330ed3 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Perduodama į ekraną „<ph name="SCREEN_NAME" />“</translation>
 <translation id="7375125077091615385">Tipas:</translation>
 <translation id="7400418766976504921">URL adresas</translation>
-<translation id="7400730245189251663">Daugiau apie „<ph name="TOPIC" />“</translation>
 <translation id="7403691278183511381">„Chrome“ pirmosios paleisties patirtis</translation>
 <translation id="7423098979219808738">Pirmiausia paklausti</translation>
 <translation id="7423538860840206698">Neleidžiama skaityti iškarpinės</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb b/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb
index 232d3905e..9f6efdf9 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Notiek apraide uz ekrānu “<ph name="SCREEN_NAME" />”</translation>
 <translation id="7375125077091615385">Veids:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Vairāk par: <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Chrome pirmās palaišanas pieredze</translation>
 <translation id="7423098979219808738">Vispirms jautāt</translation>
 <translation id="7423538860840206698">Bloķēta starpliktuves satura lasīšana</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb
index af5d092..97d3f579 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Casten naar <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Type:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Meer over <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Functionaliteit bij eerste uitvoering van Chrome</translation>
 <translation id="7423098979219808738">Eerst vragen</translation>
 <translation id="7423538860840206698">Lezen van het klembord geblokkeerd</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_no.xtb b/chrome/android/java/strings/translations/android_chrome_strings_no.xtb
index c619aa9..1870168 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_no.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_no.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Caster til <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Type:</translation>
 <translation id="7400418766976504921">Nettadresse</translation>
-<translation id="7400730245189251663">Mer om <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Førsteinntrykk ved bruk av Chrome</translation>
 <translation id="7423098979219808738">Spør først.</translation>
 <translation id="7423538860840206698">Blokkert fra å lese utklippstavlen</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb
index 01634a0f..ab9b5f2 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Przesyłam na ekran <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Typ:</translation>
 <translation id="7400418766976504921">Adres URL</translation>
-<translation id="7400730245189251663">Więcej o: <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Pierwsze uruchomienie Chrome</translation>
 <translation id="7423098979219808738">Najpierw zapytaj</translation>
 <translation id="7423538860840206698">Zablokowano odczytywanie schowka</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb b/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb
index 4f08e65..5c56651 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb
@@ -684,7 +684,6 @@
 <translation id="7366340029385295517">Transmitindo em <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Tipo:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Mais sobre <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Tela de apresentação do Chrome</translation>
 <translation id="7423098979219808738">Perguntar primeiro</translation>
 <translation id="7423538860840206698">Leitura da área de transferência bloqueada</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb b/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb
index 1d3039e..1ef1564 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">A transmitir para <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Tipo:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Mais acerca de <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Experiência de primeira execução do Chrome</translation>
 <translation id="7423098979219808738">Perguntar primeiro</translation>
 <translation id="7423538860840206698">Leitura da área de transferência bloqueada</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb
index 66c28fb..4ffb170bd 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Se proiectează pe <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Tip:</translation>
 <translation id="7400418766976504921">Adresă URL</translation>
-<translation id="7400730245189251663">Mai multe despre <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Experiența primei rulări Chrome</translation>
 <translation id="7423098979219808738">Mai întâi întreabă</translation>
 <translation id="7423538860840206698">Citirea clipboardului este blocată</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
index e295cc05..d5de496 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Транслируется на экран устройства "<ph name="SCREEN_NAME" />"</translation>
 <translation id="7375125077091615385">Тип:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663"><ph name="TOPIC" />: подробная информация</translation>
 <translation id="7403691278183511381">Первый запуск Chrome</translation>
 <translation id="7423098979219808738">Всегда спрашивать</translation>
 <translation id="7423538860840206698">Доступ к данным в буфере обмена заблокирован</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb
index 7cdf1a5..718af52 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Prenáša sa na obrazovku <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Typ:</translation>
 <translation id="7400418766976504921">Webová adresa</translation>
-<translation id="7400730245189251663">Viac o téme <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Skúsenosť pri prvom spustení Chromu</translation>
 <translation id="7423098979219808738">Najprv sa spýtať</translation>
 <translation id="7423538860840206698">Blokovať čítanie schránky</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
index 6f56462..e6c1135 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Predvajanje na zaslonu <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Vrsta:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Več o tem: <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Izkušnje ob prvem izvajanju Chroma</translation>
 <translation id="7423098979219808738">Najprej vprašaj</translation>
 <translation id="7423538860840206698">Blokirano branje vsebine odložišča</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb
index 9213f11..cc9990b 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Пребацивање на <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Тип:</translation>
 <translation id="7400418766976504921">URL адреса</translation>
-<translation id="7400730245189251663">Више о теми <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Chrome доживљај првог покретања</translation>
 <translation id="7423098979219808738">Прво питај</translation>
 <translation id="7423538860840206698">Читање привремене меморије је блокирано</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb
index e2cc383f..bd677ef 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Castar till <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Typ:</translation>
 <translation id="7400418766976504921">Webbadress</translation>
-<translation id="7400730245189251663">Mer om <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Första körningen av Chrome</translation>
 <translation id="7423098979219808738">Fråga först</translation>
 <translation id="7423538860840206698">Läsbehörighet till Urklipp har nekats</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb
index c1c489e..efaf5a09 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Inatuma kwenye <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Aina:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Maelezo zaidi kuhusu <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Hali ya Utekelezaji wa Kwanza wa Chrome</translation>
 <translation id="7423098979219808738">Uliza kwanza</translation>
 <translation id="7423538860840206698">Imezuiwa kusoma ubao wa kunakili</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_th.xtb b/chrome/android/java/strings/translations/android_chrome_strings_th.xtb
index dda8002..445075b 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_th.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_th.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">กำลังส่งไปยัง <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">ประเภท:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">คำแนะนำเพิ่มเติมเกี่ยวกับ <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">ประสบการณ์กับ First Run บน Chrome</translation>
 <translation id="7423098979219808738">ถามก่อน</translation>
 <translation id="7423538860840206698">บล็อกไม่ให้อ่านคลิปบอร์ด</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb
index 152b703..d3e6d555 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517"><ph name="SCREEN_NAME" /> ekranına yayınlanıyor</translation>
 <translation id="7375125077091615385">Tür:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663"><ph name="TOPIC" /> ile ilgili daha fazla bilgi</translation>
 <translation id="7403691278183511381">Chrome İlk Çalıştırma Deneyimi</translation>
 <translation id="7423098979219808738">Önce sor</translation>
 <translation id="7423538860840206698">Pano okuma engellendi</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb b/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb
index 9619253d..9b0401a3 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Трансляція на екран "<ph name="SCREEN_NAME" />"</translation>
 <translation id="7375125077091615385">Тип:</translation>
 <translation id="7400418766976504921">URL-адреса</translation>
-<translation id="7400730245189251663">Більше на тему "<ph name="TOPIC" />"</translation>
 <translation id="7403691278183511381">Перший запуск Chrome</translation>
 <translation id="7423098979219808738">Спершу запитувати</translation>
 <translation id="7423538860840206698">Заборонено переглядати буфер обміну</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb b/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb
index 8cbb679f..3c06c25 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">Đang truyền tới <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">Loại:</translation>
 <translation id="7400418766976504921">URL</translation>
-<translation id="7400730245189251663">Thêm thông tin về <ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Trải nghiệm lần chạy đầu tiên của Chrome</translation>
 <translation id="7423098979219808738">Hỏi trước</translation>
 <translation id="7423538860840206698">Đã chặn quyền đọc khay nhớ tạm</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb b/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
index 5a1c09cc..4f1e670 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">正在投射至<ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">类型:</translation>
 <translation id="7400418766976504921">网址</translation>
-<translation id="7400730245189251663">详细了解<ph name="TOPIC" /></translation>
 <translation id="7403691278183511381">Chrome 首次运行体验</translation>
 <translation id="7423098979219808738">先询问</translation>
 <translation id="7423538860840206698">已阻止读取剪贴板中的内容</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb b/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb
index 59d3fc7b..423c06f8 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb
@@ -685,7 +685,6 @@
 <translation id="7366340029385295517">正在投放到 <ph name="SCREEN_NAME" /></translation>
 <translation id="7375125077091615385">類型:</translation>
 <translation id="7400418766976504921">網址</translation>
-<translation id="7400730245189251663">更多「<ph name="TOPIC" />」相關內容</translation>
 <translation id="7403691278183511381">Chrome 初次使用體驗</translation>
 <translation id="7423098979219808738">先詢問我</translation>
 <translation id="7423538860840206698">禁止讀取剪貼簿</translation>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index f36aa9d..09b7b9d 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -305,10 +305,9 @@
   "java/src/org/chromium/chrome/browser/contextual_suggestions/DummyEventReporter.java",
   "java/src/org/chromium/chrome/browser/contextual_suggestions/EnabledStateMonitor.java",
   "java/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelper.java",
-  "java/src/org/chromium/chrome/browser/contextual_suggestions/PropertyKey.java",
   "java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarCoordinator.java",
-  "java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarModelChangeProcessor.java",
   "java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarView.java",
+  "java/src/org/chromium/chrome/browser/contextual_suggestions/ToolbarViewBinder.java",
   "java/src/org/chromium/chrome/browser/cookies/CanonicalCookie.java",
   "java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java",
   "java/src/org/chromium/chrome/browser/coordinator/CoordinatorLayoutForPointer.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
index ffe68663..40f1e03 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
@@ -35,6 +35,7 @@
 import org.chromium.chrome.browser.download.ui.DownloadHistoryAdapter;
 import org.chromium.chrome.browser.download.ui.DownloadHistoryItemViewHolder;
 import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper;
+import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.OfflineItemWrapper;
 import org.chromium.chrome.browser.download.ui.DownloadItemView;
 import org.chromium.chrome.browser.download.ui.DownloadManagerToolbar;
 import org.chromium.chrome.browser.download.ui.DownloadManagerUi;
@@ -52,6 +53,7 @@
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.ui.test.util.UiRestriction;
 
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -528,7 +530,7 @@
         // Select an image, download item #6.
         toggleItemSelection(2);
         Intent shareIntent = DownloadUtils.createShareIntent(
-                mUi.getBackendProvider().getSelectionDelegate().getSelectedItems());
+                mUi.getBackendProvider().getSelectionDelegate().getSelectedItems(), null);
         Assert.assertEquals("Incorrect intent action", Intent.ACTION_SEND, shareIntent.getAction());
         Assert.assertEquals("Incorrect intent mime type", "image/png", shareIntent.getType());
         Assert.assertNotNull(
@@ -543,7 +545,7 @@
         // Select another image, download item #0.
         toggleItemSelection(9);
         shareIntent = DownloadUtils.createShareIntent(
-                mUi.getBackendProvider().getSelectionDelegate().getSelectedItems());
+                mUi.getBackendProvider().getSelectionDelegate().getSelectedItems(), null);
         Assert.assertEquals(
                 "Incorrect intent action", Intent.ACTION_SEND_MULTIPLE, shareIntent.getAction());
         Assert.assertEquals("Incorrect intent mime type", "image/*", shareIntent.getType());
@@ -557,7 +559,7 @@
         // Select non-image item, download item #4.
         toggleItemSelection(6);
         shareIntent = DownloadUtils.createShareIntent(
-                mUi.getBackendProvider().getSelectionDelegate().getSelectedItems());
+                mUi.getBackendProvider().getSelectionDelegate().getSelectedItems(), null);
         Assert.assertEquals(
                 "Incorrect intent action", Intent.ACTION_SEND_MULTIPLE, shareIntent.getAction());
         Assert.assertEquals("Incorrect intent mime type", "*/*", shareIntent.getType());
@@ -571,7 +573,7 @@
         // Select an offline page #3.
         toggleItemSelection(3);
         shareIntent = DownloadUtils.createShareIntent(
-                mUi.getBackendProvider().getSelectionDelegate().getSelectedItems());
+                mUi.getBackendProvider().getSelectionDelegate().getSelectedItems(), null);
         Assert.assertEquals(
                 "Incorrect intent action", Intent.ACTION_SEND_MULTIPLE, shareIntent.getAction());
         Assert.assertEquals("Incorrect intent mime type", "*/*", shareIntent.getType());
@@ -597,7 +599,7 @@
         List<DownloadHistoryItemWrapper> selected_items =
                 mUi.getBackendProvider().getSelectionDelegate().getSelectedItems();
         Assert.assertEquals("There should be only one item selected", 1, selected_items.size());
-        Intent shareIntent = DownloadUtils.createShareIntent(selected_items);
+        Intent shareIntent = DownloadUtils.createShareIntent(selected_items, null);
 
         Assert.assertEquals("Incorrect intent action", Intent.ACTION_SEND, shareIntent.getAction());
         Assert.assertEquals("Incorrect intent mime type", "*/*", shareIntent.getType());
@@ -608,6 +610,22 @@
                 shareIntent.getParcelableExtra(Intent.EXTRA_STREAM).toString());
         Assert.assertNull("Intent expected to not have any text for offline page",
                 IntentUtils.safeGetStringExtra(shareIntent, Intent.EXTRA_TEXT));
+
+        // Pass a map that contains a new file path.
+        HashMap<String, String> newFilePathMap = new HashMap<String, String>();
+        newFilePathMap.put(((OfflineItemWrapper) selected_items.get(0)).getId(),
+                "/data/new_fake_path/Downloads/4");
+        shareIntent = DownloadUtils.createShareIntent(selected_items, newFilePathMap);
+
+        Assert.assertEquals("Incorrect intent action", Intent.ACTION_SEND, shareIntent.getAction());
+        Assert.assertEquals("Incorrect intent mime type", "*/*", shareIntent.getType());
+        Assert.assertNotNull("Intent expected to have parcelable ArrayList",
+                shareIntent.getParcelableExtra(Intent.EXTRA_STREAM));
+        Assert.assertEquals("Intent expected to have parcelable Uri",
+                "file:///data/new_fake_path/Downloads/4",
+                shareIntent.getParcelableExtra(Intent.EXTRA_STREAM).toString());
+        Assert.assertNull("Intent expected to not have any text for offline page",
+                IntentUtils.safeGetStringExtra(shareIntent, Intent.EXTRA_TEXT));
     }
 
     @Test
diff --git a/chrome/android/profiles/update_afdo_profile.py b/chrome/android/profiles/update_afdo_profile.py
index fea89cf..4a9610b 100755
--- a/chrome/android/profiles/update_afdo_profile.py
+++ b/chrome/android/profiles/update_afdo_profile.py
@@ -15,6 +15,7 @@
 https."""
 
 import argparse
+import contextlib
 import os
 import subprocess
 import sys
@@ -72,20 +73,32 @@
 def RetrieveProfile(desired_profile_name, out_path):
   # vpython is > python 2.7.9, so we can expect urllib to validate HTTPS certs
   # properly.
-  compressed_path = out_path + '.bz2'
-  u = urllib2.urlopen(GS_BASE_URL + '/' + desired_profile_name)
-  with open(compressed_path, 'wb') as f:
-    while True:
-      buf = u.read(4096)
-      if not buf:
-        break
-      f.write(buf)
+  ext = os.path.splitext(desired_profile_name)[1]
+  compressed_path = out_path + ext
+  gs_url = GS_BASE_URL + '/' + desired_profile_name
+  with contextlib.closing(urllib2.urlopen(gs_url)) as u:
+    with open(compressed_path, 'wb') as f:
+      while True:
+        buf = u.read(4096)
+        if not buf:
+          break
+        f.write(buf)
 
-  # NOTE: we can't use Python's bzip module, since it doesn't support
-  # multi-stream bzip files. It will silently succeed and give us a garbage
-  # profile.
-  # bzip2 removes the compressed file on success.
-  CheckCallOrExit(['bzip2', '-d', compressed_path])
+  if ext == '.bz2':
+    # NOTE: we can't use Python's bzip module, since it doesn't support
+    # multi-stream bzip files. It will silently succeed and give us a garbage
+    # profile.
+    # bzip2 removes the compressed file on success.
+    CheckCallOrExit(['bzip2', '-d', compressed_path])
+  elif ext == '.xz':
+    # ...And we can't use the `lzma` module, since it was introduced in python3.
+    # xz removes the compressed file on success.
+    CheckCallOrExit(['xz', '-d', compressed_path])
+  else:
+    # Wait until after downloading the file to check the file extension, so the
+    # user has something usable locally if the file extension is unrecognized.
+    raise ValueError(
+        'Only bz2 and xz extensions are supported; "%s" is not' % ext)
 
 
 def CleanProfilesDirectory():
diff --git a/chrome/app/resources/generated_resources_am.xtb b/chrome/app/resources/generated_resources_am.xtb
index a6afadaf..4956530 100644
--- a/chrome/app/resources/generated_resources_am.xtb
+++ b/chrome/app/resources/generated_resources_am.xtb
@@ -3668,7 +3668,6 @@
           ይህ ሥዕል በChromebook መለያ መግቢያ ማያ ገጽ እና ማያ ገጽ ቁልፍ ላይ ይታያል።</translation>
 <translation id="6769712124046837540">አታሚን በማከል ላይ...</translation>
 <translation id="6771503742377376720">የእውቅና ማረጋገጫ ባለስልጣን ነው</translation>
-<translation id="6773575010135450071">ተጨማሪ እርምጃዎች...</translation>
 <translation id="6777817260680419853">አቅጣጫ ማዞር ታግዷል</translation>
 <translation id="6778959797435875428">ከጣቢያዎች ድምፀ-ከል አንሳ</translation>
 <translation id="677965093459947883">በጣም ትንሽ</translation>
@@ -4199,7 +4198,6 @@
 <translation id="7629827748548208700">ትር፦ <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;ሁልጊዜ እንዲህ አይነት ፋይሎችን ክፈት</translation>
 <translation id="7632948528260659758">የሚከተሉትን የኪዮስክ መተግበሪያዎች ማዘመን አልተሳካም፦</translation>
-<translation id="7634373849852678655">ከሙሉ ማያ ገጽ ለመውጣት የመተግበሪያ አዝራሩን ይጫኑ</translation>
 <translation id="7639178625568735185">ገባኝ!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> እርስዎን ባስቀመጧቸው ይለፍ ቃላት ወደ ብቁ ጣቢያዎች ያስገባዎታል።</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (ባለቤት)</translation>
diff --git a/chrome/app/resources/generated_resources_ar.xtb b/chrome/app/resources/generated_resources_ar.xtb
index a640f51..97f3db2 100644
--- a/chrome/app/resources/generated_resources_ar.xtb
+++ b/chrome/app/resources/generated_resources_ar.xtb
@@ -3667,7 +3667,6 @@
           ستظهر هذه الصورة على قفل الشاشة وشاشة تسجيل الدخول في جهاز Chromebook.</translation>
 <translation id="6769712124046837540">جارٍ إضافة طابعة...</translation>
 <translation id="6771503742377376720">هو مرجع مصدق</translation>
-<translation id="6773575010135450071">مزيد من الإجراءات...</translation>
 <translation id="6777817260680419853">تم حظر إعادة التوجيه</translation>
 <translation id="6778959797435875428">إلغاء تجاهل المواقع</translation>
 <translation id="677965093459947883">صغير جدًا</translation>
@@ -4198,7 +4197,6 @@
 <translation id="7629827748548208700">علامة التبويب: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">فت&amp;ح هذا النوع من الملفات دومًا</translation>
 <translation id="7632948528260659758">‏فشل تحديث تطبيقات kiosk التالية:</translation>
-<translation id="7634373849852678655">الضغط على زر التطبيق للخروج من وضع ملء الشاشة</translation>
 <translation id="7639178625568735185">تم إنشاء الحساب!</translation>
 <translation id="764017888128728">يعمل <ph name="PASSWORD_MANAGER_BRAND" /> على تسجيل دخولك تلقائيًا إلى المواقع المؤهلة باستخدام كلمات المرور التي حفظتها.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (المالك)</translation>
diff --git a/chrome/app/resources/generated_resources_bg.xtb b/chrome/app/resources/generated_resources_bg.xtb
index 9c1eb6b..99347f6 100644
--- a/chrome/app/resources/generated_resources_bg.xtb
+++ b/chrome/app/resources/generated_resources_bg.xtb
@@ -3670,7 +3670,6 @@
 Снимката ще се показва на заключения екран и на този за вход в Chromebook.</translation>
 <translation id="6769712124046837540">Добавяне на принтер...</translation>
 <translation id="6771503742377376720">Е сертифициращ орган</translation>
-<translation id="6773575010135450071">Още действия...</translation>
 <translation id="6777817260680419853">Блокирано бе пренасочване</translation>
 <translation id="6778959797435875428">Включване на звука за сайтовете</translation>
 <translation id="677965093459947883">Много малък</translation>
@@ -4201,7 +4200,6 @@
 <translation id="7629827748548208700">Раздел: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Файловете от този тип да се отварят винаги</translation>
 <translation id="7632948528260659758">Актуализирането на следните павилионни приложения не бе успешно:</translation>
-<translation id="7634373849852678655">Натиснете бутона за приложения, за да излезете от режима на цял екран.</translation>
 <translation id="7639178625568735185">Разбрах!</translation>
 <translation id="764017888128728">С помощта на <ph name="PASSWORD_MANAGER_BRAND" /> автоматично влизате в отговарящи на условията сайтове с паролите, които сте запазили.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (собственик)</translation>
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb
index 9667811..107d361 100644
--- a/chrome/app/resources/generated_resources_bn.xtb
+++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -3246,7 +3246,7 @@
 <translation id="6105158702728922449">আপনার ক্যামেরা এবং মাইক্রোফোন ব্যবহার করুন৷</translation>
 <translation id="6105877918873366097">শেষবার অ্যাক্সেস করা হয়েছে</translation>
 <translation id="6107012941649240045">একে ইস্যু করা হয়েছিল</translation>
-<translation id="6112294629795967147">আকার পরিবর্তন করতে স্পর্শ করুন</translation>
+<translation id="6112294629795967147">সাইজ পরিবর্তন করতে টাচ করুন</translation>
 <translation id="6112952769866305444">ব্যক্তি <ph name="PROFILE_NAME" />, <ph name="USERNAME" /> এর সম্পাদনা করুন</translation>
 <translation id="6115424132962100663">ফিরে যেতে |<ph name="SHORTCUT" />| টিপুন</translation>
 <translation id="6116338172782435947">ক্লিপবোর্ডে কপি করা টেক্সট এবং ছবি দেখতে</translation>
@@ -3633,7 +3633,7 @@
 <translation id="6718273304615422081">জিপ করা হচ্ছে...</translation>
 <translation id="671928215901716392">স্ক্রিন লক করুন</translation>
 <translation id="67211069045302358">এই সাইটের সেটিংস রিসেট করবেন?</translation>
-<translation id="6721678857435001674">আপনার নিরাপত্তা কী তৈরি এবং মডেলটি দেখুন</translation>
+<translation id="6721678857435001674">আপনার নিরাপত্তা কী-এর কোম্পানির নাম এবং মডেলটি দেখুন</translation>
 <translation id="6721972322305477112">&amp;File</translation>
 <translation id="672213144943476270">দয়া করে অতিথি হিসাবে ব্রাউজ করার আগে আপনার প্রোফাইলটি আনলক করুন।</translation>
 <translation id="6723354935081862304">Google দস্তাবেজ এবং অন্য ক্লাউড গন্তব্যস্থল প্রিন্ট করুন৷ Google ক্লাউড প্রিন্টে প্রিন্ট করতে <ph name="BEGIN_LINK" />প্রবেশ করুন<ph name="END_LINK" /> করুন৷</translation>
@@ -3667,7 +3667,6 @@
           এই ফটোটি Chromebook সাইন-ইন স্ক্রিন এবং লক স্ক্রিনে প্রদর্শিত হবে।</translation>
 <translation id="6769712124046837540">প্রিন্টার যোগ করা হচ্ছে...</translation>
 <translation id="6771503742377376720">একটি শংসাপত্রের কর্তৃপক্ষ</translation>
-<translation id="6773575010135450071">আরও অ্যাকশন...</translation>
 <translation id="6777817260680419853">রিডাইরেক্ট ব্লক করা হয়েছে</translation>
 <translation id="6778959797435875428">সাইটগুলি আনমিউট করুন</translation>
 <translation id="677965093459947883">অতি ক্ষুদ্র</translation>
@@ -4197,7 +4196,6 @@
 <translation id="7629827748548208700">ট্যাব: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;সর্বদা এই ধরনের ফাইল খুলুন</translation>
 <translation id="7632948528260659758">নিম্নলিখিত kiosk অ্যাপ্লিকেশানগুলি আপডেট হতে ব্যর্থ হয়েছে:</translation>
-<translation id="7634373849852678655">ফুলস্ক্রিন থেকে বেরিয়ে যাওয়ার জন্য অ্যাপ বোতামটি টিপুন</translation>
 <translation id="7639178625568735185">বুঝেছি!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> স্বয়ংক্রিয়ভাবে আপনার সংরক্ষণ করা পাসওয়ার্ড দিয়ে উপযুক্ত সাইটগুলিতে আপনাকে প্রবেশ করায়।</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (মালিক)</translation>
diff --git a/chrome/app/resources/generated_resources_ca.xtb b/chrome/app/resources/generated_resources_ca.xtb
index 924c0a4..971bf3f6 100644
--- a/chrome/app/resources/generated_resources_ca.xtb
+++ b/chrome/app/resources/generated_resources_ca.xtb
@@ -3670,7 +3670,6 @@
           Aquesta foto es mostrarà a la pantalla d'inici de sessió i a la pantalla de bloqueig de Chromebook.</translation>
 <translation id="6769712124046837540">S'està afegint la impressora...</translation>
 <translation id="6771503742377376720">És una entitat emissora de certificats</translation>
-<translation id="6773575010135450071">Més accions...</translation>
 <translation id="6777817260680419853">S'ha bloquejat la redirecció</translation>
 <translation id="6778959797435875428">Activa el so dels llocs web</translation>
 <translation id="677965093459947883">Molt petita</translation>
@@ -4193,7 +4192,6 @@
 <translation id="7629827748548208700">Pestanya: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Obre &amp;sempre els fitxers d'aquest tipus</translation>
 <translation id="7632948528260659758">No s'han pogut actualitzar les aplicacions següents del quiosc:</translation>
-<translation id="7634373849852678655">Prem el botó Aplicació per sortir de la pantalla completa</translation>
 <translation id="7639178625568735185">D'acord</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> us inicia la sessió automàticament als llocs que compleixen els requisits amb les contrasenyes que heu desat.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (propietari)</translation>
diff --git a/chrome/app/resources/generated_resources_cs.xtb b/chrome/app/resources/generated_resources_cs.xtb
index 5b1ba44..a6f61ed 100644
--- a/chrome/app/resources/generated_resources_cs.xtb
+++ b/chrome/app/resources/generated_resources_cs.xtb
@@ -1492,7 +1492,7 @@
 <translation id="3280237271814976245">Uložit &amp;jako...</translation>
 <translation id="3280243678470289153">Zůstat v Chromu</translation>
 <translation id="3280431534455935878">Příprava</translation>
-<translation id="3282568296779691940">Přihlášení do Chrome</translation>
+<translation id="3282568296779691940">Přihlásit se do Chromu</translation>
 <translation id="3285322247471302225">Nová kar&amp;ta</translation>
 <translation id="3288047731229977326">Rozšíření spuštěná v režimu pro vývojáře mohou poškodit počítač. Pokud nejste vývojář, měli byste s ohledem na svou bezpečnost rozšíření spuštěná v tomto režimu deaktivovat.</translation>
 <translation id="3289856944988573801">Chcete-li zkontrolovat dostupnost aktualizací, použijte síť Ethernet nebo Wi-Fi.</translation>
@@ -3668,7 +3668,6 @@
           Tato fotka se bude zobrazovat na přihlašovací obrazovce a na obrazovce uzamčení Chromebooku.</translation>
 <translation id="6769712124046837540">Přidávání tiskárny...</translation>
 <translation id="6771503742377376720">Je certifikační autorita</translation>
-<translation id="6773575010135450071">Další akce...</translation>
 <translation id="6777817260680419853">Bylo zablokováno přesměrování</translation>
 <translation id="6778959797435875428">Zapnout zvuk webů</translation>
 <translation id="677965093459947883">Velmi malé</translation>
@@ -4195,7 +4194,6 @@
 <translation id="7629827748548208700">Karta: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Vždy otevír&amp;at soubory tohoto typu</translation>
 <translation id="7632948528260659758">Následující aplikace veřejného terminálu se nepodařilo aktualizovat:</translation>
-<translation id="7634373849852678655">Režim celé obrazovky ukončíte stisknutím tlačítka Aplikace</translation>
 <translation id="7639178625568735185">Mám to!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> vás automaticky přihlásí na vhodných webech, ke kterým máte uložená hesla.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (vlastník)</translation>
diff --git a/chrome/app/resources/generated_resources_da.xtb b/chrome/app/resources/generated_resources_da.xtb
index f5ad6a66..b318cbe 100644
--- a/chrome/app/resources/generated_resources_da.xtb
+++ b/chrome/app/resources/generated_resources_da.xtb
@@ -3672,7 +3672,6 @@
           Dette billede vises på loginskærmen og låseskærmen på Chromebook-enheden.</translation>
 <translation id="6769712124046837540">Tilføjer printer...</translation>
 <translation id="6771503742377376720">Er en certificeringsautoritet</translation>
-<translation id="6773575010135450071">Flere handlinger...</translation>
 <translation id="6777817260680419853">Omdirigeringen blev blokeret</translation>
 <translation id="6778959797435875428">Slå lyden til på websites</translation>
 <translation id="677965093459947883">Meget lille</translation>
@@ -4203,7 +4202,6 @@
 <translation id="7629827748548208700">Fane: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Åbn altid filer af denne type</translation>
 <translation id="7632948528260659758">Følgende kioskapps kan ikke opdateres:</translation>
-<translation id="7634373849852678655">Tryk på App-knappen for at afslutte fuld skærm</translation>
 <translation id="7639178625568735185">Forstået</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> logger dig automatisk ind på kvalificerede websites med adgangskoder, du har gemt.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (ejer)</translation>
diff --git a/chrome/app/resources/generated_resources_de.xtb b/chrome/app/resources/generated_resources_de.xtb
index 0da4d5e..ddafc56 100644
--- a/chrome/app/resources/generated_resources_de.xtb
+++ b/chrome/app/resources/generated_resources_de.xtb
@@ -3667,7 +3667,6 @@
           Dieses Bild wird auf dem Anmelde- und dem Sperrbildschirm Ihres Chromebooks angezeigt.</translation>
 <translation id="6769712124046837540">Drucker wird hinzugefügt...</translation>
 <translation id="6771503742377376720">Ist eine Zertifizierungsstelle</translation>
-<translation id="6773575010135450071">Weitere Aktionen...</translation>
 <translation id="6777817260680419853">Weiterleitung blockiert</translation>
 <translation id="6778959797435875428">Stummschaltung für Websites aufheben</translation>
 <translation id="677965093459947883">Sehr klein</translation>
@@ -4201,7 +4200,6 @@
 <translation id="7629827748548208700">Tab: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Dateien dieses Typs &amp;immer öffnen</translation>
 <translation id="7632948528260659758">Die folgenden Kiosk-Apps konnten nicht aktualisiert werden:</translation>
-<translation id="7634373849852678655">Zum Beenden des Vollbilds auf die App-Taste drücken</translation>
 <translation id="7639178625568735185">Fertig</translation>
 <translation id="764017888128728">Mit <ph name="PASSWORD_MANAGER_BRAND" /> werden Sie mit Ihren gespeicherten Passwörtern automatisch auf allen entsprechenden Websites angemeldet.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (Eigentümer)</translation>
diff --git a/chrome/app/resources/generated_resources_el.xtb b/chrome/app/resources/generated_resources_el.xtb
index 7d66000..6dfe889 100644
--- a/chrome/app/resources/generated_resources_el.xtb
+++ b/chrome/app/resources/generated_resources_el.xtb
@@ -3673,7 +3673,6 @@
           Αυτή η εικόνα θα εμφανιστεί στην οθόνη σύνδεσης και στην οθόνη κλειδώματος του Chromebook.</translation>
 <translation id="6769712124046837540">Προσθήκη εκτυπωτή…</translation>
 <translation id="6771503742377376720">Είναι Αρχή πιστοποίησης</translation>
-<translation id="6773575010135450071">Περισσότερες ενέργειες…</translation>
 <translation id="6777817260680419853">Η ανακατεύθυνση αποκλείστηκε</translation>
 <translation id="6778959797435875428">Κατάργηση σίγασης ιστοτόπων</translation>
 <translation id="677965093459947883">Πολύ μικρό</translation>
@@ -4204,7 +4203,6 @@
 <translation id="7629827748548208700">Καρτέλα: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Πάντα Άνοιγμα Αρχείων Αυτού του Τύπου</translation>
 <translation id="7632948528260659758">Απέτυχε η ενημέρωση για τις παρακάτω εφαρμοφές kiosk:</translation>
-<translation id="7634373849852678655">Πατήστε το κουμπί εφαρμογών για έξοδο από την πλήρη οθόνη</translation>
 <translation id="7639178625568735185">Κατάλαβα!</translation>
 <translation id="764017888128728">Το <ph name="PASSWORD_MANAGER_BRAND" /> σάς συνδέει αυτόματα σε κατάλληλους ιστότοπους, χρησιμοποιώντας τους κωδικούς πρόσβασης που έχετε αποθηκεύσει.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (κάτοχος)</translation>
diff --git a/chrome/app/resources/generated_resources_en-GB.xtb b/chrome/app/resources/generated_resources_en-GB.xtb
index d85c19d..53165b5 100644
--- a/chrome/app/resources/generated_resources_en-GB.xtb
+++ b/chrome/app/resources/generated_resources_en-GB.xtb
@@ -3671,7 +3671,6 @@
           This picture will appear on the Chromebook sign in screen and lock screen.</translation>
 <translation id="6769712124046837540">Adding printer...</translation>
 <translation id="6771503742377376720">Is a Certification Authority</translation>
-<translation id="6773575010135450071">More actions...</translation>
 <translation id="6777817260680419853">Redirect blocked</translation>
 <translation id="6778959797435875428">Unmute Sites</translation>
 <translation id="677965093459947883">Very small</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">Tab: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Always Open Files of This Type</translation>
 <translation id="7632948528260659758">The following kiosk apps have been failed for updating:</translation>
-<translation id="7634373849852678655">Press App button to exit full screen</translation>
 <translation id="7639178625568735185">Got it!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> automatically signs you in to eligible sites with passwords that you saved.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (owner)</translation>
diff --git a/chrome/app/resources/generated_resources_es-419.xtb b/chrome/app/resources/generated_resources_es-419.xtb
index 01694c1..313296c 100644
--- a/chrome/app/resources/generated_resources_es-419.xtb
+++ b/chrome/app/resources/generated_resources_es-419.xtb
@@ -3668,7 +3668,6 @@
           Esta imagen se mostrará en la pantalla de acceso y de bloqueo de Chromebook.</translation>
 <translation id="6769712124046837540">Agregando impresora…</translation>
 <translation id="6771503742377376720">Es una Entidad de certificación</translation>
-<translation id="6773575010135450071">Más acciones…</translation>
 <translation id="6777817260680419853">Se bloqueó el redireccionamiento</translation>
 <translation id="6778959797435875428">Activar el sonido de los sitios</translation>
 <translation id="677965093459947883">Muy pequeño</translation>
@@ -4199,7 +4198,6 @@
 <translation id="7629827748548208700">Pestaña: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Abrir siempre archivos de este tipo</translation>
 <translation id="7632948528260659758">No se pudieron actualizar las siguientes aplicaciones de kiosco:</translation>
-<translation id="7634373849852678655">Presionar el botón de la app para salir de la pantalla completa</translation>
 <translation id="7639178625568735185">Entendido</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> te permite acceder automáticamente a los sitios aptos con las contraseñas que guardaste.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (propietario/a)</translation>
diff --git a/chrome/app/resources/generated_resources_es.xtb b/chrome/app/resources/generated_resources_es.xtb
index 84b1a800..54997bd3 100644
--- a/chrome/app/resources/generated_resources_es.xtb
+++ b/chrome/app/resources/generated_resources_es.xtb
@@ -3668,7 +3668,6 @@
           Esta imagen se mostrará en la pantalla de bloqueo y en la de inicio de sesión del Chromebook.</translation>
 <translation id="6769712124046837540">Añadiendo impresora...</translation>
 <translation id="6771503742377376720">Es una entidad emisora de certificados.</translation>
-<translation id="6773575010135450071">Más acciones...</translation>
 <translation id="6777817260680419853">Redirección bloqueada</translation>
 <translation id="6778959797435875428">Activar sonido de sitios web</translation>
 <translation id="677965093459947883">Muy pequeño</translation>
@@ -4198,7 +4197,6 @@
 <translation id="7629827748548208700">Pestaña: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Abrir siempre archivos de este tipo</translation>
 <translation id="7632948528260659758">No se han podido actualizar las siguientes aplicaciones de kiosco:</translation>
-<translation id="7634373849852678655">Pulsa el botón Aplicación para salir del modo de pantalla completa</translation>
 <translation id="7639178625568735185">¡Listo!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> inicia sesión automáticamente en los sitios web en los que se pueda iniciar sesión con las contraseñas que hayas guardado.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (propietario)</translation>
diff --git a/chrome/app/resources/generated_resources_et.xtb b/chrome/app/resources/generated_resources_et.xtb
index 72543bc..168f357 100644
--- a/chrome/app/resources/generated_resources_et.xtb
+++ b/chrome/app/resources/generated_resources_et.xtb
@@ -3671,7 +3671,6 @@
           See pilt kuvatakse Chromebooki sisselogimisekraanil ja lukustuskuval.</translation>
 <translation id="6769712124046837540">Printeri lisamine ...</translation>
 <translation id="6771503742377376720">On sertifitseerimisorgan</translation>
-<translation id="6773575010135450071">Veel toiminguid ...</translation>
 <translation id="6777817260680419853">Ümbersuunamine blokeeriti</translation>
 <translation id="6778959797435875428">Tühista saitide vaigistus</translation>
 <translation id="677965093459947883">Väga väike</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">Vaheleht: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Ava alati &amp;seda tüüpi failid</translation>
 <translation id="7632948528260659758">Järgmiste kioskirakenduste värskendamine nurjus:</translation>
-<translation id="7634373849852678655">Täisekraanilt väljumiseks vajutage nuppu Rakendus</translation>
 <translation id="7639178625568735185">Selge.</translation>
 <translation id="764017888128728">Teenus <ph name="PASSWORD_MANAGER_BRAND" /> logib teid salvestatud paroolidega automaatselt sisse sobilikele saitidele.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (omanik)</translation>
diff --git a/chrome/app/resources/generated_resources_fa.xtb b/chrome/app/resources/generated_resources_fa.xtb
index 2d4c719..5176eb2 100644
--- a/chrome/app/resources/generated_resources_fa.xtb
+++ b/chrome/app/resources/generated_resources_fa.xtb
@@ -3667,7 +3667,6 @@
           این تصویر در صفحه ورود به سیستم و صفحه درحالت قفل Chromebook نشان داده می‌شود.</translation>
 <translation id="6769712124046837540">در حال افزودن چاپگر...</translation>
 <translation id="6771503742377376720">یک ارائه دهنده مجوز است</translation>
-<translation id="6773575010135450071">کنش‌های بیشتر...</translation>
 <translation id="6777817260680419853">هدایت کردن مسدود شده است</translation>
 <translation id="6778959797435875428">باصدا کردن سایت‌ها</translation>
 <translation id="677965093459947883">خیلی کوچک</translation>
@@ -4200,7 +4199,6 @@
 <translation id="7629827748548208700">برگه: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;همیشه این نوع فایل‌ها باز شوند</translation>
 <translation id="7632948528260659758">به‌روزرسانی برنامه‌های کیوسک زیر انجام نشد:</translation>
-<translation id="7634373849852678655">برای خروج از حالت تمام صفحه، دکمه «برنامه» را فشار دهید</translation>
 <translation id="7639178625568735185">متوجه شدم.</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> شما را به‌صورت خودکار در سایت‌های واجد شرایط با گذرواژه‌هایی که ذخیره کرده‌اید ثبت ورود می‌کند.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (مالک)</translation>
diff --git a/chrome/app/resources/generated_resources_fi.xtb b/chrome/app/resources/generated_resources_fi.xtb
index e96a5ce0..6dbad84 100644
--- a/chrome/app/resources/generated_resources_fi.xtb
+++ b/chrome/app/resources/generated_resources_fi.xtb
@@ -3671,7 +3671,6 @@
           Tämä kuva näkyy Chromebookin kirjautumisnäytöllä ja lukitusnäytöllä.</translation>
 <translation id="6769712124046837540">Tulostinta lisätään…</translation>
 <translation id="6771503742377376720">On varmenteen myöntäjä</translation>
-<translation id="6773575010135450071">Lisää toimintoja…</translation>
 <translation id="6777817260680419853">Uudelleenohjaus estetty</translation>
 <translation id="6778959797435875428">Poista sivustojen mykistys</translation>
 <translation id="677965093459947883">Hyvin pieni</translation>
@@ -4201,7 +4200,6 @@
 <translation id="7629827748548208700">Välilehti: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Avaa aina tämäntyyppiset tiedostot</translation>
 <translation id="7632948528260659758">Seuraavien kioskisovellusten päivitys epäonnistui:</translation>
-<translation id="7634373849852678655">Poistu koko näytön tilasta painamalla Sovellus-painiketta</translation>
 <translation id="7639178625568735185">Ymmärretty!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> kirjaa sinut automaattisesti kelvollisille sivustoille, joiden salasanat olet tallentanut.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (omistaja)</translation>
diff --git a/chrome/app/resources/generated_resources_fil.xtb b/chrome/app/resources/generated_resources_fil.xtb
index bbd19751..a85fd7f 100644
--- a/chrome/app/resources/generated_resources_fil.xtb
+++ b/chrome/app/resources/generated_resources_fil.xtb
@@ -3671,7 +3671,6 @@
           Lalabas ang larawang ito sa screen sa pag-sign in at lock screen ng Chromebook.</translation>
 <translation id="6769712124046837540">Idinaragdag ang printer...</translation>
 <translation id="6771503742377376720">Ay isang Certificate Authority</translation>
-<translation id="6773575010135450071">Higit pang mga pagkilos...</translation>
 <translation id="6777817260680419853">Na-block ang pag-redirect</translation>
 <translation id="6778959797435875428">I-unmute ang mga site</translation>
 <translation id="677965093459947883">Napakaliit</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">Tab: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Palaging Magbukas ng Mga File na Ganitong Uri</translation>
 <translation id="7632948528260659758">Hindi na-update ang mga sumusunod na kiosk app:</translation>
-<translation id="7634373849852678655">Pindutin ang App button para lumabas sa fullscreen</translation>
 <translation id="7639178625568735185">Nakuha ko!</translation>
 <translation id="764017888128728">Awtomatiko kang sina-sign in ng <ph name="PASSWORD_MANAGER_BRAND" /> sa mga kwalipikadong site gamit ang mga password na na-save mo.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (may-ari)</translation>
diff --git a/chrome/app/resources/generated_resources_fr.xtb b/chrome/app/resources/generated_resources_fr.xtb
index 3ae3824..dd821ba 100644
--- a/chrome/app/resources/generated_resources_fr.xtb
+++ b/chrome/app/resources/generated_resources_fr.xtb
@@ -3672,7 +3672,6 @@
           Cette photo s'affichera sur l'écran de connexion et l'écran de verrouillage du Chromebook.</translation>
 <translation id="6769712124046837540">Ajout d'une imprimante en cours…</translation>
 <translation id="6771503742377376720">Est une autorité de certification</translation>
-<translation id="6773575010135450071">Plus d'actions…</translation>
 <translation id="6777817260680419853">Redirection bloquée</translation>
 <translation id="6778959797435875428">Réactiver le son des sites</translation>
 <translation id="677965093459947883">Très petite</translation>
@@ -4203,7 +4202,6 @@
 <translation id="7629827748548208700">Onglet : <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Toujours ouvrir les fichiers de ce type</translation>
 <translation id="7632948528260659758">Échec de la mise à jour des applications kiosque suivantes :</translation>
-<translation id="7634373849852678655">Appuyez sur le bouton "Application" pour quitter le mode plein écran</translation>
 <translation id="7639178625568735185">OK</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> vous connecte automatiquement aux sites éligibles avec les mots de passe que vous avez enregistrés.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (propriétaire)</translation>
diff --git a/chrome/app/resources/generated_resources_gu.xtb b/chrome/app/resources/generated_resources_gu.xtb
index 9fe5e207..8c7b5364 100644
--- a/chrome/app/resources/generated_resources_gu.xtb
+++ b/chrome/app/resources/generated_resources_gu.xtb
@@ -3668,7 +3668,6 @@
           આ ચિત્ર Chromebook સાઇન ઇન સ્ક્રીન અને લૉક સ્ક્રીન પર દેખાશે.</translation>
 <translation id="6769712124046837540">પ્રિન્ટર ઉમેરી રહ્યું છે...</translation>
 <translation id="6771503742377376720">એ એક પ્રમાણન અધિકારી છે</translation>
-<translation id="6773575010135450071">વધુ ક્રિયાઓ...</translation>
 <translation id="6777817260680419853">રીડાયરેક્ટ કરવાનું બ્લૉક કર્યું</translation>
 <translation id="6778959797435875428">સાઇટને અનમ્યૂટ કરો</translation>
 <translation id="677965093459947883">ખૂબ નાનું</translation>
@@ -4199,7 +4198,6 @@
 <translation id="7629827748548208700">ટૅબ: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">આ પ્રકારની ફાઇલો &amp;હંમેશા ખોલો</translation>
 <translation id="7632948528260659758">નીચેની કિઓસ્ક ઍપ્લિકેશનો અપડેટ માટે નિષ્ફળ થઈ છે:</translation>
-<translation id="7634373849852678655">પૂર્ણ સ્ક્રીનથી બહાર નીકળવા માટે ઍપ બટન દબાવો</translation>
 <translation id="7639178625568735185">સમજાઈ ગયું!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" />, તમને તમે સાચવેલા પાસવર્ડ્સ વડે યોગ્ય હોય તેવી સાઇટ્સમાં આપમેળે સાઇન ઇન કરે છે.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (માલિક)</translation>
diff --git a/chrome/app/resources/generated_resources_hi.xtb b/chrome/app/resources/generated_resources_hi.xtb
index f52c2476..c856d05 100644
--- a/chrome/app/resources/generated_resources_hi.xtb
+++ b/chrome/app/resources/generated_resources_hi.xtb
@@ -3670,7 +3670,6 @@
           यह चित्र Chromebook प्रवेश स्क्रीन और लॉक स्क्रीन पर दिखाई देगा.</translation>
 <translation id="6769712124046837540">प्रिंटर जोड़ा जा रहा है...</translation>
 <translation id="6771503742377376720">एक प्रमाणन प्राधिकरण है</translation>
-<translation id="6773575010135450071">अधिक कार्रवाइयां...</translation>
 <translation id="6777817260680419853">रीडायरेक्ट ब्लॉक किया गया</translation>
 <translation id="6778959797435875428">साइटें अनम्यूट करें</translation>
 <translation id="677965093459947883">बहुत छोटा</translation>
@@ -4201,7 +4200,6 @@
 <translation id="7629827748548208700">टैब: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">इस प्रकार की फ़ाइलें &amp;हमेशा खोलें</translation>
 <translation id="7632948528260659758">निम्‍न किऑस्क&amp;#0; ऐप्‍स अपडेट होने में विफल रहे:</translation>
-<translation id="7634373849852678655">पूरी स्क्रीन से बाहर निकलने के लिए ऐप्लिकेशन बटन दबाएं</translation>
 <translation id="7639178625568735185">समझ लिया!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> आपके द्वारा सहेजे गए पासवर्ड से आपको योग्य साइट में अपने आप प्रवेश करा देता है.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (मालिक)</translation>
diff --git a/chrome/app/resources/generated_resources_hr.xtb b/chrome/app/resources/generated_resources_hr.xtb
index 7ea886a..da612cd3 100644
--- a/chrome/app/resources/generated_resources_hr.xtb
+++ b/chrome/app/resources/generated_resources_hr.xtb
@@ -3671,7 +3671,6 @@
           Ta će se slika prikazivati na zaslonu za prijavu i zaključanom zaslonu Chromebooka.</translation>
 <translation id="6769712124046837540">Dodavanje pisača...</translation>
 <translation id="6771503742377376720">jest tijelo za izdavanje certifikata</translation>
-<translation id="6773575010135450071">Više radnji...</translation>
 <translation id="6777817260680419853">Preusmjeravanje je blokirano</translation>
 <translation id="6778959797435875428">Prestani zanemarivati web-lokacije</translation>
 <translation id="677965093459947883">Vrlo mali</translation>
@@ -4201,7 +4200,6 @@
 <translation id="7629827748548208700">Kartica: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Uvijek otvori ovu vrstu datoteka</translation>
 <translation id="7632948528260659758">Ažuriranje sljedećih kiosk aplikacija nije uspjelo:</translation>
-<translation id="7634373849852678655">Pritisnite gumb aplikacije za izlazak iz cijelog zaslona</translation>
 <translation id="7639178625568735185">Shvaćam!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> može upotrijebiti spremljene zaporke kako bi vas automatski prijavio na web-lokacije koje ispunjavaju uvjete.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (vlasnik)</translation>
diff --git a/chrome/app/resources/generated_resources_hu.xtb b/chrome/app/resources/generated_resources_hu.xtb
index a8350c1b..ddf15b44 100644
--- a/chrome/app/resources/generated_resources_hu.xtb
+++ b/chrome/app/resources/generated_resources_hu.xtb
@@ -3673,7 +3673,6 @@
           Ez a kép lesz látható a Chromebook bejelentkezési és lezárási képernyőjén.</translation>
 <translation id="6769712124046837540">Nyomtató hozzáadása...</translation>
 <translation id="6771503742377376720">Tanúsítványkibocsátó</translation>
-<translation id="6773575010135450071">További műveletek…</translation>
 <translation id="6777817260680419853">Átirányítás letiltva</translation>
 <translation id="6778959797435875428">Webhelyek némításának feloldása</translation>
 <translation id="677965093459947883">Nagyon kicsi</translation>
@@ -4204,7 +4203,6 @@
 <translation id="7629827748548208700">Lap: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Az ilyen típusú fájlokat mindig nyissa meg</translation>
 <translation id="7632948528260659758">A következő kioszkalkalmazások frissítése nem sikerült:</translation>
-<translation id="7634373849852678655">A teljes képernyős megjelenítésből való kilépéshez nyomja meg az Alkalmazás gombot</translation>
 <translation id="7639178625568735185">Sikerült!</translation>
 <translation id="764017888128728">A <ph name="PASSWORD_MANAGER_BRAND" /> segítségével automatikusan bejelentkezhet adott webhelyekre a mentett jelszavaival.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (tulajdonos)</translation>
diff --git a/chrome/app/resources/generated_resources_id.xtb b/chrome/app/resources/generated_resources_id.xtb
index 2bd617f..3287898 100644
--- a/chrome/app/resources/generated_resources_id.xtb
+++ b/chrome/app/resources/generated_resources_id.xtb
@@ -3671,7 +3671,6 @@
           Gambar ini akan ditampilkan di layar login dan layar kunci Chromebook.</translation>
 <translation id="6769712124046837540">Menambahkan printer...</translation>
 <translation id="6771503742377376720">Adalah Otoritas Sertifikasi</translation>
-<translation id="6773575010135450071">Tindakan lainnya...</translation>
 <translation id="6777817260680419853">Pengalihan diblokir</translation>
 <translation id="6778959797435875428">Nyalakan notifikasi situs</translation>
 <translation id="677965093459947883">Sangat kecil</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">Tab: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Sel&amp;alu Buka File Jenis Ini</translation>
 <translation id="7632948528260659758">Aplikasi kios berikut gagal memperbarui:</translation>
-<translation id="7634373849852678655">Tekan tombol Aplikasi untuk keluar dari mode layar penuh</translation>
 <translation id="7639178625568735185">Mengerti!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> otomatis memasukkan Anda ke situs yang memenuhi syarat menggunakan sandi tersimpan.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (pemilik)</translation>
diff --git a/chrome/app/resources/generated_resources_it.xtb b/chrome/app/resources/generated_resources_it.xtb
index ecb0a60d..887060e8 100644
--- a/chrome/app/resources/generated_resources_it.xtb
+++ b/chrome/app/resources/generated_resources_it.xtb
@@ -3667,7 +3667,6 @@
           Questa immagine verrà mostrata nelle schermate di accesso e di blocco del Chromebook.</translation>
 <translation id="6769712124046837540">Aggiunta della stampante...</translation>
 <translation id="6771503742377376720">È un'autorità di certificazione</translation>
-<translation id="6773575010135450071">Altre azioni...</translation>
 <translation id="6777817260680419853">Reindirizzamento bloccato</translation>
 <translation id="6778959797435875428">Riattiva l'audio dei siti</translation>
 <translation id="677965093459947883">Molto piccole</translation>
@@ -4189,7 +4188,6 @@
 <translation id="7629827748548208700">Scheda: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Apri sempre file di questo tipo</translation>
 <translation id="7632948528260659758">Le seguenti app kiosk non sono state aggiornate:</translation>
-<translation id="7634373849852678655">Premi il pulsante App per uscire dalla modalità a schermo intero</translation>
 <translation id="7639178625568735185">Ok.</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> ti consente di accedere automaticamente ai siti idonei con le password salvate.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (proprietario)</translation>
diff --git a/chrome/app/resources/generated_resources_iw.xtb b/chrome/app/resources/generated_resources_iw.xtb
index 79480dd8..011171b75 100644
--- a/chrome/app/resources/generated_resources_iw.xtb
+++ b/chrome/app/resources/generated_resources_iw.xtb
@@ -3668,7 +3668,6 @@
           התמונה הזו תופיע במסך הכניסה לחשבון ובמסך הנעילה ב-Chromebook.</translation>
 <translation id="6769712124046837540">הוספת מדפסת...</translation>
 <translation id="6771503742377376720">הוא רשות אישורים</translation>
-<translation id="6773575010135450071">פעולות נוספות...</translation>
 <translation id="6777817260680419853">הפניה לכתובת אתר אחרת נחסמה</translation>
 <translation id="6778959797435875428">בטל השתקת אתרים</translation>
 <translation id="677965093459947883">קטן מאוד</translation>
@@ -4191,7 +4190,6 @@
 <translation id="7629827748548208700">כרטיסייה: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;פתח תמיד קבצים מסוג זה</translation>
 <translation id="7632948528260659758">עדכון יישומי הקיוסק הבאים נכשל:</translation>
-<translation id="7634373849852678655">כדי לצאת מהמסך המלא יש ללחוץ על לחצן האפליקציה</translation>
 <translation id="7639178625568735185">הבנתי</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> מכניס אותך באופן אוטומטי לאתרים כשירים באמצעות סיסמאות ששמרת.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (בעלים)</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb
index 73f14b86..74e8d5f9 100644
--- a/chrome/app/resources/generated_resources_ja.xtb
+++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -3672,7 +3672,6 @@
           この画像は Chromebook のログイン画面とロック画面に表示されます。</translation>
 <translation id="6769712124046837540">プリンタの追加...</translation>
 <translation id="6771503742377376720">認証局である</translation>
-<translation id="6773575010135450071">その他の操作...</translation>
 <translation id="6777817260680419853">リダイレクトがブロックされました</translation>
 <translation id="6778959797435875428">複数のサイトのミュートを解除</translation>
 <translation id="677965093459947883">極小</translation>
@@ -4205,7 +4204,6 @@
 <translation id="7629827748548208700">タブ:<ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">この種類のファイルは常に開く(&amp;A)</translation>
 <translation id="7632948528260659758">次のキオスクアプリを更新できませんでした:</translation>
-<translation id="7634373849852678655">全画面表示を終了するにはアプリボタンを押します</translation>
 <translation id="7639178625568735185">完了</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> では、保存したパスワードを使って対象となるサイトへの自動ログインが行われます。</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" />(所有者)</translation>
diff --git a/chrome/app/resources/generated_resources_kn.xtb b/chrome/app/resources/generated_resources_kn.xtb
index 3530bfde..7cc4a2b 100644
--- a/chrome/app/resources/generated_resources_kn.xtb
+++ b/chrome/app/resources/generated_resources_kn.xtb
@@ -3670,7 +3670,6 @@
 ಈ ಚಿತ್ರವನ್ನು Chromebook ಸೈನ್‌ ಇನ್‌ ಪರದೆ ಮತ್ತು ಲಾಕ್‌ ಪರದೆಯ ಮೇಲೆ ತೋರಿಸಲಾಗುತ್ತದೆ.</translation>
 <translation id="6769712124046837540">ಮುದ್ರಕ ಸೇರಿಸಲಾಗುತ್ತಿದೆ...</translation>
 <translation id="6771503742377376720">ಪ್ರಮಾಣಪತ್ರ ಪ್ರಾಧಿಕಾರವಾಗಿದೆ</translation>
-<translation id="6773575010135450071">ಇನ್ನಷ್ಟು ಕ್ರಿಯೆಗಳು...</translation>
 <translation id="6777817260680419853">ಮರುನಿರ್ದೇಶಿಸುವಿಕೆಯನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ</translation>
 <translation id="6778959797435875428">ಸೈಟ್‌ಗಳನ್ನು ಅನ್‌ಮ್ಯೂಟ್‌ ಮಾಡಿ</translation>
 <translation id="677965093459947883">ತುಂಬಾ ಚಿಕ್ಕದು</translation>
@@ -4199,7 +4198,6 @@
 <translation id="7629827748548208700">ಟ್ಯಾಬ್: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;ಯಾವಾಗಲೂ ಈ ಪ್ರಕಾರದ ಫೈಲ್ ಅನ್ನು ತೆರೆಯಿರಿ</translation>
 <translation id="7632948528260659758">ಕೆಳಗಿನ ಕಿಯೋಸ್ಕ್ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ನವೀಕರಿಸುವುದಕ್ಕೆ ವಿಫಲವಾಗಿದೆ:</translation>
-<translation id="7634373849852678655">ಪೂರ್ಣಪರದೆಯಿಂದ ನಿರ್ಗಮಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ ಬಟನ್‌ ಅನ್ನು ಒತ್ತಿರಿ</translation>
 <translation id="7639178625568735185">ಅರ್ಥವಾಯಿತು!</translation>
 <translation id="764017888128728">ನೀವು ಉಳಿಸಲಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳ ಮೂಲಕ ಅರ್ಹರಾಗಿರುವ ಸೈಟ್‌ಗಳಿಗೆ <ph name="PASSWORD_MANAGER_BRAND" /> ನಿಮ್ಮನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡುತ್ತದೆ.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (ಮಾಲೀಕರು)</translation>
diff --git a/chrome/app/resources/generated_resources_ko.xtb b/chrome/app/resources/generated_resources_ko.xtb
index 4f710fa..6072735 100644
--- a/chrome/app/resources/generated_resources_ko.xtb
+++ b/chrome/app/resources/generated_resources_ko.xtb
@@ -3671,7 +3671,6 @@
           이 사진이 Chromebook 로그인 화면과 잠금 화면에 표시됩니다.</translation>
 <translation id="6769712124046837540">프린터 추가 중...</translation>
 <translation id="6771503742377376720">인증 기관임</translation>
-<translation id="6773575010135450071">추가 작업...</translation>
 <translation id="6777817260680419853">리디렉션이 차단됨</translation>
 <translation id="6778959797435875428">사이트 음소거 해제</translation>
 <translation id="677965093459947883">아주 작게</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">탭: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">해당 유형의 파일 항상 열기(&amp;A)</translation>
 <translation id="7632948528260659758">다음 키오스크 앱을 업데이트하지 못했습니다.</translation>
-<translation id="7634373849852678655">앱 버튼을 눌러 전체화면을 종료하세요.</translation>
 <translation id="7639178625568735185">확인</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" />에서 저장한 비밀번호를 사용하여 적합한 사이트에 자동 로그인합니다.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" />(소유자)</translation>
diff --git a/chrome/app/resources/generated_resources_lt.xtb b/chrome/app/resources/generated_resources_lt.xtb
index 1479490d..f709a8e0 100644
--- a/chrome/app/resources/generated_resources_lt.xtb
+++ b/chrome/app/resources/generated_resources_lt.xtb
@@ -3672,7 +3672,6 @@
           Ši nuotrauka bus rodoma „Chromebook“ prisijungimo ir užrakinimo ekranuose.</translation>
 <translation id="6769712124046837540">Pridedamas spausdintuvas...</translation>
 <translation id="6771503742377376720">Yra sertifikavimo institucija</translation>
-<translation id="6773575010135450071">Daugiau veiksmų...</translation>
 <translation id="6777817260680419853">Peradresavimas užblokuotas</translation>
 <translation id="6778959797435875428">Įjungti svetainių garsą</translation>
 <translation id="677965093459947883">Labai mažas</translation>
@@ -4203,7 +4202,6 @@
 <translation id="7629827748548208700">Skirtukas: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Visada atidaryti tokio tipo failus</translation>
 <translation id="7632948528260659758">Atnaujinant šias viešojo terminalo programas įvyko klaida:</translation>
-<translation id="7634373849852678655">Palieskite programos mygtuką, kad išeitumėte iš viso ekrano režimo</translation>
 <translation id="7639178625568735185">Supratau.</translation>
 <translation id="764017888128728">„<ph name="PASSWORD_MANAGER_BRAND" />“ automatiškai prijungs jus tinkamose svetainėse naudodama išsaugotus slaptažodžius.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (savininkas)</translation>
diff --git a/chrome/app/resources/generated_resources_lv.xtb b/chrome/app/resources/generated_resources_lv.xtb
index b4abf42..fbb15fe 100644
--- a/chrome/app/resources/generated_resources_lv.xtb
+++ b/chrome/app/resources/generated_resources_lv.xtb
@@ -3671,7 +3671,6 @@
           Šis attēls būs redzams Chromebook datorā pierakstīšanās ekrānā un bloķēšanas ekrānā.</translation>
 <translation id="6769712124046837540">Printera pievienošana...</translation>
 <translation id="6771503742377376720">Ir sertifikāta izdevējiestāde</translation>
-<translation id="6773575010135450071">Citas darbības...</translation>
 <translation id="6777817260680419853">Novirzīšana bloķēta</translation>
 <translation id="6778959797435875428">Rādīt vietnes</translation>
 <translation id="677965093459947883">Ļoti mazs</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">Cilne: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Vienmēr atvērt šī veida f&amp;ailus</translation>
 <translation id="7632948528260659758">Neizdevās atjaunināt šādas kioska lietotnes:</translation>
-<translation id="7634373849852678655">Lai aizvērtu pilnekrāna režīmu, nospiediet lietotnes pogu.</translation>
 <translation id="7639178625568735185">Sapratu!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> automātiski pierakstās piemērotajās vietnēs, izmantojot jūsu saglabātās paroles.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (īpašnieks)</translation>
diff --git a/chrome/app/resources/generated_resources_ml.xtb b/chrome/app/resources/generated_resources_ml.xtb
index c2731c47..b60431c 100644
--- a/chrome/app/resources/generated_resources_ml.xtb
+++ b/chrome/app/resources/generated_resources_ml.xtb
@@ -3669,7 +3669,6 @@
           ഈ ചിത്രം Chromebook-ലെ സൈന്‍-ഇന്‍ സ്‌ക്രീനിലും ലോക്ക് സ്‌ക്രീനിലും ദൃശ്യമാകും.</translation>
 <translation id="6769712124046837540">പ്രിന്റർ ചേർക്കുന്നു...</translation>
 <translation id="6771503742377376720">ഒരു സര്‍ട്ടിഫിക്കറ്റ് അതോറിറ്റി ആണ്</translation>
-<translation id="6773575010135450071">കൂടുതൽ പ്രവർത്തനങ്ങൾ...</translation>
 <translation id="6777817260680419853">റീഡയറക്ട് ചെയ്യുന്നത് ബ്ലോക്ക് ചെയ്തു</translation>
 <translation id="6778959797435875428">സൈറ്റുകൾ അൺമ്യൂട്ട് ചെയ്യുക</translation>
 <translation id="677965093459947883">വളരെ ചെറുത്</translation>
@@ -4200,7 +4199,6 @@
 <translation id="7629827748548208700">ടാബ്: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;എല്ലായ്‌പ്പോഴും ഈ തരം ഫയലുകള്‍ തുറക്കുക</translation>
 <translation id="7632948528260659758">ഇനിപ്പറയുന്ന കിയോസ്‌ക് അപ്ലിക്കേഷനുകൾ അപ്‌ഡേറ്റുചെയ്യുന്നതിൽ പരാജയപ്പെട്ടു:</translation>
-<translation id="7634373849852678655">പൂർണ്ണസ്ക്രീനിൽ നിന്ന് പുറത്തുകടക്കാൻ ആപ്പ് ബട്ടൺ അമർത്തുക</translation>
 <translation id="7639178625568735185">ലഭിച്ചു!</translation>
 <translation id="764017888128728">നിങ്ങൾ സംരക്ഷിച്ച പാസ്‌വേഡുകൾ ഉപയോഗിച്ച് യോഗ്യമായ സൈറ്റുകളിലേക്ക് <ph name="PASSWORD_MANAGER_BRAND" /> സ്വയമേവ നിങ്ങളെ സൈൻ ഇൻ ചെയ്യിക്കുന്നു.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (ഉടമ)</translation>
diff --git a/chrome/app/resources/generated_resources_mr.xtb b/chrome/app/resources/generated_resources_mr.xtb
index bedb14c8..c33ec37 100644
--- a/chrome/app/resources/generated_resources_mr.xtb
+++ b/chrome/app/resources/generated_resources_mr.xtb
@@ -1796,7 +1796,7 @@
 <translation id="3752582316358263300">ठीक आहे...</translation>
 <translation id="3752673729237782832">माझी डिव्हाइसेस</translation>
 <translation id="3755411799582650620">आपला <ph name="PHONE_NAME" /> आता हे <ph name="DEVICE_TYPE" /> देखील अनलॉॅक करू शकतो.</translation>
-<translation id="375636864092143889">साइट आपला मायक्रोफोन वापरत आहे</translation>
+<translation id="375636864092143889">साइट तुमचा मायक्रोफोन वापरत आहे</translation>
 <translation id="3758201569871381925">कृपया आपले Hotrod डिव्‍हाइस चालू असल्‍याचे आणि टीव्‍हीशी कनेक्‍ट केल्‍याचे सुनिश्‍चित करा.</translation>
 <translation id="375841316537350618">प्रॉक्सी स्क्रिप्ट डाउनलोड करत आहे...</translation>
 <translation id="3758842566811519622">कुकीज सेट केल्या</translation>
@@ -3574,7 +3574,7 @@
 <translation id="661719348160586794">आपले सेव्ह केलेले पासवर्ड येथे दिसून येतील.</translation>
 <translation id="6618097958368085618">तरीही राहू द्या</translation>
 <translation id="6619058681307408113">लाइन प्रिंटर डिमन (LPD)</translation>
-<translation id="661907246513853610">साइट आपले स्थान ट्रॅक करू शकते</translation>
+<translation id="661907246513853610">साइट तुमचे स्थान ट्रॅक करू शकते</translation>
 <translation id="6619801788773578757">कियोस्क अॅप्लिकेशन जोडा</translation>
 <translation id="6619990499523117484">आपल्या पिन ची पुष्टी करा</translation>
 <translation id="662080504995468778">यावर रहा</translation>
@@ -3668,7 +3668,6 @@
           हे चित्र Chromebook च्या साइन इन स्क्रीन आणि लॉक स्क्रीनवर दिसेल.</translation>
 <translation id="6769712124046837540">प्रिंटर जोडणे...</translation>
 <translation id="6771503742377376720">एक प्रमाणन अधिकृतता आहे</translation>
-<translation id="6773575010135450071">अधिक क्रिया...</translation>
 <translation id="6777817260680419853">रीडिरेक्‍ट ब्लॉक केले</translation>
 <translation id="6778959797435875428">साइट सशब्द करा</translation>
 <translation id="677965093459947883">खूप लहान</translation>
@@ -3962,7 +3961,7 @@
 <translation id="7254951428499890870">आपण निदान मोडमध्ये "<ph name="APP_NAME" />" लाँच करू इच्छिता याची आपल्याला खात्री आहे?</translation>
 <translation id="7255220508626648026">कास्ट करीत आहे: <ph name="ROUTETITLE" /></translation>
 <translation id="7255935316994522020">लागू करा</translation>
-<translation id="7256069762010468647">साइट आपला कॅमेरा वापरत आहे</translation>
+<translation id="7256069762010468647">साइट तुमचा कॅमेरा वापरत आहे</translation>
 <translation id="7256405249507348194">अपरिचित एरर: <ph name="DESC" /></translation>
 <translation id="7256710573727326513">टॅबमध्ये उघडा</translation>
 <translation id="7257666756905341374">आपण कॉपी आणि पेस्ट करता तो डेटा वाचा</translation>
@@ -4198,7 +4197,6 @@
 <translation id="7629827748548208700">टॅब: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;नेहमी या प्रकारच्या फायली उघडा</translation>
 <translation id="7632948528260659758">खालील कियोस्‍क अ‍ॅप्स अद्यतनांसाठी अयशस्‍वी झाले आहेत:</translation>
-<translation id="7634373849852678655">पूर्णस्क्रीन मधून निर्गमन करण्यासाठी अॅप बटण दाबा</translation>
 <translation id="7639178625568735185">समजले!</translation>
 <translation id="764017888128728">आपण जतन केलेल्या संकेतशब्दासह <ph name="PASSWORD_MANAGER_BRAND" /> स्वयंचलितपणे आपल्याला पात्र असलेल्या साइटमध्ये साइन इन करते.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (मालक)</translation>
@@ -4990,7 +4988,7 @@
 <translation id="8904976895050290827">Chrome Sync</translation>
 <translation id="8908902564709148335">चेतावणी: आपण या संगणकावर --स्क्रिप्‍ट-आवश्‍यक-क्रिया ध्वज सक्षम केला आहे, जो या विस्‍ताराच्या क्षमता मर्यादित करतो. तथापि, अन्य डिव्‍हाइसेस कदाचित या ध्वजास समर्थन देत नाही किंवा त्यांच्यावर तो सक्षम केलेला नसेल. या डिव्‍हाइसेसवर, हा विस्तार हे देखील करू शकतो:</translation>
 <translation id="8909233240676134608">मशीन डोमेनशी जोडू शकत नाही. सर्व्हर नमूद केलेल्या Kerberos एंक्रिप्शन प्रकारांना सपोर्ट करत नाही. एंक्रिप्शन सेटिंग्जसाठी "अधिक पर्याय" पहा.</translation>
-<translation id="8909833622202089127">साइट आपले स्थान ट्रॅक करत आहे</translation>
+<translation id="8909833622202089127">साइट तुमचे स्थान ट्रॅक करत आहे</translation>
 <translation id="8910146161325739742">आपली स्क्रीन शेअर करा</translation>
 <translation id="8910222113987937043">आपल्या बुकमार्क, इतिहास आणि अन्य सेटिंग्जसाठी बदल यापुढे आपल्या Google खात्यासह संकालित केले जाणार नाहीत. तथापि, आपला विद्यमान डेटा आपल्या Google खात्यामध्ये संग्रहित केलेला असेल आणि <ph name="BEGIN_LINK" />Google डॅशबोर्ड<ph name="END_LINK" /> वर व्यवस्थापित केला जाऊ शकतो.</translation>
 <translation id="8912793549644936705">पसरवा</translation>
diff --git a/chrome/app/resources/generated_resources_ms.xtb b/chrome/app/resources/generated_resources_ms.xtb
index 65e11af..a414194 100644
--- a/chrome/app/resources/generated_resources_ms.xtb
+++ b/chrome/app/resources/generated_resources_ms.xtb
@@ -3672,7 +3672,6 @@
           Gambar ini akan dipaparkan pada skrin log masuk dan skrin kunci Chromebook.</translation>
 <translation id="6769712124046837540">Menambah pencetak...</translation>
 <translation id="6771503742377376720">Adalah Pihak Berkuasa Pensijilan</translation>
-<translation id="6773575010135450071">Lebih banyak tindakan...</translation>
 <translation id="6777817260680419853">Ubah hala disekat</translation>
 <translation id="6778959797435875428">Nyahredam tapak</translation>
 <translation id="677965093459947883">Sangat kecil</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">Tab: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Sentiasa Buka Fail Jenis Ini</translation>
 <translation id="7632948528260659758">Apl kiosk berikut telah gagal untuk mengemas kini:</translation>
-<translation id="7634373849852678655">Tekan butang Apl untuk keluar daripada skrin penuh</translation>
 <translation id="7639178625568735185">Faham!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> melog masuk anda secara automatik ke tapak web yang layak menggunakan kata laluan yang disimpan.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (pemilik)</translation>
diff --git a/chrome/app/resources/generated_resources_nl.xtb b/chrome/app/resources/generated_resources_nl.xtb
index c74ccea6..6ddc260 100644
--- a/chrome/app/resources/generated_resources_nl.xtb
+++ b/chrome/app/resources/generated_resources_nl.xtb
@@ -3672,7 +3672,6 @@
           Deze foto wordt weergegeven op het inlogscherm en vergrendelingsscherm van de Chromebook.</translation>
 <translation id="6769712124046837540">Printer toevoegen…</translation>
 <translation id="6771503742377376720">Is een certificeringsinstantie</translation>
-<translation id="6773575010135450071">Meer acties...</translation>
 <translation id="6777817260680419853">Omleiding geblokkeerd</translation>
 <translation id="6778959797435875428">Geluid van sites dempen opheffen</translation>
 <translation id="677965093459947883">Zeer klein</translation>
@@ -4203,7 +4202,6 @@
 <translation id="7629827748548208700">Tabblad: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Altijd bestanden van dit type openen</translation>
 <translation id="7632948528260659758">Bijwerken van de volgende kiosk-apps is mislukt:</translation>
-<translation id="7634373849852678655">Druk op de knop App om het volledige scherm te sluiten</translation>
 <translation id="7639178625568735185">Begrepen!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> logt je automatisch in bij geschikte sites met wachtwoorden die je hebt opgeslagen.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (eigenaar)</translation>
diff --git a/chrome/app/resources/generated_resources_no.xtb b/chrome/app/resources/generated_resources_no.xtb
index be8b8c3..57693e1 100644
--- a/chrome/app/resources/generated_resources_no.xtb
+++ b/chrome/app/resources/generated_resources_no.xtb
@@ -3662,7 +3662,6 @@
           Dette bildet vises på låse- og påloggingsskjermen på Chromebooken.</translation>
 <translation id="6769712124046837540">Legger til skriver …</translation>
 <translation id="6771503742377376720">Er en sertifiseringsinstans</translation>
-<translation id="6773575010135450071">Flere handlinger</translation>
 <translation id="6777817260680419853">Viderekobling er blokkert</translation>
 <translation id="6778959797435875428">Slå på lyden for nettsteder</translation>
 <translation id="677965093459947883">Veldig liten</translation>
@@ -4185,7 +4184,6 @@
 <translation id="7629827748548208700">Fane: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Åpne &amp;alltid filer av denne typen</translation>
 <translation id="7632948528260659758">Kunne ikke oppdatere de følgende kioskappene:</translation>
-<translation id="7634373849852678655">Trykk på appknappen for å avslutte fullskjermvisningen</translation>
 <translation id="7639178625568735185">Skjønner!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> logger deg på kvalifiserte nettsteder automatisk med passord du har lagret.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (eier)</translation>
diff --git a/chrome/app/resources/generated_resources_pl.xtb b/chrome/app/resources/generated_resources_pl.xtb
index b1931b77..c14b453b 100644
--- a/chrome/app/resources/generated_resources_pl.xtb
+++ b/chrome/app/resources/generated_resources_pl.xtb
@@ -3671,7 +3671,6 @@
           Obraz pojawi się na ekranie blokady i ekranie logowania do Chromebooka.</translation>
 <translation id="6769712124046837540">Dodaję drukarkę...</translation>
 <translation id="6771503742377376720">Jest urzędem certyfikacji</translation>
-<translation id="6773575010135450071">Więcej czynności...</translation>
 <translation id="6777817260680419853">Przekierowanie zostało zablokowane</translation>
 <translation id="6778959797435875428">Zakończ wyciszanie stron</translation>
 <translation id="677965093459947883">Bardzo mała</translation>
@@ -4194,7 +4193,6 @@
 <translation id="7629827748548208700">Karta: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Zawsze otwieraj pliki tego typu</translation>
 <translation id="7632948528260659758">Nie udało się zaktualizować tych aplikacji kiosku:</translation>
-<translation id="7634373849852678655">Naciśnij przycisk aplikacji, by wyjść z trybu pełnoekranowego</translation>
 <translation id="7639178625568735185">Rozumiem</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> automatycznie loguje Cię w odpowiednich witrynach przy użyciu zapisanych wcześniej haseł.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (właściciel)</translation>
diff --git a/chrome/app/resources/generated_resources_pt-BR.xtb b/chrome/app/resources/generated_resources_pt-BR.xtb
index 00923ee..48b39ae 100644
--- a/chrome/app/resources/generated_resources_pt-BR.xtb
+++ b/chrome/app/resources/generated_resources_pt-BR.xtb
@@ -3673,7 +3673,6 @@
           Essa imagem será exibida na tela de login e na tela de bloqueio do Chromebook.</translation>
 <translation id="6769712124046837540">Adicionando impressora...</translation>
 <translation id="6771503742377376720">É uma Autoridade de certificação</translation>
-<translation id="6773575010135450071">Mais ações...</translation>
 <translation id="6777817260680419853">Redirecionamento bloqueado</translation>
 <translation id="6778959797435875428">Parar de ignorar sites</translation>
 <translation id="677965093459947883">Muito pequeno</translation>
@@ -4205,7 +4204,6 @@
 <translation id="7629827748548208700">Guia: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Sempre abrir arquivos deste tipo</translation>
 <translation id="7632948528260659758">Os seguintes aplicativos de quiosque tiveram falha na atualização:</translation>
-<translation id="7634373849852678655">Pressione o botão do app para sair da tela cheia</translation>
 <translation id="7639178625568735185">Entendi.</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> conecta você automaticamente a sites qualificados com as senhas que você salvou.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (proprietário)</translation>
diff --git a/chrome/app/resources/generated_resources_pt-PT.xtb b/chrome/app/resources/generated_resources_pt-PT.xtb
index 90766cc..e68e1e5 100644
--- a/chrome/app/resources/generated_resources_pt-PT.xtb
+++ b/chrome/app/resources/generated_resources_pt-PT.xtb
@@ -3674,7 +3674,6 @@
           Esta imagem irá aparecer no ecrã de início de sessão e no ecrã de bloqueio do Chromebook.</translation>
 <translation id="6769712124046837540">A adicionar impressora…</translation>
 <translation id="6771503742377376720">É uma autoridade de certificação</translation>
-<translation id="6773575010135450071">Mais ações...</translation>
 <translation id="6777817260680419853">Redirecionamento bloqueado</translation>
 <translation id="6778959797435875428">Reativar som dos sites</translation>
 <translation id="677965093459947883">Muito pequeno</translation>
@@ -4205,7 +4204,6 @@
 <translation id="7629827748548208700">Separador: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Abrir Sempre Ficheiros Deste Tipo</translation>
 <translation id="7632948528260659758">A atualização das seguintes aplicações quiosque falhou:</translation>
-<translation id="7634373849852678655">Prima o botão Aplicação para sair do ecrã inteiro.</translation>
 <translation id="7639178625568735185">Entendido!</translation>
 <translation id="764017888128728">O <ph name="PASSWORD_MANAGER_BRAND" /> inicia automaticamente sessão em sites elegíveis com as palavras-passe que guardou.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (proprietário)</translation>
diff --git a/chrome/app/resources/generated_resources_ro.xtb b/chrome/app/resources/generated_resources_ro.xtb
index 3827e0a..69242c5 100644
--- a/chrome/app/resources/generated_resources_ro.xtb
+++ b/chrome/app/resources/generated_resources_ro.xtb
@@ -3671,7 +3671,6 @@
           Această fotografie se va afișa pe ecranul de conectare și de blocare al Chromebookului.</translation>
 <translation id="6769712124046837540">Se adaugă imprimanta...</translation>
 <translation id="6771503742377376720">Este o Autoritate de certificare</translation>
-<translation id="6773575010135450071">Mai multe acțiuni...</translation>
 <translation id="6777817260680419853">Redirecționarea a fost blocată</translation>
 <translation id="6778959797435875428">Activează sunetul pentru site-uri</translation>
 <translation id="677965093459947883">Foarte mică</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">Fila: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Deschide întotdeauna fișierele de acest tip</translation>
 <translation id="7632948528260659758">Următoarele aplicații de tip chioșc nu au fost actualizate:</translation>
-<translation id="7634373849852678655">Apasă butonul Aplicație pentru a ieși din ecranul complet</translation>
 <translation id="7639178625568735185">Am înțeles!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> te conectează automat pe site-urile eligibile cu parolele pe care le-ai salvat.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (proprietar)</translation>
diff --git a/chrome/app/resources/generated_resources_ru.xtb b/chrome/app/resources/generated_resources_ru.xtb
index a5c2cbb..dba5376 100644
--- a/chrome/app/resources/generated_resources_ru.xtb
+++ b/chrome/app/resources/generated_resources_ru.xtb
@@ -2069,7 +2069,7 @@
 <translation id="4181841719683918333">Языки</translation>
 <translation id="4184885522552335684">Перетащите дисплей на новое место</translation>
 <translation id="4193154014135846272">Документ Google</translation>
-<translation id="4194570336751258953">Включить функцию tap-to-click (нажатие коротким прикосновением)</translation>
+<translation id="4194570336751258953">Включить нажатие от прикосновения</translation>
 <translation id="4195643157523330669">Открыть в новой вкладке</translation>
 <translation id="4195814663415092787">Ранее открытые вкладки</translation>
 <translation id="4197674956721858839">Архивировать выбранные элементы</translation>
@@ -3672,7 +3672,6 @@
           Это изображение появится на экране входа и блокировки Chromebook.</translation>
 <translation id="6769712124046837540">Добавление принтера...</translation>
 <translation id="6771503742377376720">Является центром сертификации</translation>
-<translation id="6773575010135450071">Ещё</translation>
 <translation id="6777817260680419853">Попытка переадресации заблокирована</translation>
 <translation id="6778959797435875428">Включить звук на сайтах</translation>
 <translation id="677965093459947883">Очень мелкий</translation>
@@ -4203,7 +4202,6 @@
 <translation id="7629827748548208700">Вкладка: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Всегда открывать файлы этого типа</translation>
 <translation id="7632948528260659758">Не удалось обновить следующие киоск-приложения:</translation>
-<translation id="7634373849852678655">Нажмите кнопку приложения, чтобы выйти из полноэкранного режима</translation>
 <translation id="7639178625568735185">Готово!</translation>
 <translation id="764017888128728">С помощью <ph name="PASSWORD_MANAGER_BRAND" /> вы будете автоматически входить на сайты, для которых сохранили пароли.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (владелец)</translation>
diff --git a/chrome/app/resources/generated_resources_sk.xtb b/chrome/app/resources/generated_resources_sk.xtb
index 837007f..5d14eaa5 100644
--- a/chrome/app/resources/generated_resources_sk.xtb
+++ b/chrome/app/resources/generated_resources_sk.xtb
@@ -3669,7 +3669,6 @@
 <translation id="6766101255664245434">Urobte novú fotku alebo si zvoľte existujúcu fotku či ikonu.<ph name="LINE_BREAK" />Táto fotka sa bude zobrazovať na prihlasovacej aj uzamknutej obrazovke Chromebooku.</translation>
 <translation id="6769712124046837540">Pridáva sa tlačiareň...</translation>
 <translation id="6771503742377376720">Je certifikačnou autoritou</translation>
-<translation id="6773575010135450071">Ďalšie akcie...</translation>
 <translation id="6777817260680419853">Presmerovanie bolo zablokované</translation>
 <translation id="6778959797435875428">Zapnúť zvuk webov</translation>
 <translation id="677965093459947883">Veľmi malé</translation>
@@ -4200,7 +4199,6 @@
 <translation id="7629827748548208700">Karta: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Súbory tohto typu &amp;vždy otvoriť</translation>
 <translation id="7632948528260659758">Nepodarilo sa aktualizovať nasledujúce aplikácie Kiosku:</translation>
-<translation id="7634373849852678655">Režim celej obrazovky ukončíte stlačením tlačidla Aplikácia</translation>
 <translation id="7639178625568735185">Dobre.</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> vás automaticky prihlási na vhodných weboch pomocou hesiel, ktoré ste si uložili.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (vlastník)</translation>
diff --git a/chrome/app/resources/generated_resources_sl.xtb b/chrome/app/resources/generated_resources_sl.xtb
index cc4fb30..efcfd98 100644
--- a/chrome/app/resources/generated_resources_sl.xtb
+++ b/chrome/app/resources/generated_resources_sl.xtb
@@ -2072,7 +2072,7 @@
 <translation id="4194570336751258953">Omogoči klik z dotikom</translation>
 <translation id="4195643157523330669">Odpri v novem zavihku</translation>
 <translation id="4195814663415092787">Nadaljuj prejšnjo sejo</translation>
-<translation id="4197674956721858839">Izbor za datoteko zip</translation>
+<translation id="4197674956721858839">Stisni izbor v datoteko zip</translation>
 <translation id="4198146608511578238">Pridržite ikono zaganjalnika, če želite komunicirati s Pomočnikom Google.</translation>
 <translation id="4200689466366162458">Besede po meri</translation>
 <translation id="4200983522494130825">Nov &amp;zavihek</translation>
@@ -3657,7 +3657,7 @@
 <translation id="6742339027238151589">Dostopno skriptu</translation>
 <translation id="6745592621698551453">Posodobi</translation>
 <translation id="6746124502594467657">Premakni dol</translation>
-<translation id="674632704103926902">Omogoči vlečenje zavihkov</translation>
+<translation id="674632704103926902">Omogoči vlečenje z dotikom</translation>
 <translation id="6746392203843147041">zvišanje glasnosti</translation>
 <translation id="6748217015615267851">Upodabljalnik: <ph name="RENDERER_URL" /></translation>
 <translation id="6748465660675848252">Lahko nadaljujete, toda obnovljeni bodo samo sinhronizirani podatki in nastavitve. Vsi lokalni podatki bodo izgubljeni.</translation>
@@ -3672,7 +3672,6 @@
           Ta slika se bo prikazala na zaslonu za prijavo in zaklenjenem zaslonu Chromebooka.</translation>
 <translation id="6769712124046837540">Dodajanje tiskalnika ...</translation>
 <translation id="6771503742377376720">Je overitelj potrdil</translation>
-<translation id="6773575010135450071">Več dejanj ...</translation>
 <translation id="6777817260680419853">Preusmeritev je blokirana</translation>
 <translation id="6778959797435875428">Vklopi zvok spletnih mest</translation>
 <translation id="677965093459947883">Zelo majhna</translation>
@@ -4203,7 +4202,6 @@
 <translation id="7629827748548208700">Zavihek: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Vedno odpri to vrsto datotek</translation>
 <translation id="7632948528260659758">Teh aplikacij kioska ni bilo mogoče posodobiti:</translation>
-<translation id="7634373849852678655">Pritisnite gumb za aplikacijo, če želite zapreti celozaslonski način</translation>
 <translation id="7639178625568735185">Razumem.</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> vas z gesli, ki ste jih shranili, samodejno prijavi v ustrezna spletna mesta.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (lastnik)</translation>
diff --git a/chrome/app/resources/generated_resources_sr.xtb b/chrome/app/resources/generated_resources_sr.xtb
index d29ad1f..4c2bf58 100644
--- a/chrome/app/resources/generated_resources_sr.xtb
+++ b/chrome/app/resources/generated_resources_sr.xtb
@@ -3668,7 +3668,6 @@
           Ова слика ће се приказивати на Chromebook екрану за пријављивање и закључаном екрану.</translation>
 <translation id="6769712124046837540">Додавање штампача...</translation>
 <translation id="6771503742377376720">Јесте ауторитет за издавање сертификата</translation>
-<translation id="6773575010135450071">Још радњи...</translation>
 <translation id="6777817260680419853">Преусмеравање је блокирано</translation>
 <translation id="6778959797435875428">Укључи звук сајтова</translation>
 <translation id="677965093459947883">Јако мали</translation>
@@ -4193,7 +4192,6 @@
 <translation id="7629827748548208700">Картица: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Увек отвори датотеке овог типа</translation>
 <translation id="7632948528260659758">Ажурирање следећих киоск апликација није успело:</translation>
-<translation id="7634373849852678655">Притисните дугме Апликације да бисте изашли из режима целог екрана</translation>
 <translation id="7639178625568735185">Важи!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> вас аутоматски пријављује на сајтове који испуњавају услове помоћу лозинки које сте сачували.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (власник)</translation>
diff --git a/chrome/app/resources/generated_resources_sv.xtb b/chrome/app/resources/generated_resources_sv.xtb
index a7e747c..b86d092 100644
--- a/chrome/app/resources/generated_resources_sv.xtb
+++ b/chrome/app/resources/generated_resources_sv.xtb
@@ -3670,7 +3670,6 @@
           Den här bilden visas på inloggnings- och låsskärmen på Chromebook.</translation>
 <translation id="6769712124046837540">Lägger till skrivare ...</translation>
 <translation id="6771503742377376720">Är en certifikatutfärdare</translation>
-<translation id="6773575010135450071">Fler åtgärder ...</translation>
 <translation id="6777817260680419853">Omdirigeringen blockerades</translation>
 <translation id="6778959797435875428">Ta fram dolda webbplatser</translation>
 <translation id="677965093459947883">Mycket liten</translation>
@@ -4200,7 +4199,6 @@
 <translation id="7629827748548208700">Flik: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Öppna &amp;alltid filer av denna typ</translation>
 <translation id="7632948528260659758">Det gick inte att uppdatera följande kioskappar:</translation>
-<translation id="7634373849852678655">Tryck på appknappen om du vill lämna helskärmsläget</translation>
 <translation id="7639178625568735185">Uppfattat!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> loggar automatiskt in på godkända webbplatser med de lösenord du sparat.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (ägare)</translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb
index 90046ace..896e658 100644
--- a/chrome/app/resources/generated_resources_sw.xtb
+++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -3663,7 +3663,6 @@
           Utaiona picha hii kwenye Chromebook katika skrini ya kuingia na skrini iliyofungwa.</translation>
 <translation id="6769712124046837540">Inaongeza printa...</translation>
 <translation id="6771503742377376720">Ni Idhini ya Cheti</translation>
-<translation id="6773575010135450071">Vitendo zaidi...</translation>
 <translation id="6777817260680419853">Imezuia shughuli ya kuelekeza kwingine</translation>
 <translation id="6778959797435875428">Washa sauti za tovuti</translation>
 <translation id="677965093459947883">Ndogo sana</translation>
@@ -4194,7 +4193,6 @@
 <translation id="7629827748548208700">Kichupo: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Fungua Faili za Aina Hii Kil&amp;a Wakati</translation>
 <translation id="7632948528260659758">Programu zifuatazo za kioski zimeshindwa kusasisha:</translation>
-<translation id="7634373849852678655">Bonyeza kitufe cha Programu ili ufunge skrini nzima</translation>
 <translation id="7639178625568735185">Nimepata!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> hukuwezesha kuingia katika tovuti zinazofaa kiotomatiki kwa manenosiri uliyohifadhi.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (mmiliki)</translation>
diff --git a/chrome/app/resources/generated_resources_ta.xtb b/chrome/app/resources/generated_resources_ta.xtb
index 9f9b5b68..4d8aae3 100644
--- a/chrome/app/resources/generated_resources_ta.xtb
+++ b/chrome/app/resources/generated_resources_ta.xtb
@@ -3672,7 +3672,6 @@
           Chromebook இன் உள்நுழைவுத் திரையிலும் பூட்டுத் திரையிலும் இந்தப் படம் காட்டப்படும்.</translation>
 <translation id="6769712124046837540">பிரிண்டரைச் சேர்க்கிறது...</translation>
 <translation id="6771503742377376720">இது ஒரு சான்றளிக்கும் மையம்</translation>
-<translation id="6773575010135450071">மேலும் செயல்கள்...</translation>
 <translation id="6777817260680419853">திசைதிருப்புவது தடுக்கப்பட்டது</translation>
 <translation id="6778959797435875428">தளங்களில் ஒலி இயக்கு</translation>
 <translation id="677965093459947883">மிகச் சிறியது</translation>
@@ -4195,7 +4194,6 @@
 <translation id="7629827748548208700">தாவல்: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;எப்போதும் இந்த வகை கோப்புகளைத் திற</translation>
 <translation id="7632948528260659758">பின்வரும் கியோஸ்க் பயன்பாடுகளைப் புதுப்பிப்பதில் தோல்வி:</translation>
-<translation id="7634373849852678655">முழுத்திரையை விட்டு வெளியேற, பயன்பாட்டுப் பொத்தானை அழுத்தவும்</translation>
 <translation id="7639178625568735185">புரிந்தது!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> நீங்கள் சேமித்த கடவுச்சொற்களைப் பயன்படுத்தி தகுதியுள்ள தளங்களில் உங்களைத் தானாக உள்நுழையச் செய்யும்.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (உரிமையாளர்)</translation>
diff --git a/chrome/app/resources/generated_resources_te.xtb b/chrome/app/resources/generated_resources_te.xtb
index 56f77d3..4ce6357 100644
--- a/chrome/app/resources/generated_resources_te.xtb
+++ b/chrome/app/resources/generated_resources_te.xtb
@@ -3671,7 +3671,6 @@
           ఈ చిత్రం Chromebook సైన్ ఇన్ స్క్రీన్ మరియు లాక్ స్క్రీన్‌లలో చూపబడుతుంది.</translation>
 <translation id="6769712124046837540">ప్రింటర్‌ని జోడిస్తోంది...</translation>
 <translation id="6771503742377376720">ప్రమాణపత్ర అధికారం</translation>
-<translation id="6773575010135450071">మరిన్ని చర్యలు...</translation>
 <translation id="6777817260680419853">మళ్ళింపు బ్లాక్ చేయబడింది</translation>
 <translation id="6778959797435875428">సైట్‌లను అన్‌మ్యూట్ చేయండి</translation>
 <translation id="677965093459947883">చాలా చిన్నవిగా</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">టాబ్: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;ఎల్లప్పుడూ ఈ రకం ఫైళ్ళను తెరువు</translation>
 <translation id="7632948528260659758">క్రింది కియోస్క్ అనువర్తనాల నవీకరణ విఫలమైంది:</translation>
-<translation id="7634373849852678655">పూర్తి స్క్రీన్ నుండి నిష్క్రమించడం కోసం యాప్ బటన్‌ని నొక్కండి</translation>
 <translation id="7639178625568735185">అర్థమైంది!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> మీరు సేవ్ చేసిన పాస్‌వర్డ్‌లతో అర్హత ఉన్న సైట్‌లకు మిమ్మల్ని స్వయంచాలకంగా సైన్ ఇన్ చేస్తుంది.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (యజమాని)</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb
index 9e3b7ad3..5a98ed1 100644
--- a/chrome/app/resources/generated_resources_th.xtb
+++ b/chrome/app/resources/generated_resources_th.xtb
@@ -3671,7 +3671,6 @@
           ภาพนี้จะแสดงในหน้าลงชื่อเข้าใช้และหน้าจอล็อกของ Chromebook</translation>
 <translation id="6769712124046837540">กำลังเพิ่มเครื่องพิมพ์...</translation>
 <translation id="6771503742377376720">เป็นผู้ออกใบรับรอง</translation>
-<translation id="6773575010135450071">การทำงานเพิ่มเติม...</translation>
 <translation id="6777817260680419853">การเปลี่ยนเส้นทางถูกบล็อก</translation>
 <translation id="6778959797435875428">เปิดเสียงเว็บไซต์</translation>
 <translation id="677965093459947883">เล็กมาก</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">แท็บ: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;เปิดไฟล์ประเภทนี้เสมอ</translation>
 <translation id="7632948528260659758">แอปคีออสก์ต่อไปนี้ไม่สามารถอัปเดตได้:</translation>
-<translation id="7634373849852678655">กดปุ่มแอปเพื่อออกจากโหมดเต็มหน้าจอ</translation>
 <translation id="7639178625568735185">สำเร็จ!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> ลงชื่อเข้าใช้ให้คุณในเว็บไซต์ที่มีสิทธิ์โดยอัตโนมัติด้วยรหัสผ่านที่คุณบันทึกไว้</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (เจ้าของ)</translation>
diff --git a/chrome/app/resources/generated_resources_tr.xtb b/chrome/app/resources/generated_resources_tr.xtb
index f99e8a1..adbef15 100644
--- a/chrome/app/resources/generated_resources_tr.xtb
+++ b/chrome/app/resources/generated_resources_tr.xtb
@@ -3672,7 +3672,6 @@
           Bu resim, Chromebook oturum açma ekranında ve kilit ekranında gösterilir.</translation>
 <translation id="6769712124046837540">Yazıcı ekleniyor...</translation>
 <translation id="6771503742377376720">Sertifika Yetkilisidir</translation>
-<translation id="6773575010135450071">Diğer işlemler...</translation>
 <translation id="6777817260680419853">Yönlendirme engellendi</translation>
 <translation id="6778959797435875428">Sitelerin sesini aç</translation>
 <translation id="677965093459947883">Çok küçük</translation>
@@ -4203,7 +4202,6 @@
 <translation id="7629827748548208700">Sekme: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">Bu Tür Dosyaları &amp;Her Zaman Aç</translation>
 <translation id="7632948528260659758">Aşağıdaki kiosk uygulamaları güncellenemedi:</translation>
-<translation id="7634373849852678655">Tam ekrandan çıkmak için Uygulama düğmesine basın</translation>
 <translation id="7639178625568735185">Anlaşıldı!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" />, kaydettiğiniz şifrelerle uygun sitelerde otomatik olarak oturum açmanızı sağlar.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (cihaz sahibi)</translation>
diff --git a/chrome/app/resources/generated_resources_uk.xtb b/chrome/app/resources/generated_resources_uk.xtb
index 8c92e4d2..f9a50262 100644
--- a/chrome/app/resources/generated_resources_uk.xtb
+++ b/chrome/app/resources/generated_resources_uk.xtb
@@ -3671,7 +3671,6 @@
           Це зображення з’являтиметься на екрані входу та заблокованому екрані Chromebook.</translation>
 <translation id="6769712124046837540">Додавання принтера…</translation>
 <translation id="6771503742377376720">Є Центром сертифікації</translation>
-<translation id="6773575010135450071">Інші дії…</translation>
 <translation id="6777817260680419853">Переспрямування заблоковано</translation>
 <translation id="6778959797435875428">Увімкнути звук на сайтах</translation>
 <translation id="677965093459947883">Дуже малий</translation>
@@ -4202,7 +4201,6 @@
 <translation id="7629827748548208700">Вкладка: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Завжди відкривати файли цього типу</translation>
 <translation id="7632948528260659758">Не вдалось оновити такі додатки-термінали:</translation>
-<translation id="7634373849852678655">Щоб вийти з повноекранного режиму, натисніть кнопку додатка</translation>
 <translation id="7639178625568735185">Готово!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> зберігає ваші паролі й автоматично входить в облікові записи на сайтах.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (власник)</translation>
diff --git a/chrome/app/resources/generated_resources_vi.xtb b/chrome/app/resources/generated_resources_vi.xtb
index 9faceb19..2d947eb 100644
--- a/chrome/app/resources/generated_resources_vi.xtb
+++ b/chrome/app/resources/generated_resources_vi.xtb
@@ -3672,7 +3672,6 @@
           Hình ảnh này sẽ hiển thị trên màn hình khóa và màn hình đăng nhập của Chromebook.</translation>
 <translation id="6769712124046837540">Đang thêm máy in...</translation>
 <translation id="6771503742377376720">Là Tổ chức phát hành chứng chỉ</translation>
-<translation id="6773575010135450071">Thêm tác vụ...</translation>
 <translation id="6777817260680419853">Đã chặn chuyển hướng</translation>
 <translation id="6778959797435875428">Bật tiếng các trang web</translation>
 <translation id="677965093459947883">Rất nhỏ</translation>
@@ -4203,7 +4202,6 @@
 <translation id="7629827748548208700">Tab: <ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">&amp;Luôn Mở Loại Tệp Này</translation>
 <translation id="7632948528260659758">Không cập nhật được các ứng dụng kiosk sau:</translation>
-<translation id="7634373849852678655">Nhấn vào nút Ứng dụng để thoát khỏi chế độ toàn màn hình</translation>
 <translation id="7639178625568735185">Bỏ qua!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> tự động đăng nhập bạn vào các trang web đủ điều kiện bằng mật khẩu bạn đã lưu.</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (chủ sở hữu)</translation>
diff --git a/chrome/app/resources/generated_resources_zh-CN.xtb b/chrome/app/resources/generated_resources_zh-CN.xtb
index c8ff9584..5d60a76 100644
--- a/chrome/app/resources/generated_resources_zh-CN.xtb
+++ b/chrome/app/resources/generated_resources_zh-CN.xtb
@@ -3657,7 +3657,6 @@
           此图片将会显示在 Chromebook 的登录屏幕和锁定屏幕上。</translation>
 <translation id="6769712124046837540">添加打印机…</translation>
 <translation id="6771503742377376720">是证书授权中心</translation>
-<translation id="6773575010135450071">更多操作…</translation>
 <translation id="6777817260680419853">已阻止重定向</translation>
 <translation id="6778959797435875428">将多个网站取消静音</translation>
 <translation id="677965093459947883">特小</translation>
@@ -4179,7 +4178,6 @@
 <translation id="7629827748548208700">标签页:<ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">总是打开此类文件(&amp;A)</translation>
 <translation id="7632948528260659758">以下自助服务终端应用未能成功更新:</translation>
-<translation id="7634373849852678655">按“应用”按钮即可退出全屏模式</translation>
 <translation id="7639178625568735185">知道了!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> 会使用您保存的密码让您自动登录到符合条件的网站。</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" />(所有者)</translation>
diff --git a/chrome/app/resources/generated_resources_zh-TW.xtb b/chrome/app/resources/generated_resources_zh-TW.xtb
index 082c2fe..f171ecd9 100644
--- a/chrome/app/resources/generated_resources_zh-TW.xtb
+++ b/chrome/app/resources/generated_resources_zh-TW.xtb
@@ -3668,7 +3668,6 @@
           這張圖片會顯示在 Chromebook 的登入畫面和鎖定畫面中。</translation>
 <translation id="6769712124046837540">新增印表機...</translation>
 <translation id="6771503742377376720">這是憑證授權單位</translation>
-<translation id="6773575010135450071">更多動作...</translation>
 <translation id="6777817260680419853">已禁止重新導向</translation>
 <translation id="6778959797435875428">開啟多個網站音訊</translation>
 <translation id="677965093459947883">非常小</translation>
@@ -4196,7 +4195,6 @@
 <translation id="7629827748548208700">分頁:<ph name="TAB_NAME" /></translation>
 <translation id="7631887513477658702">一律開啟這類檔案(&amp;A)</translation>
 <translation id="7632948528260659758">下列 Kiosk 應用程式更新失敗:</translation>
-<translation id="7634373849852678655">按下應用程式按鈕即可結束全螢幕模式</translation>
 <translation id="7639178625568735185">我瞭解了!</translation>
 <translation id="764017888128728"><ph name="PASSWORD_MANAGER_BRAND" /> 會使用您儲存的密碼,讓您自動登入符合資格的網站。</translation>
 <translation id="7645176681409127223"><ph name="USER_NAME" /> (擁有者)</translation>
diff --git a/chrome/app/resources/google_chrome_strings_cs.xtb b/chrome/app/resources/google_chrome_strings_cs.xtb
index 775856c5..1e3f6b6 100644
--- a/chrome/app/resources/google_chrome_strings_cs.xtb
+++ b/chrome/app/resources/google_chrome_strings_cs.xtb
@@ -96,7 +96,7 @@
 <ph name="BEGIN_LINK_2" />Další informace<ph name="END_LINK_2" />
 
 Další pokyny naleznete v e-mailu ve svém účtu <ph name="ACCOUNT_EMAIL" />.</translation>
-<translation id="3282568296779691940">Přihlášení do Chrome</translation>
+<translation id="3282568296779691940">Přihlásit se do Chromu</translation>
 <translation id="3360895254066713204">Chrome Helper</translation>
 <translation id="3395323229510056640">Pomoc se systémem Chrome OS</translation>
 <translation id="3396977131400919238">Během instalace došlo k chybě operačního systému. Stáhněte prosím Google Chrome ještě jednou.</translation>
diff --git a/chrome/app/theme/default_100_percent/common/favicon_bookmarks.png b/chrome/app/theme/default_100_percent/common/favicon_bookmarks.png
index b220d7c4..d9bce44 100644
--- a/chrome/app/theme/default_100_percent/common/favicon_bookmarks.png
+++ b/chrome/app/theme/default_100_percent/common/favicon_bookmarks.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/favicon_conflicts.png b/chrome/app/theme/default_100_percent/common/favicon_conflicts.png
index fbd60c4..23dd5ea 100644
--- a/chrome/app/theme/default_100_percent/common/favicon_conflicts.png
+++ b/chrome/app/theme/default_100_percent/common/favicon_conflicts.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/favicon_downloads.png b/chrome/app/theme/default_100_percent/common/favicon_downloads.png
index 0f8838f..d0b7b56 100644
--- a/chrome/app/theme/default_100_percent/common/favicon_downloads.png
+++ b/chrome/app/theme/default_100_percent/common/favicon_downloads.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/favicon_extensions.png b/chrome/app/theme/default_100_percent/common/favicon_extensions.png
index e4a6522..b845820 100644
--- a/chrome/app/theme/default_100_percent/common/favicon_extensions.png
+++ b/chrome/app/theme/default_100_percent/common/favicon_extensions.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/favicon_print_preview.png b/chrome/app/theme/default_100_percent/common/favicon_print_preview.png
index 5bdb469..48ebb94 100644
--- a/chrome/app/theme/default_100_percent/common/favicon_print_preview.png
+++ b/chrome/app/theme/default_100_percent/common/favicon_print_preview.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/favicon_settings.png b/chrome/app/theme/default_100_percent/common/favicon_settings.png
index 1767934..d35b668 100644
--- a/chrome/app/theme/default_100_percent/common/favicon_settings.png
+++ b/chrome/app/theme/default_100_percent/common/favicon_settings.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/legacy/favicon_laptop.png b/chrome/app/theme/default_100_percent/legacy/favicon_laptop.png
index b420608..698ea8b 100644
--- a/chrome/app/theme/default_100_percent/legacy/favicon_laptop.png
+++ b/chrome/app/theme/default_100_percent/legacy/favicon_laptop.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/legacy/favicon_phone.png b/chrome/app/theme/default_100_percent/legacy/favicon_phone.png
index 90e5b524..ab576267 100644
--- a/chrome/app/theme/default_100_percent/legacy/favicon_phone.png
+++ b/chrome/app/theme/default_100_percent/legacy/favicon_phone.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/legacy/favicon_tablet.png b/chrome/app/theme/default_100_percent/legacy/favicon_tablet.png
index 84217a9..c1458f1 100644
--- a/chrome/app/theme/default_100_percent/legacy/favicon_tablet.png
+++ b/chrome/app/theme/default_100_percent/legacy/favicon_tablet.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/favicon_bookmarks.png b/chrome/app/theme/default_200_percent/common/favicon_bookmarks.png
index f6684d7..68a557e 100644
--- a/chrome/app/theme/default_200_percent/common/favicon_bookmarks.png
+++ b/chrome/app/theme/default_200_percent/common/favicon_bookmarks.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/favicon_conflicts.png b/chrome/app/theme/default_200_percent/common/favicon_conflicts.png
index 7694a51..fd856cb7 100644
--- a/chrome/app/theme/default_200_percent/common/favicon_conflicts.png
+++ b/chrome/app/theme/default_200_percent/common/favicon_conflicts.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/favicon_downloads.png b/chrome/app/theme/default_200_percent/common/favicon_downloads.png
index 32c4802..f232355 100644
--- a/chrome/app/theme/default_200_percent/common/favicon_downloads.png
+++ b/chrome/app/theme/default_200_percent/common/favicon_downloads.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/favicon_extensions.png b/chrome/app/theme/default_200_percent/common/favicon_extensions.png
index f893e3e1..12fbd41 100644
--- a/chrome/app/theme/default_200_percent/common/favicon_extensions.png
+++ b/chrome/app/theme/default_200_percent/common/favicon_extensions.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/favicon_print_preview.png b/chrome/app/theme/default_200_percent/common/favicon_print_preview.png
index e3efff2..f99c7c9 100644
--- a/chrome/app/theme/default_200_percent/common/favicon_print_preview.png
+++ b/chrome/app/theme/default_200_percent/common/favicon_print_preview.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/favicon_settings.png b/chrome/app/theme/default_200_percent/common/favicon_settings.png
index 73fb82d..2a92c3a 100644
--- a/chrome/app/theme/default_200_percent/common/favicon_settings.png
+++ b/chrome/app/theme/default_200_percent/common/favicon_settings.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/legacy/favicon_laptop.png b/chrome/app/theme/default_200_percent/legacy/favicon_laptop.png
index e9c35b1..5ac0165c 100644
--- a/chrome/app/theme/default_200_percent/legacy/favicon_laptop.png
+++ b/chrome/app/theme/default_200_percent/legacy/favicon_laptop.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/legacy/favicon_phone.png b/chrome/app/theme/default_200_percent/legacy/favicon_phone.png
index 03f2e6a5..7a83337 100644
--- a/chrome/app/theme/default_200_percent/legacy/favicon_phone.png
+++ b/chrome/app/theme/default_200_percent/legacy/favicon_phone.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/legacy/favicon_tablet.png b/chrome/app/theme/default_200_percent/legacy/favicon_tablet.png
index 49d13a9..ac453a6 100644
--- a/chrome/app/theme/default_200_percent/legacy/favicon_tablet.png
+++ b/chrome/app/theme/default_200_percent/legacy/favicon_tablet.png
Binary files differ
diff --git a/chrome/app/vector_icons/profile_switcher_outline.icon b/chrome/app/vector_icons/profile_switcher_outline.icon
index e9c12ce..f7efb07 100644
--- a/chrome/app/vector_icons/profile_switcher_outline.icon
+++ b/chrome/app/vector_icons/profile_switcher_outline.icon
@@ -5,7 +5,6 @@
 // This is a copy of account_circle.icon with an added path for an outline.
 // Outline:
 STROKE, 3,
-PATH_COLOR_ARGB, 0xff, 0x5a, 0x5a, 0x5a,
 MOVE_TO, 24, 4,
 CUBIC_TO, 12.95f, 4, 4, 12.95f, 4, 24,
 R_CUBIC_TO, 0, 11.05f, 8.95f, 20, 20, 20,
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 723b41d3..0e8da5e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -79,6 +79,7 @@
 #include "components/search_provider_logos/switches.h"
 #include "components/security_state/core/features.h"
 #include "components/security_state/core/security_state.h"
+#include "components/services/heap_profiling/public/cpp/switches.h"
 #include "components/signin/core/browser/profile_management_switches.h"
 #include "components/signin/core/browser/signin_buildflags.h"
 #include "components/signin/core/browser/signin_switches.h"
@@ -972,30 +973,30 @@
 const FeatureEntry::Choice kEnableOutOfProcessHeapProfilingChoices[] = {
     {flags_ui::kGenericExperimentChoiceDisabled, "", ""},
     {flag_descriptions::kEnableOutOfProcessHeapProfilingModeMinimal,
-     switches::kMemlog, switches::kMemlogModeMinimal},
+     heap_profiling::kMemlog, heap_profiling::kMemlogModeMinimal},
     {flag_descriptions::kEnableOutOfProcessHeapProfilingModeAll,
-     switches::kMemlog, switches::kMemlogModeAll},
+     heap_profiling::kMemlog, heap_profiling::kMemlogModeAll},
     {flag_descriptions::kEnableOutOfProcessHeapProfilingModeBrowser,
-     switches::kMemlog, switches::kMemlogModeBrowser},
+     heap_profiling::kMemlog, heap_profiling::kMemlogModeBrowser},
     {flag_descriptions::kEnableOutOfProcessHeapProfilingModeGpu,
-     switches::kMemlog, switches::kMemlogModeGpu},
+     heap_profiling::kMemlog, heap_profiling::kMemlogModeGpu},
     {flag_descriptions::kEnableOutOfProcessHeapProfilingModeAllRenderers,
-     switches::kMemlog, switches::kMemlogModeAllRenderers},
+     heap_profiling::kMemlog, heap_profiling::kMemlogModeAllRenderers},
     {flag_descriptions::kEnableOutOfProcessHeapProfilingModeManual,
-     switches::kMemlog, switches::kMemlogModeManual},
+     heap_profiling::kMemlog, heap_profiling::kMemlogModeManual},
 };
 
 const FeatureEntry::Choice kOOPHPStackModeChoices[] = {
     {flags_ui::kGenericExperimentChoiceDisabled, "", ""},
-    {flag_descriptions::kOOPHPStackModeNative, switches::kMemlogStackMode,
-     switches::kMemlogStackModeNative},
+    {flag_descriptions::kOOPHPStackModeNative, heap_profiling::kMemlogStackMode,
+     heap_profiling::kMemlogStackModeNative},
     {flag_descriptions::kOOPHPStackModeNativeWithThreadNames,
-     switches::kMemlogStackMode,
-     switches::kMemlogStackModeNativeWithThreadNames},
-    {flag_descriptions::kOOPHPStackModePseudo, switches::kMemlogStackMode,
-     switches::kMemlogStackModePseudo},
-    {flag_descriptions::kOOPHPStackModeMixed, switches::kMemlogStackMode,
-     switches::kMemlogStackModeMixed},
+     heap_profiling::kMemlogStackMode,
+     heap_profiling::kMemlogStackModeNativeWithThreadNames},
+    {flag_descriptions::kOOPHPStackModePseudo, heap_profiling::kMemlogStackMode,
+     heap_profiling::kMemlogStackModePseudo},
+    {flag_descriptions::kOOPHPStackModeMixed, heap_profiling::kMemlogStackMode,
+     heap_profiling::kMemlogStackModeMixed},
 };
 
 const FeatureEntry::FeatureParam kOmniboxUIMaxAutocompleteMatches3[] = {
@@ -3191,11 +3192,11 @@
      flag_descriptions::kOutOfProcessHeapProfilingKeepSmallAllocations,
      flag_descriptions::
          kOutOfProcessHeapProfilingKeepSmallAllocationsDescription,
-     kOsAll, SINGLE_VALUE_TYPE(switches::kMemlogKeepSmallAllocations)},
+     kOsAll, SINGLE_VALUE_TYPE(heap_profiling::kMemlogKeepSmallAllocations)},
 
     {"memlog-sampling", flag_descriptions::kOutOfProcessHeapProfilingSampling,
      flag_descriptions::kOutOfProcessHeapProfilingSamplingDescription, kOsAll,
-     SINGLE_VALUE_TYPE(switches::kMemlogSampling)},
+     SINGLE_VALUE_TYPE(heap_profiling::kMemlogSampling)},
 
     {"memlog-stack-mode", flag_descriptions::kOOPHPStackModeName,
      flag_descriptions::kOOPHPStackModeDescription, kOsAll,
@@ -3820,6 +3821,12 @@
      FEATURE_VALUE_TYPE(chrome::android::kHorizontalTabSwitcherAndroid)},
 #endif  // OS_ANDROID
 
+#if defined(OS_CHROMEOS)
+    {"enable-home-launcher", flag_descriptions::kEnableHomeLauncherName,
+     flag_descriptions::kEnableHomeLauncherDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(app_list::features::kEnableHomeLauncher)},
+#endif  // OS_CHROMEOS
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/contextual_suggestions/contextual_suggestions_bridge.cc b/chrome/browser/android/contextual_suggestions/contextual_suggestions_bridge.cc
index e7ad588a..e77b29b 100644
--- a/chrome/browser/android/contextual_suggestions/contextual_suggestions_bridge.cc
+++ b/chrome/browser/android/contextual_suggestions/contextual_suggestions_bridge.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/profiles/profile_android.h"
 #include "components/ntp_snippets/category.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
 #include "components/ukm/content/source_url_recorder.h"
 #include "content/public/browser/web_contents.h"
 #include "jni/ContextualSuggestionsBridge_jni.h"
@@ -138,8 +139,10 @@
   ukm::SourceId ukm_source_id =
       ukm::GetSourceIdForWebContentsDocument(web_contents);
 
-  contextual_content_suggestions_service_->ReportEvent(ukm_source_id,
-                                                       j_event_id);
+  contextual_suggestions::ContextualSuggestionsEvent event =
+      static_cast<contextual_suggestions::ContextualSuggestionsEvent>(
+          j_event_id);
+  contextual_content_suggestions_service_->ReportEvent(ukm_source_id, event);
 }
 
 void ContextualSuggestionsBridge::OnSuggestionsAvailable(
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
index 149dbc8..08685131f 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -54,6 +54,7 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "ui/base/device_form_factor.h"
+#include "ui/base/window_open_disposition.h"
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF16;
@@ -256,6 +257,7 @@
       input_.type(),
       true,
       selected_index,
+      WindowOpenDisposition::CURRENT_TAB,
       false,
       SessionTabHelper::IdForTab(web_contents),
       current_page_classification,
diff --git a/chrome/browser/android/vr/vr_shell_gl.cc b/chrome/browser/android/vr/vr_shell_gl.cc
index 65a5e64..559cd89 100644
--- a/chrome/browser/android/vr/vr_shell_gl.cc
+++ b/chrome/browser/android/vr/vr_shell_gl.cc
@@ -189,6 +189,8 @@
       webvr_js_wait_time_(kWebVRSlidingAverageSize),
       webvr_acquire_time_(kWebVRSlidingAverageSize),
       webvr_submit_time_(kWebVRSlidingAverageSize),
+      ui_processing_time_(kWebVRSlidingAverageSize),
+      ui_controller_update_time_(kWebVRSlidingAverageSize),
       weak_ptr_factory_(this) {
   GvrInit(gvr_api);
 }
@@ -1059,12 +1061,20 @@
   }
 
   // Update the render position of all UI elements (including desktop).
+  TRACE_EVENT_BEGIN0("gpu", "SceneUpdate");
+  base::TimeTicks scene_start = base::TimeTicks::Now();
   bool scene_changed =
       ui_->scene()->OnBeginFrame(current_time, render_info_primary_.head_pose);
 
   // WebVR handles controller input in OnVsync.
-  if (!ShouldDrawWebVr())
+  base::TimeDelta controller_time = base::TimeDelta();
+  if (!ShouldDrawWebVr()) {
+    TRACE_EVENT0("gpu", "Controller");
+    base::TimeTicks controller_start = base::TimeTicks::Now();
     UpdateController(render_info_primary_, current_time);
+    controller_time = base::TimeTicks::Now() - controller_start;
+    ui_controller_update_time_.AddSample(controller_time);
+  }
 
   bool textures_changed = ui_->scene()->UpdateTextures();
 
@@ -1083,6 +1093,11 @@
 
   bool dirty = ShouldDrawWebVr() || head_moved || redraw_needed;
 
+  base::TimeDelta scene_time = base::TimeTicks::Now() - scene_start;
+  // Don't double-count the controller time that was part of the scene time.
+  ui_processing_time_.AddSample(scene_time - controller_time);
+  TRACE_EVENT_END0("gpu", "SceneUpdate");
+
   if (!dirty && ui_->SkipsRedrawWhenNotDirty())
     return;
 
@@ -1139,6 +1154,8 @@
     overlay_elements = ui_->scene()->GetVisibleWebVrOverlayElementsToDraw();
   }
 
+  TRACE_COUNTER1("gpu", "VR overlay element count", overlay_elements.size());
+
   if (!overlay_elements.empty() && ShouldDrawWebVr()) {
     // WebVR content may use an arbitray size buffer. We need to draw browser UI
     // on a different buffer to make sure that our UI has enough resolution.
@@ -1380,6 +1397,10 @@
   vr_ui_fps_meter_.AddFrame(base::TimeTicks::Now());
   DVLOG(1) << "fps: " << vr_ui_fps_meter_.GetFPS();
   TRACE_COUNTER1("gpu", "VR UI FPS", vr_ui_fps_meter_.GetFPS());
+  TRACE_COUNTER2("gpu", "VR UI timing (us)", "scene update",
+                 ui_processing_time_.GetAverage().InMicroseconds(),
+                 "controller",
+                 ui_controller_update_time_.GetAverage().InMicroseconds());
 
   if (ShouldDrawWebVr()) {
     // We finished processing a frame, this may make pending WebVR
@@ -1578,9 +1599,13 @@
     // rendering as WebVR uses the gamepad api. To ensure we always handle input
     // like app button presses, update the controller here, but not in
     // DrawFrame.
+    TRACE_EVENT0("gpu", "Controller");
+    base::TimeTicks controller_start = base::TimeTicks::Now();
     device::GvrDelegate::GetGvrPoseWithNeckModel(
         gvr_api_.get(), &render_info_primary_.head_pose);
     UpdateController(render_info_primary_, frame_time);
+    ui_controller_update_time_.AddSample(base::TimeTicks::Now() -
+                                         controller_start);
   } else {
     DrawFrame(-1, frame_time);
   }
diff --git a/chrome/browser/android/vr/vr_shell_gl.h b/chrome/browser/android/vr/vr_shell_gl.h
index 93b15049..bfd05950 100644
--- a/chrome/browser/android/vr/vr_shell_gl.h
+++ b/chrome/browser/android/vr/vr_shell_gl.h
@@ -344,6 +344,9 @@
   SlidingTimeDeltaAverage webvr_acquire_time_;
   SlidingTimeDeltaAverage webvr_submit_time_;
 
+  SlidingTimeDeltaAverage ui_processing_time_;
+  SlidingTimeDeltaAverage ui_controller_update_time_;
+
   gfx::Point3F pointer_start_;
 
   RenderInfo render_info_primary_;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 93a4385..a7205fb 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -221,6 +221,9 @@
     "//ui/wm/public",
     "//url",
   ]
+  data_deps = [
+    ":dbus_service_files",
+  ]
 
   allow_circular_includes_from = [ "//chrome/browser/extensions" ]
 
@@ -1751,6 +1754,15 @@
   }
 }
 
+copy("dbus_service_files") {
+  sources = [
+    "dbus/org.chromium.ScreenLockService.conf",
+  ]
+  outputs = [
+    "$root_out_dir/dbus/{{source_file_part}}",
+  ]
+}
+
 static_library("arc_test_support") {
   testonly = true
 
diff --git a/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.cc b/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.cc
index 3ddc5c1..ec12c83e 100644
--- a/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.cc
+++ b/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.cc
@@ -14,6 +14,7 @@
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "components/arc/common/protected_buffer_manager.mojom.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/gpu_service_registry.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/outgoing_broker_client_invitation.h"
@@ -42,6 +43,14 @@
   ~ArcOemCryptoBridgeFactory() override = default;
 };
 
+mojom::ProtectedBufferManagerPtr GetGpuBufferManagerOnIOThread() {
+  // Get the Mojo interface from the GPU for dealing with secure buffers and
+  // pass that to the daemon as well in our Connect call.
+  mojom::ProtectedBufferManagerPtr gpu_buffer_manager;
+  content::BindInterfaceInGpuProcess(mojo::MakeRequest(&gpu_buffer_manager));
+  return gpu_buffer_manager;
+}
+
 }  // namespace
 
 // static
@@ -133,10 +142,19 @@
 
 void ArcOemCryptoBridge::ConnectToDaemon(
     mojom::OemCryptoServiceRequest request) {
-  // Get the Mojo interface from the GPU for dealing with secure buffers and
-  // pass that to the daemon as well in our Connect call.
-  mojom::ProtectedBufferManagerPtr gpu_buffer_manager;
-  content::BindInterfaceInGpuProcess(mojo::MakeRequest(&gpu_buffer_manager));
+  // We need to get the GPU interface on the IO thread, then after that is
+  // done it will run the Mojo call on our thread.
+  base::PostTaskAndReplyWithResult(
+      content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
+          .get(),
+      FROM_HERE, base::BindOnce(&GetGpuBufferManagerOnIOThread),
+      base::BindOnce(&ArcOemCryptoBridge::FinishConnectingToDaemon,
+                     weak_factory_.GetWeakPtr(), std::move(request)));
+}
+
+void ArcOemCryptoBridge::FinishConnectingToDaemon(
+    mojom::OemCryptoServiceRequest request,
+    mojom::ProtectedBufferManagerPtr gpu_buffer_manager) {
   oemcrypto_host_daemon_ptr_->Connect(std::move(request),
                                       std::move(gpu_buffer_manager));
 }
diff --git a/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.h b/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.h
index d4e49fbcbe..3472416 100644
--- a/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.h
+++ b/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.h
@@ -41,6 +41,9 @@
   void OnBootstrapMojoConnection(mojom::OemCryptoServiceRequest request,
                                  bool result);
   void ConnectToDaemon(mojom::OemCryptoServiceRequest request);
+  void FinishConnectingToDaemon(
+      mojom::OemCryptoServiceRequest request,
+      mojom::ProtectedBufferManagerPtr gpu_buffer_manager);
 
   ArcBridgeService* const arc_bridge_service_;  // Owned by ArcServiceManager.
   arc_oemcrypto::mojom::OemCryptoHostDaemonPtr oemcrypto_host_daemon_ptr_;
diff --git a/chrome/browser/chromeos/arc/process/arc_process.cc b/chrome/browser/chromeos/arc/process/arc_process.cc
index 8268de43..ef6f1c0 100644
--- a/chrome/browser/chromeos/arc/process/arc_process.cc
+++ b/chrome/browser/chromeos/arc/process/arc_process.cc
@@ -10,6 +10,9 @@
 
 namespace arc {
 
+constexpr char kCloudDpcrocessName[] =
+    "com.google.android.apps.work.clouddpc.arc";
+
 ArcProcess::ArcProcess(base::ProcessId nspid,
                        base::ProcessId pid,
                        const std::string& process_name,
@@ -37,14 +40,20 @@
 ArcProcess& ArcProcess::operator=(ArcProcess&& other) = default;
 
 bool ArcProcess::IsImportant() const {
-  return process_state() <= mojom::ProcessState::IMPORTANT_FOREGROUND;
+  return process_state() <= mojom::ProcessState::IMPORTANT_FOREGROUND ||
+         IsArcProtected();
 }
 
 bool ArcProcess::IsKernelKillable() const {
-  // Protect PERSISTENT, PERSISTENT_UI, and our HOME processes since they should
-  // never be killed even by the kernel. Returning false for them allows their
-  // OOM adjustment scores to remain negative.
-  return process_state() > arc::mojom::ProcessState::PERSISTENT_UI;
+  // Protect PERSISTENT, PERSISTENT_UI, our HOME and custom set of ARC processes
+  // since they should never be killed even by the kernel. Returning false for
+  // them allows their OOM adjustment scores to remain negative.
+  return process_state() > arc::mojom::ProcessState::PERSISTENT_UI &&
+         !IsArcProtected();
+}
+
+bool ArcProcess::IsArcProtected() const {
+  return process_name() == kCloudDpcrocessName;
 }
 
 std::ostream& operator<<(std::ostream& out, const ArcProcess& arc_process) {
diff --git a/chrome/browser/chromeos/arc/process/arc_process.h b/chrome/browser/chromeos/arc/process/arc_process.h
index 3536915..ddf242e 100644
--- a/chrome/browser/chromeos/arc/process/arc_process.h
+++ b/chrome/browser/chromeos/arc/process/arc_process.h
@@ -53,6 +53,9 @@
   bool IsKernelKillable() const;
 
  private:
+  // Returns true if this is ARC protected process which we don't allow to kill.
+  bool IsArcProtected() const;
+
   base::ProcessId nspid_;
   base::ProcessId pid_;
   std::string process_name_;
diff --git a/chrome/browser/chromeos/arc/process/arc_process_unittest.cc b/chrome/browser/chromeos/arc/process/arc_process_unittest.cc
index 4027e41f..bcdd2cf 100644
--- a/chrome/browser/chromeos/arc/process/arc_process_unittest.cc
+++ b/chrome/browser/chromeos/arc/process/arc_process_unittest.cc
@@ -122,12 +122,17 @@
   EXPECT_FALSE(ArcProcess(0, 0, "process", mojom::ProcessState::CACHED_EMPTY,
                           kIsNotFocused, 0)
                    .IsImportant());
+
+  // Custom ARC protected processes.
+  EXPECT_TRUE(ArcProcess(0, 0, "com.google.android.apps.work.clouddpc.arc",
+                         mojom::ProcessState::SERVICE, kIsNotFocused, 0)
+                  .IsImportant());
 }
 
 TEST(ArcProcess, TestIsKernelKillable) {
   constexpr bool kIsNotFocused = false;
 
-  // Only PERSISITENT* processes are protected from the kernel OOM killer.
+  // PERSISITENT* processes are protected from the kernel OOM killer.
   EXPECT_FALSE(ArcProcess(0, 0, "process", mojom::ProcessState::PERSISTENT,
                           kIsNotFocused, 0)
                    .IsKernelKillable());
@@ -189,6 +194,11 @@
   EXPECT_TRUE(ArcProcess(0, 0, "process", mojom::ProcessState::CACHED_EMPTY,
                          kIsNotFocused, 0)
                   .IsKernelKillable());
+
+  // Set of custom processes that are protected from the kernel OOM killer.
+  EXPECT_FALSE(ArcProcess(0, 0, "com.google.android.apps.work.clouddpc.arc",
+                          mojom::ProcessState::SERVICE, kIsNotFocused, 0)
+                   .IsKernelKillable());
 }
 
 // Tests operator<<() does not crash and returns non-empty result, at least.
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 5ef27bf..fea1a0c 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -339,18 +339,21 @@
           std::make_unique<DisplayPowerServiceProvider>(
               std::make_unique<ChromeDisplayPowerServiceProviderDelegate>()));
     }
-    // TODO(teravest): Remove this provider once all callers are using
-    // |liveness_service_| instead: http://crbug.com/644322
+    // TODO(derat): Remove this provider once all callers are using
+    // |liveness_service_| instead: https://crbug.com/644322
     service_providers.push_back(
         std::make_unique<LivenessServiceProvider>(kLibCrosServiceInterface));
-    service_providers.push_back(std::make_unique<ScreenLockServiceProvider>());
+    // TODO(derat): Remove this provider once session_manager is using
+    // |screen_lock_service_| instead: https://crbug.com/827680
+    service_providers.push_back(std::make_unique<ScreenLockServiceProvider>(
+        kLibCrosServiceInterface, kLockScreen));
 
     display_service_providers.push_back(
         std::make_unique<ConsoleServiceProvider>(
             &console_service_provider_delegate_));
 
-    // TODO(teravest): Remove this provider once all callers are using
-    // |kiosk_info_service_| instead: http://crbug.com/703229
+    // TODO(derat): Remove this provider once all callers are using
+    // |kiosk_info_service_| instead: https://crbug.com/703229
     service_providers.push_back(std::make_unique<KioskInfoService>(
         kLibCrosServiceInterface, kGetKioskAppRequiredPlatforVersion));
     cros_dbus_service_ = CrosDBusService::Create(
@@ -381,6 +384,13 @@
             std::make_unique<LivenessServiceProvider>(
                 kLivenessServiceInterface)));
 
+    screen_lock_service_ = CrosDBusService::Create(
+        kScreenLockServiceName, dbus::ObjectPath(kScreenLockServicePath),
+        CrosDBusService::CreateServiceProviderList(
+            std::make_unique<ScreenLockServiceProvider>(
+                kScreenLockServiceInterface,
+                kScreenLockServiceShowLockScreenMethod)));
+
     virtual_file_request_service_ = CrosDBusService::Create(
         kVirtualFileRequestServiceName,
         dbus::ObjectPath(kVirtualFileRequestServicePath),
@@ -479,6 +489,7 @@
   std::unique_ptr<CrosDBusService> proxy_resolution_service_;
   std::unique_ptr<CrosDBusService> kiosk_info_service_;
   std::unique_ptr<CrosDBusService> liveness_service_;
+  std::unique_ptr<CrosDBusService> screen_lock_service_;
   std::unique_ptr<CrosDBusService> virtual_file_request_service_;
   std::unique_ptr<CrosDBusService> component_updater_service_;
   std::unique_ptr<CrosDBusService> finch_features_service_;
diff --git a/chrome/browser/chromeos/dbus/org.chromium.ScreenLockService.conf b/chrome/browser/chromeos/dbus/org.chromium.ScreenLockService.conf
new file mode 100644
index 0000000..8442532
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/org.chromium.ScreenLockService.conf
@@ -0,0 +1,23 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<!--
+  Copyright 2018 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.
+-->
+<busconfig>
+  <policy user="chronos">
+    <allow own="org.chromium.ScreenLockService"/>
+    <allow receive_sender="org.chromium.ScreenLockService"
+           receive_interface="org.chromium.ScreenLockServiceInterface"/>
+    <allow send_destination="org.chromium.ScreenLockService"/>
+  </policy>
+
+  <!--
+    session_manager uses this service to ask Chrome to show the lock screen.
+  -->
+  <policy user="root">
+    <allow send_destination="org.chromium.ScreenLockService"
+           send_interface="org.chromium.ScreenLockServiceInterface"/>
+  </policy>
+</busconfig>
diff --git a/chrome/browser/chromeos/dbus/screen_lock_service_provider.cc b/chrome/browser/chromeos/dbus/screen_lock_service_provider.cc
index 1368df6..273585c 100644
--- a/chrome/browser/chromeos/dbus/screen_lock_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/screen_lock_service_provider.cc
@@ -12,21 +12,23 @@
 
 namespace chromeos {
 
-ScreenLockServiceProvider::ScreenLockServiceProvider()
-    : weak_ptr_factory_(this) {
-}
+ScreenLockServiceProvider::ScreenLockServiceProvider(
+    const std::string& interface_name,
+    const std::string& method_name)
+    : interface_name_(interface_name),
+      method_name_(method_name),
+      weak_ptr_factory_(this) {}
 
 ScreenLockServiceProvider::~ScreenLockServiceProvider() {}
 
 void ScreenLockServiceProvider::Start(
     scoped_refptr<dbus::ExportedObject> exported_object) {
   exported_object->ExportMethod(
-      kLibCrosServiceInterface,
-      kLockScreen,
-      base::Bind(&ScreenLockServiceProvider::LockScreen,
-                 weak_ptr_factory_.GetWeakPtr()),
-      base::Bind(&ScreenLockServiceProvider::OnExported,
-                 weak_ptr_factory_.GetWeakPtr()));
+      interface_name_, method_name_,
+      base::BindRepeating(&ScreenLockServiceProvider::ShowLockScreen,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&ScreenLockServiceProvider::OnExported,
+                          weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ScreenLockServiceProvider::OnExported(const std::string& interface_name,
@@ -38,12 +40,12 @@
   }
 }
 
-void ScreenLockServiceProvider::LockScreen(
+void ScreenLockServiceProvider::ShowLockScreen(
     dbus::MethodCall* method_call,
     dbus::ExportedObject::ResponseSender response_sender) {
-  // Please add any additional logic to ScreenLocker::HandleLockScreenRequest()
-  // instead of placing it here.
-  ScreenLocker::HandleLockScreenRequest();
+  // Please add any additional logic to
+  // ScreenLocker::HandleShowLockScreenRequest() instead of placing it here.
+  ScreenLocker::HandleShowLockScreenRequest();
   response_sender.Run(dbus::Response::FromMethodCall(method_call));
 }
 
diff --git a/chrome/browser/chromeos/dbus/screen_lock_service_provider.h b/chrome/browser/chromeos/dbus/screen_lock_service_provider.h
index 4238f07..3e77bf5 100644
--- a/chrome/browser/chromeos/dbus/screen_lock_service_provider.h
+++ b/chrome/browser/chromeos/dbus/screen_lock_service_provider.h
@@ -20,12 +20,16 @@
 
 namespace chromeos {
 
-// This class exports a "LockScreen" D-Bus methods that the session manager
-// calls to instruct Chrome to lock the screen.
+// This class exports a D-Bus method that the session_manager calls to instruct
+// Chrome to show the lock screen.
 class ScreenLockServiceProvider
     : public CrosDBusService::ServiceProviderInterface {
  public:
-  ScreenLockServiceProvider();
+  // |interface_name| and |method_name| are exposed so the method can be
+  // exported on both org.chromium.LibCrosService and
+  // org.chromium.ScreenLockService: https://crbug.com/827680
+  ScreenLockServiceProvider(const std::string& interface_name,
+                            const std::string& method_name);
   ~ScreenLockServiceProvider() override;
 
   // CrosDBusService::ServiceProviderInterface overrides:
@@ -39,8 +43,14 @@
                   bool success);
 
   // Called on UI thread in response to D-Bus requests.
-  void LockScreen(dbus::MethodCall* method_call,
-                  dbus::ExportedObject::ResponseSender response_sender);
+  void ShowLockScreen(dbus::MethodCall* method_call,
+                      dbus::ExportedObject::ResponseSender response_sender);
+
+  // D-Bus interface and method names.
+  // TODO(derat): Remove once LibCrosService support is unneeded:
+  // https://crbug.com/827680
+  const std::string interface_name_;
+  const std::string method_name_;
 
   // Keep this last so that all weak pointers will be invalidated at the
   // beginning of destruction.
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index 7a02d4b..c51b14a 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -123,7 +123,9 @@
   bool session_started() const { return session_started_; }
 
   // SessionManagerClient::StubDelegate overrides:
-  void LockScreenForStub() override { ScreenLocker::HandleLockScreenRequest(); }
+  void LockScreenForStub() override {
+    ScreenLocker::HandleShowLockScreenRequest();
+  }
 
   // NotificationObserver overrides:
   void Observe(int type,
@@ -148,7 +150,7 @@
   // UserAddingScreen::Observer overrides:
   void OnUserAddingFinished() override {
     UserAddingScreen::Get()->RemoveObserver(this);
-    ScreenLocker::HandleLockScreenRequest();
+    ScreenLocker::HandleShowLockScreenRequest();
   }
 
  private:
@@ -488,8 +490,8 @@
 }
 
 // static
-void ScreenLocker::HandleLockScreenRequest() {
-  VLOG(1) << "Received LockScreen request from session manager";
+void ScreenLocker::HandleShowLockScreenRequest() {
+  VLOG(1) << "Received ShowLockScreen request from session manager";
   DCHECK(g_screen_lock_observer);
   if (UserAddingScreen::Get()->IsRunning()) {
     VLOG(1) << "Waiting for user adding screen to stop";
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.h b/chrome/browser/chromeos/login/lock/screen_locker.h
index f61944b..8c716ae0 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/screen_locker.h
@@ -168,8 +168,8 @@
   static void InitClass();
   static void ShutDownClass();
 
-  // Handles a request from the session manager to lock the screen.
-  static void HandleLockScreenRequest();
+  // Handles a request from the session manager to show the lock screen.
+  static void HandleShowLockScreenRequest();
 
   // Show the screen locker.
   static void Show();
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
index e637bfe7..fda1f312 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
@@ -195,7 +195,7 @@
 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, LockScreenWhileAddingUser) {
   UserAddingScreen::Get()->Start();
   content::RunAllPendingInMessageLoop();
-  ScreenLocker::HandleLockScreenRequest();
+  ScreenLocker::HandleShowLockScreenRequest();
 }
 
 // Test how locking the screen affects an active fullscreen window.
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn
index 8c728737..012ca0c 100644
--- a/chrome/browser/devtools/BUILD.gn
+++ b/chrome/browser/devtools/BUILD.gn
@@ -10,25 +10,6 @@
   import("//tools/grit/grit_rule.gni")
 }
 
-action("devtools_protocol_constants") {
-  script = "devtools_protocol_constants_generator.py"
-  deps = [
-    "//third_party/WebKit/Source/core/inspector:protocol_version",
-  ]
-  blink_protocol = "$root_gen_dir/blink/core/inspector/protocol.json"
-  inputs = [
-    blink_protocol,
-  ]
-  outputs = [
-    "$target_gen_dir/devtools_protocol_constants.cc",
-    "$target_gen_dir/devtools_protocol_constants.h",
-  ]
-
-  args = [ "chrome" ]
-  args += rebase_path(outputs, root_build_dir)
-  args += [ rebase_path(blink_protocol, root_build_dir) ]
-}
-
 if (!is_android) {
   _inspector_protocol = "//third_party/inspector_protocol"
   import("$_inspector_protocol/inspector_protocol.gni")
@@ -41,6 +22,8 @@
     "protocol/page.h",
     "protocol/protocol.cc",
     "protocol/protocol.h",
+    "protocol/target.cc",
+    "protocol/target.h",
   ]
 
   if (is_chromeos) {
@@ -100,11 +83,7 @@
 
 static_library("devtools") {
   # Note: new sources and deps should be generally added in (!is_android) below.
-  sources = [
-    "devtools_protocol.cc",
-    "devtools_protocol.h",
-  ]
-  sources += get_target_outputs(":devtools_protocol_constants")
+  sources = []
 
   configs += [
     "//build/config/compiler:no_size_t_to_int_warning",
@@ -113,7 +92,6 @@
   ]
 
   deps = [
-    ":devtools_protocol_constants",
     "//base",
     "//content/public/browser",
     "//net",
@@ -211,6 +189,8 @@
       "protocol/browser_handler.h",
       "protocol/page_handler.cc",
       "protocol/page_handler.h",
+      "protocol/target_handler.cc",
+      "protocol/target_handler.h",
       "protocol_string.cc",
       "protocol_string.h",
     ]
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
index 35ee33fd..cea9163bf 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
@@ -6,16 +6,14 @@
 
 #include <utility>
 
-#include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/devtools/chrome_devtools_session.h"
 #include "chrome/browser/devtools/device/android_device_manager.h"
 #include "chrome/browser/devtools/device/tcp_device_provider.h"
-#include "chrome/browser/devtools/devtools_protocol.h"
-#include "chrome/browser/devtools/devtools_protocol_constants.h"
 #include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/devtools/protocol/target_handler.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -40,10 +38,6 @@
 
 namespace {
 
-const char kLocationsParam[] = "locations";
-const char kHostParam[] = "host";
-const char kPortParam[] = "port";
-
 bool GetExtensionInfo(content::WebContents* wc,
                       std::string* name,
                       std::string* type) {
@@ -71,35 +65,23 @@
   return false;
 }
 
-std::string ToString(std::unique_ptr<base::DictionaryValue> value) {
-  std::string json;
-  base::JSONWriter::Write(*value, &json);
-  return json;
-}
+ChromeDevToolsManagerDelegate* g_instance;
 
 }  // namespace
 
-class ChromeDevToolsManagerDelegate::HostData {
- public:
-  HostData() {}
-  ~HostData() {}
-
-  RemoteLocations& remote_locations() { return remote_locations_; }
-
-  void set_remote_locations(RemoteLocations& locations) {
-    remote_locations_.swap(locations);
-  }
-
- private:
-  RemoteLocations remote_locations_;
-};
+// static
+ChromeDevToolsManagerDelegate* ChromeDevToolsManagerDelegate::GetInstance() {
+  return g_instance;
+}
 
 ChromeDevToolsManagerDelegate::ChromeDevToolsManagerDelegate() {
-  content::DevToolsAgentHost::AddObserver(this);
+  DCHECK(!g_instance);
+  g_instance = this;
 }
 
 ChromeDevToolsManagerDelegate::~ChromeDevToolsManagerDelegate() {
-  content::DevToolsAgentHost::RemoveObserver(this);
+  DCHECK(g_instance == this);
+  g_instance = nullptr;
 }
 
 void ChromeDevToolsManagerDelegate::Inspect(
@@ -111,19 +93,6 @@
     DevToolsAgentHost* agent_host,
     content::DevToolsAgentHostClient* client,
     base::DictionaryValue* command_dict) {
-  int id = 0;
-  std::string method;
-  base::DictionaryValue* params = nullptr;
-  if (!DevToolsProtocol::ParseCommand(command_dict, &id, &method, &params))
-    return false;
-
-  if (method == chrome::devtools::Target::setRemoteLocations::kName) {
-    auto result = SetRemoteLocations(agent_host, id, params);
-    DCHECK(result);
-    client->DispatchProtocolMessage(agent_host, ToString(std::move(result)));
-    return true;
-  }
-
   DCHECK(sessions_.find(client) != sessions_.end());
   auto response = sessions_[client]->dispatcher()->dispatch(
       protocol::toProtocolValue(command_dict, 1000));
@@ -188,21 +157,6 @@
   return true;
 }
 
-void ChromeDevToolsManagerDelegate::DevToolsAgentHostAttached(
-    content::DevToolsAgentHost* agent_host) {
-  DCHECK(host_data_.find(agent_host) == host_data_.end());
-  host_data_[agent_host].reset(new ChromeDevToolsManagerDelegate::HostData());
-}
-
-void ChromeDevToolsManagerDelegate::DevToolsAgentHostDetached(
-    content::DevToolsAgentHost* agent_host) {
-  // This class is created lazily, so it may not know about some attached hosts.
-  if (host_data_.find(agent_host) != host_data_.end()) {
-    host_data_.erase(agent_host);
-    UpdateDeviceDiscovery();
-  }
-}
-
 void ChromeDevToolsManagerDelegate::DevicesAvailable(
     const DevToolsDeviceDiscovery::CompleteDevices& devices) {
   DevToolsAgentHost::List remote_targets;
@@ -217,8 +171,11 @@
 
 void ChromeDevToolsManagerDelegate::UpdateDeviceDiscovery() {
   RemoteLocations remote_locations;
-  for (const auto& pair : host_data_) {
-    RemoteLocations& locations = pair.second->remote_locations();
+  for (const auto& it : sessions_) {
+    TargetHandler* target_handler = it.second->target_handler();
+    if (!target_handler)
+      continue;
+    RemoteLocations& locations = target_handler->remote_locations();
     remote_locations.insert(locations.begin(), locations.end());
   }
 
@@ -256,43 +213,3 @@
   }
   remote_locations_.swap(remote_locations);
 }
-
-std::unique_ptr<base::DictionaryValue>
-ChromeDevToolsManagerDelegate::SetRemoteLocations(
-    content::DevToolsAgentHost* agent_host,
-    int command_id,
-    base::DictionaryValue* params) {
-  // Could have been created late.
-  if (host_data_.find(agent_host) == host_data_.end())
-    DevToolsAgentHostAttached(agent_host);
-
-  std::set<net::HostPortPair> tcp_locations;
-  base::ListValue* locations;
-  if (!params->GetList(kLocationsParam, &locations))
-    return DevToolsProtocol::CreateInvalidParamsResponse(command_id,
-                                                         kLocationsParam);
-  for (const auto& item : *locations) {
-    if (!item.is_dict()) {
-      return DevToolsProtocol::CreateInvalidParamsResponse(command_id,
-                                                           kLocationsParam);
-    }
-    const base::DictionaryValue* dictionary =
-        static_cast<const base::DictionaryValue*>(&item);
-    std::string host;
-    if (!dictionary->GetStringWithoutPathExpansion(kHostParam, &host)) {
-      return DevToolsProtocol::CreateInvalidParamsResponse(command_id,
-                                                           kLocationsParam);
-    }
-    int port = 0;
-    if (!dictionary->GetIntegerWithoutPathExpansion(kPortParam, &port)) {
-      return DevToolsProtocol::CreateInvalidParamsResponse(command_id,
-                                                           kLocationsParam);
-    }
-    tcp_locations.insert(net::HostPortPair(host, port));
-  }
-
-  host_data_[agent_host]->set_remote_locations(tcp_locations);
-  UpdateDeviceDiscovery();
-
-  return DevToolsProtocol::CreateSuccessResponse(command_id, nullptr);
-}
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.h b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
index 6b81036..365ab67 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.h
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
@@ -17,13 +17,11 @@
 #include "chrome/browser/devtools/protocol/protocol.h"
 #include "content/public/browser/devtools_agent_host_observer.h"
 #include "content/public/browser/devtools_manager_delegate.h"
-#include "net/base/host_port_pair.h"
 
 class ChromeDevToolsSession;
+using RemoteLocations = std::set<net::HostPortPair>;
 
-class ChromeDevToolsManagerDelegate :
-    public content::DevToolsManagerDelegate,
-    public content::DevToolsAgentHostObserver {
+class ChromeDevToolsManagerDelegate : public content::DevToolsManagerDelegate {
  public:
   static const char kTypeApp[];
   static const char kTypeBackgroundPage[];
@@ -31,10 +29,11 @@
   ChromeDevToolsManagerDelegate();
   ~ChromeDevToolsManagerDelegate() override;
 
+  static ChromeDevToolsManagerDelegate* GetInstance();
+  void UpdateDeviceDiscovery();
+
  private:
-  class HostData;
   friend class DevToolsManagerDelegateTest;
-  using RemoteLocations = std::set<net::HostPortPair>;
 
   // content::DevToolsManagerDelegate implementation.
   void Inspect(content::DevToolsAgentHost* agent_host) override;
@@ -52,23 +51,9 @@
   std::string GetDiscoveryPageHTML() override;
   bool HasBundledFrontendResources() override;
 
-  // content::DevToolsAgentHostObserver overrides.
-  void DevToolsAgentHostAttached(
-      content::DevToolsAgentHost* agent_host) override;
-  void DevToolsAgentHostDetached(
-      content::DevToolsAgentHost* agent_host) override;
-
-  void UpdateDeviceDiscovery();
   void DevicesAvailable(
       const DevToolsDeviceDiscovery::CompleteDevices& devices);
 
-  std::unique_ptr<base::DictionaryValue> SetRemoteLocations(
-      content::DevToolsAgentHost* agent_host,
-      int command_id,
-      base::DictionaryValue* params);
-
-  std::map<content::DevToolsAgentHost*, std::unique_ptr<HostData>> host_data_;
-
   std::map<content::DevToolsAgentHostClient*,
            std::unique_ptr<ChromeDevToolsSession>>
       sessions_;
diff --git a/chrome/browser/devtools/chrome_devtools_session.cc b/chrome/browser/devtools/chrome_devtools_session.cc
index 2ee5b2a..7640f4ca 100644
--- a/chrome/browser/devtools/chrome_devtools_session.cc
+++ b/chrome/browser/devtools/chrome_devtools_session.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/devtools/protocol/browser_handler.h"
 #include "chrome/browser/devtools/protocol/page_handler.h"
+#include "chrome/browser/devtools/protocol/target_handler.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_agent_host_client.h"
 
@@ -24,6 +25,8 @@
       agent_host->GetType() == content::DevToolsAgentHost::kTypePage) {
     page_handler_ = std::make_unique<PageHandler>(agent_host->GetWebContents(),
                                                   dispatcher_.get());
+    target_handler_ = std::make_unique<TargetHandler>(
+        agent_host->GetWebContents(), dispatcher_.get());
   }
   browser_handler_ = std::make_unique<BrowserHandler>(dispatcher_.get());
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/devtools/chrome_devtools_session.h b/chrome/browser/devtools/chrome_devtools_session.h
index c292b68..69edba9 100644
--- a/chrome/browser/devtools/chrome_devtools_session.h
+++ b/chrome/browser/devtools/chrome_devtools_session.h
@@ -17,6 +17,7 @@
 
 class BrowserHandler;
 class PageHandler;
+class TargetHandler;
 class WindowManagerHandler;
 
 class ChromeDevToolsSession : public protocol::FrontendChannel {
@@ -27,6 +28,8 @@
 
   protocol::UberDispatcher* dispatcher() { return dispatcher_.get(); }
 
+  TargetHandler* target_handler() { return target_handler_.get(); }
+
  private:
   // protocol::FrontendChannel:
   void sendProtocolResponse(
@@ -42,6 +45,7 @@
   std::unique_ptr<protocol::UberDispatcher> dispatcher_;
   std::unique_ptr<BrowserHandler> browser_handler_;
   std::unique_ptr<PageHandler> page_handler_;
+  std::unique_ptr<TargetHandler> target_handler_;
 #if defined(OS_CHROMEOS)
   std::unique_ptr<WindowManagerHandler> window_manager_protocl_handler_;
 #endif
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.cc b/chrome/browser/devtools/device/devtools_android_bridge.cc
index 8148747b..0fde5e6 100644
--- a/chrome/browser/devtools/device/devtools_android_bridge.cc
+++ b/chrome/browser/devtools/device/devtools_android_bridge.cc
@@ -32,7 +32,6 @@
 #include "chrome/browser/devtools/device/port_forwarding_controller.h"
 #include "chrome/browser/devtools/device/tcp_device_provider.h"
 #include "chrome/browser/devtools/device/usb/usb_device_provider.h"
-#include "chrome/browser/devtools/devtools_protocol.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/devtools/remote_debugging_server.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/devtools/device/devtools_device_discovery.cc b/chrome/browser/devtools/device/devtools_device_discovery.cc
index 88df200..fbada04 100644
--- a/chrome/browser/devtools/device/devtools_device_discovery.cc
+++ b/chrome/browser/devtools/device/devtools_device_discovery.cc
@@ -16,7 +16,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/devtools/devtools_protocol.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -39,7 +38,7 @@
 const char kBrowserTargetSocket[] = "/devtools/browser";
 const int kPollingIntervalMs = 1000;
 
-const char kPageReloadCommand[] = "Page.reload";
+const char kPageReloadCommand[] = "{'method': 'Page.reload', id: 1}";
 
 const char kWebViewSocketPrefix[] = "webview_devtools_remote";
 
@@ -56,12 +55,10 @@
 class ProtocolCommand
     : public AndroidDeviceManager::AndroidWebSocket::Delegate {
  public:
-  ProtocolCommand(
-      scoped_refptr<AndroidDeviceManager::Device> device,
-      const std::string& socket,
-      const std::string& target_path,
-      const std::string& command,
-      const base::Closure callback);
+  ProtocolCommand(scoped_refptr<AndroidDeviceManager::Device> device,
+                  const std::string& socket,
+                  const std::string& target_path,
+                  const std::string& command);
 
  private:
   void OnSocketOpened() override;
@@ -70,7 +67,6 @@
   ~ProtocolCommand() override;
 
   const std::string command_;
-  const base::Closure callback_;
   std::unique_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
 
   DISALLOW_COPY_AND_ASSIGN(ProtocolCommand);
@@ -80,12 +76,9 @@
     scoped_refptr<AndroidDeviceManager::Device> device,
     const std::string& socket,
     const std::string& target_path,
-    const std::string& command,
-    const base::Closure callback)
+    const std::string& command)
     : command_(command),
-      callback_(callback),
-      web_socket_(device->CreateWebSocket(socket, target_path, this)) {
-}
+      web_socket_(device->CreateWebSocket(socket, target_path, this)) {}
 
 void ProtocolCommand::OnSocketOpened() {
   web_socket_->SendFrame(command_);
@@ -100,8 +93,6 @@
 }
 
 ProtocolCommand::~ProtocolCommand() {
-  if (!callback_.is_null())
-    callback_.Run();
 }
 
 // AgentHostDelegate ----------------------------------------------------------
@@ -186,11 +177,6 @@
   void SendMessageToBackend(content::DevToolsExternalAgentProxy* proxy,
                             const std::string& message) override;
 
-  void SendProtocolCommand(const std::string& target_path,
-                           const std::string& method,
-                           std::unique_ptr<base::DictionaryValue> params,
-                           const base::Closure callback);
-
   scoped_refptr<AndroidDeviceManager::Device> device_;
   std::string browser_id_;
   std::string local_id_;
@@ -344,8 +330,10 @@
 }
 
 void AgentHostDelegate::Reload() {
-  SendProtocolCommand(target_path_, kPageReloadCommand, nullptr,
-                      base::Closure());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (target_path_.empty())
+    return;
+  new ProtocolCommand(device_, browser_id_, target_path_, kPageReloadCommand);
 }
 
 bool AgentHostDelegate::Close() {
@@ -369,20 +357,6 @@
   it->second->SendMessageToBackend(message);
 }
 
-void AgentHostDelegate::SendProtocolCommand(
-    const std::string& target_path,
-    const std::string& method,
-    std::unique_ptr<base::DictionaryValue> params,
-    const base::Closure callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (target_path.empty())
-    return;
-  new ProtocolCommand(
-      device_, browser_id_, target_path,
-      DevToolsProtocol::SerializeCommand(1, method, std::move(params)),
-      callback);
-}
-
 }  // namespace
 
 // DevToolsDeviceDiscovery::DiscoveryRequest ----------------------------------
diff --git a/chrome/browser/devtools/device/port_forwarding_controller.cc b/chrome/browser/devtools/device/port_forwarding_controller.cc
index 2be73ab..ecbe9ae 100644
--- a/chrome/browser/devtools/device/port_forwarding_controller.cc
+++ b/chrome/browser/devtools/device/port_forwarding_controller.cc
@@ -9,14 +9,14 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
 #include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
-#include "chrome/browser/devtools/devtools_protocol.h"
-#include "chrome/browser/devtools/devtools_protocol_constants.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
@@ -45,6 +45,74 @@
   kStatusOK = 0,
 };
 
+const char kErrorCodeParam[] = "code";
+const char kErrorParam[] = "error";
+const char kIdParam[] = "id";
+const char kMethodParam[] = "method";
+const char kParamsParam[] = "params";
+
+const char kBindMethod[] = "bind";
+const char kUnbindMethod[] = "unbind";
+const char kAcceptedEvent[] = "accepted";
+const char kPortParam[] = "port";
+const char kConnectionIdParam[] = "connectionId";
+
+static bool ParseNotification(const std::string& json,
+                              std::string* method,
+                              std::unique_ptr<base::DictionaryValue>* params) {
+  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  if (!value || !value->is_dict())
+    return false;
+
+  std::unique_ptr<base::DictionaryValue> dict(
+      static_cast<base::DictionaryValue*>(value.release()));
+
+  if (!dict->GetString(kMethodParam, method))
+    return false;
+
+  std::unique_ptr<base::Value> params_value;
+  dict->Remove(kParamsParam, &params_value);
+  if (params_value && params_value->is_dict())
+    params->reset(static_cast<base::DictionaryValue*>(params_value.release()));
+
+  return true;
+}
+
+static bool ParseResponse(const std::string& json,
+                          int* command_id,
+                          int* error_code) {
+  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  if (!value || !value->is_dict())
+    return false;
+
+  std::unique_ptr<base::DictionaryValue> dict(
+      static_cast<base::DictionaryValue*>(value.release()));
+
+  if (!dict->GetInteger(kIdParam, command_id))
+    return false;
+
+  *error_code = 0;
+  base::DictionaryValue* error_dict = nullptr;
+  if (dict->GetDictionary(kErrorParam, &error_dict))
+    error_dict->GetInteger(kErrorCodeParam, error_code);
+  return true;
+}
+
+static std::string SerializeCommand(
+    int command_id,
+    const std::string& method,
+    std::unique_ptr<base::DictionaryValue> params) {
+  base::DictionaryValue command;
+  command.SetInteger(kIdParam, command_id);
+  command.SetString(kMethodParam, method);
+  if (params)
+    command.Set(kParamsParam, std::move(params));
+
+  std::string json_command;
+  base::JSONWriter::Write(command, &json_command);
+  return json_command;
+}
+
 net::NetworkTrafficAnnotationTag kPortForwardingControllerTrafficAnnotation =
     net::DefineNetworkTrafficAnnotation("port_forwarding_controller_socket",
                                         R"(
@@ -75,8 +143,6 @@
             "here."
         })");
 
-namespace tethering = ::chrome::devtools::Tethering;
-
 class SocketTunnel {
  public:
   static void StartTunnel(const std::string& host,
@@ -297,10 +363,8 @@
     const ForwardingMap& new_forwarding_map) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (connected_) {
-    SerializeChanges(tethering::unbind::kName,
-        new_forwarding_map, forwarding_map_);
-    SerializeChanges(tethering::bind::kName,
-        forwarding_map_, new_forwarding_map);
+    SerializeChanges(kUnbindMethod, new_forwarding_map, forwarding_map_);
+    SerializeChanges(kBindMethod, forwarding_map_, new_forwarding_map);
   }
   forwarding_map_ = new_forwarding_map;
 }
@@ -326,15 +390,15 @@
     const std::string& method, int port) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue);
-  if (method == tethering::bind::kName) {
-    params->SetInteger(tethering::bind::kParamPort, port);
+  if (method == kBindMethod) {
+    params->SetInteger(kPortParam, port);
   } else {
-    DCHECK_EQ(tethering::unbind::kName, method);
-    params->SetInteger(tethering::unbind::kParamPort, port);
+    DCHECK_EQ(kUnbindMethod, method);
+    params->SetInteger(kPortParam, port);
   }
   int id = ++command_id_;
 
-  if (method == tethering::bind::kName) {
+  if (method == kBindMethod) {
     pending_responses_[id] =
         base::Bind(&Connection::ProcessBindResponse,
                    base::Unretained(this), port);
@@ -357,15 +421,14 @@
 #endif  // BUILDFLAG(DEBUG_DEVTOOLS)
   }
 
-  web_socket_->SendFrame(
-      DevToolsProtocol::SerializeCommand(id, method, std::move(params)));
+  web_socket_->SendFrame(SerializeCommand(id, method, std::move(params)));
 }
 
 bool PortForwardingController::Connection::ProcessResponse(
     const std::string& message) {
   int id = 0;
   int error_code = 0;
-  if (!DevToolsProtocol::ParseResponse(message, &id, &error_code))
+  if (!ParseResponse(message, &id, &error_code))
     return false;
 
   CommandCallbackMap::iterator it = pending_responses_.find(id);
@@ -402,7 +465,7 @@
 void PortForwardingController::Connection::OnSocketOpened() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   connected_ = true;
-  SerializeChanges(tethering::bind::kName, ForwardingMap(), forwarding_map_);
+  SerializeChanges(kBindMethod, ForwardingMap(), forwarding_map_);
 }
 
 void PortForwardingController::Connection::OnSocketClosed() {
@@ -417,17 +480,16 @@
 
   std::string method;
   std::unique_ptr<base::DictionaryValue> params;
-  if (!DevToolsProtocol::ParseNotification(message, &method, &params))
+  if (!ParseNotification(message, &method, &params))
     return;
 
-  if (method != tethering::accepted::kName || !params)
+  if (method != kAcceptedEvent || !params)
     return;
 
   int port;
   std::string connection_id;
-  if (!params->GetInteger(tethering::accepted::kParamPort, &port) ||
-      !params->GetString(tethering::accepted::kParamConnectionId,
-                         &connection_id))
+  if (!params->GetInteger(kPortParam, &port) ||
+      !params->GetString(kConnectionIdParam, &connection_id))
     return;
 
   std::map<int, std::string>::iterator it = forwarding_map_.find(port);
diff --git a/chrome/browser/devtools/devtools_protocol.cc b/chrome/browser/devtools/devtools_protocol.cc
deleted file mode 100644
index 3eb8251..0000000
--- a/chrome/browser/devtools/devtools_protocol.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/devtools/devtools_protocol.h"
-
-#include <utility>
-
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/stringprintf.h"
-
-namespace {
-
-const char kErrorCodeParam[] = "code";
-const char kErrorParam[] = "error";
-const char kErrorMessageParam[] = "message";
-const char kIdParam[] = "id";
-const char kMethodParam[] = "method";
-const char kParamsParam[] = "params";
-const char kResultParam[] = "result";
-
-// JSON RPC 2.0 spec: http://www.jsonrpc.org/specification#error_object
-enum Error { kErrorInvalidParams = -32602, kErrorServerError = -32000 };
-
-}  // namespace
-
-// static
-std::string DevToolsProtocol::SerializeCommand(
-    int command_id,
-    const std::string& method,
-    std::unique_ptr<base::DictionaryValue> params) {
-  base::DictionaryValue command;
-  command.SetInteger(kIdParam, command_id);
-  command.SetString(kMethodParam, method);
-  if (params)
-    command.Set(kParamsParam, std::move(params));
-
-  std::string json_command;
-  base::JSONWriter::Write(command, &json_command);
-  return json_command;
-}
-
-// static
-std::unique_ptr<base::DictionaryValue>
-DevToolsProtocol::CreateInvalidParamsResponse(int command_id,
-                                              const std::string& param) {
-  std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue());
-  response->SetInteger(kIdParam, command_id);
-  auto error_object = std::make_unique<base::DictionaryValue>();
-  error_object->SetInteger(kErrorCodeParam, kErrorInvalidParams);
-  error_object->SetString(kErrorMessageParam,
-      base::StringPrintf("Missing or invalid '%s' parameter", param.c_str()));
-  response->Set(kErrorParam, std::move(error_object));
-
-  return response;
-}
-
-// static
-std::unique_ptr<base::DictionaryValue> DevToolsProtocol::CreateErrorResponse(
-    int command_id,
-    const std::string& error_message) {
-  std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue());
-  response->SetInteger(kIdParam, command_id);
-  auto error_object = std::make_unique<base::DictionaryValue>();
-  error_object->SetInteger(kErrorCodeParam, kErrorServerError);
-  error_object->SetString(kErrorMessageParam, error_message);
-  response->Set(kErrorParam, std::move(error_object));
-
-  return response;
-}
-
-// static
-std::unique_ptr<base::DictionaryValue> DevToolsProtocol::CreateSuccessResponse(
-    int command_id,
-    std::unique_ptr<base::DictionaryValue> result) {
-  std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue());
-  response->SetInteger(kIdParam, command_id);
-  response->Set(kResultParam, result
-                                  ? std::move(result)
-                                  : std::make_unique<base::DictionaryValue>());
-
-  return response;
-}
-
-// static
-bool DevToolsProtocol::ParseCommand(base::DictionaryValue* command,
-                                    int* command_id,
-                                    std::string* method,
-                                    base::DictionaryValue** params) {
-  if (!command)
-    return false;
-
-  if (!command->GetInteger(kIdParam, command_id) || *command_id < 0)
-    return false;
-
-  if (!command->GetString(kMethodParam, method))
-    return false;
-
-  if (!command->GetDictionary(kParamsParam, params))
-    *params = nullptr;
-
-  return true;
-}
-
-// static
-bool DevToolsProtocol::ParseNotification(
-    const std::string& json,
-    std::string* method,
-    std::unique_ptr<base::DictionaryValue>* params) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
-  if (!value || !value->is_dict())
-    return false;
-
-  std::unique_ptr<base::DictionaryValue> dict(
-      static_cast<base::DictionaryValue*>(value.release()));
-
-  if (!dict->GetString(kMethodParam, method))
-    return false;
-
-  std::unique_ptr<base::Value> params_value;
-  dict->Remove(kParamsParam, &params_value);
-  if (params_value && params_value->is_dict())
-    params->reset(static_cast<base::DictionaryValue*>(params_value.release()));
-
-  return true;
-}
-
-// static
-bool DevToolsProtocol::ParseResponse(const std::string& json,
-                                     int* command_id,
-                                     int* error_code) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
-  if (!value || !value->is_dict())
-    return false;
-
-  std::unique_ptr<base::DictionaryValue> dict(
-      static_cast<base::DictionaryValue*>(value.release()));
-
-  if (!dict->GetInteger(kIdParam, command_id))
-    return false;
-
-  *error_code = 0;
-  base::DictionaryValue* error_dict = nullptr;
-  if (dict->GetDictionary(kErrorParam, &error_dict))
-    error_dict->GetInteger(kErrorCodeParam, error_code);
-  return true;
-}
diff --git a/chrome/browser/devtools/devtools_protocol.h b/chrome/browser/devtools/devtools_protocol.h
deleted file mode 100644
index 7ba104df..0000000
--- a/chrome/browser/devtools/devtools_protocol.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
-#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
-
-#include <memory>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/values.h"
-
-// Utility class for processing DevTools remote debugging messages.
-class DevToolsProtocol {
- public:
-  // Caller maintains ownership of |command|. |*params| is owned by |command|.
-  static bool ParseCommand(base::DictionaryValue* command,
-                           int* command_id,
-                           std::string* method,
-                           base::DictionaryValue** params);
-
-  static bool ParseNotification(const std::string& json,
-                                std::string* method,
-                                std::unique_ptr<base::DictionaryValue>* params);
-
-  static bool ParseResponse(const std::string& json,
-                            int* command_id,
-                            int* error_code);
-
-  static std::string SerializeCommand(
-      int command_id,
-      const std::string& method,
-      std::unique_ptr<base::DictionaryValue> params);
-
-  static std::unique_ptr<base::DictionaryValue> CreateSuccessResponse(
-      int command_id,
-      std::unique_ptr<base::DictionaryValue> result);
-
-  static std::unique_ptr<base::DictionaryValue> CreateInvalidParamsResponse(
-      int command_id,
-      const std::string& param);
-
-  static std::unique_ptr<base::DictionaryValue> CreateErrorResponse(
-      int command_id,
-      const std::string& error_message);
-
- private:
-  DevToolsProtocol() {}
-  ~DevToolsProtocol() {}
-};
-
-#endif  // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
diff --git a/chrome/browser/devtools/devtools_protocol_constants_generator.py b/chrome/browser/devtools/devtools_protocol_constants_generator.py
deleted file mode 100755
index 2ab803f..0000000
--- a/chrome/browser/devtools/devtools_protocol_constants_generator.py
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/python
-# 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.
-
-import sys
-import string
-import json
-
-package = sys.argv[1]
-output_cc_path = sys.argv[2]
-output_h_path = sys.argv[3]
-blink_protocol_path = sys.argv[4]
-
-template_h = string.Template("""\
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ${PACKAGE}_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
-#define ${PACKAGE}_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
-
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// Generated by
-//  chrome/browser/devtools/devtools_protocol_constants_generator.py from
-//  gen/blink/core/inspector/protocol.json
-
-#include <string>
-
-namespace $package {
-namespace devtools {
-
-extern const char kProtocolVersion[];
-
-bool IsSupportedProtocolVersion(const std::string& version);
-
-extern const char kResult[];
-$contents
-
-}  // devtools
-}  // $package
-
-#endif  // ${PACKAGE}_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
-""")
-
-template_cc = string.Template("""\
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// Generated by
-//  chrome/browser/devtools/devtools_protocol_constants_generator.py from
-//  gen/blink/core/inspector/protocol.json
-
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "$package/browser/devtools/devtools_protocol_constants.h"
-
-namespace $package {
-namespace devtools {
-
-const char kProtocolVersion[] = "$major.$minor";
-
-bool IsSupportedProtocolVersion(const std::string& version) {
-  std::vector<base::StringPiece> tokens = base::SplitStringPiece(
-      version, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-  int major, minor;
-  return tokens.size() == 2 &&
-      base::StringToInt(tokens[0], &major) && major == $major &&
-      base::StringToInt(tokens[1], &minor) && minor <= $minor;
-}
-
-const char kResult[] = "result";
-$contents
-
-}  // devtools
-}  // $package
-""")
-
-def Capitalize(s):
-  return s[:1].capitalize() + s[1:]
-
-def ToIdentifier(s):
-  return "".join([Capitalize(part) for part in s.split("-")])
-
-references = []
-
-def CreateNamespace(domain_name, data, keys, prefixes, name = None):
-  result = {}
-  if name:
-    result["kName"] = name
-  for i, key in enumerate(keys):
-    if key in data:
-      for parameter in data[key]:
-        parameter_name = parameter["name"];
-        result[prefixes[i] + Capitalize(parameter_name)] = parameter_name
-        if "enum" in parameter:
-          enum_name = Capitalize(parameter_name)
-          result[enum_name] = {}
-          for enum in parameter["enum"]:
-            result[enum_name]["kEnum" + ToIdentifier(enum)] = enum
-        reference = ""
-        if "$ref" in parameter:
-          reference = parameter["$ref"]
-        if "items" in parameter and "$ref" in parameter["items"]:
-          reference = parameter["items"]["$ref"]
-        if reference:
-          if not "." in reference:
-            reference = domain_name + "." + reference
-          references.append(reference)
-  return result
-
-def FormatContents(tree, indent, format_string):
-  outer = dict((key, value) for key, value in tree.iteritems()
-                if not isinstance(value, dict))
-  inner = dict((key, value) for key, value in tree.iteritems()
-              if isinstance(value, dict))
-  body = ""
-  body += "".join(indent + format_string.format(key, value)
-                 for (key, value) in sorted(outer.items()))
-  body += "".join(FormatNamespace(key, value, indent, format_string)
-                 for (key, value) in sorted(inner.items()))
-  return body
-
-def FormatNamespace(title, tree, indent, format_string):
-  if (not tree):
-    return ""
-  body = '\n' + indent + "namespace " + title + " {\n"
-  body += FormatContents(tree, indent + "  ", format_string)
-  body += indent + "} // " + title + "\n"
-  return body
-
-def CreateHeader(tree, output_file):
-  contents = FormatContents(tree, "", "extern const char {0}[];\n")
-  output_file.write(template_h.substitute({
-      "contents": contents,
-      "package": package,
-      "PACKAGE": package.upper()
-  }))
-
-def CreateBody(tree, version, output_file):
-  contents = FormatContents(tree, "", "const char {0}[] = \"{1}\";\n")
-  output_file.write(template_cc.substitute({
-      "major": version["major"],
-      "minor": version["minor"],
-      "contents": contents,
-      "package": package
-  }))
-
-blink_protocol_data = open(blink_protocol_path).read()
-blink_protocol = json.loads(blink_protocol_data)
-blink_version = blink_protocol["version"]
-
-domains = blink_protocol["domains"]
-
-namespace_tree = {}
-
-for domain in domains:
-  domain_value = {}
-  domain_namespace_name = Capitalize(domain["domain"])
-  if "commands" in domain:
-    for command in domain["commands"]:
-      domain_value[command["name"]] = CreateNamespace(domain["domain"],
-          command, ["parameters", "returns"], ["kParam", "kResponse"],
-          domain_namespace_name + "." + command["name"])
-
-  if "events" in domain:
-    for event in domain["events"]:
-      domain_value[event["name"]] = CreateNamespace(domain["domain"],
-          event, ["parameters"], ["kParam"],
-          domain_namespace_name + "." + event["name"])
-  if domain_value:
-    namespace_tree[domain_namespace_name] = domain_value
-
-while (references):
-  reference = references.pop();
-  path = reference.split(".");
-  parent_namespace = namespace_tree;
-  for path_segment in path[0:-1]:
-    if path_segment not in parent_namespace:
-      parent_namespace[path_segment] = {}
-    parent_namespace = parent_namespace[path_segment]
-  if (path[-1] not in parent_namespace):
-    try:
-      domain = [d for d in domains if d["domain"] == path[0]][0]
-      ref_type = [t for t in domain["types"] if t["id"] == path[1]][0]
-      parent_namespace[ref_type["id"]] = CreateNamespace(path[0],
-          ref_type, ["properties"], ["kParam"])
-    except IndexError:
-      sys.stderr.write("Failed to resolve type [{0}].\n".format(reference))
-      sys.exit(1)
-
-for (namespace_name, namespace) in namespace_tree.items():
-  namespace["kName"] = namespace_name
-
-with open(output_cc_path, "w") as f:
-  CreateBody(namespace_tree, blink_version, f)
-
-with open(output_h_path, "w") as f:
-  CreateHeader(namespace_tree, f)
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 143ad34..62c56f8 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -26,7 +26,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/devtools/devtools_file_watcher.h"
-#include "chrome/browser/devtools/devtools_protocol.h"
 #include "chrome/browser/devtools/url_constants.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/infobars/infobar_service.h"
diff --git a/chrome/browser/devtools/inspector_protocol_config.json b/chrome/browser/devtools/inspector_protocol_config.json
index 826d3589..0a1c3ab0 100644
--- a/chrome/browser/devtools/inspector_protocol_config.json
+++ b/chrome/browser/devtools/inspector_protocol_config.json
@@ -17,6 +17,11 @@
                 "include_events": []
             },
             {
+                "domain": "Target",
+                "include": [ "setRemoteLocations" ],
+                "include_events": []
+            },
+            {
                 "domain": "WindowManager"
             }
         ]
diff --git a/chrome/browser/devtools/protocol/target_handler.cc b/chrome/browser/devtools/protocol/target_handler.cc
new file mode 100644
index 0000000..573b6ac
--- /dev/null
+++ b/chrome/browser/devtools/protocol/target_handler.cc
@@ -0,0 +1,40 @@
+// Copyright 2018 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/devtools/protocol/target_handler.h"
+
+#include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
+
+TargetHandler::TargetHandler(content::WebContents* web_contents,
+                             protocol::UberDispatcher* dispatcher) {
+  DCHECK(web_contents);
+  protocol::Target::Dispatcher::wire(dispatcher, this);
+}
+
+TargetHandler::~TargetHandler() {
+  ChromeDevToolsManagerDelegate* delegate =
+      ChromeDevToolsManagerDelegate::GetInstance();
+  if (delegate)
+    delegate->UpdateDeviceDiscovery();
+}
+
+protocol::Response TargetHandler::SetRemoteLocations(
+    std::unique_ptr<protocol::Array<protocol::Target::RemoteLocation>>
+        locations) {
+  remote_locations_.clear();
+  if (!locations)
+    return protocol::Response::OK();
+
+  for (size_t i = 0; i < locations->length(); ++i) {
+    auto* item = locations->get(i);
+    remote_locations_.insert(
+        net::HostPortPair(item->GetHost(), item->GetPort()));
+  }
+
+  ChromeDevToolsManagerDelegate* delegate =
+      ChromeDevToolsManagerDelegate::GetInstance();
+  if (delegate)
+    delegate->UpdateDeviceDiscovery();
+  return protocol::Response::OK();
+}
diff --git a/chrome/browser/devtools/protocol/target_handler.h b/chrome/browser/devtools/protocol/target_handler.h
new file mode 100644
index 0000000..6529337f
--- /dev/null
+++ b/chrome/browser/devtools/protocol/target_handler.h
@@ -0,0 +1,39 @@
+// Copyright 2018 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_DEVTOOLS_PROTOCOL_TARGET_HANDLER_H_
+#define CHROME_BROWSER_DEVTOOLS_PROTOCOL_TARGET_HANDLER_H_
+
+#include <set>
+
+#include "chrome/browser/devtools/protocol/forward.h"
+#include "chrome/browser/devtools/protocol/target.h"
+#include "net/base/host_port_pair.h"
+
+namespace content {
+class WebContents;
+}
+
+using RemoteLocations = std::set<net::HostPortPair>;
+
+class TargetHandler : public protocol::Target::Backend {
+ public:
+  TargetHandler(content::WebContents* web_contents,
+                protocol::UberDispatcher* dispatcher);
+  ~TargetHandler() override;
+
+  RemoteLocations& remote_locations() { return remote_locations_; }
+
+  // Target::Backend:
+  protocol::Response SetRemoteLocations(
+      std::unique_ptr<protocol::Array<protocol::Target::RemoteLocation>>
+          in_locations) override;
+
+ private:
+  RemoteLocations remote_locations_;
+
+  DISALLOW_COPY_AND_ASSIGN(TargetHandler);
+};
+
+#endif  // CHROME_BROWSER_DEVTOOLS_PROTOCOL_TARGET_HANDLER_H_
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.h b/chrome/browser/extensions/api/automation_internal/automation_internal_api.h
index 2971910d..8450b31 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.h
+++ b/chrome/browser/extensions/api/automation_internal/automation_internal_api.h
@@ -56,7 +56,8 @@
 
 class AutomationInternalEnableFrameFunction : public UIThreadExtensionFunction {
   DECLARE_EXTENSION_FUNCTION("automationInternal.enableFrame",
-                             AUTOMATIONINTERNAL_PERFORMACTION)
+                             AUTOMATIONINTERNAL_ENABLEFRAME)
+
  protected:
   ~AutomationInternalEnableFrameFunction() override {}
 
@@ -76,7 +77,7 @@
 class AutomationInternalQuerySelectorFunction
     : public UIThreadExtensionFunction {
   DECLARE_EXTENSION_FUNCTION("automationInternal.querySelector",
-                             AUTOMATIONINTERNAL_ENABLEDESKTOP)
+                             AUTOMATIONINTERNAL_QUERYSELECTOR)
 
  public:
   typedef base::Callback<void(const std::string& error,
diff --git a/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc b/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc
index 08ca770..3547cd4c 100644
--- a/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc
+++ b/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc
@@ -55,8 +55,9 @@
     return true;
   }
 
-  std::unique_ptr<base::DictionaryValue> user_settings(
-      params->user_settings.ToValue());
+  base::Value user_settings_value =
+      base::Value::FromUniquePtrValue(params->user_settings.ToValue());
+
   CloudPrintProxyService* service =
       CloudPrintProxyServiceFactory::GetForProfile(GetProfile());
   if (!service) {
@@ -64,7 +65,8 @@
     return false;
   }
   service->EnableForUserWithRobot(params->credentials, params->robot_email,
-                                  params->user_email, *user_settings);
+                                  params->user_email,
+                                  std::move(user_settings_value));
   SendResponse(true);
   return true;
 }
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.h b/chrome/browser/extensions/api/debugger/debugger_api.h
index e716e7e..dfb2a63 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.h
+++ b/chrome/browser/extensions/api/debugger/debugger_api.h
@@ -89,7 +89,7 @@
 // Implements the debugger.getTargets() extension function.
 class DebuggerGetTargetsFunction : public DebuggerFunction {
  public:
-  DECLARE_EXTENSION_FUNCTION("debugger.getTargets", DEBUGGER_ATTACH)
+  DECLARE_EXTENSION_FUNCTION("debugger.getTargets", DEBUGGER_GETTARGETS)
 
   DebuggerGetTargetsFunction();
 
diff --git a/chrome/browser/extensions/api/notifications/notifications_api.h b/chrome/browser/extensions/api/notifications/notifications_api.h
index b52400a6..3cda4331 100644
--- a/chrome/browser/extensions/api/notifications/notifications_api.h
+++ b/chrome/browser/extensions/api/notifications/notifications_api.h
@@ -135,7 +135,7 @@
 
  private:
   DECLARE_EXTENSION_FUNCTION("notifications.getPermissionLevel",
-                             NOTIFICATIONS_GET_ALL)
+                             NOTIFICATIONS_GETPERMISSIONLEVEL)
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index b83c1da..47d3336 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -1725,25 +1725,27 @@
   return false;
 }
 
-WebContents* TabsCaptureVisibleTabFunction::GetWebContentsForID(int window_id) {
+WebContents* TabsCaptureVisibleTabFunction::GetWebContentsForID(
+    int window_id,
+    std::string* error) {
   Browser* browser = NULL;
-  if (!GetBrowserFromWindowID(chrome_details_, window_id, &browser, &error_))
-    return NULL;
+  if (!GetBrowserFromWindowID(chrome_details_, window_id, &browser, error))
+    return nullptr;
 
   WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
   if (!contents) {
-    error_ = "No active web contents to capture";
-    return NULL;
+    *error = "No active web contents to capture";
+    return nullptr;
   }
 
   if (!extension()->permissions_data()->CanCaptureVisiblePage(
-          SessionTabHelper::IdForTab(contents).id(), &error_)) {
-    return NULL;
+          SessionTabHelper::IdForTab(contents).id(), error)) {
+    return nullptr;
   }
   return contents;
 }
 
-bool TabsCaptureVisibleTabFunction::RunAsync() {
+ExtensionFunction::ResponseAction TabsCaptureVisibleTabFunction::Run() {
   using api::extension_types::ImageDetails;
 
   EXTENSION_FUNCTION_VALIDATE(args_);
@@ -1758,16 +1760,22 @@
     image_details = ImageDetails::FromValue(*spec);
   }
 
-  WebContents* contents = GetWebContentsForID(context_id);
+  std::string error;
+  WebContents* contents = GetWebContentsForID(context_id, &error);
+  // TODO(wjmaclean): If |error| was populated, shouldn't we send error
+  // response? Currently doing that will fail
+  // ExtensionApiCaptureTest.CaptureNullWindow test.
 
   const CaptureResult capture_result = CaptureAsync(
       contents, image_details.get(),
       base::BindOnce(&TabsCaptureVisibleTabFunction::CopyFromSurfaceComplete,
                      this));
-  if (capture_result == OK)
-    return true;
-  SetErrorMessage(capture_result);
-  return false;
+  if (capture_result == OK) {
+    // CopyFromSurfaceComplete might have already responded.
+    return did_respond() ? AlreadyResponded() : RespondLater();
+  }
+
+  return RespondNow(Error(CaptureResultToErrorMessage(capture_result)));
 }
 
 void TabsCaptureVisibleTabFunction::OnCaptureSuccess(const SkBitmap& bitmap) {
@@ -1777,16 +1785,16 @@
     return;
   }
 
-  SetResult(std::make_unique<base::Value>(base64_result));
-  SendResponse(true);
+  Respond(OneArgument(std::make_unique<base::Value>(base64_result)));
 }
 
 void TabsCaptureVisibleTabFunction::OnCaptureFailure(CaptureResult result) {
-  SetErrorMessage(result);
-  SendResponse(false);
+  Respond(Error(CaptureResultToErrorMessage(result)));
 }
 
-void TabsCaptureVisibleTabFunction::SetErrorMessage(CaptureResult result) {
+// static.
+std::string TabsCaptureVisibleTabFunction::CaptureResultToErrorMessage(
+    CaptureResult result) {
   const char* reason_description = "internal error";
   switch (result) {
     case FAILURE_REASON_READBACK_FAILED:
@@ -1799,15 +1807,14 @@
       reason_description = "view is invisible";
       break;
     case FAILURE_REASON_SCREEN_SHOTS_DISABLED:
-      error_ = keys::kScreenshotsDisabled;
-      return;
+      return keys::kScreenshotsDisabled;
     case OK:
-      NOTREACHED()
-          << "SetErrorMessage should not be called with a successful result";
-      return;
+      NOTREACHED() << "CaptureResultToErrorMessage should not be called"
+                      " with a successful result";
+      return kUnknownErrorDoNotUse;
   }
-  error_ = ErrorUtils::FormatErrorMessage("Failed to capture tab: *",
-                                          reason_description);
+  return ErrorUtils::FormatErrorMessage("Failed to capture tab: *",
+                                        reason_description);
 }
 
 void TabsCaptureVisibleTabFunction::RegisterProfilePrefs(
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.h b/chrome/browser/extensions/api/tabs/tabs_api.h
index 7fe5521c..4bc091b 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.h
+++ b/chrome/browser/extensions/api/tabs/tabs_api.h
@@ -197,14 +197,14 @@
 
 class TabsCaptureVisibleTabFunction
     : public extensions::WebContentsCaptureClient,
-      public AsyncExtensionFunction {
+      public UIThreadExtensionFunction {
  public:
   TabsCaptureVisibleTabFunction();
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
   // ExtensionFunction implementation.
   bool HasPermission() override;
-  bool RunAsync() override;
+  ResponseAction Run() override;
 
  protected:
   ~TabsCaptureVisibleTabFunction() override {}
@@ -212,7 +212,7 @@
  private:
   ChromeExtensionFunctionDetails chrome_details_;
 
-  content::WebContents* GetWebContentsForID(int window_id);
+  content::WebContents* GetWebContentsForID(int window_id, std::string* error);
 
   // extensions::WebContentsCaptureClient:
   bool IsScreenshotEnabled() const override;
@@ -221,9 +221,11 @@
   void OnCaptureFailure(CaptureResult result) override;
 
  private:
-  void SetErrorMessage(CaptureResult result);
-
   DECLARE_EXTENSION_FUNCTION("tabs.captureVisibleTab", TABS_CAPTUREVISIBLETAB)
+
+  static std::string CaptureResultToErrorMessage(CaptureResult result);
+
+  DISALLOW_COPY_AND_ASSIGN(TabsCaptureVisibleTabFunction);
 };
 
 // Implement API call tabs.executeScript and tabs.insertCSS.
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
index a9bb1cb..b134be01 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -383,12 +383,14 @@
     if (extension && extension->is_hosted_app())
       return false;
 
-    // http://crbug.com/600441 workaround: Extension process reuse, implemented
-    // in ShouldTryToUseExistingProcessHost(), means that extension processes
-    // aren't always actually dedicated to a single origin.
-    // TODO(nick): Fix this.
-    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-            ::switches::kSitePerProcess))
+    // Extensions are allowed to share processes, even in --site-per-process
+    // currently. See https://crbug.com/600441#c1 for some background on the
+    // intersection of extension process reuse and site isolation.
+    //
+    // TODO(nick): Fix this, possibly by revamping the extensions process model
+    // so that sharing is determined by privilege level, as described in
+    // https://crbug.com/766267
+    if (extension)
       return false;
   }
   return true;
diff --git a/chrome/browser/extensions/extension_function_registration_test.cc b/chrome/browser/extensions/extension_function_registration_test.cc
new file mode 100644
index 0000000..fe75530
--- /dev/null
+++ b/chrome/browser/extensions/extension_function_registration_test.cc
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "extensions/browser/extension_function_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/common/one_shot_event.h"
+
+namespace extensions {
+
+using ExtensionFunctionRegistrationTest = ExtensionBrowserTest;
+
+// Test that all functions are registered with unique names, histogram values,
+// and factories. This is a browser test (rather than a unit test) to (help)
+// ensure that all the optional factories and services are indeed instantiated.
+IN_PROC_BROWSER_TEST_F(ExtensionFunctionRegistrationTest,
+                       CheckForDuplicateEntries) {
+  // Verify the ExtensionSystem is ready (and thus all extension functions
+  // registered) before checking.
+  base::RunLoop run_loop;
+  ExtensionSystem::Get(profile())->ready().Post(FROM_HERE,
+                                                run_loop.QuitClosure());
+  run_loop.Run();
+
+  const ExtensionFunctionRegistry::FactoryMap& factories =
+      ExtensionFunctionRegistry::GetInstance().GetFactoriesForTesting();
+  // Sanity check: Many, many functions should have been registered.
+  EXPECT_GT(factories.size(), 500u);
+
+  std::set<std::string> seen_names;
+  std::set<functions::HistogramValue> seen_histograms;
+  for (const auto& key_value : factories) {
+    const ExtensionFunctionRegistry::FactoryEntry& entry = key_value.second;
+    SCOPED_TRACE(entry.function_name_);
+    EXPECT_TRUE(seen_names.insert(entry.function_name_).second);
+    // NOTE: We explicitly don't check the factory here. On certain platforms
+    // with enough compiler optimization, the templated factories are re-used
+    // for different functions.
+    // EXPECT_TRUE(seen_factories.insert(entry.factory_).second);
+
+    // The chrome.test API uses an "unknown" histogram value, but should be the
+    // only API that does.
+    if (entry.histogram_value_ == functions::UNKNOWN) {
+      EXPECT_TRUE(base::StartsWith(entry.function_name_, "test.",
+                                   base::CompareCase::SENSITIVE));
+    } else {
+      EXPECT_TRUE(seen_histograms.insert(entry.histogram_value_).second);
+    }
+  }
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/process_management_browsertest.cc b/chrome/browser/extensions/process_management_browsertest.cc
index e3f4d728..50124d9 100644
--- a/chrome/browser/extensions/process_management_browsertest.cc
+++ b/chrome/browser/extensions/process_management_browsertest.cc
@@ -42,6 +42,12 @@
 
 namespace {
 
+bool IsExtensionProcessSharingAllowed() {
+  // TODO(nick): Currently, process sharing is allowed even in
+  // --site-per-process. Lock this down.  https://crbug.com/766267
+  return true;
+}
+
 class ProcessManagementTest : public ExtensionBrowserTest {
  private:
   // This is needed for testing isolated apps, which are still experimental.
@@ -268,12 +274,11 @@
   EXPECT_EQ(web1_host, web2_host);
   EXPECT_NE(web1_host, extension1_host);
 
-  if (!content::AreAllSitesIsolatedForTesting()) {
+  if (IsExtensionProcessSharingAllowed()) {
     // Extensions only share with each other ...
     EXPECT_EQ(extension1_host, extension2_host);
   } else {
-    // ... unless site-per-process is enabled - in this case no sharing
-    // is possible.
+    // Unless extensions are not allowed to share, even with each other.
     EXPECT_NE(extension1_host, extension2_host);
   }
 }
@@ -333,13 +338,13 @@
 
   // We've loaded 5 extensions with background pages
   // (api_test/browser_action/*), 1 extension without background page
-  // (api_test/management), and one isolated app. We expect only 2 unique
-  // processes hosting the background pages/scripts of these extensions without
-  // site-per-process (which extension gets assigned to which process is
-  // randomized).  With site-per-process (which is not subject to the 1/3rd of
-  // process limit cap) each of the 5 background pages/scripts will be hosted in
-  // a separate process.
-  if (!content::AreAllSitesIsolatedForTesting())
+  // (api_test/management), and one isolated app. With extension process
+  // sharing, we expect only 2 unique processes hosting the background
+  // pages/scripts of these extensions (which extension gets assigned to which
+  // process is randomized).  If extension process sharing is disabled, there is
+  // no process limit, and each of the 5 background pages/scripts will be hosted
+  // in a separate process.
+  if (IsExtensionProcessSharingAllowed())
     EXPECT_EQ(2u, process_ids.size());
   else
     EXPECT_EQ(5u, process_ids.size());
diff --git a/chrome/browser/extensions/process_manager_browsertest.cc b/chrome/browser/extensions/process_manager_browsertest.cc
index 6e9d78a..78f04bf 100644
--- a/chrome/browser/extensions/process_manager_browsertest.cc
+++ b/chrome/browser/extensions/process_manager_browsertest.cc
@@ -59,6 +59,12 @@
 
 namespace {
 
+bool IsExtensionProcessSharingAllowed() {
+  // TODO(nick): Currently, process sharing is allowed even in
+  // --site-per-process. Lock this down.  https://crbug.com/766267
+  return true;
+}
+
 void AddFrameToSet(std::set<content::RenderFrameHost*>* frames,
                    content::RenderFrameHost* rfh) {
   if (rfh->IsRenderFrameLive())
@@ -719,10 +725,9 @@
 
   EXPECT_EQ(kNumExtensions, installed_extensions.size());
 
-  if (content::AreAllSitesIsolatedForTesting()) {
+  if (!IsExtensionProcessSharingAllowed()) {
     EXPECT_EQ(kNumExtensions, processes.size()) << "Extension process reuse is "
-                                                   "expected to be disabled in "
-                                                   "--site-per-process.";
+                                                   "expected to be disabled.";
   } else {
     EXPECT_LT(processes.size(), kNumExtensions)
         << "Expected extension process reuse, but none happened.";
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 899d3a2..491a88f0 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2941,6 +2941,10 @@
 const char kWakeOnPacketsDescription[] =
     "Enables waking the device based on the receipt of some network packets.";
 
+const char kEnableHomeLauncherName[] = "Enable home launcher";
+const char kEnableHomeLauncherDescription[] =
+    "Enable home launcher in tablet mode.";
+
 #endif  // defined(OS_CHROMEOS)
 
 // Random platform combinations -----------------------------------------------
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 9062dc97..92459be 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1793,6 +1793,9 @@
 extern const char kWakeOnPacketsName[];
 extern const char kWakeOnPacketsDescription[];
 
+extern const char kEnableHomeLauncherName[];
+extern const char kEnableHomeLauncherDescription[];
+
 #endif  // #if defined(OS_CHROMEOS)
 
 // Random platform combinations -----------------------------------------------
diff --git a/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
index df8bc4c..dc7e75b 100644
--- a/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
@@ -16,6 +16,7 @@
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/ntp_snippets/contextual/contextual_content_suggestions_service.h"
 #include "components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
 #include "components/ntp_snippets/remote/cached_image_fetcher.h"
 #include "components/ntp_snippets/remote/remote_suggestions_database.h"
 #include "components/prefs/pref_service.h"
@@ -107,10 +108,12 @@
               std::make_unique<suggestions::ImageDecoderImpl>(),
               request_context.get()),
           pref_service, contextual_suggestions_database.get());
+  auto metrics_reporter = std::make_unique<
+      contextual_suggestions::ContextualSuggestionsMetricsReporter>();
   auto* service = new ContextualContentSuggestionsService(
       std::move(contextual_suggestions_fetcher),
       std::move(cached_image_fetcher),
-      std::move(contextual_suggestions_database));
+      std::move(contextual_suggestions_database), std::move(metrics_reporter));
 
   return service;
 }
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.cc b/chrome/browser/offline_pages/android/offline_page_bridge.cc
index d95e63eb..3bac7fd 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.cc
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.cc
@@ -659,36 +659,64 @@
       params, base::Bind(&SavePageLaterCallback, j_callback_ref));
 }
 
-void OfflinePageBridge::PublishInternalPage(
+void OfflinePageBridge::PublishInternalPageByOfflineId(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj,
-    const JavaParamRef<jobject>& j_profile,
     const jlong j_offline_id,
-    const base::android::JavaParamRef<jstring>& j_title,
-    const base::android::JavaParamRef<jstring>& j_url,
-    const base::android::JavaParamRef<jstring>& j_file_path,
-    const jlong j_file_size,
     const base::android::JavaParamRef<jobject>& j_published_callback) {
   ScopedJavaGlobalRef<jobject> j_published_callback_ref;
   j_published_callback_ref.Reset(env, j_published_callback);
 
-  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
   OfflinePageModel* offline_page_model =
-      OfflinePageModelFactory::GetForBrowserContext(profile);
-  DCHECK(offline_page_model != nullptr);
-  // Since we only need base functionaity of the OfflinePageArchiver, we don't
-  // need to pass a web_contents to the Archiver constructor.
-  std::unique_ptr<OfflinePageArchiver> archiver(new OfflinePageMHTMLArchiver());
-  GURL url = GURL(ConvertJavaStringToUTF8(env, j_url));
-  base::FilePath file_path(ConvertJavaStringToUTF8(env, j_file_path));
-  ClientId client_id;  // Use an empty client id.
-  OfflinePageItem offline_page(url, (int64_t)j_offline_id, client_id, file_path,
-                               j_file_size);
-  offline_page.title = ConvertJavaStringToUTF16(env, j_title);
+      OfflinePageModelFactory::GetForBrowserContext(browser_context_);
+  DCHECK(offline_page_model);
 
+  offline_page_model->GetPageByOfflineId(
+      j_offline_id,
+      base::Bind(&OfflinePageBridge::PublishInternalArchive,
+                 weak_ptr_factory_.GetWeakPtr(), j_published_callback_ref));
+}
+
+void OfflinePageBridge::PublishInternalPageByGuid(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    const base::android::JavaParamRef<jstring>& j_guid,
+    const base::android::JavaParamRef<jobject>& j_published_callback) {
+  ScopedJavaGlobalRef<jobject> j_published_callback_ref;
+  j_published_callback_ref.Reset(env, j_published_callback);
+
+  OfflinePageModel* offline_page_model =
+      OfflinePageModelFactory::GetForBrowserContext(browser_context_);
+  DCHECK(offline_page_model);
+
+  offline_page_model->GetPageByGuid(
+      ConvertJavaStringToUTF8(env, j_guid),
+      base::Bind(&OfflinePageBridge::PublishInternalArchive,
+                 weak_ptr_factory_.GetWeakPtr(), j_published_callback_ref));
+}
+
+void OfflinePageBridge::PublishInternalArchive(
+    const ScopedJavaGlobalRef<jobject>& j_callback_obj,
+    const OfflinePageItem* offline_page) {
+  if (!offline_page) {
+    PublishPageDone(j_callback_obj, base::FilePath(), false /*success*/);
+    return;
+  }
+
+  OfflinePageModel* offline_page_model =
+      OfflinePageModelFactory::GetForBrowserContext(browser_context_);
+  DCHECK(offline_page_model);
+
+  // If it has already been published, bail out.
+  if (!offline_page_model->IsArchiveInInternalDir(offline_page->file_path)) {
+    PublishPageDone(j_callback_obj, offline_page->file_path, true /*success*/);
+    return;
+  }
+
+  std::unique_ptr<OfflinePageArchiver> archiver(new OfflinePageMHTMLArchiver());
   offline_page_model->PublishInternalArchive(
-      offline_page, std::move(archiver),
-      base::BindOnce(&PublishPageDone, std::move(j_published_callback_ref)));
+      *offline_page, std::move(archiver),
+      base::BindOnce(&PublishPageDone, std::move(j_callback_obj)));
 }
 
 ScopedJavaLocalRef<jstring> OfflinePageBridge::GetOfflinePageHeaderForReload(
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.h b/chrome/browser/offline_pages/android/offline_page_bridge.h
index 003527f..9e49a6a9 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.h
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.h
@@ -128,15 +128,16 @@
                      const base::android::JavaParamRef<jstring>& j_origin,
                      jboolean user_requested);
 
-  void PublishInternalPage(
+  void PublishInternalPageByOfflineId(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jobject>& j_profile,
       const jlong j_offline_id,
-      const base::android::JavaParamRef<jstring>& j_title,
-      const base::android::JavaParamRef<jstring>& j_url,
-      const base::android::JavaParamRef<jstring>& j_file_path,
-      const jlong j_size,
+      const base::android::JavaParamRef<jobject>& j_published_callback);
+
+  void PublishInternalPageByGuid(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jstring>& j_guid,
       const base::android::JavaParamRef<jobject>& j_published_callback);
 
   jboolean IsShowingOfflinePreview(
@@ -250,6 +251,10 @@
       JNIEnv* env,
       const ClientId& clientId) const;
 
+  void PublishInternalArchive(
+      const base::android::ScopedJavaGlobalRef<jobject>& j_callback_obj,
+      const OfflinePageItem* offline_page);
+
   base::android::ScopedJavaGlobalRef<jobject> java_ref_;
   // Not owned.
   content::BrowserContext* browser_context_;
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 3fabcfd1..1fdb31a 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -155,16 +155,20 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/result_codes.h"
+#include "content/public/common/service_manager_connection.h"
+#include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/web_preferences.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/download_test_observer.h"
 #include "content/public/test/mock_notification_observer.h"
+#include "content/public/test/network_service_test_helper.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
@@ -200,6 +204,10 @@
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_interceptor.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "services/network/public/mojom/network_service_test.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
@@ -730,6 +738,37 @@
     UpdateProviderPolicy(policies);
   }
 
+  void SetShouldRequireCTForTesting(bool* required) {
+    if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+      network::mojom::NetworkServiceTestPtr network_service_test;
+      content::ServiceManagerConnection::GetForProcess()
+          ->GetConnector()
+          ->BindInterface(content::mojom::kNetworkServiceName,
+                          &network_service_test);
+      network::mojom::NetworkServiceTest::ShouldRequireCT required_ct;
+      if (!required) {
+        required_ct =
+            network::mojom::NetworkServiceTest::ShouldRequireCT::RESET;
+      } else {
+        required_ct =
+            *required
+                ? network::mojom::NetworkServiceTest::ShouldRequireCT::REQUIRE
+                : network::mojom::NetworkServiceTest::ShouldRequireCT::
+                      DONT_REQUIRE;
+      }
+
+      mojo::ScopedAllowSyncCallForTesting allow_sync_call;
+      network_service_test->SetShouldRequireCT(required_ct);
+      return;
+    }
+
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(
+            &net::TransportSecurityState::SetShouldRequireCTForTesting,
+            required));
+  }
+
 #if defined(OS_CHROMEOS)
   class QuitMessageLoopAfterScreenshot
       : public ChromeScreenshotGrabberTestObserver {
@@ -3762,23 +3801,14 @@
 
 IN_PROC_BROWSER_TEST_F(PolicyTest,
                        CertificateTransparencyEnforcementDisabledForUrls) {
-  // Cleanup any globals even if the test fails.
-  base::ScopedClosureRunner cleanup(base::Bind(
-      base::IgnoreResult(&BrowserThread::PostTask), BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&net::TransportSecurityState::SetShouldRequireCTForTesting,
-                 nullptr)));
-
   net::EmbeddedTestServer https_server_ok(net::EmbeddedTestServer::TYPE_HTTPS);
   https_server_ok.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
   https_server_ok.ServeFilesFromSourceDirectory("chrome/test/data");
   ASSERT_TRUE(https_server_ok.Start());
 
   // Require CT for all hosts (in the absence of policy).
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::BindOnce(net::TransportSecurityState::SetShouldRequireCTForTesting,
-                     base::Owned(new bool(true))));
+  bool required = true;
+  SetShouldRequireCTForTesting(&required);
 
   ui_test_utils::NavigateToURL(browser(), https_server_ok.GetURL("/"));
 
@@ -3806,6 +3836,8 @@
   UpdateProviderPolicy(policies);
   FlushBlacklistPolicy();
 
+  SetShouldRequireCTForTesting(nullptr);
+
   ui_test_utils::NavigateToURL(browser(),
                                https_server_ok.GetURL("/simple.html"));
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index b2f4591..87607cca 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -70,7 +70,7 @@
 #include "chrome/common/secure_origin_whitelist.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/browsing_data/core/pref_names.h"
-#include "components/certificate_transparency/ct_policy_manager.h"
+#include "components/certificate_transparency/pref_names.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/dom_distiller/core/distilled_page_prefs.h"
 #include "components/feature_engagement/buildflags.h"
@@ -488,7 +488,7 @@
   // User prefs. Please keep this list alphabetized.
   autofill::AutofillManager::RegisterProfilePrefs(registry);
   browsing_data::prefs::RegisterBrowserUserPrefs(registry);
-  certificate_transparency::CTPolicyManager::RegisterPrefs(registry);
+  certificate_transparency::prefs::RegisterPrefs(registry);
   ChromeContentBrowserClient::RegisterProfilePrefs(registry);
   ChromeVersionService::RegisterProfilePrefs(registry);
   chrome_browser_net::Predictor::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
index 18ea996..7419f6422 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
@@ -93,16 +93,16 @@
     const std::string& robot_auth_code,
     const std::string& robot_email,
     const std::string& user_email,
-    const base::DictionaryValue& user_preferences) {
+    base::Value user_preferences) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents",
                             ServiceProcessControl::SERVICE_EVENT_ENABLE,
                             ServiceProcessControl::SERVICE_EVENT_MAX);
   if (profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled)) {
     InvokeServiceTask(
-        base::Bind(&CloudPrintProxyService::EnableCloudPrintProxyWithRobot,
-                   weak_factory_.GetWeakPtr(), robot_auth_code, robot_email,
-                   user_email, base::Owned(user_preferences.DeepCopy())));
+        base::BindOnce(&CloudPrintProxyService::EnableCloudPrintProxyWithRobot,
+                       weak_factory_.GetWeakPtr(), robot_auth_code, robot_email,
+                       user_email, std::move(user_preferences)));
   }
 }
 
@@ -195,12 +195,11 @@
     const std::string& robot_auth_code,
     const std::string& robot_email,
     const std::string& user_email,
-    const base::DictionaryValue* user_preferences) {
+    base::Value user_preferences) {
   ServiceProcessControl* process_control = GetServiceProcessControl();
   DCHECK(process_control->IsConnected());
   GetCloudPrintProxy().EnableCloudPrintProxyWithRobot(
-      robot_auth_code, robot_email, user_email,
-      std::move(*user_preferences->CreateDeepCopy()));
+      robot_auth_code, robot_email, user_email, std::move(user_preferences));
 
   // Assume the IPC worked.
   profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, user_email);
@@ -226,8 +225,8 @@
   ApplyCloudPrintConnectorPolicy();
 }
 
-bool CloudPrintProxyService::InvokeServiceTask(const base::Closure& task) {
-  GetServiceProcessControl()->Launch(task, base::Closure());
+bool CloudPrintProxyService::InvokeServiceTask(base::OnceClosure task) {
+  GetServiceProcessControl()->Launch(std::move(task), base::OnceClosure());
   return true;
 }
 
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
index 9e66695..93f7db2 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/common/cloud_print.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -25,10 +26,6 @@
 class Profile;
 class ServiceProcessControl;
 
-namespace base {
-class DictionaryValue;
-}  // namespace base
-
 // Layer between the browser user interface and the cloud print proxy code
 // running in the service process.
 class CloudPrintProxyService : public KeyedService {
@@ -47,11 +44,10 @@
   void GetPrinters(const PrintersCallback& callback);
 
   // Enables/disables cloud printing for the user
-  virtual void EnableForUserWithRobot(
-      const std::string& robot_auth_code,
-      const std::string& robot_email,
-      const std::string& user_email,
-      const base::DictionaryValue& user_settings);
+  virtual void EnableForUserWithRobot(const std::string& robot_auth_code,
+                                      const std::string& robot_email,
+                                      const std::string& user_email,
+                                      base::Value user_settings);
   virtual void DisableForUser();
 
   // Query the service process for the status of the cloud print proxy and
@@ -68,11 +64,10 @@
   // Methods that send an IPC to the service.
   void GetCloudPrintProxyPrinters(const PrintersCallback& callback);
   void RefreshCloudPrintProxyStatus();
-  void EnableCloudPrintProxyWithRobot(
-      const std::string& robot_auth_code,
-      const std::string& robot_email,
-      const std::string& user_email,
-      const base::DictionaryValue* user_preferences);
+  void EnableCloudPrintProxyWithRobot(const std::string& robot_auth_code,
+                                      const std::string& robot_email,
+                                      const std::string& user_email,
+                                      base::Value user_preferences);
   void DisableCloudPrintProxy();
 
   // Callback that gets the cloud print proxy info.
@@ -83,7 +78,7 @@
   // Invoke a task that gets run after the service process successfully
   // launches. The task typically involves sending an IPC to the service
   // process.
-  bool InvokeServiceTask(const base::Closure& task);
+  bool InvokeServiceTask(base::OnceClosure task);
 
   // Checks the policy. Returns true if nothing needs to be done (the policy is
   // not set or the connector is not enabled).
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
index 48ef108..b793f0ed 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
@@ -51,12 +51,16 @@
 
   MockServiceProcessControl() : connected_(false) { }
 
+  ~MockServiceProcessControl() override {}
+
   MOCK_CONST_METHOD0(IsConnected, bool());
 
-  MOCK_METHOD2(Launch, void(const base::Closure&, const base::Closure&));
+  void Launch(base::OnceClosure success_task,
+              base::OnceClosure failure_task) override;
+
   MOCK_METHOD0(Disconnect, void());
 
-  void SetConnectSuccessMockExpectations(bool post_task);
+  void SetConnectSuccessMockExpectations();
 
  private:
   bool connected_;
@@ -68,28 +72,22 @@
   return std::string("dorothy@somewhere.otr");
 }
 
-void CallTask(const base::Closure& task) {
-  if (!task.is_null())
-    task.Run();
+void CallTask(base::OnceClosure task) {
+  if (task)
+    std::move(task).Run();
 }
 
-void PostTask(const base::Closure& task) {
-  if (!task.is_null())
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
+void MockServiceProcessControl::Launch(base::OnceClosure success_task,
+                                       base::OnceClosure failure_task) {
+  connected_ = true;
+  CallTask(std::move(success_task));
 }
 
-void MockServiceProcessControl::SetConnectSuccessMockExpectations(
-    bool post_task) {
+void MockServiceProcessControl::SetConnectSuccessMockExpectations() {
   EXPECT_CALL(*this, IsConnected()).WillRepeatedly(ReturnPointee(&connected_));
 
-  EXPECT_CALL(*this, Launch(_, _))
-      .WillRepeatedly(
-          DoAll(Assign(&connected_, true),
-                WithArgs<0>(Invoke(post_task ? PostTask : CallTask))));
-
   EXPECT_CALL(*this, Disconnect()).Times(AtMost(1))
       .WillRepeatedly(Assign(&connected_, false));
-
 }
 
 class MockCloudPrintProxy : public cloud_print::mojom::CloudPrint {
@@ -189,7 +187,7 @@
   void EnableForUser() {
     EnableForUserWithRobot("123", "123@gmail.com",
                            MockServiceProcessControl::EnabledUserId(),
-                           base::DictionaryValue());
+                           base::Value(base::Value::Type::DICTIONARY));
   }
 
  private:
@@ -220,12 +218,12 @@
 
 TEST_F(CloudPrintProxyPolicyTest, VerifyExpectations) {
   MockServiceProcessControl mock_control;
-  mock_control.SetConnectSuccessMockExpectations(false);
+  mock_control.SetConnectSuccessMockExpectations();
 
   EXPECT_FALSE(mock_control.IsConnected());
-  mock_control.Launch(base::Closure(), base::Closure());
+  mock_control.Launch(base::OnceClosure(), base::OnceClosure());
   EXPECT_TRUE(mock_control.IsConnected());
-  mock_control.Launch(base::Closure(), base::Closure());
+  mock_control.Launch(base::OnceClosure(), base::OnceClosure());
   EXPECT_TRUE(mock_control.IsConnected());
   mock_control.Disconnect();
   EXPECT_FALSE(mock_control.IsConnected());
@@ -235,8 +233,7 @@
   TestCloudPrintProxyService service(&profile_);
 
   service.GetMockCloudPrintProxy().ReturnDisabledInfo();
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
       profile_.GetTestingPrefService();
@@ -252,8 +249,7 @@
 TEST_F(CloudPrintProxyPolicyTest, StartWithNoPolicyProxyEnabled) {
   TestCloudPrintProxyService service(&profile_);
 
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
   service.GetMockCloudPrintProxy().ReturnEnabledInfo();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
@@ -271,8 +267,7 @@
 TEST_F(CloudPrintProxyPolicyTest, StartWithPolicySetProxyDisabled) {
   TestCloudPrintProxyService service(&profile_);
 
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
   service.GetMockCloudPrintProxy().ReturnDisabledInfo();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
@@ -290,8 +285,7 @@
 TEST_F(CloudPrintProxyPolicyTest, StartWithPolicySetProxyEnabled) {
   TestCloudPrintProxyService service(&profile_);
 
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
   service.GetMockCloudPrintProxy().ReturnEnabledInfo();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
@@ -310,8 +304,7 @@
 TEST_F(CloudPrintProxyPolicyTest, StartWithNoPolicyProxyDisabledThenSetPolicy) {
   TestCloudPrintProxyService service(&profile_);
 
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
   service.GetMockCloudPrintProxy().ReturnDisabledInfo();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
@@ -333,8 +326,7 @@
 TEST_F(CloudPrintProxyPolicyTest, StartWithNoPolicyProxyEnabledThenSetPolicy) {
   TestCloudPrintProxyService service(&profile_);
 
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
   service.GetMockCloudPrintProxy().ReturnEnabledInfo();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
@@ -359,8 +351,7 @@
        StartWithPolicySetProxyDisabledThenClearPolicy) {
   TestCloudPrintProxyService service(&profile_);
 
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
   service.GetMockCloudPrintProxy().ReturnDisabledInfo();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
@@ -381,8 +372,7 @@
        StartWithPolicySetProxyEnabledThenClearPolicy) {
   TestCloudPrintProxyService service(&profile_);
 
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
   service.GetMockCloudPrintProxy().ReturnEnabledInfo();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
@@ -403,8 +393,7 @@
 TEST_F(CloudPrintProxyPolicyTest, StartWithNoPolicyProxyDisabledThenEnable) {
   TestCloudPrintProxyService service(&profile_);
 
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
   service.GetMockCloudPrintProxy().ReturnDisabledInfo();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
@@ -427,8 +416,7 @@
        StartWithPolicySetProxyEnabledThenClearPolicyAndEnable) {
   TestCloudPrintProxyService service(&profile_);
 
-  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations(
-      false);
+  service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations();
   service.GetMockCloudPrintProxy().ReturnEnabledInfo();
 
   sync_preferences::TestingPrefServiceSyncable* prefs =
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index e2e3c46..60ba0278 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -97,6 +97,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "components/certificate_transparency/pref_names.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/domain_reliability/monitor.h"
@@ -572,6 +573,21 @@
       base::Bind(&ProfileImpl::UpdateIsEphemeralInStorage,
                  base::Unretained(this)));
 
+  // When any of the following CT preferences change, we schedule an update
+  // to aggregate the actual update using a |ct_policy_update_timer_|.
+  pref_change_registrar_.Add(
+      certificate_transparency::prefs::kCTRequiredHosts,
+      base::Bind(&ProfileImpl::ScheduleUpdateCTPolicy, base::Unretained(this)));
+  pref_change_registrar_.Add(
+      certificate_transparency::prefs::kCTExcludedHosts,
+      base::Bind(&ProfileImpl::ScheduleUpdateCTPolicy, base::Unretained(this)));
+  pref_change_registrar_.Add(
+      certificate_transparency::prefs::kCTExcludedSPKIs,
+      base::Bind(&ProfileImpl::ScheduleUpdateCTPolicy, base::Unretained(this)));
+  pref_change_registrar_.Add(
+      certificate_transparency::prefs::kCTExcludedLegacySPKIs,
+      base::Bind(&ProfileImpl::ScheduleUpdateCTPolicy, base::Unretained(this)));
+
   media_device_id_salt_ = new MediaDeviceIDSalt(prefs_.get());
 
   // It would be nice to use PathService for fetching this directory, but
@@ -683,6 +699,8 @@
 #endif
 
   content::URLDataSource::Add(this, new PrefsInternalsSource(this));
+
+  ScheduleUpdateCTPolicy();
 }
 
 base::FilePath ProfileImpl::last_selected_directory() {
@@ -1354,6 +1372,36 @@
   }
 }
 
+std::vector<std::string> TranslateStringArray(const base::ListValue* list) {
+  std::vector<std::string> strings;
+  for (const base::Value& value : *list) {
+    DCHECK(value.is_string());
+    strings.push_back(value.GetString());
+  }
+  return strings;
+}
+
+void ProfileImpl::ScheduleUpdateCTPolicy() {
+  ct_policy_update_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(0),
+                                this, &ProfileImpl::UpdateCTPolicy);
+}
+
+void ProfileImpl::UpdateCTPolicy() {
+  const base::ListValue* ct_required =
+      prefs_->GetList(certificate_transparency::prefs::kCTRequiredHosts);
+  const base::ListValue* ct_excluded =
+      prefs_->GetList(certificate_transparency::prefs::kCTExcludedHosts);
+  const base::ListValue* ct_excluded_spkis =
+      prefs_->GetList(certificate_transparency::prefs::kCTExcludedSPKIs);
+  const base::ListValue* ct_excluded_legacy_spkis =
+      prefs_->GetList(certificate_transparency::prefs::kCTExcludedLegacySPKIs);
+
+  GetDefaultStoragePartition(this)->GetNetworkContext()->SetCTPolicy(
+      TranslateStringArray(ct_required), TranslateStringArray(ct_excluded),
+      TranslateStringArray(ct_excluded_spkis),
+      TranslateStringArray(ct_excluded_legacy_spkis));
+}
+
 // Gets the media cache parameters from the command line. |cache_path| will be
 // set to the user provided path, or will not be touched if there is not an
 // argument. |max_size| will be the user provided value or zero by default.
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index dd5d3df..aaeaa75 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -190,6 +190,9 @@
   void UpdateNameInStorage();
   void UpdateAvatarInStorage();
   void UpdateIsEphemeralInStorage();
+  void UpdateCTPolicy();
+
+  void ScheduleUpdateCTPolicy();
 
   void GetMediaCacheParameters(base::FilePath* cache_path, int* max_size);
 
@@ -283,6 +286,9 @@
 
   chrome_browser_net::Predictor* predictor_;
 
+  // Used to post schedule CT policy updates
+  base::OneShotTimer ct_policy_update_timer_;
+
   DISALLOW_COPY_AND_ASSIGN(ProfileImpl);
 };
 
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 4981d9d4..def7c4a0 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -51,7 +51,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/about_handler/about_protocol_handler.h"
-#include "components/certificate_transparency/ct_policy_manager.h"
 #include "components/certificate_transparency/tree_state_tracker.h"
 #include "components/content_settings/core/browser/content_settings_provider.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
@@ -547,11 +546,6 @@
   }
 #endif
 
-  // The CTPolicyManager shares the same constraints of needing to be cleaned
-  // up on the UI thread.
-  ct_policy_manager_.reset(new certificate_transparency::CTPolicyManager(
-      pref_service, io_task_runner));
-
   if (!IsOffTheRecord()) {
     // Add policy headers for non-incognito requests.
     policy::PolicyHeaderService* policy_header_service =
@@ -1284,9 +1278,6 @@
   main_request_context_->transport_security_state()->SetExpectCTReporter(
       expect_ct_reporter_.get());
 
-  main_request_context_->transport_security_state()->SetRequireCTDelegate(
-      ct_policy_manager_->GetDelegate());
-
   resource_context_->host_resolver_ =
       io_thread_globals->system_request_context->host_resolver();
   resource_context_->request_context_ = main_request_context_;
@@ -1441,8 +1432,6 @@
   safe_browsing_enabled_.Destroy();
   safe_browsing_whitelist_domains_.Destroy();
   network_prediction_options_.Destroy();
-  if (ct_policy_manager_)
-    ct_policy_manager_->Shutdown();
   incognito_availibility_pref_.Destroy();
 #if BUILDFLAG(ENABLE_PLUGINS)
   always_open_pdf_externally_.Destroy();
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 43283b01..d107a41 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -55,7 +55,6 @@
 }
 
 namespace certificate_transparency {
-class CTPolicyManager;
 class TreeStateTracker;
 }
 
@@ -627,8 +626,6 @@
   // URLRequestContextStorage), and must be disconnected from it before it's
   // destroyed.
   mutable std::unique_ptr<net::ReportSender> certificate_report_sender_;
-  mutable std::unique_ptr<certificate_transparency::CTPolicyManager>
-      ct_policy_manager_;
 
   mutable std::unique_ptr<net::URLRequestContext> extensions_request_context_;
   // One URLRequestContext per isolated app for main and media requests.
diff --git a/chrome/browser/profiling_host/memlog_browsertest.cc b/chrome/browser/profiling_host/memlog_browsertest.cc
index 75f6a2ae..c1c5740 100644
--- a/chrome/browser/profiling_host/memlog_browsertest.cc
+++ b/chrome/browser/profiling_host/memlog_browsertest.cc
@@ -16,6 +16,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/services/heap_profiling/public/cpp/switches.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
@@ -43,30 +44,30 @@
     InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
     if (GetParam().start_profiling_with_command_line_flag) {
       if (GetParam().mode == ProfilingProcessHost::Mode::kAllRenderers) {
-        command_line->AppendSwitchASCII(switches::kMemlog,
-                                        switches::kMemlogModeAllRenderers);
+        command_line->AppendSwitchASCII(
+            heap_profiling::kMemlog, heap_profiling::kMemlogModeAllRenderers);
       } else if (GetParam().mode == ProfilingProcessHost::Mode::kAll) {
-        command_line->AppendSwitchASCII(switches::kMemlog,
-                                        switches::kMemlogModeAll);
+        command_line->AppendSwitchASCII(heap_profiling::kMemlog,
+                                        heap_profiling::kMemlogModeAll);
       } else {
         NOTREACHED();
       }
 
       if (GetParam().stack_mode == mojom::StackMode::PSEUDO) {
-        command_line->AppendSwitchASCII(switches::kMemlogStackMode,
-                                        switches::kMemlogStackModePseudo);
+        command_line->AppendSwitchASCII(heap_profiling::kMemlogStackMode,
+                                        heap_profiling::kMemlogStackModePseudo);
       } else if (GetParam().stack_mode ==
                  mojom::StackMode::NATIVE_WITH_THREAD_NAMES) {
         command_line->AppendSwitchASCII(
-            switches::kMemlogStackMode,
-            switches::kMemlogStackModeNativeWithThreadNames);
+            heap_profiling::kMemlogStackMode,
+            heap_profiling::kMemlogStackModeNativeWithThreadNames);
       } else if (GetParam().stack_mode ==
                  mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES) {
-        command_line->AppendSwitchASCII(switches::kMemlogStackMode,
-                                        switches::kMemlogStackModeNative);
+        command_line->AppendSwitchASCII(heap_profiling::kMemlogStackMode,
+                                        heap_profiling::kMemlogStackModeNative);
       } else if (GetParam().stack_mode == mojom::StackMode::MIXED) {
-        command_line->AppendSwitchASCII(switches::kMemlogStackMode,
-                                        switches::kMemlogStackModeMixed);
+        command_line->AppendSwitchASCII(heap_profiling::kMemlogStackMode,
+                                        heap_profiling::kMemlogStackModeMixed);
       } else {
         NOTREACHED();
       }
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc
index 61f90ee..de3fdef 100644
--- a/chrome/browser/profiling_host/profiling_process_host.cc
+++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -34,6 +34,7 @@
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/services/heap_profiling/public/cpp/sender_pipe.h"
+#include "components/services/heap_profiling/public/cpp/switches.h"
 #include "components/services/heap_profiling/public/mojom/constants.mojom.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_child_process_host.h"
@@ -272,21 +273,21 @@
 ProfilingProcessHost::Mode ProfilingProcessHost::GetModeForStartup() {
   const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
 #if BUILDFLAG(USE_ALLOCATOR_SHIM)
-  if (cmdline->HasSwitch(switches::kMemlog) ||
+  if (cmdline->HasSwitch(heap_profiling::kMemlog) ||
       base::FeatureList::IsEnabled(kOOPHeapProfilingFeature)) {
     if (cmdline->HasSwitch(switches::kEnableHeapProfiling)) {
       // PartitionAlloc doesn't support chained allocation hooks so we can't
       // run both heap profilers at the same time.
       LOG(ERROR) << "--" << switches::kEnableHeapProfiling
-                 << " specified with --" << switches::kMemlog
+                 << " specified with --" << heap_profiling::kMemlog
                  << "which are not compatible. Memlog will be disabled.";
       return Mode::kNone;
     }
 
     std::string mode;
     // Respect the commandline switch above the field trial.
-    if (cmdline->HasSwitch(switches::kMemlog)) {
-      mode = cmdline->GetSwitchValueASCII(switches::kMemlog);
+    if (cmdline->HasSwitch(heap_profiling::kMemlog)) {
+      mode = cmdline->GetSwitchValueASCII(heap_profiling::kMemlog);
     } else {
       mode = base::GetFieldTrialParamValueByFeature(
           kOOPHeapProfilingFeature, kOOPHeapProfilingFeatureMode);
@@ -296,8 +297,8 @@
   }
   return Mode::kNone;
 #else
-  LOG_IF(ERROR, cmdline->HasSwitch(switches::kMemlog))
-      << "--" << switches::kMemlog
+  LOG_IF(ERROR, cmdline->HasSwitch(heap_profiling::kMemlog))
+      << "--" << heap_profiling::kMemlog
       << " specified but it will have no effect because the use_allocator_shim "
       << "is not available in this build.";
   return Mode::kNone;
@@ -307,22 +308,22 @@
 // static
 ProfilingProcessHost::Mode ProfilingProcessHost::ConvertStringToMode(
     const std::string& mode) {
-  if (mode == switches::kMemlogModeAll)
+  if (mode == heap_profiling::kMemlogModeAll)
     return Mode::kAll;
-  if (mode == switches::kMemlogModeAllRenderers)
+  if (mode == heap_profiling::kMemlogModeAllRenderers)
     return Mode::kAllRenderers;
-  if (mode == switches::kMemlogModeManual)
+  if (mode == heap_profiling::kMemlogModeManual)
     return Mode::kManual;
-  if (mode == switches::kMemlogModeMinimal)
+  if (mode == heap_profiling::kMemlogModeMinimal)
     return Mode::kMinimal;
-  if (mode == switches::kMemlogModeBrowser)
+  if (mode == heap_profiling::kMemlogModeBrowser)
     return Mode::kBrowser;
-  if (mode == switches::kMemlogModeGpu)
+  if (mode == heap_profiling::kMemlogModeGpu)
     return Mode::kGpu;
-  if (mode == switches::kMemlogModeRendererSampling)
+  if (mode == heap_profiling::kMemlogModeRendererSampling)
     return Mode::kRendererSampling;
   DLOG(ERROR) << "Unsupported value: \"" << mode << "\" passed to --"
-              << switches::kMemlog;
+              << heap_profiling::kMemlog;
   return Mode::kNone;
 }
 
@@ -332,8 +333,8 @@
   std::string stack_mode;
 
   // Respect the commandline switch above the field trial.
-  if (cmdline->HasSwitch(switches::kMemlogStackMode)) {
-    stack_mode = cmdline->GetSwitchValueASCII(switches::kMemlogStackMode);
+  if (cmdline->HasSwitch(heap_profiling::kMemlogStackMode)) {
+    stack_mode = cmdline->GetSwitchValueASCII(heap_profiling::kMemlogStackMode);
   } else {
     stack_mode = base::GetFieldTrialParamValueByFeature(
         kOOPHeapProfilingFeature, kOOPHeapProfilingFeatureStackMode);
@@ -345,23 +346,23 @@
 // static
 mojom::StackMode ProfilingProcessHost::ConvertStringToStackMode(
     const std::string& input) {
-  if (input == switches::kMemlogStackModeNative)
+  if (input == heap_profiling::kMemlogStackModeNative)
     return profiling::mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES;
-  if (input == switches::kMemlogStackModeNativeWithThreadNames)
+  if (input == heap_profiling::kMemlogStackModeNativeWithThreadNames)
     return profiling::mojom::StackMode::NATIVE_WITH_THREAD_NAMES;
-  if (input == switches::kMemlogStackModePseudo)
+  if (input == heap_profiling::kMemlogStackModePseudo)
     return profiling::mojom::StackMode::PSEUDO;
-  if (input == switches::kMemlogStackModeMixed)
+  if (input == heap_profiling::kMemlogStackModeMixed)
     return profiling::mojom::StackMode::MIXED;
   DLOG(ERROR) << "Unsupported value: \"" << input << "\" passed to --"
-              << switches::kMemlogStackMode;
+              << heap_profiling::kMemlogStackMode;
   return profiling::mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES;
 }
 
 // static
 bool ProfilingProcessHost::GetShouldSampleForStartup() {
   const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-  if (cmdline->HasSwitch(switches::kMemlogSampling))
+  if (cmdline->HasSwitch(heap_profiling::kMemlogSampling))
     return true;
 
   return base::GetFieldTrialParamByFeatureAsBool(
@@ -372,9 +373,9 @@
 // static
 uint32_t ProfilingProcessHost::GetSamplingRateForStartup() {
   const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-  if (cmdline->HasSwitch(switches::kMemlogSamplingRate)) {
+  if (cmdline->HasSwitch(heap_profiling::kMemlogSamplingRate)) {
     std::string rate_as_string =
-        cmdline->GetSwitchValueASCII(switches::kMemlogSamplingRate);
+        cmdline->GetSwitchValueASCII(heap_profiling::kMemlogSamplingRate);
     int rate_as_int = 1;
     if (!base::StringToInt(rate_as_string, &rate_as_int)) {
       LOG(ERROR) << "Could not parse sampling rate: " << rate_as_string;
@@ -690,7 +691,7 @@
   // Set some state for heap dumps.
   bool keep_small_allocations =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kMemlogKeepSmallAllocations);
+          heap_profiling::kMemlogKeepSmallAllocations);
   SetKeepSmallAllocations(keep_small_allocations);
 
   // Grab a HeapProfiler InterfacePtr and pass that to memory instrumentation.
diff --git a/chrome/browser/profiling_host/profiling_process_host_unittest.cc b/chrome/browser/profiling_host/profiling_process_host_unittest.cc
index cb35ae3..1345627 100644
--- a/chrome/browser/profiling_host/profiling_process_host_unittest.cc
+++ b/chrome/browser/profiling_host/profiling_process_host_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/services/heap_profiling/public/cpp/switches.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -44,16 +45,8 @@
 TEST(ProfilingProcessHost, GetModeForStartup_Commandline) {
   {
     base::test::ScopedCommandLine scoped_command_line;
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kMemlog,
-                                                              "");
-    EXPECT_EQ(ProfilingProcessHost::Mode::kNone,
-              ProfilingProcessHost::GetModeForStartup());
-  }
-
-  {
-    base::test::ScopedCommandLine scoped_command_line;
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kMemlog,
-                                                              "invalid");
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        heap_profiling::kMemlog, "");
     EXPECT_EQ(ProfilingProcessHost::Mode::kNone,
               ProfilingProcessHost::GetModeForStartup());
   }
@@ -61,7 +54,15 @@
   {
     base::test::ScopedCommandLine scoped_command_line;
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kMemlog, switches::kMemlogModeAll);
+        heap_profiling::kMemlog, "invalid");
+    EXPECT_EQ(ProfilingProcessHost::Mode::kNone,
+              ProfilingProcessHost::GetModeForStartup());
+  }
+
+  {
+    base::test::ScopedCommandLine scoped_command_line;
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        heap_profiling::kMemlog, heap_profiling::kMemlogModeAll);
     EXPECT_EQ(ProfilingProcessHost::Mode::kAll,
               ProfilingProcessHost::GetModeForStartup());
   }
@@ -69,7 +70,7 @@
   {
     base::test::ScopedCommandLine scoped_command_line;
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kMemlog, switches::kMemlogModeBrowser);
+        heap_profiling::kMemlog, heap_profiling::kMemlogModeBrowser);
     EXPECT_EQ(ProfilingProcessHost::Mode::kBrowser,
               ProfilingProcessHost::GetModeForStartup());
   }
@@ -77,7 +78,7 @@
   {
     base::test::ScopedCommandLine scoped_command_line;
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kMemlog, switches::kMemlogModeMinimal);
+        heap_profiling::kMemlog, heap_profiling::kMemlogModeMinimal);
     EXPECT_EQ(ProfilingProcessHost::Mode::kMinimal,
               ProfilingProcessHost::GetModeForStartup());
   }
@@ -85,7 +86,7 @@
   {
     base::test::ScopedCommandLine scoped_command_line;
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kMemlog, switches::kMemlogModeGpu);
+        heap_profiling::kMemlog, heap_profiling::kMemlogModeGpu);
     EXPECT_EQ(ProfilingProcessHost::Mode::kGpu,
               ProfilingProcessHost::GetModeForStartup());
   }
@@ -93,7 +94,7 @@
   {
     base::test::ScopedCommandLine scoped_command_line;
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kMemlog, switches::kMemlogModeRendererSampling);
+        heap_profiling::kMemlog, heap_profiling::kMemlogModeRendererSampling);
     EXPECT_EQ(ProfilingProcessHost::Mode::kRendererSampling,
               ProfilingProcessHost::GetModeForStartup());
   }
@@ -126,7 +127,7 @@
   {
     base::test::ScopedFeatureList scoped_feature_list;
     parameters[profiling::kOOPHeapProfilingFeatureMode] =
-        switches::kMemlogModeAll;
+        heap_profiling::kMemlogModeAll;
     scoped_feature_list.InitAndEnableFeatureWithParameters(
         profiling::kOOPHeapProfilingFeature, parameters);
     EXPECT_EQ(ProfilingProcessHost::Mode::kAll,
@@ -136,7 +137,7 @@
   {
     base::test::ScopedFeatureList scoped_feature_list;
     parameters[profiling::kOOPHeapProfilingFeatureMode] =
-        switches::kMemlogModeBrowser;
+        heap_profiling::kMemlogModeBrowser;
     scoped_feature_list.InitAndEnableFeatureWithParameters(
         profiling::kOOPHeapProfilingFeature, parameters);
     EXPECT_EQ(ProfilingProcessHost::Mode::kBrowser,
@@ -146,7 +147,7 @@
   {
     base::test::ScopedFeatureList scoped_feature_list;
     parameters[profiling::kOOPHeapProfilingFeatureMode] =
-        switches::kMemlogModeMinimal;
+        heap_profiling::kMemlogModeMinimal;
     scoped_feature_list.InitAndEnableFeatureWithParameters(
         profiling::kOOPHeapProfilingFeature, parameters);
     EXPECT_EQ(ProfilingProcessHost::Mode::kMinimal,
@@ -156,7 +157,7 @@
   {
     base::test::ScopedFeatureList scoped_feature_list;
     parameters[profiling::kOOPHeapProfilingFeatureMode] =
-        switches::kMemlogModeGpu;
+        heap_profiling::kMemlogModeGpu;
     scoped_feature_list.InitAndEnableFeatureWithParameters(
         profiling::kOOPHeapProfilingFeature, parameters);
     EXPECT_EQ(ProfilingProcessHost::Mode::kGpu,
@@ -166,7 +167,7 @@
   {
     base::test::ScopedFeatureList scoped_feature_list;
     parameters[profiling::kOOPHeapProfilingFeatureMode] =
-        switches::kMemlogModeRendererSampling;
+        heap_profiling::kMemlogModeRendererSampling;
     scoped_feature_list.InitAndEnableFeatureWithParameters(
         profiling::kOOPHeapProfilingFeature, parameters);
     EXPECT_EQ(ProfilingProcessHost::Mode::kRendererSampling,
@@ -178,12 +179,12 @@
 TEST(ProfilingProcessHost, GetModeForStartup_CommandLinePrecedence) {
   base::test::ScopedCommandLine scoped_command_line;
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kMemlog, switches::kMemlogModeAll);
+      heap_profiling::kMemlog, heap_profiling::kMemlogModeAll);
 
   base::test::ScopedFeatureList scoped_feature_list;
   std::map<std::string, std::string> parameters;
   parameters[profiling::kOOPHeapProfilingFeatureMode] =
-      switches::kMemlogModeMinimal;
+      heap_profiling::kMemlogModeMinimal;
   scoped_feature_list.InitAndEnableFeatureWithParameters(
       profiling::kOOPHeapProfilingFeature, parameters);
 
@@ -197,7 +198,7 @@
   {
     base::test::ScopedCommandLine scoped_command_line;
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kMemlog, switches::kMemlogModeAll);
+        heap_profiling::kMemlog, heap_profiling::kMemlogModeAll);
     EXPECT_EQ(ProfilingProcessHost::Mode::kNone,
               ProfilingProcessHost::GetModeForStartup());
   }
@@ -206,7 +207,7 @@
     base::test::ScopedFeatureList scoped_feature_list;
     std::map<std::string, std::string> parameters;
     parameters[profiling::kOOPHeapProfilingFeatureMode] =
-        switches::kMemlogModeMinimal;
+        heap_profiling::kMemlogModeMinimal;
     scoped_feature_list.InitAndEnableFeatureWithParameters(
         profiling::kOOPHeapProfilingFeature, parameters);
     EXPECT_EQ(ProfilingProcessHost::Mode::kNone,
diff --git a/chrome/browser/service_process/service_process_control.cc b/chrome/browser/service_process/service_process_control.cc
index 00e3d77f..3d36ce7 100644
--- a/chrome/browser/service_process/service_process_control.cc
+++ b/chrome/browser/service_process/service_process_control.cc
@@ -159,7 +159,7 @@
 void ServiceProcessControl::RunAllTasksHelper(TaskList* task_list) {
   TaskList::iterator index = task_list->begin();
   while (index != task_list->end()) {
-    (*index).Run();
+    std::move(*index).Run();
     index = task_list->erase(index);
   }
 }
@@ -168,16 +168,15 @@
   return !!service_process_;
 }
 
-void ServiceProcessControl::Launch(const base::Closure& success_task,
-                                   const base::Closure& failure_task) {
+void ServiceProcessControl::Launch(base::OnceClosure success_task,
+                                   base::OnceClosure failure_task) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  base::Closure failure = failure_task;
-  if (!success_task.is_null())
-    connect_success_tasks_.push_back(success_task);
+  if (success_task)
+    connect_success_tasks_.emplace_back(std::move(success_task));
 
-  if (!failure.is_null())
-    connect_failure_tasks_.push_back(failure);
+  if (failure_task)
+    connect_failure_tasks_.emplace_back(std::move(failure_task));
 
   // If we already in the process of launching, then we are done.
   if (launcher_.get())
diff --git a/chrome/browser/service_process/service_process_control.h b/chrome/browser/service_process/service_process_control.h
index 2fe97bba..8bad1b45 100644
--- a/chrome/browser/service_process/service_process_control.h
+++ b/chrome/browser/service_process/service_process_control.h
@@ -87,8 +87,8 @@
   // Note that if we are already connected to service process then
   // |success_task| can be invoked in the context of the Launch call.
   // Virtual for testing.
-  virtual void Launch(const base::Closure& success_task,
-                      const base::Closure& failure_task);
+  virtual void Launch(base::OnceClosure success_task,
+                      base::OnceClosure failure_task);
 
   // Disconnect the IPC channel from the service process.
   // Virtual for testing.
@@ -155,7 +155,7 @@
 
   friend struct base::DefaultSingletonTraits<ServiceProcessControl>;
 
-  typedef std::vector<base::Closure> TaskList;
+  using TaskList = std::vector<base::OnceClosure>;
 
   void OnChannelConnected();
   void OnChannelError();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 4b92eba..814a0a53 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2865,8 +2865,6 @@
       "views/harmony/harmony_layout_provider.h",
       "views/harmony/harmony_typography_provider.cc",
       "views/harmony/harmony_typography_provider.h",
-      "views/harmony/material_refresh_layout_provider.cc",
-      "views/harmony/material_refresh_layout_provider.h",
       "views/harmony/textfield_layout.cc",
       "views/harmony/textfield_layout.h",
       "views/hover_button.cc",
diff --git a/chrome/browser/ui/app_list/crostini/crostini_util.cc b/chrome/browser/ui/app_list/crostini/crostini_util.cc
index aa09b96..67a6f22 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_util.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_util.cc
@@ -40,5 +40,5 @@
 
 bool IsCrostiniAppId(const std::string& app_id) {
   return strncmp(app_id.c_str(), kCrostiniAppIdPrefix,
-                 sizeof(kCrostiniAppIdPrefix)) == 0;
+                 sizeof(kCrostiniAppIdPrefix) - 1) == 0;
 }
diff --git a/chrome/browser/ui/app_list/search/arc_app_result.cc b/chrome/browser/ui/app_list/search/arc_app_result.cc
index 443c999..8c718e7 100644
--- a/chrome/browser/ui/app_list/search/arc_app_result.cc
+++ b/chrome/browser/ui/app_list/search/arc_app_result.cc
@@ -26,8 +26,8 @@
   std::string id = kArcAppPrefix;
   id += app_id;
   set_id(id);
-  icon_loader_.reset(
-      new ArcAppIconLoader(profile, GetPreferredIconDimension(this), this));
+  icon_loader_.reset(new ArcAppIconLoader(
+      profile, GetPreferredIconDimension(display_type()), this));
   icon_loader_->FetchImage(app_id);
 }
 
diff --git a/chrome/browser/ui/app_list/search/extension_app_result.cc b/chrome/browser/ui/app_list/search/extension_app_result.cc
index c662925..53c057a 100644
--- a/chrome/browser/ui/app_list/search/extension_app_result.cc
+++ b/chrome/browser/ui/app_list/search/extension_app_result.cc
@@ -41,7 +41,7 @@
 
   is_platform_app_ = extension->is_platform_app();
   icon_ = extensions::ChromeAppIconService::Get(profile)->CreateIcon(
-      this, app_id, GetPreferredIconDimension(this));
+      this, app_id, GetPreferredIconDimension(display_type()));
 
   StartObservingExtensionRegistry();
 }
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.cc b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.cc
index eb1815a..14edcc5 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.cc
+++ b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.cc
@@ -40,7 +40,7 @@
             chromeos::launcher_search_provider::kMaxSearchResultScore);
 
   icon_image_loader_.reset(new LauncherSearchIconImageLoaderImpl(
-      icon_url, profile, extension, GetPreferredIconDimension(this),
+      icon_url, profile, extension, GetPreferredIconDimension(display_type()),
       std::move(error_reporter)));
   icon_image_loader_->LoadResources();
 
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc
index a39e073..36710d3 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -87,7 +87,7 @@
     case AutocompleteMatchType::CLIPBOARD:
     case AutocompleteMatchType::PHYSICAL_WEB:
     case AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW:
-    case AutocompleteMatchType::TAB_SEARCH:
+    case AutocompleteMatchType::TAB_SEARCH_DEPRECATED:
       return kIcDomainIcon;
 
     case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED:
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_result.cc b/chrome/browser/ui/app_list/search/webstore/webstore_result.cc
index c78f333b..d48253db 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_result.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_result.cc
@@ -58,7 +58,7 @@
   InitAndStartObserving();
   UpdateActions();
 
-  int icon_dimension = GetPreferredIconDimension(this);
+  int icon_dimension = GetPreferredIconDimension(display_type());
   icon_ = gfx::ImageSkia(
       std::make_unique<UrlIconSource>(
           base::Bind(&WebstoreResult::OnIconLoaded, weak_factory_.GetWeakPtr()),
diff --git a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
index df2ec31..9161999 100644
--- a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
+++ b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
@@ -83,7 +83,7 @@
 
   // Skip handling ARC++ windows.
   if (strncmp(window_app_id->c_str(), kArcAppIdPrefix,
-              sizeof(kArcAppIdPrefix)) == 0)
+              sizeof(kArcAppIdPrefix) - 1) == 0)
     return;
 
   // Skip when this window has been handled. This can happen when the window
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
index e300a5d..c7c12aa 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
@@ -29,9 +29,8 @@
 
 namespace {
 
-const SkColor kButtonHoverColor = SkColorSetARGB(20, 0, 0, 0);
-const SkColor kButtonPressedColor = SkColorSetARGB(31, 0, 0, 0);
-const SkColor kAvatarIconColor = SkColorSetRGB(0x5a, 0x5a, 0x5a);
+constexpr SkColor kButtonHoverColor = SkColorSetARGB(20, 0, 0, 0);
+constexpr SkColor kButtonPressedColor = SkColorSetARGB(31, 0, 0, 0);
 
 const CGFloat kButtonHeight = 24;
 
@@ -246,8 +245,8 @@
       base::mac::ObjCCastStrict<AvatarButton>(button_);
 
   if (useGenericButton) {
-    NSImage* avatarIcon = NSImageFromImageSkia(
-        gfx::CreateVectorIcon(kUserAccountAvatarIcon, 18, kAvatarIconColor));
+    NSImage* avatarIcon = NSImageFromImageSkia(gfx::CreateVectorIcon(
+        kUserAccountAvatarIcon, 18, gfx::kChromeIconGrey));
     [button setDefaultImage:avatarIcon];
     [button setHoverImage:nil];
     [button setPressedImage:nil];
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
index f470583..5be5f6c 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
@@ -15,6 +15,7 @@
 #import "ui/base/cocoa/nsview_additions.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/theme_provider.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image_skia_util_mac.h"
 #include "ui/gfx/paint_vector_icon.h"
 
@@ -232,7 +233,7 @@
   return themeIsDark ? SK_ColorWHITE
                      : (provider && provider->ShouldIncreaseContrast()
                             ? SK_ColorBLACK
-                            : SkColorSetRGB(0x5A, 0x5A, 0x5A));
+                            : gfx::kChromeIconGrey);
 }
 
 - (NSImage*)browserToolsIconForFillColor:(SkColor)fillColor {
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index 0cf6e06..df801d8 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -7,6 +7,7 @@
 #include <dwmapi.h>
 #include <utility>
 
+#include "base/trace_event/common/trace_event_common.h"
 #include "base/win/windows_version.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/chrome_dll_resource.h"
@@ -419,6 +420,7 @@
 // GlassBrowserFrameView, views::View overrides:
 
 void GlassBrowserFrameView::OnPaint(gfx::Canvas* canvas) {
+  TRACE_EVENT0("views.frame", "GlassBrowserFrameView::OnPaint");
   if (ShouldCustomDrawSystemTitlebar())
     PaintTitlebar(canvas);
   if (!browser_view()->IsTabStripVisible())
@@ -430,6 +432,7 @@
 }
 
 void GlassBrowserFrameView::Layout() {
+  TRACE_EVENT0("views.frame", "GlassBrowserFrameView::Layout");
   if (ShouldCustomDrawSystemTitlebar()) {
     // The profile switcher button depends on the caption button layout, so this
     // must be called prior to LayoutProfileSwitcher().
@@ -606,6 +609,7 @@
 }
 
 void GlassBrowserFrameView::PaintTitlebar(gfx::Canvas* canvas) const {
+  TRACE_EVENT0("views.frame", "GlassBrowserFrameView::PaintTitlebar");
   gfx::Rect tabstrip_bounds = GetBoundsForTabStrip(browser_view()->tabstrip());
 
   cc::PaintFlags flags;
@@ -784,6 +788,7 @@
 }
 
 void GlassBrowserFrameView::LayoutTitleBar() {
+  TRACE_EVENT0("views.frame", "GlassBrowserFrameView::LayoutTitleBar");
   if (!ShowCustomIcon() && !ShowCustomTitle())
     return;
 
@@ -819,12 +824,14 @@
 
 void GlassBrowserFrameView::LayoutCaptionButton(Windows10CaptionButton* button,
                                                 int previous_button_x) {
+  TRACE_EVENT0("views.frame", "GlassBrowserFrameView::LayoutCaptionButton");
   gfx::Size button_size = button->GetPreferredSize();
   button->SetBounds(previous_button_x - button_size.width(), WindowTopY(),
                     button_size.width(), button_size.height());
 }
 
 void GlassBrowserFrameView::LayoutCaptionButtons() {
+  TRACE_EVENT0("views.frame", "GlassBrowserFrameView::LayoutCaptionButtons");
   LayoutCaptionButton(close_button_, width());
 
   LayoutCaptionButton(restore_button_, close_button_->x());
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index 1f956b6..a3f0710e7 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -455,6 +455,7 @@
 
 // views::View:
 void OpaqueBrowserFrameView::OnPaint(gfx::Canvas* canvas) {
+  TRACE_EVENT0("views.frame", "OpaqueBrowserFrameView::OnPaint");
   if (frame()->IsFullscreen())
     return;  // Nothing is visible, so don't bother to paint.
 
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
index 1fcb8a5..cf7231c 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -642,6 +642,7 @@
 // OpaqueBrowserFrameViewLayout, views::LayoutManager:
 
 void OpaqueBrowserFrameViewLayout::Layout(views::View* host) {
+  TRACE_EVENT0("views.frame", "OpaqueBrowserFrameViewLayout::Layout");
   // Reset all our data so that everything is invisible.
   int top_area_padding = TopAreaPadding();
   leading_button_start_ = top_area_padding;
diff --git a/chrome/browser/ui/views/harmony/chrome_layout_provider.cc b/chrome/browser/ui/views/harmony/chrome_layout_provider.cc
index 3dba5720..acbf8b2 100644
--- a/chrome/browser/ui/views/harmony/chrome_layout_provider.cc
+++ b/chrome/browser/ui/views/harmony/chrome_layout_provider.cc
@@ -9,7 +9,6 @@
 #include "base/logging.h"
 #include "chrome/browser/ui/views/harmony/chrome_typography.h"
 #include "chrome/browser/ui/views/harmony/harmony_layout_provider.h"
-#include "chrome/browser/ui/views/harmony/material_refresh_layout_provider.h"
 #include "ui/base/material_design/material_design_controller.h"
 
 namespace {
@@ -38,9 +37,6 @@
 // static
 std::unique_ptr<views::LayoutProvider>
 ChromeLayoutProvider::CreateLayoutProvider() {
-  if (ui::MaterialDesignController::GetMode() ==
-      ui::MaterialDesignController::MATERIAL_REFRESH)
-    return std::make_unique<MaterialRefreshLayoutProvider>();
   return ui::MaterialDesignController::IsSecondaryUiMaterial()
              ? std::make_unique<HarmonyLayoutProvider>()
              : std::make_unique<ChromeLayoutProvider>();
diff --git a/chrome/browser/ui/views/harmony/material_refresh_layout_provider.cc b/chrome/browser/ui/views/harmony/material_refresh_layout_provider.cc
deleted file mode 100644
index 77d5d78..0000000
--- a/chrome/browser/ui/views/harmony/material_refresh_layout_provider.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/views/harmony/material_refresh_layout_provider.h"
-
-int MaterialRefreshLayoutProvider::GetCornerRadiusMetric(
-    ChromeEmphasisMetric emphasis_metric,
-    const gfx::Rect& bounds) const {
-  switch (emphasis_metric) {
-    case EMPHASIS_LOW:
-      return 4;
-    case EMPHASIS_MEDIUM:
-      return 8;
-    case EMPHASIS_HIGH:
-      return std::min(bounds.width(), bounds.height()) / 2;
-    default:
-      NOTREACHED();
-      return 0;
-  }
-}
diff --git a/chrome/browser/ui/views/harmony/material_refresh_layout_provider.h b/chrome/browser/ui/views/harmony/material_refresh_layout_provider.h
deleted file mode 100644
index 47ef6cf..0000000
--- a/chrome/browser/ui/views/harmony/material_refresh_layout_provider.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2018 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_UI_VIEWS_HARMONY_MATERIAL_REFRESH_LAYOUT_PROVIDER_H_
-#define CHROME_BROWSER_UI_VIEWS_HARMONY_MATERIAL_REFRESH_LAYOUT_PROVIDER_H_
-
-#include "base/macros.h"
-#include "chrome/browser/ui/views/harmony/harmony_layout_provider.h"
-
-class MaterialRefreshLayoutProvider : public HarmonyLayoutProvider {
- public:
-  MaterialRefreshLayoutProvider() = default;
-  ~MaterialRefreshLayoutProvider() override = default;
-
-  int GetCornerRadiusMetric(
-      ChromeEmphasisMetric emphasis_metric,
-      const gfx::Rect& bounds = gfx::Rect()) const override;
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_HARMONY_MATERIAL_REFRESH_LAYOUT_PROVIDER_H_
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index a06796a..072349c 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -243,8 +243,7 @@
   keyword_view_->icon()->SetVisible(match_.associated_keyword.get());
 
   if (OmniboxFieldTrial::InTabSwitchSuggestionWithButtonTrial() &&
-      match.type == AutocompleteMatchType::TAB_SEARCH &&
-      !keyword_view_->icon()->visible()) {
+      match.has_tab_match && !keyword_view_->icon()->visible()) {
     suggestion_tab_switch_button_ =
         std::make_unique<OmniboxTabSwitchButton>(this, GetTextHeight());
     suggestion_tab_switch_button_->set_owned_by_client();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
index 45867e9..119ed41e 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -121,8 +121,7 @@
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, MaintainCursorAfterFocusCycle);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, OnBlur);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, DoNotNavigateOnDrop);
-  FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsSteadyStateElisionsTest,
-                           UnelideOnArrowKey);
+  friend class OmniboxViewViewsSteadyStateElisionsTest;
 
   // Update the field with |text| and set the selection.
   void SetTextAndSelectedRange(const base::string16& text,
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index 1e3ee02c..ac8c54a6 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -184,8 +184,8 @@
   OmniboxViewViewsTest();
 
   TestToolbarModel* toolbar_model() { return &toolbar_model_; }
-  TestingOmniboxView* omnibox_view() { return omnibox_view_.get(); }
-  views::Textfield* omnibox_textfield() { return omnibox_view(); }
+  TestingOmniboxView* omnibox_view() const { return omnibox_view_.get(); }
+  views::Textfield* omnibox_textfield() const { return omnibox_view(); }
   ui::TextEditCommand scheduled_text_edit_command() const {
     return test_api_->scheduled_text_edit_command();
   }
@@ -436,6 +436,17 @@
     ExpectElidedUrlDisplayed();
   }
 
+  bool IsSelectAll() const { return omnibox_view()->IsSelectAll(); }
+
+  void FocusAndSelectAll() {
+    omnibox_textfield()->OnFocus();
+    EXPECT_EQ(OMNIBOX_FOCUS_VISIBLE, omnibox_view()->model()->focus_state());
+
+    omnibox_view()->SelectAll(true);
+    EXPECT_TRUE(omnibox_view()->IsSelectAll());
+    ExpectElidedUrlDisplayed();
+  }
+
   void ExpectFullUrlDisplayed() {
     EXPECT_EQ(base::ASCIIToUTF16("https://example.com"),
               omnibox_view()->text());
@@ -463,12 +474,7 @@
 }
 
 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UnelideOnArrowKey) {
-  omnibox_textfield()->OnFocus();
-  EXPECT_EQ(OMNIBOX_FOCUS_VISIBLE, omnibox_view()->model()->focus_state());
-
-  omnibox_view()->SelectAll(true);
-  EXPECT_TRUE(omnibox_view()->IsSelectAll());
-  ExpectElidedUrlDisplayed();
+  FocusAndSelectAll();
 
   // Right key should unelide and move the cursor to the end.
   omnibox_textfield_view()->OnKeyPressed(
@@ -481,9 +487,7 @@
 
   // Blur and restore the elided URL.
   omnibox_textfield()->OnBlur();
-  omnibox_textfield()->OnFocus();
-  omnibox_view()->SelectAll(true);
-  ExpectElidedUrlDisplayed();
+  FocusAndSelectAll();
 
   // Left key should unelide and move the cursor to the beginning of the elided
   // part.
@@ -494,3 +498,36 @@
   EXPECT_EQ(8U, start);
   EXPECT_EQ(8U, end);
 }
+
+TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UnelideOnHomeKey) {
+  FocusAndSelectAll();
+
+  // Home key should unelide and move the cursor to the beginning of the full
+  // unelided URL.
+  omnibox_textfield_view()->OnKeyPressed(
+      ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_HOME, 0));
+  ExpectFullUrlDisplayed();
+  size_t start, end;
+  omnibox_view()->GetSelectionBounds(&start, &end);
+  EXPECT_EQ(0U, start);
+  EXPECT_EQ(0U, end);
+}
+
+TEST_F(OmniboxViewViewsSteadyStateElisionsTest, GestureTaps) {
+  ui::GestureEvent tap_down(0, 0, 0, ui::EventTimeForNow(),
+                            ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
+  omnibox_textfield_view()->OnGestureEvent(&tap_down);
+
+  // Select all on first tap.
+  ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP);
+  tap_details.set_tap_count(1);
+  ui::GestureEvent tap(0, 0, 0, ui::EventTimeForNow(), tap_details);
+  omnibox_textfield_view()->OnGestureEvent(&tap);
+
+  EXPECT_TRUE(IsSelectAll());
+  ExpectElidedUrlDisplayed();
+
+  // Unelide on second tap (cursor placement).
+  omnibox_textfield_view()->OnGestureEvent(&tap);
+  ExpectFullUrlDisplayed();
+}
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
index b8f959a..366be32 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -170,9 +170,8 @@
 
 std::unique_ptr<views::View>
 PaymentHandlerWebFlowViewController::CreateHeaderContentView() {
-  const GURL origin = web_contents()
-                          ? web_contents()->GetLastCommittedURL().GetOrigin()
-                          : GURL();
+  const GURL origin =
+      web_contents() ? web_contents()->GetVisibleURL().GetOrigin() : GURL();
   std::unique_ptr<views::Background> background = GetHeaderBackground();
   return std::make_unique<ReadOnlyOriginView>(GetSheetTitle(), origin,
                                               background->get_color(), this);
@@ -215,4 +214,12 @@
   UpdateHeaderView();
 }
 
+void PaymentHandlerWebFlowViewController::DidAttachInterstitialPage() {
+  UpdateHeaderView();
+}
+
+void PaymentHandlerWebFlowViewController::DidDetachInterstitialPage() {
+  UpdateHeaderView();
+}
+
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h
index 15b4b8a..fd4beb4 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h
@@ -51,6 +51,8 @@
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
   void TitleWasSet(content::NavigationEntry* entry) override;
+  void DidAttachInterstitialPage() override;
+  void DidDetachInterstitialPage() override;
 
   Profile* profile_;
   GURL target_;
diff --git a/chrome/browser/ui/views/profiles/avatar_button.cc b/chrome/browser/ui/views/profiles/avatar_button.cc
index e3cdcc8e1..7c01bbd0a 100644
--- a/chrome/browser/ui/views/profiles/avatar_button.cc
+++ b/chrome/browser/ui/views/profiles/avatar_button.cc
@@ -244,7 +244,7 @@
     SetBorder(nullptr);
     generic_avatar_ =
         gfx::CreateVectorIcon(kProfileSwitcherOutlineIcon,
-                              kGenericAvatarIconSize, gfx::kPlaceholderColor);
+                              kGenericAvatarIconSize, gfx::kChromeIconGrey);
 #endif
   } else if (apply_ink_drop) {
     SetInkDropMode(InkDropMode::ON);
@@ -254,7 +254,7 @@
     SetBorder(std::make_unique<AvatarButtonThemedBorder>());
     generic_avatar_ =
         gfx::CreateVectorIcon(kProfileSwitcherOutlineIcon,
-                              kGenericAvatarIconSize, gfx::kPlaceholderColor);
+                              kGenericAvatarIconSize, gfx::kChromeIconGrey);
 #elif defined(OS_WIN)
     DCHECK_EQ(AvatarButtonStyle::NATIVE, button_style);
     SetBorder(views::CreateEmptyBorder(kBorderInsets));
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 68dd931..919215d 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -1222,7 +1222,13 @@
   const SkColor title_color = theme_provider->GetColor(IsActive() ?
       ThemeProperties::COLOR_TAB_TEXT :
       ThemeProperties::COLOR_BACKGROUND_TAB_TEXT);
-  const SkColor new_button_color = SkColorSetA(title_color, 0xA0);
+
+  SkColor new_button_color = title_color;
+  if (IsActive()) {
+    // This alpha value (0x2f) blends GoogleGrey800 close to GoogleGrey700.
+    new_button_color = color_utils::BlendTowardOppositeLuma(title_color, 0x2f);
+  }
+
   if (button_color_ != new_button_color) {
     button_color_ = new_button_color;
     title_->SetEnabledColor(title_color);
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 4f0796d3..85316f39 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -264,7 +264,7 @@
       VR_BIND(AutocompleteMatch::Type, SuggestionBinding, element_binding,
               model->model()->type, VectorIcon, p_icon,
               view->SetIcon(AutocompleteMatch::TypeToVectorIcon(
-                  value, /*is_bookmark=*/false))));
+                  value, /*is_bookmark=*/false, /*is_tab_match=*/false))));
   element_binding->set_view(background.get());
   scene->AddUiElement(kOmniboxSuggestions, std::move(background));
 }
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 69644d62..6ce81b9 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -454,24 +454,6 @@
 // Forces the maximum disk space to be used by the media cache, in bytes.
 const char kMediaCacheSize[]                = "media-cache-size";
 
-// Enables the out-of-process memory logging.
-const char kMemlog[] = "memlog";
-const char kMemlogKeepSmallAllocations[] = "memlog-keep-small-allocations";
-const char kMemlogModeAll[] = "all";
-const char kMemlogModeAllRenderers[] = "all-renderers";
-const char kMemlogModeBrowser[] = "browser";
-const char kMemlogModeGpu[] = "gpu";
-const char kMemlogModeManual[] = "manual";
-const char kMemlogModeMinimal[] = "minimal";
-const char kMemlogModeRendererSampling[] = "renderer-sampling";
-const char kMemlogSampling[] = "memlog-sampling";
-const char kMemlogSamplingRate[] = "memlog-sampling-rate";
-const char kMemlogStackMode[] = "memlog-stack-mode";
-const char kMemlogStackModeMixed[] = "mixed";
-const char kMemlogStackModeNative[] = "native";
-const char kMemlogStackModeNativeWithThreadNames[] = "native-with-thread-names";
-const char kMemlogStackModePseudo[] = "pseudo";
-
 // Allows setting a different destination ID for connection-monitoring GCM
 // messages. Useful when running against a non-prod management server.
 const char kMonitoringDestinationID[]       = "monitoring-destination-id";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 38d6f284..c5254cc 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -140,22 +140,6 @@
 extern const char kLoadMediaRouterComponentExtension[];
 extern const char kMakeDefaultBrowser[];
 extern const char kMediaCacheSize[];
-extern const char kMemlog[];
-extern const char kMemlogKeepSmallAllocations[];
-extern const char kMemlogModeAll[];
-extern const char kMemlogModeAllRenderers[];
-extern const char kMemlogModeBrowser[];
-extern const char kMemlogModeGpu[];
-extern const char kMemlogModeManual[];
-extern const char kMemlogModeMinimal[];
-extern const char kMemlogModeRendererSampling[];
-extern const char kMemlogSampling[];
-extern const char kMemlogSamplingRate[];
-extern const char kMemlogStackMode[];
-extern const char kMemlogStackModeMixed[];
-extern const char kMemlogStackModeNative[];
-extern const char kMemlogStackModeNativeWithThreadNames[];
-extern const char kMemlogStackModePseudo[];
 extern const char kMonitoringDestinationID[];
 extern const char kNetLogCaptureMode[];
 extern const char kNoDefaultBrowserCheck[];
diff --git a/chrome/service/cloud_print/cloud_print_message_handler.cc b/chrome/service/cloud_print/cloud_print_message_handler.cc
index 25d402e..c1c6977 100644
--- a/chrome/service/cloud_print/cloud_print_message_handler.cc
+++ b/chrome/service/cloud_print/cloud_print_message_handler.cc
@@ -33,11 +33,8 @@
     const std::string& robot_email,
     const std::string& user_email,
     base::Value user_settings) {
-  std::unique_ptr<base::DictionaryValue> user_settings_dict =
-      base::DictionaryValue::From(
-          base::Value::ToUniquePtrValue(std::move(user_settings)));
   proxy_provider_->GetCloudPrintProxy()->EnableForUserWithRobot(
-      robot_auth_code, robot_email, user_email, *user_settings_dict);
+      robot_auth_code, robot_email, user_email, std::move(user_settings));
 }
 
 void CloudPrintMessageHandler::GetCloudPrintProxyInfo(
diff --git a/chrome/service/cloud_print/cloud_print_proxy.cc b/chrome/service/cloud_print/cloud_print_proxy.cc
index 4a2edec1..8d9db0c 100644
--- a/chrome/service/cloud_print/cloud_print_proxy.cc
+++ b/chrome/service/cloud_print/cloud_print_proxy.cc
@@ -73,11 +73,10 @@
   }
 }
 
-void CloudPrintProxy::EnableForUserWithRobot(
-    const std::string& robot_auth_code,
-    const std::string& robot_email,
-    const std::string& user_email,
-    const base::DictionaryValue& user_settings) {
+void CloudPrintProxy::EnableForUserWithRobot(const std::string& robot_auth_code,
+                                             const std::string& robot_email,
+                                             const std::string& user_email,
+                                             base::Value user_settings) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   ShutdownBackend();
diff --git a/chrome/service/cloud_print/cloud_print_proxy.h b/chrome/service/cloud_print/cloud_print_proxy.h
index da9395f..00ef6f3 100644
--- a/chrome/service/cloud_print/cloud_print_proxy.h
+++ b/chrome/service/cloud_print/cloud_print_proxy.h
@@ -12,6 +12,7 @@
 
 #include "base/macros.h"
 #include "base/sequence_checker.h"
+#include "base/values.h"
 #include "chrome/service/cloud_print/cloud_print_proxy_backend.h"
 #include "chrome/service/cloud_print/cloud_print_wipeout.h"
 
@@ -47,11 +48,10 @@
 
   // Enables/disables cloud printing for the user
   void EnableForUser();
-  void EnableForUserWithRobot(
-      const std::string& robot_auth_code,
-      const std::string& robot_email,
-      const std::string& user_email,
-      const base::DictionaryValue& user_settings);
+  void EnableForUserWithRobot(const std::string& robot_auth_code,
+                              const std::string& robot_email,
+                              const std::string& user_email,
+                              base::Value user_settings);
   void UnregisterPrintersAndDisableForUser();
   void DisableForUser();
   // Returns the proxy info.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index a8772a3..f486e52 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1260,6 +1260,7 @@
         "../browser/extensions/extension_disabled_ui_browsertest.cc",
         "../browser/extensions/extension_dom_clipboard_apitest.cc",
         "../browser/extensions/extension_fileapi_apitest.cc",
+        "../browser/extensions/extension_function_registration_test.cc",
         "../browser/extensions/extension_function_test_utils.cc",
         "../browser/extensions/extension_function_test_utils.h",
         "../browser/extensions/extension_functional_browsertest.cc",
diff --git a/chrome/test/vr/auto_bisect.py b/chrome/test/vr/auto_bisect.py
index 3b97939..14ae654 100755
--- a/chrome/test/vr/auto_bisect.py
+++ b/chrome/test/vr/auto_bisect.py
@@ -24,6 +24,14 @@
 import time
 
 
+SUPPORTED_JSON_RESULT_FORMATS = {
+  'chartjson': 'The standard JSON output format for Telemetry.',
+  'printedjson': ('The JSON output format generated from parsing stdout from '
+                 'a test. This is the format used by tests that use '
+                 '//testing/perf/perf_test.h'),
+}
+
+
 class TempDir():
   """Context manager for temp dirs since Python 2 doesn't have one."""
   def __enter__(self):
@@ -97,6 +105,10 @@
                            'bisecting flaky metrics that fluctuate between '
                            'good/bad values, but can significantly increase '
                            'bisect time.')
+  parser.add_argument('--expected-json-result-format', default='chartjson',
+                      help='The data format the JSON results from the test are '
+                           'expected to be in. Supported values are: ' +
+                           (', '.join(SUPPORTED_JSON_RESULT_FORMATS.keys())))
 
   parser.add_argument_group('swarming arguments')
   parser.add_argument('--swarming-server', required=True,
@@ -143,6 +155,12 @@
         '--num-attempts-before-marking-good set to invalid value %d' %
         args.num_attempts_before_marking_good)
 
+  # Make sure the provided data format is supported.
+  if args.expected_json_result_format not in SUPPORTED_JSON_RESULT_FORMATS:
+    raise RuntimeError(
+        '--expected-json-result-format set to invalid value %s' %
+        args.expected_json_result_format)
+
   return (args, unknown_args)
 
 
@@ -178,6 +196,9 @@
   if args.num_attempts_before_marking_good > 1:
     print ('Each revision must be found to be good %d times before actually '
            'being marked as good' % args.num_attempts_before_marking_good)
+  print 'The data format that will be expected is %s: %s' % (
+      args.expected_json_result_format,
+      SUPPORTED_JSON_RESULT_FORMATS[args.expected_json_result_format])
   print '======'
   print 'The test target %s will be built to %s' % (args.build_target,
                                                     args.build_output_dir)
@@ -315,15 +336,20 @@
   with open(
       os.path.join(output_dir, '0', 'perftest-output.json'), 'r') as infile:
     perf_results = json.load(infile)
-    all_results = perf_results.get(unicode('charts'), {}).get(
-        unicode(args.metric), {}).get(unicode(args.story), {}).get(
-        unicode('values'), [])
+    all_results = []
+    if args.expected_json_result_format == 'chartjson':
+      all_results = perf_results.get(unicode('charts'), {}).get(
+          unicode(args.metric), {}).get(unicode(args.story), {}).get(
+          unicode('values'), [])
+    elif args.expected_json_result_format == 'printedjson':
+      all_results = perf_results.get(args.metric, {}).get('traces', {}).get(
+          args.story, [])
     if len(all_results) == 0:
       raise RuntimeError('Got no results for the story/metric combo. '
                          'Is there a typo in one of them?')
     result = all_results[0]
     print 'Got result %s' % str(result)
-  return result
+  return float(result)
 
 
 def RunBisectStep(args, unknown_args, revision, output_dir):
diff --git a/chromecast/media/cma/backend/audio_decoder_for_mixer.cc b/chromecast/media/cma/backend/audio_decoder_for_mixer.cc
index a7d4131..1740d427 100644
--- a/chromecast/media/cma/backend/audio_decoder_for_mixer.cc
+++ b/chromecast/media/cma/backend/audio_decoder_for_mixer.cc
@@ -57,6 +57,11 @@
 
 }  // namespace
 
+// static
+bool MediaPipelineBackend::AudioDecoder::RequiresDecryption() {
+  return true;
+}
+
 AudioDecoderForMixer::RateShifterInfo::RateShifterInfo(float playback_rate)
     : rate(playback_rate), input_frames(0), output_frames(0) {}
 
diff --git a/chromecast/media/cma/backend/audio_decoder_wrapper.cc b/chromecast/media/cma/backend/audio_decoder_wrapper.cc
index 47e8bd1..aaa5cf6 100644
--- a/chromecast/media/cma/backend/audio_decoder_wrapper.cc
+++ b/chromecast/media/cma/backend/audio_decoder_wrapper.cc
@@ -107,7 +107,9 @@
 }
 
 bool AudioDecoderWrapper::RequiresDecryption() {
-  return decoder_.IsUsingSoftwareDecoder();
+  return (MediaPipelineBackend::AudioDecoder::RequiresDecryption &&
+          MediaPipelineBackend::AudioDecoder::RequiresDecryption()) ||
+         decoder_.IsUsingSoftwareDecoder();
 }
 
 }  // namespace media
diff --git a/chromecast/public/media/media_pipeline_backend.h b/chromecast/public/media/media_pipeline_backend.h
index e7a75cb1..4695edc4 100644
--- a/chromecast/public/media/media_pipeline_backend.h
+++ b/chromecast/public/media/media_pipeline_backend.h
@@ -154,6 +154,11 @@
     static int64_t GetMinimumBufferedTime(const AudioConfig& config)
         __attribute__((__weak__));
 
+    // Returns true if the audio decoder requires that encrypted buffers be
+    // decrypted before being passed to PushBuffer().
+    CHROMECAST_EXPORT static bool RequiresDecryption()
+        __attribute__((__weak__));
+
    protected:
     ~AudioDecoder() override {}
   };
diff --git a/chromeos/dbus/services/chrome_features_service_provider.h b/chromeos/dbus/services/chrome_features_service_provider.h
index 91d394b..ce45be3 100644
--- a/chromeos/dbus/services/chrome_features_service_provider.h
+++ b/chromeos/dbus/services/chrome_features_service_provider.h
@@ -27,7 +27,7 @@
 // % dbus-send --system --type=method_call --print-reply
 //     --dest=org.chromium.ChromeFeaturesService
 //     /org/chromium/ChromeFeaturesService
-//     org.chromium.ChromeFeaturesService.IsCrostiniEnabled
+//     org.chromium.ChromeFeaturesServiceInterface.IsCrostiniEnabled
 //
 // % (returns true if Crostini is enabled, otherwise returns false)
 class CHROMEOS_EXPORT ChromeFeaturesServiceProvider
diff --git a/chromeos/services/device_sync/BUILD.gn b/chromeos/services/device_sync/BUILD.gn
index 45c0e72..01b1b75 100644
--- a/chromeos/services/device_sync/BUILD.gn
+++ b/chromeos/services/device_sync/BUILD.gn
@@ -79,6 +79,7 @@
     "//base",
     "//base/test:test_support",
     "//chromeos/services/device_sync/public/mojom",
+    "//chromeos/services/device_sync/public/mojom:unit_tests",
     "//components/cryptauth",
     "//components/cryptauth:test_support",
     "//mojo/common",
diff --git a/chromeos/services/device_sync/public/mojom/BUILD.gn b/chromeos/services/device_sync/public/mojom/BUILD.gn
index d3c1630..e27a1f09 100644
--- a/chromeos/services/device_sync/public/mojom/BUILD.gn
+++ b/chromeos/services/device_sync/public/mojom/BUILD.gn
@@ -14,3 +14,21 @@
     "//mojo/public/mojom/base",
   ]
 }
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "device_sync_mojom_traits_unittest.cc",
+  ]
+
+  deps = [
+    ":mojom",
+    "//base",
+    "//base/test:test_support",
+    "//components/cryptauth",
+    "//mojo/common",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//testing/gtest",
+  ]
+}
diff --git a/chromeos/services/device_sync/public/mojom/OWNERS b/chromeos/services/device_sync/public/mojom/OWNERS
index 08850f4..ae29a36aa 100644
--- a/chromeos/services/device_sync/public/mojom/OWNERS
+++ b/chromeos/services/device_sync/public/mojom/OWNERS
@@ -1,2 +1,6 @@
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromeos/services/device_sync/public/mojom/device_sync.mojom b/chromeos/services/device_sync/public/mojom/device_sync.mojom
index 90cb4d8..b525a2a 100644
--- a/chromeos/services/device_sync/public/mojom/device_sync.mojom
+++ b/chromeos/services/device_sync/public/mojom/device_sync.mojom
@@ -11,8 +11,8 @@
 // create the BLE channel, both devices must possess the other's BeaconSeeds.
 struct BeaconSeed {
   string data;
-  mojo_base.mojom.TimeTicks start_time;
-  mojo_base.mojom.TimeTicks end_time;
+  mojo_base.mojom.Time start_time;
+  mojo_base.mojom.Time end_time;
 };
 
 // Metadata describing a remote device with which the current device can
@@ -21,9 +21,6 @@
   // Public key used to authenticate a communication channel.
   string public_key;
 
-  // Identifier which is unique to each device.
-  string device_id;
-
   // Identifier for the user to whom this device is registered.
   string user_id;
 
@@ -31,6 +28,9 @@
   // model, but this value is editable.
   string device_name;
 
+  // Encryption key used for communication with this device.
+  string persistent_symmetric_key;
+
   // True if this device has the capability of unlocking another device via
   // EasyUnlock.
   bool unlock_key;
@@ -38,7 +38,11 @@
   // True if this device can enable a Wi-Fi hotspot to support Instant
   // Tethering (i.e., the device supports mobile data and its model supports the
   // feature).
-  bool mobile_hotspot_supported;
+  bool supports_mobile_hotspot;
+
+  // The time at which this device's metadata was last updated on the CryptAuth
+  // back-end.
+  mojo_base.mojom.Time last_update_time;
 
   // Seeds belonging to the device. Each seed has start and end timestamps which
   // indicate how long the seed is valid, and each device has enough associated
diff --git a/chromeos/services/device_sync/public/mojom/device_sync.typemap b/chromeos/services/device_sync/public/mojom/device_sync.typemap
new file mode 100644
index 0000000..65ff0bd
--- /dev/null
+++ b/chromeos/services/device_sync/public/mojom/device_sync.typemap
@@ -0,0 +1,29 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//chromeos/services/device_sync/public/mojom/device_sync.mojom"
+
+public_headers = [
+  "//components/cryptauth/proto/cryptauth_api.pb.h",
+  "//components/cryptauth/remote_device.h",
+]
+
+traits_headers = [
+  "//chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.h",
+]
+
+sources = [
+  "//chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.cc",
+  "//chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.h",
+]
+
+public_deps = [
+  "//components/cryptauth",
+  "//components/cryptauth/proto",
+]
+
+type_mappings = [
+  "chromeos.device_sync.mojom.BeaconSeed=cryptauth::BeaconSeed",
+  "chromeos.device_sync.mojom.RemoteDevice=cryptauth::RemoteDevice",
+]
diff --git a/chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.cc b/chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.cc
new file mode 100644
index 0000000..cf67a25
--- /dev/null
+++ b/chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.cc
@@ -0,0 +1,135 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.h"
+
+#include "mojo/public/cpp/base/time_mojom_traits.h"
+
+namespace mojo {
+
+const std::string& StructTraits<
+    chromeos::device_sync::mojom::BeaconSeedDataView,
+    cryptauth::BeaconSeed>::data(const cryptauth::BeaconSeed& beacon_seed) {
+  return beacon_seed.data();
+}
+
+base::Time
+StructTraits<chromeos::device_sync::mojom::BeaconSeedDataView,
+             cryptauth::BeaconSeed>::start_time(const cryptauth::BeaconSeed&
+                                                    beacon_seed) {
+  return base::Time::FromJavaTime(beacon_seed.start_time_millis());
+}
+
+base::Time StructTraits<
+    chromeos::device_sync::mojom::BeaconSeedDataView,
+    cryptauth::BeaconSeed>::end_time(const cryptauth::BeaconSeed& beacon_seed) {
+  return base::Time::FromJavaTime(beacon_seed.end_time_millis());
+}
+
+bool StructTraits<chromeos::device_sync::mojom::BeaconSeedDataView,
+                  cryptauth::BeaconSeed>::
+    Read(chromeos::device_sync::mojom::BeaconSeedDataView in,
+         cryptauth::BeaconSeed* out) {
+  std::string beacon_seed_data;
+  base::Time start_time;
+  base::Time end_time;
+
+  if (!in.ReadData(&beacon_seed_data) || !in.ReadStartTime(&start_time) ||
+      !in.ReadEndTime(&end_time)) {
+    return false;
+  }
+
+  out->set_data(beacon_seed_data);
+  out->set_start_time_millis(start_time.ToJavaTime());
+  out->set_end_time_millis(end_time.ToJavaTime());
+
+  return true;
+};
+
+const std::string&
+StructTraits<chromeos::device_sync::mojom::RemoteDeviceDataView,
+             cryptauth::RemoteDevice>::public_key(const cryptauth::RemoteDevice&
+                                                      remote_device) {
+  return remote_device.public_key;
+}
+
+const std::string&
+StructTraits<chromeos::device_sync::mojom::RemoteDeviceDataView,
+             cryptauth::RemoteDevice>::user_id(const cryptauth::RemoteDevice&
+                                                   remote_device) {
+  return remote_device.user_id;
+}
+
+const std::string& StructTraits<
+    chromeos::device_sync::mojom::RemoteDeviceDataView,
+    cryptauth::RemoteDevice>::device_name(const cryptauth::RemoteDevice&
+                                              remote_device) {
+  return remote_device.name;
+}
+
+const std::string&
+StructTraits<chromeos::device_sync::mojom::RemoteDeviceDataView,
+             cryptauth::RemoteDevice>::
+    persistent_symmetric_key(const cryptauth::RemoteDevice& remote_device) {
+  return remote_device.persistent_symmetric_key;
+}
+
+bool StructTraits<chromeos::device_sync::mojom::RemoteDeviceDataView,
+                  cryptauth::RemoteDevice>::
+    unlock_key(const cryptauth::RemoteDevice& remote_device) {
+  return remote_device.unlock_key;
+}
+
+bool StructTraits<chromeos::device_sync::mojom::RemoteDeviceDataView,
+                  cryptauth::RemoteDevice>::
+    supports_mobile_hotspot(const cryptauth::RemoteDevice& remote_device) {
+  return remote_device.supports_mobile_hotspot;
+}
+
+base::Time StructTraits<chromeos::device_sync::mojom::RemoteDeviceDataView,
+                        cryptauth::RemoteDevice>::
+    last_update_time(const cryptauth::RemoteDevice& remote_device) {
+  return base::Time::FromJavaTime(remote_device.last_update_time_millis);
+}
+
+const std::vector<cryptauth::BeaconSeed>& StructTraits<
+    chromeos::device_sync::mojom::RemoteDeviceDataView,
+    cryptauth::RemoteDevice>::beacon_seeds(const cryptauth::RemoteDevice&
+                                               remote_device) {
+  return remote_device.beacon_seeds;
+}
+
+bool StructTraits<chromeos::device_sync::mojom::RemoteDeviceDataView,
+                  cryptauth::RemoteDevice>::
+    Read(chromeos::device_sync::mojom::RemoteDeviceDataView in,
+         cryptauth::RemoteDevice* out) {
+  std::string user_id;
+  std::string device_name;
+  std::string public_key;
+  std::string persistent_symmetric_key;
+  base::Time last_update_time;
+  std::vector<cryptauth::BeaconSeed> beacon_seeds_out;
+
+  if (!in.ReadUserId(&user_id) || !in.ReadDeviceName(&device_name) ||
+      !in.ReadPublicKey(&public_key) ||
+      !in.ReadPersistentSymmetricKey(&persistent_symmetric_key) ||
+      !in.ReadLastUpdateTime(&last_update_time) ||
+      !in.ReadBeaconSeeds(&beacon_seeds_out)) {
+    return false;
+  }
+
+  out->user_id = user_id;
+  out->name = device_name;
+  out->public_key = public_key;
+  out->persistent_symmetric_key = persistent_symmetric_key;
+  out->unlock_key = in.unlock_key();
+  out->supports_mobile_hotspot = in.supports_mobile_hotspot();
+  out->last_update_time_millis = last_update_time.ToJavaTime();
+
+  out->LoadBeaconSeeds(beacon_seeds_out);
+
+  return true;
+}
+
+}  // namespace mojo
diff --git a/chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.h b/chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.h
new file mode 100644
index 0000000..ca3bfcd
--- /dev/null
+++ b/chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.h
@@ -0,0 +1,57 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_PUBLIC_MOJOM_DEVICE_SYNC_MOJOM_TRAITS_H_
+#define CHROMEOS_SERVICES_DEVICE_SYNC_PUBLIC_MOJOM_DEVICE_SYNC_MOJOM_TRAITS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/time/time.h"
+#include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+#include "components/cryptauth/remote_device.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+
+namespace mojo {
+
+template <>
+class StructTraits<chromeos::device_sync::mojom::BeaconSeedDataView,
+                   cryptauth::BeaconSeed> {
+ public:
+  static const std::string& data(const cryptauth::BeaconSeed& beacon_seed);
+  static base::Time start_time(const cryptauth::BeaconSeed& beacon_seed);
+  static base::Time end_time(const cryptauth::BeaconSeed& beacon_seed);
+
+  static bool Read(chromeos::device_sync::mojom::BeaconSeedDataView in,
+                   cryptauth::BeaconSeed* out);
+};
+
+template <>
+class StructTraits<chromeos::device_sync::mojom::RemoteDeviceDataView,
+                   cryptauth::RemoteDevice> {
+ public:
+  static const std::string& public_key(
+      const cryptauth::RemoteDevice& remote_device);
+  static const std::string& user_id(
+      const cryptauth::RemoteDevice& remote_device);
+  static const std::string& device_name(
+      const cryptauth::RemoteDevice& remote_device);
+  static const std::string& persistent_symmetric_key(
+      const cryptauth::RemoteDevice& remote_device);
+  static bool unlock_key(const cryptauth::RemoteDevice& remote_device);
+  static bool supports_mobile_hotspot(
+      const cryptauth::RemoteDevice& remote_device);
+  static base::Time last_update_time(
+      const cryptauth::RemoteDevice& remote_device);
+  static const std::vector<cryptauth::BeaconSeed>& beacon_seeds(
+      const cryptauth::RemoteDevice& remote_device);
+
+  static bool Read(chromeos::device_sync::mojom::RemoteDeviceDataView in,
+                   cryptauth::RemoteDevice* out);
+};
+
+}  // namespace mojo
+
+#endif  // CHROMEOS_SERVICES_DEVICE_SYNC_PUBLIC_MOJOM_DEVICE_SYNC_MOJOM_TRAITS_H_
diff --git a/chromeos/services/device_sync/public/mojom/device_sync_mojom_traits_unittest.cc b/chromeos/services/device_sync/public/mojom/device_sync_mojom_traits_unittest.cc
new file mode 100644
index 0000000..c4961e6
--- /dev/null
+++ b/chromeos/services/device_sync/public/mojom/device_sync_mojom_traits_unittest.cc
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/services/device_sync/public/mojom/device_sync_mojom_traits.h"
+
+#include "base/time/time.h"
+#include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+#include "components/cryptauth/remote_device.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kTestBeaconSeedData[] = "data";
+const int64_t kTestBeaconSeedStartTimeMillis = 1L;
+const int64_t kTestBeaconSeedEndTimeMillis = 2L;
+
+cryptauth::BeaconSeed CreateTestBeaconSeed() {
+  cryptauth::BeaconSeed beacon_seed;
+
+  beacon_seed.set_data(kTestBeaconSeedData);
+  beacon_seed.set_start_time_millis(kTestBeaconSeedStartTimeMillis);
+  beacon_seed.set_end_time_millis(kTestBeaconSeedEndTimeMillis);
+
+  return beacon_seed;
+}
+
+}  // namespace
+
+TEST(DeviceSyncMojomStructTraitsTest, BeaconSeed) {
+  cryptauth::BeaconSeed input = CreateTestBeaconSeed();
+
+  cryptauth::BeaconSeed output;
+  EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
+              chromeos::device_sync::mojom::BeaconSeed>(&input, &output));
+
+  EXPECT_EQ(kTestBeaconSeedData, output.data());
+  EXPECT_EQ(kTestBeaconSeedStartTimeMillis, output.start_time_millis());
+  EXPECT_EQ(kTestBeaconSeedEndTimeMillis, output.end_time_millis());
+}
+
+TEST(DeviceSyncMojomStructTraitsTest, RemoteDevice) {
+  cryptauth::RemoteDevice input;
+  input.user_id = "userId";
+  input.name = "name";
+  input.public_key = "publicKey";
+  input.persistent_symmetric_key = "persistentSymmetricKey";
+  input.unlock_key = true;
+  input.supports_mobile_hotspot = true;
+  input.last_update_time_millis = 3L;
+  input.LoadBeaconSeeds({CreateTestBeaconSeed()});
+
+  cryptauth::RemoteDevice output;
+  EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
+              chromeos::device_sync::mojom::RemoteDevice>(&input, &output));
+
+  EXPECT_EQ("userId", output.user_id);
+  EXPECT_EQ("name", output.name);
+  EXPECT_EQ("publicKey", output.public_key);
+  EXPECT_EQ("persistentSymmetricKey", output.persistent_symmetric_key);
+  EXPECT_TRUE(output.unlock_key);
+  EXPECT_TRUE(output.supports_mobile_hotspot);
+  EXPECT_EQ(3L, output.last_update_time_millis);
+  ASSERT_EQ(1u, output.beacon_seeds.size());
+  EXPECT_EQ(kTestBeaconSeedData, output.beacon_seeds[0].data());
+  EXPECT_EQ(kTestBeaconSeedStartTimeMillis,
+            output.beacon_seeds[0].start_time_millis());
+  EXPECT_EQ(kTestBeaconSeedEndTimeMillis,
+            output.beacon_seeds[0].end_time_millis());
+}
diff --git a/chromeos/services/device_sync/public/mojom/typemaps.gni b/chromeos/services/device_sync/public/mojom/typemaps.gni
new file mode 100644
index 0000000..0a71cbc
--- /dev/null
+++ b/chromeos/services/device_sync/public/mojom/typemaps.gni
@@ -0,0 +1,6 @@
+# Copyright 2018 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.
+
+typemaps =
+    [ "//chromeos/services/device_sync/public/mojom/device_sync.typemap" ]
diff --git a/components/cbor/cbor_writer.cc b/components/cbor/cbor_writer.cc
index d6e09fa5..47497a9 100644
--- a/components/cbor/cbor_writer.cc
+++ b/components/cbor/cbor_writer.cc
@@ -103,10 +103,10 @@
                 base::checked_cast<uint64_t>(simple_value));
       return true;
     }
-
-    default:
-      break;
   }
+
+  // This is needed because, otherwise, MSVC complains that not all paths return
+  // a value. We should be able to remove it once MSVC builders are gone.
   NOTREACHED();
   return false;
 }
diff --git a/components/certificate_transparency/ct_policy_manager.cc b/components/certificate_transparency/ct_policy_manager.cc
index 8b00064..d896d33 100644
--- a/components/certificate_transparency/ct_policy_manager.cc
+++ b/components/certificate_transparency/ct_policy_manager.cc
@@ -10,6 +10,7 @@
 #include <set>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -19,9 +20,6 @@
 #include "base/strings/string_util.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
-#include "components/certificate_transparency/pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
 #include "components/url_formatter/url_fixer.h"
 #include "components/url_matcher/url_matcher.h"
 #include "crypto/sha2.h"
@@ -166,16 +164,15 @@
 class CTPolicyManager::CTDelegate
     : public net::TransportSecurityState::RequireCTDelegate {
  public:
-  explicit CTDelegate(
-      scoped_refptr<base::SequencedTaskRunner> network_task_runner);
+  explicit CTDelegate();
   ~CTDelegate() override = default;
 
-  // Called on the prefs task runner. Updates the CTDelegate to require CT
+  // Updates the CTDelegate to require CT
   // for |required_hosts|, and exclude |excluded_hosts| from CT policies.
-  void UpdateFromPrefs(const base::ListValue* required_hosts,
-                       const base::ListValue* excluded_hosts,
-                       const base::ListValue* excluded_spkis,
-                       const base::ListValue* excluded_legacy_spkis);
+  void UpdateCTPolicies(const std::vector<std::string>& required_hosts,
+                        const std::vector<std::string>& excluded_hosts,
+                        const std::vector<std::string>& excluded_spkis,
+                        const std::vector<std::string>& excluded_legacy_spkis);
 
   // RequireCTDelegate implementation
   // Called on the network task runner.
@@ -203,33 +200,32 @@
                  const net::HashValueVector& hashes,
                  bool* ct_required) const;
 
-  // Called on the |network_task_runner_|. Updates the |url_matcher_| to
+  // Updates the |url_matcher_| to
   // require CT for |required_hosts| and exclude |excluded_hosts|, both
   // of which are Lists of Strings which are URLBlacklist filters, and
   // updates |excluded_spkis| and |excluded_legacy_spkis| to exclude CT for
   // those SPKIs, which are encoded as strings using net::HashValue::ToString.
-  void Update(base::ListValue required_hosts,
-              base::ListValue excluded_hosts,
-              base::ListValue excluded_spkis,
-              base::ListValue excluded_legacy_spkis);
+  void Update(const std::vector<std::string>& required_hosts,
+              const std::vector<std::string>& excluded_hosts,
+              const std::vector<std::string>& excluded_spkis,
+              const std::vector<std::string>& excluded_legacy_spkis);
 
   // Parses the filters from |host_patterns|, adding them as filters to
   // |filters_| (with |ct_required| indicating whether or not CT is required
   // for that host), and updating |*conditions| with the corresponding
   // URLMatcher::Conditions to match the host.
   void AddFilters(bool ct_required,
-                  const base::ListValue& host_patterns,
+                  const std::vector<std::string>& host_patterns,
                   url_matcher::URLMatcherConditionSet::Vector* conditions);
 
   // Parses the SPKIs from |list|, setting |*hashes| to the sorted set of all
   // valid SPKIs.
-  void ParseSpkiHashes(const base::ListValue& list,
+  void ParseSpkiHashes(const std::vector<std::string> list,
                        net::HashValueVector* hashes) const;
 
   // Returns true if |lhs| has greater precedence than |rhs|.
   bool FilterTakesPrecedence(const Filter& lhs, const Filter& rhs) const;
 
-  scoped_refptr<base::SequencedTaskRunner> network_task_runner_;
   std::unique_ptr<url_matcher::URLMatcher> url_matcher_;
   url_matcher::URLMatcherConditionSet::ID next_id_;
   std::map<url_matcher::URLMatcherConditionSet::ID, Filter> filters_;
@@ -241,24 +237,15 @@
   DISALLOW_COPY_AND_ASSIGN(CTDelegate);
 };
 
-CTPolicyManager::CTDelegate::CTDelegate(
-    scoped_refptr<base::SequencedTaskRunner> network_task_runner)
-    : network_task_runner_(std::move(network_task_runner)),
-      url_matcher_(new url_matcher::URLMatcher),
-      next_id_(0) {}
+CTPolicyManager::CTDelegate::CTDelegate()
+    : url_matcher_(new url_matcher::URLMatcher), next_id_(0) {}
 
-void CTPolicyManager::CTDelegate::UpdateFromPrefs(
-    const base::ListValue* required_hosts,
-    const base::ListValue* excluded_hosts,
-    const base::ListValue* excluded_spkis,
-    const base::ListValue* excluded_legacy_spkis) {
-  network_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&CTDelegate::Update, base::Unretained(this),
-                     base::ListValue(required_hosts->GetList()),
-                     base::ListValue(excluded_hosts->GetList()),
-                     base::ListValue(excluded_spkis->GetList()),
-                     base::ListValue(excluded_legacy_spkis->GetList())));
+void CTPolicyManager::CTDelegate::UpdateCTPolicies(
+    const std::vector<std::string>& required_hosts,
+    const std::vector<std::string>& excluded_hosts,
+    const std::vector<std::string>& excluded_spkis,
+    const std::vector<std::string>& excluded_legacy_spkis) {
+  Update(required_hosts, excluded_hosts, excluded_spkis, excluded_legacy_spkis);
 }
 
 net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel
@@ -266,7 +253,6 @@
     const std::string& hostname,
     const net::X509Certificate* chain,
     const net::HashValueVector& hashes) {
-  DCHECK(network_task_runner_->RunsTasksInCurrentSequence());
 
   bool ct_required = false;
   if (MatchHostname(hostname, &ct_required) ||
@@ -394,12 +380,10 @@
 }
 
 void CTPolicyManager::CTDelegate::Update(
-    base::ListValue required_hosts,
-    base::ListValue excluded_hosts,
-    base::ListValue excluded_spkis,
-    base::ListValue excluded_legacy_spkis) {
-  DCHECK(network_task_runner_->RunsTasksInCurrentSequence());
-
+    const std::vector<std::string>& required_hosts,
+    const std::vector<std::string>& excluded_hosts,
+    const std::vector<std::string>& excluded_spkis,
+    const std::vector<std::string>& excluded_legacy_spkis) {
   url_matcher_.reset(new url_matcher::URLMatcher);
   filters_.clear();
   next_id_ = 0;
@@ -429,13 +413,9 @@
 
 void CTPolicyManager::CTDelegate::AddFilters(
     bool ct_required,
-    const base::ListValue& hosts,
+    const std::vector<std::string>& hosts,
     url_matcher::URLMatcherConditionSet::Vector* conditions) {
-  for (const base::Value& host : hosts) {
-    if (!host.is_string())
-      continue;
-    std::string pattern = host.GetString();
-
+  for (const auto& pattern : hosts) {
     Filter filter;
     filter.ct_required = ct_required;
 
@@ -493,14 +473,12 @@
 }
 
 void CTPolicyManager::CTDelegate::ParseSpkiHashes(
-    const base::ListValue& list,
+    const std::vector<std::string> list,
     net::HashValueVector* hashes) const {
   hashes->clear();
-  for (const base::Value& value : list.GetList()) {
-    if (!value.is_string())
-      continue;
+  for (const auto& value : list) {
     net::HashValue hash;
-    if (!hash.FromString(value.GetString())) {
+    if (!hash.FromString(value)) {
       continue;
     }
     hashes->push_back(std::move(hash));
@@ -523,68 +501,21 @@
   return false;
 }
 
-// static
-void CTPolicyManager::RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterListPref(prefs::kCTRequiredHosts);
-  registry->RegisterListPref(prefs::kCTExcludedHosts);
-  registry->RegisterListPref(prefs::kCTExcludedSPKIs);
-  registry->RegisterListPref(prefs::kCTExcludedLegacySPKIs);
-}
-
-CTPolicyManager::CTPolicyManager(
-    PrefService* pref_service,
-    scoped_refptr<base::SequencedTaskRunner> network_task_runner)
-    : delegate_(new CTDelegate(std::move(network_task_runner))),
-      weak_factory_(this) {
-  pref_change_registrar_.Init(pref_service);
-  pref_change_registrar_.Add(
-      prefs::kCTRequiredHosts,
-      base::BindRepeating(&CTPolicyManager::ScheduleUpdate,
-                          base::Unretained(this)));
-  pref_change_registrar_.Add(
-      prefs::kCTExcludedHosts,
-      base::BindRepeating(&CTPolicyManager::ScheduleUpdate,
-                          base::Unretained(this)));
-  pref_change_registrar_.Add(
-      prefs::kCTExcludedSPKIs,
-      base::BindRepeating(&CTPolicyManager::ScheduleUpdate,
-                          base::Unretained(this)));
-  pref_change_registrar_.Add(
-      prefs::kCTExcludedLegacySPKIs,
-      base::BindRepeating(&CTPolicyManager::ScheduleUpdate,
-                          base::Unretained(this)));
-
-  ScheduleUpdate();
-}
+CTPolicyManager::CTPolicyManager() : delegate_(new CTDelegate()) {}
 
 CTPolicyManager::~CTPolicyManager() {}
 
-void CTPolicyManager::Shutdown() {
-  // Cancel any pending updates, since the preferences are going away.
-  weak_factory_.InvalidateWeakPtrs();
-  pref_change_registrar_.RemoveAll();
+void CTPolicyManager::UpdateCTPolicies(
+    const std::vector<std::string>& required_hosts,
+    const std::vector<std::string>& excluded_hosts,
+    const std::vector<std::string>& excluded_spkis,
+    const std::vector<std::string>& excluded_legacy_spkis) {
+  delegate_->UpdateCTPolicies(required_hosts, excluded_hosts, excluded_spkis,
+                              excluded_legacy_spkis);
 }
 
 net::TransportSecurityState::RequireCTDelegate* CTPolicyManager::GetDelegate() {
   return delegate_.get();
 }
 
-void CTPolicyManager::ScheduleUpdate() {
-  // Cancel any pending updates, and schedule a new update. If this method
-  // is called again, this pending update will be cancelled because the weak
-  // pointer is invalidated, and the new update will take precedence.
-  weak_factory_.InvalidateWeakPtrs();
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&CTPolicyManager::Update, weak_factory_.GetWeakPtr()));
-}
-
-void CTPolicyManager::Update() {
-  delegate_->UpdateFromPrefs(
-      pref_change_registrar_.prefs()->GetList(prefs::kCTRequiredHosts),
-      pref_change_registrar_.prefs()->GetList(prefs::kCTExcludedHosts),
-      pref_change_registrar_.prefs()->GetList(prefs::kCTExcludedSPKIs),
-      pref_change_registrar_.prefs()->GetList(prefs::kCTExcludedLegacySPKIs));
-}
-
 }  // namespace certificate_transparency
diff --git a/components/certificate_transparency/ct_policy_manager.h b/components/certificate_transparency/ct_policy_manager.h
index 15b09a0a..88f3b97 100644
--- a/components/certificate_transparency/ct_policy_manager.h
+++ b/components/certificate_transparency/ct_policy_manager.h
@@ -9,16 +9,8 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "components/prefs/pref_change_registrar.h"
 #include "net/http/transport_security_state.h"
 
-namespace base {
-class SequencedTaskRunner;
-}  // base
-
-class PrefRegistrySimple;
-
 namespace certificate_transparency {
 
 // CTPolicyManager serves as the bridge between the Certificate Transparency
@@ -27,26 +19,10 @@
 // CT-related policies.
 class CTPolicyManager {
  public:
-  // Registers the preferences related to Certificate Transparency policy
-  // in the given pref registry.
-  static void RegisterPrefs(PrefRegistrySimple* registry);
-
-  // Creates a CTPolicyManager that will monitor the preferences on
-  // |pref_service| and make them available to a RequireCTDelegate that
-  // can be used on |network_task_runner|.
-  //
-  // The CTPolicyManager should be constructed on the same task runner
-  // associated with the |pref_service|, but can be destructed on any
-  // task runner, provided that Shutdown() has been called.
-  CTPolicyManager(PrefService* pref_service,
-                  scoped_refptr<base::SequencedTaskRunner> network_task_runner);
+  // Creates a CTPolicyManager that will provide a RequireCTDelegate delegate.
+  CTPolicyManager();
   ~CTPolicyManager();
 
-  // Unregisters the CTPolicyManager from the preference subsystem. This
-  // should be called on the same task runner that the pref service
-  // it was constructed with lives on.
-  void Shutdown();
-
   // Returns a RequireCTDelegate that responds based on the policies set via
   // preferences.
   //
@@ -55,29 +31,21 @@
   //   - The most specific host is preferred.
   //   - Requiring CT is preferred over excluding CT
   //
-  // This object MUST only be used on the network task runner supplied during
-  // construction, MAY be used after Shutdown() is called (at which point,
-  // it will reflect the last status before Shutdown() was called), and
-  // MUST NOT be used after this object has been deleted.
   net::TransportSecurityState::RequireCTDelegate* GetDelegate();
 
+  // Updates the CTDelegate to require CT for |required_hosts|, and exclude
+  // |excluded_hosts| from CT policies.  In addtion, this method updates
+  // |excluded_spkis| and |excluded_legacy_spkis| intended for use within an
+  // Enterprise (see https://crbug.com/824184).
+  void UpdateCTPolicies(const std::vector<std::string>& required_hosts,
+                        const std::vector<std::string>& excluded_hosts,
+                        const std::vector<std::string>& excluded_spkis,
+                        const std::vector<std::string>& excluded_legacy_spkis);
+
  private:
   class CTDelegate;
-
-  // Schedules an update of the CTPolicyDelegate. As it's possible that
-  // multiple preferences may be updated at the same time, this exists to
-  // schedule only a single update.
-  void ScheduleUpdate();
-
-  // Performs the actual update of the CTPolicyDelegate once preference
-  // changes have quiesced.
-  void Update();
-
-  PrefChangeRegistrar pref_change_registrar_;
   std::unique_ptr<CTDelegate> delegate_;
 
-  base::WeakPtrFactory<CTPolicyManager> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(CTPolicyManager);
 };
 
diff --git a/components/certificate_transparency/ct_policy_manager_unittest.cc b/components/certificate_transparency/ct_policy_manager_unittest.cc
index 82573f8..9d3b3b1 100644
--- a/components/certificate_transparency/ct_policy_manager_unittest.cc
+++ b/components/certificate_transparency/ct_policy_manager_unittest.cc
@@ -27,15 +27,6 @@
 
 namespace {
 
-std::unique_ptr<base::ListValue> ListValueFromStrings(
-    const std::vector<const char*>& strings) {
-  std::unique_ptr<base::ListValue> result(new base::ListValue);
-  for (auto* const str : strings) {
-    result->AppendString(str);
-  }
-  return result;
-}
-
 class CTPolicyManagerTest : public ::testing::Test {
  public:
   CTPolicyManagerTest() : message_loop_(base::MessageLoop::TYPE_IO) {}
@@ -51,7 +42,6 @@
 
  protected:
   base::TestMessageLoop message_loop_;
-  TestingPrefServiceSimple pref_service_;
   scoped_refptr<net::X509Certificate> cert_;
   net::HashValueVector hashes_;
 };
@@ -59,38 +49,34 @@
 // Treat the preferences as a black box as far as naming, but ensure that
 // preferences get registered.
 TEST_F(CTPolicyManagerTest, RegistersPrefs) {
-  auto registered_prefs = std::distance(pref_service_.registry()->begin(),
-                                        pref_service_.registry()->end());
-  CTPolicyManager::RegisterPrefs(pref_service_.registry());
-  auto newly_registered_prefs = std::distance(pref_service_.registry()->begin(),
-                                              pref_service_.registry()->end());
+  TestingPrefServiceSimple pref_service;
+  auto registered_prefs = std::distance(pref_service.registry()->begin(),
+                                        pref_service.registry()->end());
+  certificate_transparency::prefs::RegisterPrefs(pref_service.registry());
+  auto newly_registered_prefs = std::distance(pref_service.registry()->begin(),
+                                              pref_service.registry()->end());
   EXPECT_NE(registered_prefs, newly_registered_prefs);
 }
 
 TEST_F(CTPolicyManagerTest, DelegateChecksRequired) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  // Register preferences and set up initial state
-  CTPolicyManager::RegisterPrefs(pref_service_.registry());
-  CTPolicyManager manager(&pref_service_, message_loop_.task_runner());
-  base::RunLoop().RunUntilIdle();
+  CTPolicyManager manager;
 
   net::TransportSecurityState::RequireCTDelegate* delegate =
       manager.GetDelegate();
   ASSERT_TRUE(delegate);
 
-  // No preferences should yield the default results.
+  // No required host set yet.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
             delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
-  // Now set a preference, pump the message loop, and ensure things are now
-  // reflected.
-  pref_service_.SetManagedPref(
-      prefs::kCTRequiredHosts,
-      ListValueFromStrings(std::vector<const char*>{"google.com"}));
-  base::RunLoop().RunUntilIdle();
+  // Add a required host
+  manager.UpdateCTPolicies(
+      std::vector<std::string>{"google.com"}, std::vector<std::string>(),
+      std::vector<std::string>(), std::vector<std::string>());
 
-  // The new preferences should take effect.
+  // The new setting should take effect.
   EXPECT_EQ(CTRequirementLevel::REQUIRED,
             delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 }
@@ -98,27 +84,22 @@
 TEST_F(CTPolicyManagerTest, DelegateChecksExcluded) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  // Register preferences and set up initial state
-  CTPolicyManager::RegisterPrefs(pref_service_.registry());
-  CTPolicyManager manager(&pref_service_, message_loop_.task_runner());
-  base::RunLoop().RunUntilIdle();
+  CTPolicyManager manager;
 
   net::TransportSecurityState::RequireCTDelegate* delegate =
       manager.GetDelegate();
   ASSERT_TRUE(delegate);
 
-  // No preferences should yield the default results.
+  // No setting should yield the default results.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
             delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
-  // Now set a preference, pump the message loop, and ensure things are now
-  // reflected.
-  pref_service_.SetManagedPref(
-      prefs::kCTExcludedHosts,
-      ListValueFromStrings(std::vector<const char*>{"google.com"}));
-  base::RunLoop().RunUntilIdle();
+  // Add a excluded host
+  manager.UpdateCTPolicies(
+      std::vector<std::string>(), std::vector<std::string>{"google.com"},
+      std::vector<std::string>(), std::vector<std::string>());
 
-  // The new preferences should take effect.
+  // The new setting should take effect.
   EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
             delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 }
@@ -126,29 +107,25 @@
 TEST_F(CTPolicyManagerTest, IgnoresInvalidEntries) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  // Register preferences and set up initial state
-  CTPolicyManager::RegisterPrefs(pref_service_.registry());
-  CTPolicyManager manager(&pref_service_, message_loop_.task_runner());
-  base::RunLoop().RunUntilIdle();
+  CTPolicyManager manager;
 
   net::TransportSecurityState::RequireCTDelegate* delegate =
       manager.GetDelegate();
   ASSERT_TRUE(delegate);
 
-  // No preferences should yield the default results.
+  // No setting should yield the default results.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
             delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
-  // Now setup invalid preferences (that is, that fail to be parsable as
+  // Now setup invalid state (that is, that fail to be parsable as
   // URLs).
-  pref_service_.SetManagedPref(
-      prefs::kCTRequiredHosts,
-      ListValueFromStrings(std::vector<const char*>{
+  manager.UpdateCTPolicies(
+      std::vector<std::string>{
           "file:///etc/fstab", "file://withahost/etc/fstab",
           "file:///c|/Windows", "*", "https://*", "example.com",
-          "https://example.test:invalid_port",
-      }));
-  base::RunLoop().RunUntilIdle();
+          "https://example.test:invalid_port"},
+      std::vector<std::string>(), std::vector<std::string>(),
+      std::vector<std::string>());
 
   // Wildcards are ignored (both * and https://*).
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
@@ -172,16 +149,13 @@
 TEST_F(CTPolicyManagerTest, AppliesPriority) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  // Register preferences and set up initial state
-  CTPolicyManager::RegisterPrefs(pref_service_.registry());
-  CTPolicyManager manager(&pref_service_, message_loop_.task_runner());
-  base::RunLoop().RunUntilIdle();
+  CTPolicyManager manager;
 
   net::TransportSecurityState::RequireCTDelegate* delegate =
       manager.GetDelegate();
   ASSERT_TRUE(delegate);
 
-  // No preferences should yield the default results.
+  // No setting should yield the default results.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
             delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
   EXPECT_EQ(
@@ -205,16 +179,12 @@
 
   // Set up policies that exclude it for a domain and all of its subdomains,
   // but then require it for a specific host.
-  pref_service_.SetManagedPref(
-      prefs::kCTExcludedHosts,
-      ListValueFromStrings(std::vector<const char*>{
-          "example.com", ".sub.example.com", ".sub.accounts.example.com",
-          "test.example.com"}));
-  pref_service_.SetManagedPref(
-      prefs::kCTRequiredHosts,
-      ListValueFromStrings(std::vector<const char*>{
-          "sub.example.com", "accounts.example.com", "test.example.com"}));
-  base::RunLoop().RunUntilIdle();
+  manager.UpdateCTPolicies(
+      std::vector<std::string>{"sub.example.com", "accounts.example.com",
+                               "test.example.com"},
+      std::vector<std::string>{"example.com", ".sub.example.com",
+                               ".sub.accounts.example.com", "test.example.com"},
+      std::vector<std::string>(), std::vector<std::string>());
 
   EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
             delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
@@ -244,74 +214,11 @@
       delegate->IsCTRequiredForHost("test.example.com", cert_.get(), hashes_));
 }
 
-// Ensure that the RequireCTDelegate is still valid and usable after Shutdown
-// has been called. Preferences should no longer sync, but the old results
-// should still be returned.
-TEST_F(CTPolicyManagerTest, UsableAfterShutdown) {
-  using CTRequirementLevel =
-      net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  // Register preferences and set up initial state
-  CTPolicyManager::RegisterPrefs(pref_service_.registry());
-  CTPolicyManager manager(&pref_service_, message_loop_.task_runner());
-  base::RunLoop().RunUntilIdle();
-
-  net::TransportSecurityState::RequireCTDelegate* delegate =
-      manager.GetDelegate();
-  ASSERT_TRUE(delegate);
-
-  // No preferences should yield the default results.
-  EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
-
-  // Now set a preference, pump the message loop, and ensure things are now
-  // reflected.
-  pref_service_.SetManagedPref(
-      prefs::kCTRequiredHosts,
-      ListValueFromStrings(std::vector<const char*>{"google.com"}));
-  base::RunLoop().RunUntilIdle();
-
-  // The new preferences should take effect.
-  EXPECT_EQ(CTRequirementLevel::REQUIRED,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
-
-  // Shut down the preferences, which should unregister any observers.
-  manager.Shutdown();
-  base::RunLoop().RunUntilIdle();
-
-  // Update the preferences again, which should do nothing; the
-  // RequireCTDelegate should continue to be valid and return the old results.
-  EXPECT_EQ(CTRequirementLevel::REQUIRED,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
-  EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
-  EXPECT_EQ(
-      CTRequirementLevel::DEFAULT,
-      delegate->IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
-  pref_service_.SetManagedPref(
-      prefs::kCTRequiredHosts,
-      ListValueFromStrings(std::vector<const char*>{"sub.example.com"}));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(CTRequirementLevel::REQUIRED,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
-  EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
-  EXPECT_EQ(
-      CTRequirementLevel::DEFAULT,
-      delegate->IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
-
-  // And it should still be possible to get the delegate, even after calling
-  // Shutdown().
-  EXPECT_TRUE(manager.GetDelegate());
-}
-
 TEST_F(CTPolicyManagerTest, SupportsOrgRestrictions) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
 
-  // Register preferences and set up initial state
-  CTPolicyManager::RegisterPrefs(pref_service_.registry());
-  CTPolicyManager manager(&pref_service_, message_loop_.task_runner());
-  base::RunLoop().RunUntilIdle();
+  CTPolicyManager manager;
 
   net::TransportSecurityState::RequireCTDelegate* delegate =
       manager.GetDelegate();
@@ -432,25 +339,20 @@
           net::x509_util::DupCryptoBuffer(leaf->cert_buffer()),
           std::move(intermediates));
     }
-    std::unique_ptr<base::ListValue> excluded_spkis =
-        std::make_unique<base::ListValue>();
-    pref_service_.SetManagedPref(prefs::kCTExcludedSPKIs,
-                                 std::move(excluded_spkis));
-    base::RunLoop().RunUntilIdle();
+    manager.UpdateCTPolicies(
+        std::vector<std::string>(), std::vector<std::string>(),
+        std::vector<std::string>(), std::vector<std::string>());
 
     // There should be no existing settings.
     EXPECT_EQ(CTRequirementLevel::DEFAULT,
               delegate->IsCTRequiredForHost("google.com", leaf.get(), hashes));
 
-    // Update the preference
-    excluded_spkis = std::make_unique<base::ListValue>();
-    excluded_spkis->AppendString(test.spki.ToString());
+    manager.UpdateCTPolicies(std::vector<std::string>(),
+                             std::vector<std::string>(),
+                             std::vector<std::string>{test.spki.ToString()},
+                             std::vector<std::string>());
 
-    pref_service_.SetManagedPref(prefs::kCTExcludedSPKIs,
-                                 std::move(excluded_spkis));
-    base::RunLoop().RunUntilIdle();
-
-    // The new preferences should take effect.
+    // The new setting should take effect.
     EXPECT_EQ(test.expected,
               delegate->IsCTRequiredForHost("google.com", leaf.get(), hashes));
   }
@@ -459,11 +361,7 @@
 TEST_F(CTPolicyManagerTest, SupportsLegacyCaRestrictions) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-
-  // Register preferences and set up initial state
-  CTPolicyManager::RegisterPrefs(pref_service_.registry());
-  CTPolicyManager manager(&pref_service_, message_loop_.task_runner());
-  base::RunLoop().RunUntilIdle();
+  CTPolicyManager manager;
 
   net::TransportSecurityState::RequireCTDelegate* delegate =
       manager.GetDelegate();
@@ -479,29 +377,30 @@
 
   hashes_.push_back(net::HashValue(legacy_spki));
 
-  // No preferences should yield the default results.
+  // No setting should yield the default results.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
             delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
-  // Setting a preference to a non-legacy CA should not work.
+  // Setting to a non-legacy CA should not work.
   std::string leaf_hash_string = hashes_.front().ToString();
-  pref_service_.SetManagedPref(
-      prefs::kCTExcludedLegacySPKIs,
-      ListValueFromStrings(std::vector<const char*>{leaf_hash_string.c_str()}));
-  base::RunLoop().RunUntilIdle();
+  manager.UpdateCTPolicies(
+      std::vector<std::string>(), std::vector<std::string>(),
+      std::vector<std::string>(), std::vector<std::string>{leaf_hash_string});
 
-  // The new preference should have no effect, because the hash for |cert_|
+  // This setting should have no effect, because the hash for |cert_|
   // is not a legacy CA hash.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
             delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
-  // Now set the preference to a truly legacy CA, and create a chain that
+  // Now set to a truly legacy CA, and create a chain that
   // contains that legacy CA hash.
   std::string legacy_ca_hash_string = hashes_.back().ToString();
-  pref_service_.SetManagedPref(prefs::kCTExcludedLegacySPKIs,
-                               ListValueFromStrings(std::vector<const char*>{
-                                   legacy_ca_hash_string.c_str()}));
-  base::RunLoop().RunUntilIdle();
+
+  manager.UpdateCTPolicies(std::vector<std::string>(),
+                           std::vector<std::string>(),
+                           std::vector<std::string>(),
+                           std::vector<std::string>{legacy_ca_hash_string});
+
   EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
             delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 }
diff --git a/components/certificate_transparency/pref_names.cc b/components/certificate_transparency/pref_names.cc
index ffdef26..776a518 100644
--- a/components/certificate_transparency/pref_names.cc
+++ b/components/certificate_transparency/pref_names.cc
@@ -3,10 +3,19 @@
 // found in the LICENSE file.
 
 #include "components/certificate_transparency/pref_names.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/prefs/pref_registry_simple.h"
 
 namespace certificate_transparency {
 namespace prefs {
 
+void RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterListPref(prefs::kCTRequiredHosts);
+  registry->RegisterListPref(prefs::kCTExcludedHosts);
+  registry->RegisterListPref(prefs::kCTExcludedSPKIs);
+  registry->RegisterListPref(prefs::kCTExcludedLegacySPKIs);
+}
+
 const char kCTRequiredHosts[] = "certificate_transparency.required_hosts";
 
 const char kCTExcludedHosts[] = "certificate_transparency.excluded_hosts";
diff --git a/components/certificate_transparency/pref_names.h b/components/certificate_transparency/pref_names.h
index bf6c6181..b7153c5 100644
--- a/components/certificate_transparency/pref_names.h
+++ b/components/certificate_transparency/pref_names.h
@@ -5,9 +5,15 @@
 #ifndef COMPONENTS_CERTIFICATE_TRANSPARENCY_PREF_NAMES_H_
 #define COMPONENTS_CERTIFICATE_TRANSPARENCY_PREF_NAMES_H_
 
+class PrefRegistrySimple;
+
 namespace certificate_transparency {
 namespace prefs {
 
+// Registers the preferences related to Certificate Transparency policy
+// in the given pref registry.
+void RegisterPrefs(PrefRegistrySimple* registry);
+
 // The set of hosts (as URLBlacklist-syntax filters) for which Certificate
 // Transparency is required to be present.
 extern const char kCTRequiredHosts[];
diff --git a/components/download/internal/common/BUILD.gn b/components/download/internal/common/BUILD.gn
index 2e0d0b2..c1f8f812 100644
--- a/components/download/internal/common/BUILD.gn
+++ b/components/download/internal/common/BUILD.gn
@@ -3,7 +3,10 @@
 # found in the LICENSE file.
 
 source_set("internal") {
-  visibility = [ "//components/download/public/common:public" ]
+  visibility = [
+    ":for_tests",
+    "//components/download/public/common:public",
+  ]
 
   configs += [
     "//components/download/public/common:components_download_implementation",
@@ -23,17 +26,22 @@
     "download_job.cc",
     "download_job_factory.cc",
     "download_job_impl.cc",
+    "download_job_impl.h",
     "download_response_handler.cc",
     "download_stats.cc",
     "download_task_runner.cc",
     "download_ukm_helper.cc",
     "download_utils.cc",
     "download_worker.cc",
+    "download_worker.h",
     "parallel_download_job.cc",
+    "parallel_download_job.h",
     "parallel_download_utils.cc",
+    "parallel_download_utils.h",
     "rate_estimator.cc",
     "resource_downloader.cc",
     "save_package_download_job.cc",
+    "save_package_download_job.h",
     "stream_handle_input_stream.cc",
     "url_download_handler_factory.cc",
   ]
@@ -54,9 +62,25 @@
   ]
 }
 
+# tests need to access both public and internal sources. So in the component
+# build case, we exclude the internal dependency as it is included in the
+# test_support target under public.
+group("for_tests") {
+  visibility = [ ":unit_tests" ]
+  if (!is_component_build) {
+    public_deps = [
+      ":internal",
+    ]
+  }
+}
+
 source_set("unit_tests") {
   testonly = true
 
+  if (is_component_build) {
+    check_includes = false
+  }
+
   sources = [
     "base_file_unittest.cc",
     "base_file_win_unittest.cc",
@@ -69,6 +93,7 @@
   ]
 
   deps = [
+    ":for_tests",
     "//base/test:test_support",
     "//components/download/public/common:test_support",
     "//components/ukm:test_support",
diff --git a/components/download/internal/common/download_file_impl.cc b/components/download/internal/common/download_file_impl.cc
index b012c08d..d136334 100644
--- a/components/download/internal/common/download_file_impl.cc
+++ b/components/download/internal/common/download_file_impl.cc
@@ -15,11 +15,11 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "components/download/internal/common/parallel_download_utils.h"
 #include "components/download/public/common/download_create_info.h"
 #include "components/download/public/common/download_destination_observer.h"
 #include "components/download/public/common/download_interrupt_reasons_utils.h"
 #include "components/download/public/common/download_stats.h"
-#include "components/download/public/common/parallel_download_utils.h"
 #include "crypto/secure_hash.h"
 #include "crypto/sha2.h"
 #include "mojo/public/c/system/types.h"
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc
index 5ea5be9f..7181a2c 100644
--- a/components/download/internal/common/download_item_impl.cc
+++ b/components/download/internal/common/download_item_impl.cc
@@ -40,17 +40,17 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner_util.h"
 #include "components/download/downloader/in_progress/download_entry.h"
+#include "components/download/internal/common/download_job_impl.h"
+#include "components/download/internal/common/parallel_download_utils.h"
 #include "components/download/public/common/download_danger_type.h"
 #include "components/download/public/common/download_file.h"
 #include "components/download/public/common/download_interrupt_reasons.h"
 #include "components/download/public/common/download_item_impl_delegate.h"
 #include "components/download/public/common/download_job_factory.h"
-#include "components/download/public/common/download_job_impl.h"
 #include "components/download/public/common/download_stats.h"
 #include "components/download/public/common/download_task_runner.h"
 #include "components/download/public/common/download_ukm_helper.h"
 #include "components/download/public/common/download_url_parameters.h"
-#include "components/download/public/common/parallel_download_utils.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
diff --git a/components/download/internal/common/download_job_factory.cc b/components/download/internal/common/download_job_factory.cc
index 2f60eca..0087d61 100644
--- a/components/download/internal/common/download_job_factory.cc
+++ b/components/download/internal/common/download_job_factory.cc
@@ -7,12 +7,12 @@
 #include <memory>
 
 #include "base/memory/ptr_util.h"
+#include "components/download/internal/common/download_job_impl.h"
+#include "components/download/internal/common/parallel_download_job.h"
+#include "components/download/internal/common/parallel_download_utils.h"
+#include "components/download/internal/common/save_package_download_job.h"
 #include "components/download/public/common/download_item.h"
-#include "components/download/public/common/download_job_impl.h"
 #include "components/download/public/common/download_stats.h"
-#include "components/download/public/common/parallel_download_job.h"
-#include "components/download/public/common/parallel_download_utils.h"
-#include "components/download/public/common/save_package_download_job.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace download {
diff --git a/components/download/internal/common/download_job_impl.cc b/components/download/internal/common/download_job_impl.cc
index 43b515af..e653a87 100644
--- a/components/download/internal/common/download_job_impl.cc
+++ b/components/download/internal/common/download_job_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/download/public/common/download_job_impl.h"
+#include "components/download/internal/common/download_job_impl.h"
 
 namespace download {
 
diff --git a/components/download/public/common/download_job_impl.h b/components/download/internal/common/download_job_impl.h
similarity index 80%
rename from components/download/public/common/download_job_impl.h
rename to components/download/internal/common/download_job_impl.h
index e580caf2..5be902d 100644
--- a/components/download/public/common/download_job_impl.h
+++ b/components/download/internal/common/download_job_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_JOB_IMPL_H_
-#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_JOB_IMPL_H_
+#ifndef COMPONENTS_DOWNLOAD_INTERNAL_COMMON_DOWNLOAD_JOB_IMPL_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_COMMON_DOWNLOAD_JOB_IMPL_H_
 
 #include "components/download/public/common/download_export.h"
 #include "components/download/public/common/download_job.h"
@@ -32,4 +32,4 @@
 
 }  //  namespace download
 
-#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_JOB_IMPL_H_
+#endif  // COMPONENTS_DOWNLOAD_INTERNAL_COMMON_DOWNLOAD_JOB_IMPL_H_
diff --git a/components/download/internal/common/download_worker.cc b/components/download/internal/common/download_worker.cc
index b49ce93..c05b1f8a 100644
--- a/components/download/internal/common/download_worker.cc
+++ b/components/download/internal/common/download_worker.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/download/public/common/download_worker.h"
+#include "components/download/internal/common/download_worker.h"
 
 #include "base/message_loop/message_loop.h"
 #include "components/download/public/common/download_create_info.h"
diff --git a/components/download/public/common/download_worker.h b/components/download/internal/common/download_worker.h
similarity index 95%
rename from components/download/public/common/download_worker.h
rename to components/download/internal/common/download_worker.h
index 8865f28..8996f08 100644
--- a/components/download/public/common/download_worker.h
+++ b/components/download/internal/common/download_worker.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 COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_WORKER_H_
-#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_WORKER_H_
+#ifndef COMPONENTS_DOWNLOAD_INTERNAL_COMMON_DOWNLOAD_WORKER_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_COMMON_DOWNLOAD_WORKER_H_
 
 #include <memory>
 
diff --git a/components/download/internal/common/parallel_download_job.cc b/components/download/internal/common/parallel_download_job.cc
index 202d3b29..d1d3e0b8 100644
--- a/components/download/internal/common/parallel_download_job.cc
+++ b/components/download/internal/common/parallel_download_job.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/download/public/common/parallel_download_job.h"
+#include "components/download/internal/common/parallel_download_job.h"
 
 #include <algorithm>
 
@@ -10,9 +10,9 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
+#include "components/download/internal/common/parallel_download_utils.h"
 #include "components/download/public/common/download_create_info.h"
 #include "components/download/public/common/download_stats.h"
-#include "components/download/public/common/parallel_download_utils.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace download {
diff --git a/components/download/public/common/parallel_download_job.h b/components/download/internal/common/parallel_download_job.h
similarity index 90%
rename from components/download/public/common/parallel_download_job.h
rename to components/download/internal/common/parallel_download_job.h
index 50f2d9a1..c37fb07 100644
--- a/components/download/public/common/parallel_download_job.h
+++ b/components/download/internal/common/parallel_download_job.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 COMPONENTS_DOWNLOAD_PUBLIC_COMMON_PARALLEL_DOWNLOAD_JOB_H_
-#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_PARALLEL_DOWNLOAD_JOB_H_
+#ifndef COMPONENTS_DOWNLOAD_INTERNAL_COMMON_PARALLEL_DOWNLOAD_JOB_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_COMMON_PARALLEL_DOWNLOAD_JOB_H_
 
 #include <memory>
 #include <unordered_map>
@@ -11,9 +11,10 @@
 
 #include "base/macros.h"
 #include "base/timer/timer.h"
+#include "components/download/internal/common/download_job_impl.h"
+#include "components/download/internal/common/download_worker.h"
 #include "components/download/public/common/download_export.h"
-#include "components/download/public/common/download_job_impl.h"
-#include "components/download/public/common/download_worker.h"
+#include "components/download/public/common/parallel_download_configs.h"
 
 namespace net {
 class URLRequestContextGetter;
@@ -121,4 +122,4 @@
 
 }  //  namespace download
 
-#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_PARALLEL_DOWNLOAD_JOB_H_
+#endif  // COMPONENTS_DOWNLOAD_INTERNAL_COMMON_PARALLEL_DOWNLOAD_JOB_H_
diff --git a/components/download/internal/common/parallel_download_job_unittest.cc b/components/download/internal/common/parallel_download_job_unittest.cc
index 490b7a8..e422666 100644
--- a/components/download/internal/common/parallel_download_job_unittest.cc
+++ b/components/download/internal/common/parallel_download_job_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 "components/download/public/common/parallel_download_job.h"
+#include "components/download/internal/common/parallel_download_job.h"
 
 #include <utility>
 #include <vector>
@@ -11,13 +11,13 @@
 #include "base/run_loop.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
+#include "components/download/internal/common/parallel_download_utils.h"
 #include "components/download/public/common/download_create_info.h"
 #include "components/download/public/common/download_destination_observer.h"
 #include "components/download/public/common/download_file_impl.h"
 #include "components/download/public/common/download_task_runner.h"
 #include "components/download/public/common/mock_download_item.h"
 #include "components/download/public/common/mock_input_stream.h"
-#include "components/download/public/common/parallel_download_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/download/internal/common/parallel_download_utils.cc b/components/download/internal/common/parallel_download_utils.cc
index f1c56cf..88148139 100644
--- a/components/download/internal/common/parallel_download_utils.cc
+++ b/components/download/internal/common/parallel_download_utils.cc
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/download/public/common/parallel_download_utils.h"
+#include "components/download/internal/common/parallel_download_utils.h"
 
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 #include "components/download/public/common/download_features.h"
 #include "components/download/public/common/download_save_info.h"
+#include "components/download/public/common/parallel_download_configs.h"
 
 namespace download {
 
diff --git a/components/download/public/common/parallel_download_utils.h b/components/download/internal/common/parallel_download_utils.h
similarity index 70%
rename from components/download/public/common/parallel_download_utils.h
rename to components/download/internal/common/parallel_download_utils.h
index 2e76d9b..eab3eb0 100644
--- a/components/download/public/common/parallel_download_utils.h
+++ b/components/download/internal/common/parallel_download_utils.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 COMPONENTS_DOWNLOAD_PUBLIC_COMMON_PARALLEL_DOWNLOAD_UTILS_H_
-#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_PARALLEL_DOWNLOAD_UTILS_H_
+#ifndef COMPONENTS_DOWNLOAD_INTERNAL_COMMON_PARALLEL_DOWNLOAD_UTILS_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_COMMON_PARALLEL_DOWNLOAD_UTILS_H_
 
 #include <vector>
 
@@ -11,32 +11,8 @@
 #include "components/download/public/common/download_file_impl.h"
 #include "components/download/public/common/download_item.h"
 
-// TODO(qinmin): move all the code here to parallel_download_utils_impl.h once
-// parallel download code is moved to components/download.
 namespace download {
 
-// Finch parameter key value to enable parallel download. Used in enabled
-// experiment group that needs other parameters, such as min_slice_size, but
-// don't want to actually do parallel download.
-constexpr char kEnableParallelDownloadFinchKey[] = "enable_parallel_download";
-
-// Finch parameter key value for minimum slice size in bytes to use parallel
-// download.
-constexpr char kMinSliceSizeFinchKey[] = "min_slice_size";
-
-// Finch parameter key value for number of parallel requests in a parallel
-// download, including the original request.
-constexpr char kParallelRequestCountFinchKey[] = "request_count";
-
-// Finch parameter key value for the delay time in milliseconds to send
-// parallel requests after response of the original request is handled.
-constexpr char kParallelRequestDelayFinchKey[] = "parallel_request_delay";
-
-// Finch parameter key value for the remaining time in seconds that is required
-// to send parallel requests.
-constexpr char kParallelRequestRemainingTimeFinchKey[] =
-    "parallel_request_remaining_time";
-
 // Given an array of slices that are received, returns an array of slices to
 // download. |received_slices| must be ordered by offsets.
 COMPONENTS_DOWNLOAD_EXPORT std::vector<DownloadItem::ReceivedSlice>
@@ -100,4 +76,4 @@
 
 }  //  namespace download
 
-#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_PARALLEL_DOWNLOAD_UTILS_H_
+#endif  // COMPONENTS_DOWNLOAD_INTERNAL_COMMON_PARALLEL_DOWNLOAD_UTILS_H_
diff --git a/components/download/internal/common/parallel_download_utils_unittest.cc b/components/download/internal/common/parallel_download_utils_unittest.cc
index 5a239a0..7981868 100644
--- a/components/download/internal/common/parallel_download_utils_unittest.cc
+++ b/components/download/internal/common/parallel_download_utils_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 "components/download/public/common/parallel_download_utils.h"
+#include "components/download/internal/common/parallel_download_utils.h"
 
 #include <map>
 #include <memory>
@@ -13,7 +13,7 @@
 #include "components/download/public/common/download_file_impl.h"
 #include "components/download/public/common/download_save_info.h"
 #include "components/download/public/common/mock_input_stream.h"
-#include "components/download/public/common/parallel_download_utils.h"
+#include "components/download/public/common/parallel_download_configs.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/download/internal/common/save_package_download_job.cc b/components/download/internal/common/save_package_download_job.cc
index 8c505b0..ae0c927 100644
--- a/components/download/internal/common/save_package_download_job.cc
+++ b/components/download/internal/common/save_package_download_job.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/download/public/common/save_package_download_job.h"
+#include "components/download/internal/common/save_package_download_job.h"
 
 namespace download {
 
diff --git a/components/download/public/common/save_package_download_job.h b/components/download/internal/common/save_package_download_job.h
similarity index 68%
rename from components/download/public/common/save_package_download_job.h
rename to components/download/internal/common/save_package_download_job.h
index f9c032d..fea7fb1 100644
--- a/components/download/public/common/save_package_download_job.h
+++ b/components/download/internal/common/save_package_download_job.h
@@ -2,18 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_DOWNLOAD_PUBLIC_COMMON_SAVE_PACKAGE_DOWNLOAD_JOB_H_
-#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_SAVE_PACKAGE_DOWNLOAD_JOB_H_
+#ifndef COMPONENTS_DOWNLOAD_INTERNAL_COMMON_SAVE_PACKAGE_DOWNLOAD_JOB_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_COMMON_SAVE_PACKAGE_DOWNLOAD_JOB_H_
 
 #include "base/macros.h"
-#include "components/download/public/common/download_export.h"
 #include "components/download/public/common/download_item.h"
 #include "components/download/public/common/download_job.h"
 #include "components/download/public/common/download_request_handle_interface.h"
 
 namespace download {
 
-class COMPONENTS_DOWNLOAD_EXPORT SavePackageDownloadJob : public DownloadJob {
+class SavePackageDownloadJob : public DownloadJob {
  public:
   SavePackageDownloadJob(
       DownloadItem* download_item,
@@ -29,4 +28,4 @@
 
 }  //  namespace download
 
-#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_SAVE_PACKAGE_DOWNLOAD_JOB_H_
+#endif  // COMPONENTS_DOWNLOAD_INTERNAL_COMMON_SAVE_PACKAGE_DOWNLOAD_JOB_H_
diff --git a/components/download/public/common/BUILD.gn b/components/download/public/common/BUILD.gn
index 8dd829e..046a9d0 100644
--- a/components/download/public/common/BUILD.gn
+++ b/components/download/public/common/BUILD.gn
@@ -30,11 +30,12 @@
     "download_interrupt_reasons.h",
     "download_interrupt_reasons_utils.h",
     "download_item.h",
+    "download_item_factory.cc",
+    "download_item_factory.h",
     "download_item_impl.h",
     "download_item_impl_delegate.h",
     "download_job.h",
     "download_job_factory.h",
-    "download_job_impl.h",
     "download_request_handle_interface.h",
     "download_response_handler.h",
     "download_save_info.cc",
@@ -46,15 +47,12 @@
     "download_url_parameters.cc",
     "download_url_parameters.h",
     "download_utils.h",
-    "download_worker.h",
     "input_stream.cc",
     "input_stream.h",
-    "parallel_download_job.h",
-    "parallel_download_utils.h",
+    "parallel_download_configs.h",
     "rate_estimator.h",
     "resource_downloader.h",
     "resume_mode.h",
-    "save_package_download_job.h",
     "stream_handle_input_stream.h",
     "url_download_handler_factory.h",
   ]
@@ -122,6 +120,8 @@
     "mock_download_file.h",
     "mock_download_item.cc",
     "mock_download_item.h",
+    "mock_download_item_impl.cc",
+    "mock_download_item_impl.h",
     "mock_input_stream.cc",
     "mock_input_stream.h",
   ]
@@ -129,6 +129,7 @@
   public_deps = [
     ":public",
     "//base",
+    "//net",
     "//testing/gmock",
     "//url",
   ]
diff --git a/components/download/public/common/download_item_factory.cc b/components/download/public/common/download_item_factory.cc
new file mode 100644
index 0000000..bfbc08a
--- /dev/null
+++ b/components/download/public/common/download_item_factory.cc
@@ -0,0 +1,15 @@
+// Copyright 2018 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.
+//
+// The DownloadItemFactory is used to produce different DownloadItems.
+// It is separate from the DownloadManager to allow download manager
+// unit tests to control the items produced.
+
+#include "components/download/public/common/download_item_factory.h"
+
+namespace download {
+
+DownloadItemFactory::~DownloadItemFactory() = default;
+
+}  // namespace download
diff --git a/components/download/public/common/download_item_factory.h b/components/download/public/common/download_item_factory.h
new file mode 100644
index 0000000..0ceeea5
--- /dev/null
+++ b/components/download/public/common/download_item_factory.h
@@ -0,0 +1,82 @@
+// 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.
+//
+// The DownloadItemFactory is used to produce different DownloadItems.
+// It is separate from the DownloadManager to allow download manager
+// unit tests to control the items produced.
+
+#ifndef COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_ITEM_FACTORY_H_
+#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_ITEM_FACTORY_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "components/download/public/common/download_export.h"
+#include "components/download/public/common/download_item.h"
+
+class GURL;
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace download {
+
+struct DownloadCreateInfo;
+class DownloadItemImpl;
+class DownloadItemImplDelegate;
+class DownloadRequestHandleInterface;
+
+class COMPONENTS_DOWNLOAD_EXPORT DownloadItemFactory {
+ public:
+  virtual ~DownloadItemFactory();
+
+  virtual DownloadItemImpl* CreatePersistedItem(
+      DownloadItemImplDelegate* delegate,
+      const std::string& guid,
+      uint32_t download_id,
+      const base::FilePath& current_path,
+      const base::FilePath& target_path,
+      const std::vector<GURL>& url_chain,
+      const GURL& referrer_url,
+      const GURL& site_url,
+      const GURL& tab_url,
+      const GURL& tab_refererr_url,
+      const std::string& mime_type,
+      const std::string& original_mime_type,
+      base::Time start_time,
+      base::Time end_time,
+      const std::string& etag,
+      const std::string& last_modified,
+      int64_t received_bytes,
+      int64_t total_bytes,
+      const std::string& hash,
+      DownloadItem::DownloadState state,
+      DownloadDangerType danger_type,
+      DownloadInterruptReason interrupt_reason,
+      bool opened,
+      base::Time last_access_time,
+      bool transient,
+      const std::vector<DownloadItem::ReceivedSlice>& received_slices) = 0;
+
+  virtual DownloadItemImpl* CreateActiveItem(
+      DownloadItemImplDelegate* delegate,
+      uint32_t download_id,
+      const DownloadCreateInfo& info) = 0;
+
+  virtual DownloadItemImpl* CreateSavePageItem(
+      DownloadItemImplDelegate* delegate,
+      uint32_t download_id,
+      const base::FilePath& path,
+      const GURL& url,
+      const std::string& mime_type,
+      std::unique_ptr<DownloadRequestHandleInterface> request_handle) = 0;
+};
+
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_ITEM_FACTORY_H_
diff --git a/components/download/public/common/mock_download_item_impl.cc b/components/download/public/common/mock_download_item_impl.cc
new file mode 100644
index 0000000..176e5df
--- /dev/null
+++ b/components/download/public/common/mock_download_item_impl.cc
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/download/public/common/mock_download_item_impl.h"
+
+namespace download {
+
+MockDownloadItemImpl::MockDownloadItemImpl(DownloadItemImplDelegate* delegate)
+    : DownloadItemImpl(delegate,
+                       std::string("7d122682-55b5-4a47-a253-36cadc3e5bee"),
+                       DownloadItem::kInvalidId,
+                       base::FilePath(),
+                       base::FilePath(),
+                       std::vector<GURL>(),
+                       GURL(),
+                       GURL(),
+                       GURL(),
+                       GURL(),
+                       "application/octet-stream",
+                       "application/octet-stream",
+                       base::Time(),
+                       base::Time(),
+                       std::string(),
+                       std::string(),
+                       0,
+                       0,
+                       std::string(),
+                       DownloadItem::COMPLETE,
+                       DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+                       DOWNLOAD_INTERRUPT_REASON_NONE,
+                       false,
+                       base::Time(),
+                       true,
+                       DownloadItem::ReceivedSlices()) {}
+
+MockDownloadItemImpl::~MockDownloadItemImpl() = default;
+
+}  // namespace download
diff --git a/content/browser/download/mock_download_item_impl.h b/components/download/public/common/mock_download_item_impl.h
similarity index 79%
rename from content/browser/download/mock_download_item_impl.h
rename to components/download/public/common/mock_download_item_impl.h
index d0eb549..752eda53 100644
--- a/content/browser/download/mock_download_item_impl.h
+++ b/components/download/public/common/mock_download_item_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_DOWNLOAD_MOCK_DOWNLOAD_ITEM_IMPL_H_
-#define CONTENT_BROWSER_DOWNLOAD_MOCK_DOWNLOAD_ITEM_IMPL_H_
+#ifndef COMPONENTS_DOWNLOAD_PUBLIC_COMMON_MOCK_DOWNLOAD_ITEM_IMPL_H_
+#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_MOCK_DOWNLOAD_ITEM_IMPL_H_
 
 #include <memory>
 #include <string>
@@ -16,24 +16,24 @@
 #include "components/download/public/common/download_request_handle_interface.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-namespace content {
+namespace download {
 
 class DownloadManager;
 
-class MockDownloadItemImpl : public download::DownloadItemImpl {
+class MockDownloadItemImpl : public DownloadItemImpl {
  public:
   // Use history constructor for minimal base object.
-  explicit MockDownloadItemImpl(download::DownloadItemImplDelegate* delegate);
+  explicit MockDownloadItemImpl(DownloadItemImplDelegate* delegate);
   ~MockDownloadItemImpl() override;
 
   MOCK_METHOD5(OnDownloadTargetDetermined,
                void(const base::FilePath&,
                     TargetDisposition,
-                    download::DownloadDangerType,
+                    DownloadDangerType,
                     const base::FilePath&,
-                    download::DownloadInterruptReason));
-  MOCK_METHOD1(AddObserver, void(download::DownloadItem::Observer*));
-  MOCK_METHOD1(RemoveObserver, void(download::DownloadItem::Observer*));
+                    DownloadInterruptReason));
+  MOCK_METHOD1(AddObserver, void(DownloadItem::Observer*));
+  MOCK_METHOD1(RemoveObserver, void(DownloadItem::Observer*));
   MOCK_METHOD0(UpdateObservers, void());
   MOCK_METHOD0(CanShowInFolder, bool());
   MOCK_METHOD0(CanOpenDownload, bool());
@@ -50,17 +50,15 @@
   }
   MOCK_METHOD0(OnDownloadedFileRemoved, void());
   void Start(
-      std::unique_ptr<download::DownloadFile> download_file,
-      std::unique_ptr<download::DownloadRequestHandleInterface> req_handle,
-      const download::DownloadCreateInfo& create_info,
+      std::unique_ptr<DownloadFile> download_file,
+      std::unique_ptr<DownloadRequestHandleInterface> req_handle,
+      const DownloadCreateInfo& create_info,
       scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
       net::URLRequestContextGetter* url_request_context_getter) override {
     MockStart(download_file.get(), req_handle.get());
   }
 
-  MOCK_METHOD2(MockStart,
-               void(download::DownloadFile*,
-                    download::DownloadRequestHandleInterface*));
+  MOCK_METHOD2(MockStart, void(DownloadFile*, DownloadRequestHandleInterface*));
 
   MOCK_METHOD0(Remove, void());
   MOCK_CONST_METHOD1(TimeRemaining, bool(base::TimeDelta*));
@@ -73,8 +71,7 @@
   MOCK_CONST_METHOD0(GetTargetFilePath, const base::FilePath&());
   MOCK_CONST_METHOD0(GetTargetDisposition, TargetDisposition());
   MOCK_METHOD2(OnContentCheckCompleted,
-               void(download::DownloadDangerType,
-                    download::DownloadInterruptReason));
+               void(DownloadDangerType, DownloadInterruptReason));
   MOCK_CONST_METHOD0(GetState, DownloadState());
   MOCK_CONST_METHOD0(GetUrlChain, const std::vector<GURL>&());
   MOCK_METHOD1(SetTotalBytes, void(int64_t));
@@ -103,7 +100,7 @@
   MOCK_CONST_METHOD0(GetOpenWhenComplete, bool());
   MOCK_METHOD1(SetOpenWhenComplete, void(bool));
   MOCK_CONST_METHOD0(GetFileExternallyRemoved, bool());
-  MOCK_CONST_METHOD0(GetDangerType, download::DownloadDangerType());
+  MOCK_CONST_METHOD0(GetDangerType, DownloadDangerType());
   MOCK_CONST_METHOD0(IsDangerous, bool());
   MOCK_METHOD0(GetAutoOpened, bool());
   MOCK_CONST_METHOD0(GetForcedFilePath, const base::FilePath&());
@@ -115,12 +112,13 @@
   MOCK_CONST_METHOD0(GetLastAccessTime, base::Time());
   MOCK_CONST_METHOD0(GetLastModifiedTime, const std::string&());
   MOCK_CONST_METHOD0(GetETag, const std::string&());
-  MOCK_CONST_METHOD0(GetLastReason, download::DownloadInterruptReason());
+  MOCK_CONST_METHOD0(GetLastReason, DownloadInterruptReason());
   MOCK_CONST_METHOD0(GetFileNameToReportUser, base::FilePath());
   MOCK_METHOD1(SetDisplayName, void(const base::FilePath&));
   // May be called when vlog is on.
   std::string DebugString(bool verbose) const override { return std::string(); }
 };
-}  // namespace content
 
-#endif  // CONTENT_BROWSER_DOWNLOAD_MOCK_DOWNLOAD_ITEM_IMPL_H_
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_MOCK_DOWNLOAD_ITEM_IMPL_H_
diff --git a/components/download/public/common/parallel_download_configs.h b/components/download/public/common/parallel_download_configs.h
new file mode 100644
index 0000000..25ade91b
--- /dev/null
+++ b/components/download/public/common/parallel_download_configs.h
@@ -0,0 +1,34 @@
+// Copyright 2018 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_DOWNLOAD_PUBLIC_COMMON_PARALLEL_DOWNLOAD_CONFIGS_H_
+#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_PARALLEL_DOWNLOAD_CONFIGS_H_
+
+namespace download {
+
+// Finch parameter key value to enable parallel download. Used in enabled
+// experiment group that needs other parameters, such as min_slice_size, but
+// don't want to actually do parallel download.
+constexpr char kEnableParallelDownloadFinchKey[] = "enable_parallel_download";
+
+// Finch parameter key value for minimum slice size in bytes to use parallel
+// download.
+constexpr char kMinSliceSizeFinchKey[] = "min_slice_size";
+
+// Finch parameter key value for number of parallel requests in a parallel
+// download, including the original request.
+constexpr char kParallelRequestCountFinchKey[] = "request_count";
+
+// Finch parameter key value for the delay time in milliseconds to send
+// parallel requests after response of the original request is handled.
+constexpr char kParallelRequestDelayFinchKey[] = "parallel_request_delay";
+
+// Finch parameter key value for the remaining time in seconds that is required
+// to send parallel requests.
+constexpr char kParallelRequestRemainingTimeFinchKey[] =
+    "parallel_request_remaining_time";
+
+}  //  namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_PARALLEL_DOWNLOAD_CONFIGS_H_
diff --git a/components/mirroring/service/BUILD.gn b/components/mirroring/service/BUILD.gn
index 3e2ee46..a8f92d0 100644
--- a/components/mirroring/service/BUILD.gn
+++ b/components/mirroring/service/BUILD.gn
@@ -4,10 +4,30 @@
 
 import("//testing/test.gni")
 
+source_set("interface") {
+  sources = [
+    "interface.h",
+  ]
+
+  public_deps = [
+    "//base",
+  ]
+
+  deps = [
+    "//media/capture/mojom:video_capture",
+    "//media/cast:common",
+    "//media/mojo/interfaces",
+    "//net",
+    "//services/network/public/mojom",
+  ]
+}
+
 source_set("service") {
   sources = [
     "rtp_stream.cc",
     "rtp_stream.h",
+    "session.cc",
+    "session.h",
     "udp_socket_client.cc",
     "udp_socket_client.h",
     "video_capture_client.cc",
@@ -19,6 +39,7 @@
   ]
 
   deps = [
+    ":interface",
     "//media",
     "//media/capture/mojom:video_capture",
     "//media/cast:common",
@@ -26,6 +47,7 @@
     "//media/cast:sender",
     "//media/mojo/common:common",
     "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/system",
     "//net",
     "//services/network/public/mojom",
     "//ui/gfx",
@@ -37,12 +59,16 @@
   sources = [
     "fake_network_service.cc",
     "fake_network_service.h",
+    "fake_video_capture_host.cc",
+    "fake_video_capture_host.h",
     "rtp_stream_unittest.cc",
+    "session_unittest.cc",
     "udp_socket_client_unittest.cc",
     "video_capture_client_unittest.cc",
   ]
 
   deps = [
+    ":interface",
     ":service",
     "//base",
     "//base/test:test_support",
@@ -52,6 +78,7 @@
     "//media/cast:net",
     "//media/cast:sender",
     "//media/cast:test_support",
+    "//media/cast:test_support",
     "//mojo/public/cpp/bindings",
     "//net",
     "//services/network/public/mojom",
diff --git a/components/mirroring/service/fake_network_service.h b/components/mirroring/service/fake_network_service.h
index cdc0062..8237bef 100644
--- a/components/mirroring/service/fake_network_service.h
+++ b/components/mirroring/service/fake_network_service.h
@@ -88,6 +88,11 @@
       const std::string& profile_id,
       network::mojom::NetworkConditionsPtr conditions) override {}
   void SetAcceptLanguage(const std::string& new_accept_language) override {}
+  void SetCTPolicy(
+      const std::vector<std::string>& required_hosts,
+      const std::vector<std::string>& excluded_hosts,
+      const std::vector<std::string>& excluded_spkis,
+      const std::vector<std::string>& excluded_legacy_spkis) override {}
   void AddHSTSForTesting(const std::string& host,
                          base::Time expiry,
                          bool include_subdomains,
diff --git a/components/mirroring/service/fake_video_capture_host.cc b/components/mirroring/service/fake_video_capture_host.cc
new file mode 100644
index 0000000..b3552f4
--- /dev/null
+++ b/components/mirroring/service/fake_video_capture_host.cc
@@ -0,0 +1,56 @@
+// Copyright 2018 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/mirroring/service/fake_video_capture_host.h"
+
+#include "media/base/video_frame.h"
+#include "mojo/public/cpp/system/buffer.h"
+
+namespace mirroring {
+
+FakeVideoCaptureHost::FakeVideoCaptureHost(
+    media::mojom::VideoCaptureHostRequest request)
+    : binding_(this, std::move(request)) {}
+FakeVideoCaptureHost::~FakeVideoCaptureHost() {}
+
+void FakeVideoCaptureHost::Start(
+    int32_t device_id,
+    int32_t session_id,
+    const media::VideoCaptureParams& params,
+    media::mojom::VideoCaptureObserverPtr observer) {
+  ASSERT_TRUE(observer);
+  observer_ = std::move(observer);
+  observer_->OnStateChanged(media::mojom::VideoCaptureState::STARTED);
+}
+
+void FakeVideoCaptureHost::Stop(int32_t device_id) {
+  if (!observer_)
+    return;
+
+  observer_->OnStateChanged(media::mojom::VideoCaptureState::ENDED);
+  observer_.reset();
+  OnStopped();
+}
+
+void FakeVideoCaptureHost::SendOneFrame(const gfx::Size& size,
+                                        base::TimeTicks capture_time) {
+  if (!observer_)
+    return;
+
+  mojo::ScopedSharedBufferHandle buffer =
+      mojo::SharedBufferHandle::Create(5000);
+  memset(buffer->Map(5000).get(), 125, 5000);
+  observer_->OnBufferCreated(0, std::move(buffer));
+  media::VideoFrameMetadata metadata;
+  metadata.SetDouble(media::VideoFrameMetadata::FRAME_RATE, 30);
+  metadata.SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME,
+                        capture_time);
+  observer_->OnBufferReady(
+      0, media::mojom::VideoFrameInfo::New(
+             base::TimeDelta(), metadata.CopyInternalValues(),
+             media::PIXEL_FORMAT_I420, media::VideoPixelStorage::CPU, size,
+             gfx::Rect(size)));
+}
+
+}  // namespace mirroring
diff --git a/components/mirroring/service/fake_video_capture_host.h b/components/mirroring/service/fake_video_capture_host.h
new file mode 100644
index 0000000..f74af05
--- /dev/null
+++ b/components/mirroring/service/fake_video_capture_host.h
@@ -0,0 +1,54 @@
+// Copyright 2018 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_MIRRORING_SERVICE_FAKE_VIDEO_CAPTURE_HOST_H_
+#define COMPONENTS_MIRRORING_SERVICE_FAKE_VIDEO_CAPTURE_HOST_H_
+
+#include "media/capture/mojom/video_capture.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mirroring {
+
+class FakeVideoCaptureHost final : public media::mojom::VideoCaptureHost {
+ public:
+  explicit FakeVideoCaptureHost(media::mojom::VideoCaptureHostRequest request);
+  ~FakeVideoCaptureHost() override;
+
+  // mojom::VideoCaptureHost implementations
+  MOCK_METHOD1(RequestRefreshFrame, void(int32_t));
+  MOCK_METHOD3(ReleaseBuffer, void(int32_t, int32_t, double));
+  MOCK_METHOD1(Pause, void(int32_t));
+  MOCK_METHOD3(Resume,
+               void(int32_t, int32_t, const media::VideoCaptureParams&));
+  MOCK_METHOD0(OnStopped, void());
+
+  void Start(int32_t device_id,
+             int32_t session_id,
+             const media::VideoCaptureParams& params,
+             media::mojom::VideoCaptureObserverPtr observer) override;
+  void Stop(int32_t device_id) override;
+
+  void GetDeviceSupportedFormats(
+      int32_t device_id,
+      int32_t session_id,
+      GetDeviceSupportedFormatsCallback callback) override {}
+  void GetDeviceFormatsInUse(int32_t device_id,
+                             int32_t session_id,
+                             GetDeviceFormatsInUseCallback callback) override {}
+
+  // Create one video frame and send it to |observer_|.
+  void SendOneFrame(const gfx::Size& size, base::TimeTicks capture_time);
+
+ private:
+  mojo::Binding<media::mojom::VideoCaptureHost> binding_;
+  media::mojom::VideoCaptureObserverPtr observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeVideoCaptureHost);
+};
+
+}  // namespace mirroring
+
+#endif  // COMPONENTS_MIRRORING_SERVICE_FAKE_VIDEO_CAPTURE_HOST_H_
diff --git a/components/mirroring/service/interface.h b/components/mirroring/service/interface.h
new file mode 100644
index 0000000..501280ef
--- /dev/null
+++ b/components/mirroring/service/interface.h
@@ -0,0 +1,72 @@
+// Copyright 2018 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_MIRRORING_SERVICE_INTERFACE_H_
+#define COMPONENTS_MIRRORING_SERVICE_INTERFACE_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/values.h"
+#include "media/capture/mojom/video_capture.mojom.h"
+#include "media/cast/cast_config.h"
+#include "net/base/ip_endpoint.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+
+namespace mirroring {
+
+// TODO(xjz): All interfaces defined in this file will be replaced with mojo
+// interfaces.
+
+// Errors occurred in a mirroring session.
+enum SessionError {
+  SESSION_START_ERROR,   // Error occurred while starting.
+  AUDIO_CAPTURE_ERROR,   // Error occurred in audio capturing.
+  VIDEO_CAPTURE_ERROR,   // Error occurred in video capturing.
+  CAST_STREAMING_ERROR,  // Error occurred in cast streaming.
+  CAST_TRANSPORT_ERROR,  // Error occurred in cast transport.
+};
+
+enum SessionType {
+  AUDIO_ONLY,
+  VIDEO_ONLY,
+  AUDIO_AND_VIDEO,
+};
+
+class SessionClient {
+ public:
+  virtual ~SessionClient() {}
+
+  // Called when error occurred. The session will be stopped.
+  virtual void OnError(SessionError error) = 0;
+
+  // Called when session completes starting.
+  virtual void DidStart() = 0;
+
+  // Called when the session is stopped.
+  virtual void DidStop() = 0;
+
+  virtual void GetVideoCaptureHost(
+      media::mojom::VideoCaptureHostRequest request) = 0;
+  virtual void GetNewWorkContext(
+      network::mojom::NetworkContextRequest request) = 0;
+  // TODO(xjz): Add interface to get AudioCaptureHost.
+  // TODO(xjz): Add interface for HW encoder profiles query and VEA create
+  // support.
+
+  // TODO(xjz): Change this with an interface to send/receive messages to/from
+  // receiver through cast channel, and generate/parse the OFFER/ANSWER message
+  // in Mirroing service.
+  using GetAnswerCallback = base::OnceCallback<void(
+      const media::cast::FrameSenderConfig& audio_config,
+      const media::cast::FrameSenderConfig& video_config)>;
+  virtual void DoOfferAnswerExchange(
+      const std::vector<media::cast::FrameSenderConfig>& audio_configs,
+      const std::vector<media::cast::FrameSenderConfig>& video_configs,
+      GetAnswerCallback callback) = 0;
+};
+
+}  // namespace mirroring
+
+#endif  // COMPONENTS_MIRRORING_SERVICE_INTERFACE_H_
diff --git a/components/mirroring/service/rtp_stream.cc b/components/mirroring/service/rtp_stream.cc
index d892b186..1051557 100644
--- a/components/mirroring/service/rtp_stream.cc
+++ b/components/mirroring/service/rtp_stream.cc
@@ -175,6 +175,10 @@
   video_sender_->InsertRawVideoFrame(std::move(video_frame), reference_time);
 }
 
+void VideoRtpStream::SetTargetPlayoutDelay(base::TimeDelta playout_delay) {
+  video_sender_->SetTargetPlayoutDelay(playout_delay);
+}
+
 void VideoRtpStream::OnRefreshTimerFired() {
   ++consecutive_refresh_count_;
   if (consecutive_refresh_count_ >= kMaxConsecutiveRefreshFrames)
@@ -211,4 +215,8 @@
   audio_sender_->InsertAudio(std::move(audio_bus), capture_time);
 }
 
+void AudioRtpStream::SetTargetPlayoutDelay(base::TimeDelta playout_delay) {
+  audio_sender_->SetTargetPlayoutDelay(playout_delay);
+}
+
 }  // namespace mirroring
diff --git a/components/mirroring/service/rtp_stream.h b/components/mirroring/service/rtp_stream.h
index 919e298..ef5788d 100644
--- a/components/mirroring/service/rtp_stream.h
+++ b/components/mirroring/service/rtp_stream.h
@@ -78,6 +78,12 @@
   // |video_frame| is required to provide REFERENCE_TIME in the metadata.
   void InsertVideoFrame(scoped_refptr<media::VideoFrame> video_frame);
 
+  base::WeakPtr<VideoRtpStream> AsWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
+
+  void SetTargetPlayoutDelay(base::TimeDelta playout_delay);
+
  private:
   void OnRefreshTimerFired();
 
@@ -115,6 +121,8 @@
   void InsertAudio(std::unique_ptr<media::AudioBus> audio_bus,
                    base::TimeTicks estimated_capture_time);
 
+  void SetTargetPlayoutDelay(base::TimeDelta playout_delay);
+
  private:
   const std::unique_ptr<media::cast::AudioSender> audio_sender_;
   const base::WeakPtr<RtpStreamClient> client_;
diff --git a/components/mirroring/service/session.cc b/components/mirroring/service/session.cc
new file mode 100644
index 0000000..1d97af99
--- /dev/null
+++ b/components/mirroring/service/session.cc
@@ -0,0 +1,326 @@
+// Copyright 2018 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/mirroring/service/session.h"
+
+#include "base/logging.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
+#include "components/mirroring/service/udp_socket_client.h"
+#include "components/mirroring/service/video_capture_client.h"
+#include "media/cast/net/cast_transport.h"
+#include "media/cast/sender/audio_sender.h"
+#include "media/cast/sender/video_sender.h"
+#include "media/video/video_encode_accelerator.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+using media::cast::FrameSenderConfig;
+using media::cast::RtpPayloadType;
+using media::cast::CastTransportStatus;
+using media::cast::FrameEvent;
+using media::cast::PacketEvent;
+using media::cast::OperationalStatus;
+using media::cast::Packet;
+
+namespace mirroring {
+
+namespace {
+
+// The interval for CastTransport to send Frame/PacketEvents to Session for
+// logging.
+constexpr base::TimeDelta kSendEventsInterval = base::TimeDelta::FromSeconds(1);
+
+// The duration for OFFER/ANSWER exchange. If timeout, notify the client that
+// the session failed to start.
+constexpr base::TimeDelta kOfferAnswerExchangeTimeout =
+    base::TimeDelta::FromSeconds(15);
+
+class TransportClient final : public media::cast::CastTransport::Client {
+ public:
+  explicit TransportClient(Session* session) : session_(session) {}
+  ~TransportClient() override {}
+
+  // media::cast::CastTransport::Client implementation.
+
+  void OnStatusChanged(CastTransportStatus status) override {
+    session_->OnTransportStatusChanged(status);
+  }
+
+  void OnLoggingEventsReceived(
+      std::unique_ptr<std::vector<FrameEvent>> frame_events,
+      std::unique_ptr<std::vector<PacketEvent>> packet_events) override {
+    session_->OnLoggingEventsReceived(std::move(frame_events),
+                                      std::move(packet_events));
+  }
+
+  void ProcessRtpPacket(std::unique_ptr<Packet> packet) override {
+    NOTREACHED();
+  }
+
+ private:
+  Session* const session_;  // Outlives this class.
+
+  DISALLOW_COPY_AND_ASSIGN(TransportClient);
+};
+
+}  // namespace
+
+Session::Session(SessionType session_type,
+                 const net::IPEndPoint& receiver_endpoint,
+                 SessionClient* client)
+    : client_(client), weak_factory_(this) {
+  DCHECK(client_);
+
+  std::vector<FrameSenderConfig> audio_configs;
+  std::vector<FrameSenderConfig> video_configs;
+  if (session_type != SessionType::VIDEO_ONLY)
+    audio_configs = AudioRtpStream::GetSupportedConfigs();
+  if (session_type != SessionType::AUDIO_ONLY)
+    video_configs = VideoRtpStream::GetSupportedConfigs(this);
+  start_timeout_timer_.Start(
+      FROM_HERE, kOfferAnswerExchangeTimeout,
+      base::BindRepeating(&Session::OnOfferAnswerExchangeTimeout,
+                          weak_factory_.GetWeakPtr()));
+  client_->DoOfferAnswerExchange(
+      audio_configs, video_configs,
+      base::BindOnce(&Session::StartInternal, weak_factory_.GetWeakPtr(),
+                     receiver_endpoint));
+}
+
+Session::~Session() {
+  StopSession();
+}
+
+void Session::StartInternal(const net::IPEndPoint& receiver_endpoint,
+                            const FrameSenderConfig& audio_config,
+                            const FrameSenderConfig& video_config) {
+  DVLOG(1) << __func__;
+  start_timeout_timer_.Stop();
+
+  DCHECK(!video_capture_client_);
+  DCHECK(!cast_transport_);
+  DCHECK(!audio_stream_);
+  DCHECK(!video_stream_);
+  DCHECK(!cast_environment_);
+  DCHECK(client_);
+
+  if (audio_config.rtp_payload_type == RtpPayloadType::REMOTE_AUDIO ||
+      video_config.rtp_payload_type == RtpPayloadType::REMOTE_VIDEO) {
+    NOTIMPLEMENTED();  // TODO(xjz): Add support for media remoting.
+    return;
+  }
+
+  const bool has_audio =
+      (audio_config.rtp_payload_type < RtpPayloadType::AUDIO_LAST) &&
+      (audio_config.rtp_payload_type >= RtpPayloadType::FIRST);
+  const bool has_video =
+      (video_config.rtp_payload_type > RtpPayloadType::AUDIO_LAST) &&
+      (video_config.rtp_payload_type < RtpPayloadType::LAST);
+  if (!has_audio && !has_video) {
+    VLOG(1) << "Incorrect ANSWER message: No audio or Video.";
+    client_->OnError(SESSION_START_ERROR);
+    return;
+  }
+
+  audio_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits(
+      {base::TaskPriority::USER_BLOCKING,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+      base::SingleThreadTaskRunnerThreadMode::DEDICATED);
+  video_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits(
+      {base::TaskPriority::USER_BLOCKING,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+      base::SingleThreadTaskRunnerThreadMode::DEDICATED);
+  cast_environment_ = new media::cast::CastEnvironment(
+      base::DefaultTickClock::GetInstance(),
+      base::ThreadTaskRunnerHandle::Get(), audio_encode_thread_,
+      video_encode_thread_);
+  network::mojom::NetworkContextPtr network_context;
+  client_->GetNewWorkContext(mojo::MakeRequest(&network_context));
+  auto udp_client = std::make_unique<UdpSocketClient>(
+      receiver_endpoint, std::move(network_context),
+      base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(),
+                     SessionError::CAST_TRANSPORT_ERROR));
+  cast_transport_ = media::cast::CastTransport::Create(
+      cast_environment_->Clock(), kSendEventsInterval,
+      std::make_unique<TransportClient>(this), std::move(udp_client),
+      base::ThreadTaskRunnerHandle::Get());
+
+  if (has_audio) {
+    auto audio_sender = std::make_unique<media::cast::AudioSender>(
+        cast_environment_, audio_config,
+        base::BindRepeating(&Session::OnEncoderStatusChange,
+                            weak_factory_.GetWeakPtr()),
+        cast_transport_.get());
+    audio_stream_ = std::make_unique<AudioRtpStream>(
+        std::move(audio_sender), weak_factory_.GetWeakPtr());
+    // TODO(xjz): Start audio capturing.
+    NOTIMPLEMENTED();
+  }
+
+  if (has_video) {
+    auto video_sender = std::make_unique<media::cast::VideoSender>(
+        cast_environment_, video_config,
+        base::BindRepeating(&Session::OnEncoderStatusChange,
+                            weak_factory_.GetWeakPtr()),
+        base::BindRepeating(&Session::CreateVideoEncodeAccelerator,
+                            weak_factory_.GetWeakPtr()),
+        base::BindRepeating(&Session::CreateVideoEncodeMemory,
+                            weak_factory_.GetWeakPtr()),
+        cast_transport_.get(),
+        base::BindRepeating(&Session::SetTargetPlayoutDelay,
+                            weak_factory_.GetWeakPtr()));
+    video_stream_ = std::make_unique<VideoRtpStream>(
+        std::move(video_sender), weak_factory_.GetWeakPtr());
+    media::mojom::VideoCaptureHostPtr video_host;
+    client_->GetVideoCaptureHost(mojo::MakeRequest(&video_host));
+    video_capture_client_ =
+        std::make_unique<VideoCaptureClient>(std::move(video_host));
+    video_capture_client_->Start(
+        base::BindRepeating(&VideoRtpStream::InsertVideoFrame,
+                            video_stream_->AsWeakPtr()),
+        base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(),
+                       SessionError::VIDEO_CAPTURE_ERROR));
+  }
+
+  client_->DidStart();
+}
+
+void Session::ReportError(SessionError error) {
+  DVLOG(1) << __func__ << ": error=" << error;
+  if (client_)
+    client_->OnError(error);
+  StopSession();
+}
+
+void Session::StopSession() {
+  DVLOG(1) << __func__;
+  if (!client_)
+    return;
+
+  weak_factory_.InvalidateWeakPtrs();
+  start_timeout_timer_.Stop();
+  audio_encode_thread_ = nullptr;
+  video_encode_thread_ = nullptr;
+  video_capture_client_.reset();
+  audio_stream_.reset();
+  video_stream_.reset();
+  cast_transport_.reset();
+  cast_environment_ = nullptr;
+  client_->DidStop();
+  client_ = nullptr;
+}
+
+void Session::OnError(const std::string& message) {
+  VLOG(1) << message;
+  ReportError(SessionError::CAST_STREAMING_ERROR);
+}
+
+void Session::RequestRefreshFrame() {
+  DVLOG(3) << __func__;
+  if (video_capture_client_)
+    video_capture_client_->RequestRefreshFrame();
+}
+
+void Session::OnEncoderStatusChange(OperationalStatus status) {
+  switch (status) {
+    case OperationalStatus::STATUS_UNINITIALIZED:
+    case OperationalStatus::STATUS_CODEC_REINIT_PENDING:
+    // Not an error.
+    // TODO(miu): As an optimization, signal the client to pause sending more
+    // frames until the state becomes STATUS_INITIALIZED again.
+    case OperationalStatus::STATUS_INITIALIZED:
+      break;
+    case OperationalStatus::STATUS_INVALID_CONFIGURATION:
+    case OperationalStatus::STATUS_UNSUPPORTED_CODEC:
+    case OperationalStatus::STATUS_CODEC_INIT_FAILED:
+    case OperationalStatus::STATUS_CODEC_RUNTIME_ERROR:
+      DVLOG(1) << "OperationalStatus error.";
+      ReportError(SessionError::CAST_STREAMING_ERROR);
+      break;
+  }
+}
+
+media::VideoEncodeAccelerator::SupportedProfiles
+Session::GetSupportedVideoEncodeAcceleratorProfiles() {
+  // TODO(xjz): Establish GPU channel and query for the supported profiles.
+  return media::VideoEncodeAccelerator::SupportedProfiles();
+}
+
+void Session::CreateVideoEncodeAccelerator(
+    const media::cast::ReceiveVideoEncodeAcceleratorCallback& callback) {
+  DVLOG(1) << __func__;
+  // TODO(xjz): Establish GPU channel and create the
+  // media::MojoVideoEncodeAccelerator with the gpu info.
+  if (!callback.is_null())
+    callback.Run(video_encode_thread_, nullptr);
+}
+
+void Session::CreateVideoEncodeMemory(
+    size_t size,
+    const media::cast::ReceiveVideoEncodeMemoryCallback& callback) {
+  DVLOG(1) << __func__;
+
+  mojo::ScopedSharedBufferHandle mojo_buf =
+      mojo::SharedBufferHandle::Create(size);
+  if (!mojo_buf->is_valid()) {
+    LOG(WARNING) << "Browser failed to allocate shared memory.";
+    callback.Run(nullptr);
+    return;
+  }
+
+  base::SharedMemoryHandle shared_buf;
+  if (mojo::UnwrapSharedMemoryHandle(std::move(mojo_buf), &shared_buf, nullptr,
+                                     nullptr) != MOJO_RESULT_OK) {
+    LOG(WARNING) << "Browser failed to allocate shared memory.";
+    callback.Run(nullptr);
+    return;
+  }
+
+  callback.Run(std::make_unique<base::SharedMemory>(shared_buf, false));
+}
+
+void Session::OnTransportStatusChanged(CastTransportStatus status) {
+  DVLOG(1) << __func__ << ": status=" << status;
+  switch (status) {
+    case CastTransportStatus::TRANSPORT_STREAM_UNINITIALIZED:
+    case CastTransportStatus::TRANSPORT_STREAM_INITIALIZED:
+      return;  // Not errors, do nothing.
+    case CastTransportStatus::TRANSPORT_INVALID_CRYPTO_CONFIG:
+      DVLOG(1) << "Warning: unexpected status: "
+               << "TRANSPORT_INVALID_CRYPTO_CONFIG";
+      ReportError(SessionError::CAST_TRANSPORT_ERROR);
+      break;
+    case CastTransportStatus::TRANSPORT_SOCKET_ERROR:
+      DVLOG(1) << "Warning: unexpected status: "
+               << "TRANSPORT_SOCKET_ERROR";
+      ReportError(SessionError::CAST_TRANSPORT_ERROR);
+      break;
+  }
+}
+
+void Session::OnLoggingEventsReceived(
+    std::unique_ptr<std::vector<FrameEvent>> frame_events,
+    std::unique_ptr<std::vector<PacketEvent>> packet_events) {
+  DCHECK(cast_environment_);
+  cast_environment_->logger()->DispatchBatchOfEvents(std::move(frame_events),
+                                                     std::move(packet_events));
+}
+
+void Session::SetTargetPlayoutDelay(base::TimeDelta playout_delay) {
+  if (audio_stream_)
+    audio_stream_->SetTargetPlayoutDelay(playout_delay);
+  if (video_stream_)
+    video_stream_->SetTargetPlayoutDelay(playout_delay);
+}
+
+void Session::OnOfferAnswerExchangeTimeout() {
+  VLOG(1) << "OFFER/ANSWER exchange timed out.";
+  DCHECK(client_);
+  client_->OnError(SESSION_START_ERROR);
+}
+
+}  // namespace mirroring
diff --git a/components/mirroring/service/session.h b/components/mirroring/service/session.h
new file mode 100644
index 0000000..00cf32b7
--- /dev/null
+++ b/components/mirroring/service/session.h
@@ -0,0 +1,92 @@
+// Copyright 2018 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_MIRRORING_SERVICE_SESSION_H_
+#define COMPONENTS_MIRRORING_SERVICE_SESSION_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "components/mirroring/service/interface.h"
+#include "components/mirroring/service/rtp_stream.h"
+#include "media/cast/cast_environment.h"
+#include "media/cast/net/cast_transport_defines.h"
+
+namespace media {
+
+namespace cast {
+class CastTransport;
+}  // namespace cast
+
+}  // namespace media
+
+namespace mirroring {
+
+class VideoCaptureClient;
+
+class Session final : public RtpStreamClient {
+ public:
+  Session(SessionType session_type,
+          const net::IPEndPoint& receiver_endpoint,
+          SessionClient* client);
+  ~Session() override;
+
+  // RtpStreamClient implemenation.
+  void OnError(const std::string& message) override;
+  void RequestRefreshFrame() override;
+  media::VideoEncodeAccelerator::SupportedProfiles
+  GetSupportedVideoEncodeAcceleratorProfiles() override;
+  void CreateVideoEncodeAccelerator(
+      const media::cast::ReceiveVideoEncodeAcceleratorCallback& callback)
+      override;
+  void CreateVideoEncodeMemory(
+      size_t size,
+      const media::cast::ReceiveVideoEncodeMemoryCallback& callback) override;
+
+  // Callbacks by media::cast::CastTransport::Client.
+  void OnTransportStatusChanged(media::cast::CastTransportStatus status);
+  void OnLoggingEventsReceived(
+      std::unique_ptr<std::vector<media::cast::FrameEvent>> frame_events,
+      std::unique_ptr<std::vector<media::cast::PacketEvent>> packet_events);
+
+ private:
+  // Callback when OFFER/ANSWER message exchange finishes. Starts a mirroing
+  // session.
+  void StartInternal(const net::IPEndPoint& receiver_endpoint,
+                     const media::cast::FrameSenderConfig& audio_config,
+                     const media::cast::FrameSenderConfig& video_config);
+
+  void StopSession();
+
+  // Notify |client_| that error occurred and close the session.
+  void ReportError(SessionError error);
+
+  // Callback by Audio/VideoSender to indicate encoder status change.
+  void OnEncoderStatusChange(media::cast::OperationalStatus status);
+
+  // Callback by media::cast::VideoSender to set a new target playout delay.
+  void SetTargetPlayoutDelay(base::TimeDelta playout_delay);
+
+  // Callback by |start_timeout_timer_|.
+  void OnOfferAnswerExchangeTimeout();
+
+  SessionClient* client_ = nullptr;
+
+  // Create on StartInternal().
+  std::unique_ptr<AudioRtpStream> audio_stream_;
+  std::unique_ptr<VideoRtpStream> video_stream_;
+  std::unique_ptr<VideoCaptureClient> video_capture_client_;
+  scoped_refptr<media::cast::CastEnvironment> cast_environment_ = nullptr;
+  std::unique_ptr<media::cast::CastTransport> cast_transport_;
+  scoped_refptr<base::SingleThreadTaskRunner> audio_encode_thread_ = nullptr;
+  scoped_refptr<base::SingleThreadTaskRunner> video_encode_thread_ = nullptr;
+
+  // Fire if the OFFER/ANSWER exchange times out.
+  base::OneShotTimer start_timeout_timer_;
+
+  base::WeakPtrFactory<Session> weak_factory_;
+};
+
+}  // namespace mirroring
+
+#endif  // COMPONENTS_MIRRORING_SERVICE_SESSION_H_
diff --git a/components/mirroring/service/session_unittest.cc b/components/mirroring/service/session_unittest.cc
new file mode 100644
index 0000000..751fa584
--- /dev/null
+++ b/components/mirroring/service/session_unittest.cc
@@ -0,0 +1,124 @@
+// Copyright 2018 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/mirroring/service/session.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "components/mirroring/service/fake_network_service.h"
+#include "components/mirroring/service/fake_video_capture_host.h"
+#include "components/mirroring/service/interface.h"
+#include "media/cast/test/utility/default_config.h"
+#include "media/cast/test/utility/net_utility.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InvokeWithoutArgs;
+using ::testing::_;
+using media::cast::FrameSenderConfig;
+using media::cast::Packet;
+
+namespace mirroring {
+
+class SessionTest : public SessionClient, public ::testing::Test {
+ public:
+  SessionTest() : weak_factory_(this) {
+    testing_clock_.Advance(base::TimeTicks::Now() - base::TimeTicks());
+  }
+
+  ~SessionTest() override { scoped_task_environment_.RunUntilIdle(); }
+
+  // SessionClient implemenation.
+  MOCK_METHOD1(OnError, void(SessionError));
+  MOCK_METHOD0(DidStart, void());
+  MOCK_METHOD0(DidStop, void());
+  MOCK_METHOD0(OnOfferAnswerExchange, void());
+  MOCK_METHOD0(OnGetVideoCaptureHost, void());
+  MOCK_METHOD0(OnGetNetworkContext, void());
+
+  void GetVideoCaptureHost(
+      media::mojom::VideoCaptureHostRequest request) override {
+    video_host_ = std::make_unique<FakeVideoCaptureHost>(std::move(request));
+    OnGetVideoCaptureHost();
+  }
+
+  void GetNewWorkContext(
+      network::mojom::NetworkContextRequest request) override {
+    network_context_ = std::make_unique<MockNetworkContext>(std::move(request));
+    OnGetNetworkContext();
+  }
+
+  void DoOfferAnswerExchange(
+      const std::vector<FrameSenderConfig>& audio_configs,
+      const std::vector<FrameSenderConfig>& video_configs,
+      GetAnswerCallback callback) override {
+    OnOfferAnswerExchange();
+    std::move(callback).Run(FrameSenderConfig(),
+                            media::cast::GetDefaultVideoSenderConfig());
+  }
+
+ protected:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  base::SimpleTestTickClock testing_clock_;
+
+  std::unique_ptr<Session> session_;
+  std::unique_ptr<FakeVideoCaptureHost> video_host_;
+  std::unique_ptr<MockNetworkContext> network_context_;
+
+  base::WeakPtrFactory<SessionTest> weak_factory_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SessionTest);
+};
+
+TEST_F(SessionTest, Mirroring) {
+  // Start a mirroring session.
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(*this, OnGetVideoCaptureHost()).Times(1);
+    EXPECT_CALL(*this, OnGetNetworkContext()).Times(1);
+    EXPECT_CALL(*this, OnOfferAnswerExchange()).Times(1);
+    EXPECT_CALL(*this, DidStart())
+        .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+    session_ =
+        std::make_unique<Session>(SessionType::AUDIO_AND_VIDEO,
+                                  media::cast::test::GetFreeLocalPort(), this);
+    run_loop.Run();
+  }
+
+  scoped_task_environment_.RunUntilIdle();
+
+  {
+    base::RunLoop run_loop;
+    // Expect to send out some UDP packets.
+    EXPECT_CALL(*network_context_->udp_socket(), OnSend())
+        .Times(testing::AtLeast(1));
+    EXPECT_CALL(*video_host_, ReleaseBuffer(_, _, _))
+        .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+    // Send one video frame to the consumer.
+    video_host_->SendOneFrame(gfx::Size(64, 32), testing_clock_.NowTicks());
+    run_loop.Run();
+  }
+
+  scoped_task_environment_.RunUntilIdle();
+
+  // Stop the session.
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(*video_host_, OnStopped()).Times(1);
+    EXPECT_CALL(*this, DidStop())
+        .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+    session_.reset();
+    run_loop.Run();
+  }
+  scoped_task_environment_.RunUntilIdle();
+}
+
+}  // namespace mirroring
diff --git a/components/mirroring/service/video_capture_client.cc b/components/mirroring/service/video_capture_client.cc
index 575284f..ef4e437 100644
--- a/components/mirroring/service/video_capture_client.cc
+++ b/components/mirroring/service/video_capture_client.cc
@@ -203,7 +203,7 @@
 
   frame->metadata()->MergeInternalValuesFrom(*info->metadata);
 
-  frame_deliver_callback_.Run(frame, reference_time);
+  frame_deliver_callback_.Run(frame);
 }
 
 void VideoCaptureClient::OnBufferDestroyed(int32_t buffer_id) {
diff --git a/components/mirroring/service/video_capture_client.h b/components/mirroring/service/video_capture_client.h
index a0e22f8..3c43cd0 100644
--- a/components/mirroring/service/video_capture_client.h
+++ b/components/mirroring/service/video_capture_client.h
@@ -29,9 +29,8 @@
   explicit VideoCaptureClient(media::mojom::VideoCaptureHostPtr host);
   ~VideoCaptureClient() override;
 
-  using FrameDeliverCallback =
-      base::RepeatingCallback<void(scoped_refptr<media::VideoFrame> video_frame,
-                                   base::TimeTicks estimated_capture_time)>;
+  using FrameDeliverCallback = base::RepeatingCallback<void(
+      scoped_refptr<media::VideoFrame> video_frame)>;
   void Start(FrameDeliverCallback deliver_callback,
              base::OnceClosure error_callback);
 
diff --git a/components/mirroring/service/video_capture_client_unittest.cc b/components/mirroring/service/video_capture_client_unittest.cc
index 5b9d40b..ba7cc0006 100644
--- a/components/mirroring/service/video_capture_client_unittest.cc
+++ b/components/mirroring/service/video_capture_client_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/run_loop.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
+#include "components/mirroring/service/fake_video_capture_host.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -18,49 +19,6 @@
 
 namespace {
 
-class FakeVideoCaptureHost final : public media::mojom::VideoCaptureHost {
- public:
-  explicit FakeVideoCaptureHost(media::mojom::VideoCaptureHostRequest request)
-      : binding_(this, std::move(request)) {}
-  ~FakeVideoCaptureHost() override {}
-
-  // mojom::VideoCaptureHost implementations
-  MOCK_METHOD1(RequestRefreshFrame, void(int32_t));
-  MOCK_METHOD3(ReleaseBuffer, void(int32_t, int32_t, double));
-  MOCK_METHOD1(Pause, void(int32_t));
-  MOCK_METHOD3(Resume,
-               void(int32_t, int32_t, const media::VideoCaptureParams&));
-  MOCK_METHOD0(OnStopped, void());
-
-  void Start(int32_t device_id,
-             int32_t session_id,
-             const media::VideoCaptureParams& params,
-             media::mojom::VideoCaptureObserverPtr observer) override {
-    client_ = std::move(observer);
-    client_->OnStateChanged(media::mojom::VideoCaptureState::STARTED);
-  }
-
-  void Stop(int32_t device_id) override {
-    client_->OnStateChanged(media::mojom::VideoCaptureState::ENDED);
-    client_.reset();
-    OnStopped();
-  }
-
-  void GetDeviceSupportedFormats(
-      int32_t device_id,
-      int32_t session_id,
-      GetDeviceSupportedFormatsCallback callback) override {}
-  void GetDeviceFormatsInUse(int32_t device_id,
-                             int32_t session_id,
-                             GetDeviceFormatsInUseCallback callback) override {}
-
- private:
-  mojo::Binding<media::mojom::VideoCaptureHost> binding_;
-  media::mojom::VideoCaptureObserverPtr client_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeVideoCaptureHost);
-};
-
 media::mojom::VideoFrameInfoPtr GetVideoFrameInfo(const gfx::Size& size) {
   media::VideoFrameMetadata metadata;
   metadata.SetDouble(media::VideoFrameMetadata::FRAME_RATE, 30);
@@ -95,8 +53,7 @@
   }
 
   MOCK_METHOD1(OnFrameReceived, void(const gfx::Size&));
-  void OnFrameReady(scoped_refptr<media::VideoFrame> video_frame,
-                    base::TimeTicks estimated_capture_time) {
+  void OnFrameReady(scoped_refptr<media::VideoFrame> video_frame) {
     video_frame->metadata()->SetDouble(
         media::VideoFrameMetadata::RESOURCE_UTILIZATION, 0.6);
     OnFrameReceived(video_frame->coded_size());
diff --git a/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc b/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc
index 0e84f1b..4f9af9b 100644
--- a/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc
+++ b/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc
@@ -22,6 +22,8 @@
 static const char kSampleClusterTitle[] = "Cluster title filler";
 }  // namespace
 
+using contextual_suggestions::ContextualSuggestionsMetricsReporter;
+
 ContextualContentSuggestionsService::Cluster::Cluster() = default;
 
 ContextualContentSuggestionsService::Cluster::Cluster(Cluster&& other) =
@@ -33,12 +35,15 @@
     std::unique_ptr<ContextualSuggestionsFetcher>
         contextual_suggestions_fetcher,
     std::unique_ptr<CachedImageFetcher> image_fetcher,
-    std::unique_ptr<RemoteSuggestionsDatabase> contextual_suggestions_database)
+    std::unique_ptr<RemoteSuggestionsDatabase> contextual_suggestions_database,
+    std::unique_ptr<ContextualSuggestionsMetricsReporter> metrics_reporter)
     : contextual_suggestions_database_(
           std::move(contextual_suggestions_database)),
       contextual_suggestions_fetcher_(
           std::move(contextual_suggestions_fetcher)),
-      image_fetcher_(std::move(image_fetcher)) {}
+      image_fetcher_(std::move(image_fetcher)),
+      metrics_reporter_(std::move(metrics_reporter)),
+      last_ukm_source_id_(ukm::kInvalidSourceId) {}
 
 ContextualContentSuggestionsService::~ContextualContentSuggestionsService() =
     default;
@@ -82,7 +87,19 @@
 
 void ContextualContentSuggestionsService::ReportEvent(
     ukm::SourceId ukm_source_id,
-    int event_id) {}
+    contextual_suggestions::ContextualSuggestionsEvent event) {
+  DCHECK(ukm_source_id != ukm::kInvalidSourceId);
+
+  // Flush the previous page (if any) and setup the new page.
+  if (ukm_source_id != last_ukm_source_id_) {
+    if (last_ukm_source_id_ != ukm::kInvalidSourceId)
+      metrics_reporter_->Flush();
+    last_ukm_source_id_ = ukm_source_id;
+    metrics_reporter_->SetupForPage(ukm_source_id);
+  }
+
+  metrics_reporter_->RecordEvent(event);
+}
 
 // TODO(gaschler): Cache contextual suggestions at run-time.
 void ContextualContentSuggestionsService::DidFetchContextualSuggestions(
@@ -118,4 +135,10 @@
   std::move(callback).Run(kSamplePeekText, std::move(clusters));
 }
 
+void ContextualContentSuggestionsService::Shutdown() {
+  if (last_ukm_source_id_ != ukm::kInvalidSourceId)
+    metrics_reporter_->Flush();
+  last_ukm_source_id_ = ukm::kInvalidSourceId;
+}
+
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/contextual/contextual_content_suggestions_service.h b/components/ntp_snippets/contextual/contextual_content_suggestions_service.h
index 53b5750..eecbfe3e 100644
--- a/components/ntp_snippets/contextual/contextual_content_suggestions_service.h
+++ b/components/ntp_snippets/contextual/contextual_content_suggestions_service.h
@@ -17,6 +17,7 @@
 #include "components/ntp_snippets/callbacks.h"
 #include "components/ntp_snippets/content_suggestion.h"
 #include "components/ntp_snippets/contextual/contextual_suggestions_fetcher.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 
 namespace ntp_snippets {
@@ -47,7 +48,10 @@
           contextual_suggestions_fetcher,
       std::unique_ptr<CachedImageFetcher> image_fetcher,
       std::unique_ptr<RemoteSuggestionsDatabase>
-          contextual_suggestions_database);
+          contextual_suggestions_database,
+      std::unique_ptr<
+          contextual_suggestions::ContextualSuggestionsMetricsReporter>
+          metrics_reporter);
   ~ContextualContentSuggestionsService() override;
 
   using FetchContextualSuggestionsCallback =
@@ -75,8 +79,11 @@
       ImageFetchedCallback callback);
 
   // Used to report events using various metrics (e.g. UMA, UKM).
-  // TODO(donnd): Change type of event ID, implement.
-  void ReportEvent(ukm::SourceId sourceId, int event_id);
+  void ReportEvent(ukm::SourceId sourceId,
+                   contextual_suggestions::ContextualSuggestionsEvent event);
+
+  // KeyedService overrides.
+  void Shutdown() override;
 
  private:
   void DidFetchContextualSuggestions(
@@ -99,6 +106,13 @@
 
   std::unique_ptr<CachedImageFetcher> image_fetcher_;
 
+  std::unique_ptr<contextual_suggestions::ContextualSuggestionsMetricsReporter>
+      metrics_reporter_;
+
+  // The most recent SourceId in use by metrics_reporter_, or
+  // ukm::kInvalidSourceId.
+  ukm::SourceId last_ukm_source_id_;
+
   // Look up by ContentSuggestion::ID::id_within_category() aka std::string to
   // get image URL.
   std::map<std::string, GURL> image_url_by_id_;
diff --git a/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc b/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc
index d8ab9a1f..612e34c 100644
--- a/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc
+++ b/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc
@@ -18,6 +18,7 @@
 #include "components/ntp_snippets/content_suggestion.h"
 #include "components/ntp_snippets/contextual/contextual_suggestion.h"
 #include "components/ntp_snippets/contextual/contextual_suggestions_fetcher.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
 #include "components/ntp_snippets/remote/cached_image_fetcher.h"
 #include "components/ntp_snippets/remote/json_to_categories.h"
 #include "components/ntp_snippets/remote/remote_suggestions_database.h"
@@ -125,10 +126,13 @@
     std::unique_ptr<FakeContextualSuggestionsFetcher> fetcher =
         std::make_unique<FakeContextualSuggestionsFetcher>();
     fetcher_ = fetcher.get();
+    auto metrics_reporter = std::make_unique<
+        contextual_suggestions::ContextualSuggestionsMetricsReporter>();
     source_ = std::make_unique<ContextualContentSuggestionsService>(
         std::move(fetcher),
         std::make_unique<FakeCachedImageFetcher>(&pref_service_),
-        std::unique_ptr<RemoteSuggestionsDatabase>());
+        std::unique_ptr<RemoteSuggestionsDatabase>(),
+        std::move(metrics_reporter));
   }
 
   FakeContextualSuggestionsFetcher* fetcher() { return fetcher_; }
diff --git a/components/offline_pages/core/model/get_pages_task.cc b/components/offline_pages/core/model/get_pages_task.cc
index ef58bf5..09c36a2 100644
--- a/components/offline_pages/core/model/get_pages_task.cc
+++ b/components/offline_pages/core/model/get_pages_task.cc
@@ -235,6 +235,25 @@
   return result;
 }
 
+ReadResult ReadPagesByGuid(const std::string& guid, sql::Connection* db) {
+  ReadResult result;
+  if (!db) {
+    result.success = false;
+    return result;
+  }
+
+  static const char kSql[] = "SELECT " OFFLINE_PAGE_PROJECTION
+                             " FROM offlinepages_v1"
+                             " WHERE client_id = ?";
+  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+  statement.BindString(0, guid);
+  while (statement.Step())
+    result.pages.emplace_back(MakeOfflinePageItem(&statement));
+
+  result.success = true;
+  return result;
+}
+
 ReadResult ReadPagesBySizeAndDigest(int64_t file_size,
                                     const std::string& digest,
                                     sql::Connection* db) {
@@ -380,6 +399,16 @@
 }
 
 // static
+std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingGuid(
+    OfflinePageMetadataStoreSQL* store,
+    const SingleOfflinePageItemCallback& callback,
+    const std::string& guid) {
+  return base::WrapUnique(
+      new GetPagesTask(store, base::BindOnce(&ReadPagesByGuid, guid),
+                       base::Bind(&WrapInMultipleItemsCallback, callback)));
+}
+
+// static
 std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingSizeAndDigest(
     OfflinePageMetadataStoreSQL* store,
     const SingleOfflinePageItemCallback& callback,
diff --git a/components/offline_pages/core/model/get_pages_task.h b/components/offline_pages/core/model/get_pages_task.h
index e405ae5..af3ffd48 100644
--- a/components/offline_pages/core/model/get_pages_task.h
+++ b/components/offline_pages/core/model/get_pages_task.h
@@ -92,6 +92,13 @@
       const SingleOfflinePageItemCallback& callback,
       int64_t offline_id);
 
+  // Creates |GetPagesTask| reading a single page matching provided |guid| from
+  // DB.
+  static std::unique_ptr<GetPagesTask> CreateTaskMatchingGuid(
+      OfflinePageMetadataStoreSQL* store,
+      const SingleOfflinePageItemCallback& callback,
+      const std::string& guid);
+
   // Creates |GetPagesTask| reading a single page matching provided |file_size|
   // and |digest| from DB.
   static std::unique_ptr<GetPagesTask> CreateTaskMatchingSizeAndDigest(
diff --git a/components/offline_pages/core/model/get_pages_task_unittest.cc b/components/offline_pages/core/model/get_pages_task_unittest.cc
index 966a9ad..a8d7d0a 100644
--- a/components/offline_pages/core/model/get_pages_task_unittest.cc
+++ b/components/offline_pages/core/model/get_pages_task_unittest.cc
@@ -217,6 +217,20 @@
   EXPECT_EQ(item_1, single_page_result());
 }
 
+TEST_F(GetPagesTaskTest, GetPageByGuid) {
+  OfflinePageItem item_1 = generator()->CreateItem();
+  store_test_util()->InsertItem(item_1);
+  OfflinePageItem item_2 = generator()->CreateItem();
+  store_test_util()->InsertItem(item_2);
+  OfflinePageItem item_3 = generator()->CreateItem();
+  store_test_util()->InsertItem(item_3);
+
+  RunTask(GetPagesTask::CreateTaskMatchingGuid(
+      store(), get_single_page_callback(), item_1.client_id.id));
+
+  EXPECT_EQ(item_1, single_page_result());
+}
+
 TEST_F(GetPagesTaskTest, GetPageBySizeAndDigest) {
   static const int64_t kFileSize1 = 123LL;
   static const int64_t kFileSize2 = 999999LL;
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc
index 6e83c768..4d4b61420 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -319,6 +319,14 @@
   task_queue_.AddTask(std::move(task));
 }
 
+void OfflinePageModelTaskified::GetPageByGuid(
+    const std::string& guid,
+    const SingleOfflinePageItemCallback& callback) {
+  auto task =
+      GetPagesTask::CreateTaskMatchingGuid(store_.get(), callback, guid);
+  task_queue_.AddTask(std::move(task));
+}
+
 void OfflinePageModelTaskified::GetPagesByClientIds(
     const std::vector<ClientId>& client_ids,
     const MultipleOfflinePageItemCallback& callback) {
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.h b/components/offline_pages/core/model/offline_page_model_taskified.h
index 867bf9a..be193313 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.h
+++ b/components/offline_pages/core/model/offline_page_model_taskified.h
@@ -103,6 +103,8 @@
   void GetPageByOfflineId(
       int64_t offline_id,
       const SingleOfflinePageItemCallback& callback) override;
+  void GetPageByGuid(const std::string& guid,
+                     const SingleOfflinePageItemCallback& callback) override;
   void GetPagesByClientIds(
       const std::vector<ClientId>& client_ids,
       const MultipleOfflinePageItemCallback& callback) override;
diff --git a/components/offline_pages/core/offline_page_model.h b/components/offline_pages/core/offline_page_model.h
index 63b5b16..141e59c 100644
--- a/components/offline_pages/core/offline_page_model.h
+++ b/components/offline_pages/core/offline_page_model.h
@@ -176,6 +176,12 @@
       int64_t offline_id,
       const SingleOfflinePageItemCallback& callback) = 0;
 
+  // Returns zero or one offline page associated with a specified |guid|.
+  // Note: this should only be used for the case that |guid| can uniquely
+  // identify the page regardless its namespace.
+  virtual void GetPageByGuid(const std::string& guid,
+                             const SingleOfflinePageItemCallback& callback) = 0;
+
   // Retrieves all pages associated with any of |client_ids|.
   virtual void GetPagesByClientIds(
       const std::vector<ClientId>& client_ids,
diff --git a/components/offline_pages/core/stub_offline_page_model.cc b/components/offline_pages/core/stub_offline_page_model.cc
index 64c808c..80ad5689 100644
--- a/components/offline_pages/core/stub_offline_page_model.cc
+++ b/components/offline_pages/core/stub_offline_page_model.cc
@@ -46,6 +46,9 @@
 void StubOfflinePageModel::GetPageByOfflineId(
     int64_t offline_id,
     const SingleOfflinePageItemCallback& callback) {}
+void StubOfflinePageModel::GetPageByGuid(
+    const std::string& guid,
+    const SingleOfflinePageItemCallback& callback) {}
 void StubOfflinePageModel::GetPagesByURL(
     const GURL& url,
     URLSearchMode url_search_mode,
diff --git a/components/offline_pages/core/stub_offline_page_model.h b/components/offline_pages/core/stub_offline_page_model.h
index 2927e7a..2a64463a 100644
--- a/components/offline_pages/core/stub_offline_page_model.h
+++ b/components/offline_pages/core/stub_offline_page_model.h
@@ -52,6 +52,8 @@
   void GetPageByOfflineId(
       int64_t offline_id,
       const SingleOfflinePageItemCallback& callback) override;
+  void GetPageByGuid(const std::string& guid,
+                     const SingleOfflinePageItemCallback& callback) override;
   void GetPagesByURL(const GURL& url,
                      URLSearchMode url_search_mode,
                      const MultipleOfflinePageItemCallback& callback) override;
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 17c960b..c6df279 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -92,6 +92,7 @@
       swap_contents_and_description(false),
       transition(ui::PAGE_TRANSITION_GENERATED),
       type(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED),
+      has_tab_match(false),
       subtype_identifier(0),
       from_previous(false) {}
 
@@ -107,6 +108,7 @@
       swap_contents_and_description(false),
       transition(ui::PAGE_TRANSITION_TYPED),
       type(type),
+      has_tab_match(false),
       subtype_identifier(0),
       from_previous(false) {}
 
@@ -130,6 +132,7 @@
       answer(SuggestionAnswer::copy(match.answer.get())),
       transition(match.transition),
       type(match.type),
+      has_tab_match(match.has_tab_match),
       subtype_identifier(match.subtype_identifier),
       associated_keyword(match.associated_keyword.get()
                              ? new AutocompleteMatch(*match.associated_keyword)
@@ -170,6 +173,7 @@
   answer = SuggestionAnswer::copy(match.answer.get());
   transition = match.transition;
   type = match.type;
+  has_tab_match = match.has_tab_match;
   subtype_identifier = match.subtype_identifier;
   associated_keyword.reset(
       match.associated_keyword.get()
@@ -188,7 +192,8 @@
 
 // static
 const gfx::VectorIcon& AutocompleteMatch::TypeToVectorIcon(Type type,
-                                                           bool is_bookmark) {
+                                                           bool is_bookmark,
+                                                           bool is_tab_match) {
 #if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS)
   const bool is_touch_ui =
       ui::MaterialDesignController::IsTouchOptimizedUiEnabled();
@@ -196,13 +201,11 @@
   if (is_bookmark)
     return is_touch_ui ? omnibox::kTouchableBookmarkIcon : omnibox::kStarIcon;
 
+  if (is_tab_match &&
+      !OmniboxFieldTrial::InTabSwitchSuggestionWithButtonTrial()) {
+    return omnibox::kTabIcon;
+  }
   switch (type) {
-    case Type::TAB_SEARCH:
-      if (!OmniboxFieldTrial::InTabSwitchSuggestionWithButtonTrial())
-        return omnibox::kTabIcon;
-      // Behave like history match.
-      FALLTHROUGH;
-
     case Type::URL_WHAT_YOU_TYPED:
     case Type::HISTORY_URL:
     case Type::HISTORY_TITLE:
@@ -214,6 +217,7 @@
     case Type::CLIPBOARD:
     case Type::PHYSICAL_WEB:
     case Type::PHYSICAL_WEB_OVERFLOW:
+    case Type::TAB_SEARCH_DEPRECATED:
       return is_touch_ui ? omnibox::kTouchablePageIcon : omnibox::kHttpIcon;
 
     case Type::SEARCH_WHAT_YOU_TYPED:
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index 43d2252..2176b5d0 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -117,7 +117,9 @@
   // Gets the vector icon identifier for the icon to be shown for |type|. If
   // |is_bookmark| is true, returns a bookmark icon rather than what the type
   // would determine.
-  static const gfx::VectorIcon& TypeToVectorIcon(Type type, bool is_bookmark);
+  static const gfx::VectorIcon& TypeToVectorIcon(Type type,
+                                                 bool is_bookmark,
+                                                 bool is_tab_match);
 
   // Comparison function for determining when one match is better than another.
   static bool MoreRelevant(const AutocompleteMatch& elem1,
@@ -416,6 +418,9 @@
   // Type of this match.
   Type type;
 
+  // True if we saw a tab that matched this suggestion.
+  bool has_tab_match;
+
   // Used to identify the specific source / type for suggestions by the
   // suggest server. See |result_subtype_identifier| in omnibox.proto for more
   // details.
diff --git a/components/omnibox/browser/autocomplete_match_type.cc b/components/omnibox/browser/autocomplete_match_type.cc
index 7e2c0b81..8371614 100644
--- a/components/omnibox/browser/autocomplete_match_type.cc
+++ b/components/omnibox/browser/autocomplete_match_type.cc
@@ -97,7 +97,7 @@
       0,                               // VOICE_SUGGEST
       0,                               // PHYSICAL_WEB
       0,                               // PHYSICAL_WEB_OVERFLOW
-      IDS_ACC_AUTOCOMPLETE_HISTORY,    // TAB_SEARCH
+      IDS_ACC_AUTOCOMPLETE_HISTORY,    // TAB_SEARCH_DEPRECATED
   };
   static_assert(arraysize(message_ids) == AutocompleteMatchType::NUM_TYPES,
                 "message_ids must have NUM_TYPES elements");
diff --git a/components/omnibox/browser/autocomplete_match_type.h b/components/omnibox/browser/autocomplete_match_type.h
index 0698791..a6cb831 100644
--- a/components/omnibox/browser/autocomplete_match_type.h
+++ b/components/omnibox/browser/autocomplete_match_type.h
@@ -59,8 +59,8 @@
     PHYSICAL_WEB                = 21,  // A Physical Web nearby URL.
     PHYSICAL_WEB_OVERFLOW       = 22,  // An item representing multiple
                                        // Physical Web nearby URLs.
-    TAB_SEARCH                  = 23,  // A suggested open tab, based on its
-                                       // URL or title, via HQP.
+    TAB_SEARCH_DEPRECATED       = 23,  // A suggested open tab, based on its
+                                       // URL or title, via HQP (deprecated).
     NUM_TYPES,
   };
   // clang-format on
diff --git a/components/omnibox/browser/history_provider.cc b/components/omnibox/browser/history_provider.cc
index 63d0abc..2268c97 100644
--- a/components/omnibox/browser/history_provider.cc
+++ b/components/omnibox/browser/history_provider.cc
@@ -110,7 +110,7 @@
   for (auto& match : matches_) {
     // If url is in a tab, change type, update classification.
     if (client()->IsTabOpenWithURL(match.destination_url, input)) {
-      match.type = AutocompleteMatchType::TAB_SEARCH;
+      match.has_tab_match = true;
       if (OmniboxFieldTrial::InTabSwitchSuggestionWithButtonTrial())
         continue;
       const base::string16 switch_tab_message =
diff --git a/components/omnibox/browser/history_provider.h b/components/omnibox/browser/history_provider.h
index fbd6762..5328a8b 100644
--- a/components/omnibox/browser/history_provider.h
+++ b/components/omnibox/browser/history_provider.h
@@ -45,8 +45,9 @@
 
   AutocompleteProviderClient* client() { return client_; }
 
-  // Converts matches whose URL matches a tab's URL to TAB_SEARCH matches.
-  // Fixes up description as well. |input| can be null; if provided,
+  // Sets |has_tab_match| in matches whose URL matches an open tab's URL.
+  // Also, fixes up the description if not using another UI element to
+  // annotate (e.g. tab switch button). |input| can be null; if provided,
   // the match can be more precise (e.g. scheme presence).
   void ConvertOpenTabMatches(const AutocompleteInput* input);
 
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index d657ed0..15cdb15 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -644,6 +644,7 @@
       input_.type(),
       popup_open,
       dropdown_ignored ? 0 : index,
+      disposition,
       !pasted_text.empty(),
       SessionID::InvalidValue(), // don't know tab ID; set later if appropriate
       ClassifyPage(),
diff --git a/components/omnibox/browser/omnibox_log.cc b/components/omnibox/browser/omnibox_log.cc
index 00c30abd..2ae624e 100644
--- a/components/omnibox/browser/omnibox_log.cc
+++ b/components/omnibox/browser/omnibox_log.cc
@@ -10,6 +10,7 @@
     metrics::OmniboxInputType input_type,
     bool is_popup_open,
     size_t selected_index,
+    WindowOpenDisposition disposition,
     bool is_paste_and_go,
     SessionID tab_id,
     metrics::OmniboxEventProto::PageClassification current_page_classification,
@@ -22,6 +23,7 @@
       input_type(input_type),
       is_popup_open(is_popup_open),
       selected_index(selected_index),
+      disposition(disposition),
       is_paste_and_go(is_paste_and_go),
       tab_id(tab_id),
       current_page_classification(current_page_classification),
diff --git a/components/omnibox/browser/omnibox_log.h b/components/omnibox/browser/omnibox_log.h
index b281bc5..ab7ebd6 100644
--- a/components/omnibox/browser/omnibox_log.h
+++ b/components/omnibox/browser/omnibox_log.h
@@ -13,6 +13,7 @@
 #include "components/sessions/core/session_id.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "third_party/metrics_proto/omnibox_input_type.pb.h"
+#include "ui/base/window_open_disposition.h"
 
 class AutocompleteResult;
 
@@ -24,6 +25,7 @@
              metrics::OmniboxInputType input_type,
              bool is_popup_open,
              size_t selected_index,
+             WindowOpenDisposition disposition,
              bool is_paste_and_go,
              SessionID tab_id,
              metrics::OmniboxEventProto::PageClassification
@@ -51,6 +53,10 @@
   // dropdown is closed (and therefore there is only one implicit suggestion).
   size_t selected_index;
 
+  // The disposition used to open the match. Currently, only SWITCH_TO_TAB
+  // is relevant to the log; all other dispositions are treated identically.
+  WindowOpenDisposition disposition;
+
   // True if this is a paste-and-search or paste-and-go omnibox interaction.
   // (The codebase refers to both these types as paste-and-go.)
   bool is_paste_and_go;
diff --git a/components/omnibox/browser/omnibox_metrics_provider.cc b/components/omnibox/browser/omnibox_metrics_provider.cc
index 367c6b8..f7a9afe 100644
--- a/components/omnibox/browser/omnibox_metrics_provider.cc
+++ b/components/omnibox/browser/omnibox_metrics_provider.cc
@@ -68,14 +68,11 @@
       return OmniboxEventProto::Suggestion::PHYSICAL_WEB;
     case AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW:
       return OmniboxEventProto::Suggestion::PHYSICAL_WEB_OVERFLOW;
-    case AutocompleteMatchType::TAB_SEARCH:
-      // TODO(crbug.com/46672): Create a specific type and move this result
-      // under it.
-      return OmniboxEventProto::Suggestion::UNKNOWN_RESULT_TYPE;
     case AutocompleteMatchType::VOICE_SUGGEST:
       // VOICE_SUGGEST matches are only used in Java and are not logged,
       // so we should never reach this case.
     case AutocompleteMatchType::CONTACT_DEPRECATED:
+    case AutocompleteMatchType::TAB_SEARCH_DEPRECATED:
     case AutocompleteMatchType::NUM_TYPES:
       break;
   }
@@ -130,6 +127,8 @@
   omnibox_event->set_just_deleted_text(log.just_deleted_text);
   omnibox_event->set_num_typed_terms(static_cast<int>(terms.size()));
   omnibox_event->set_selected_index(log.selected_index);
+  omnibox_event->set_selected_tab_match(log.disposition ==
+                                        WindowOpenDisposition::SWITCH_TO_TAB);
   if (log.completed_length != base::string16::npos)
     omnibox_event->set_completed_length(log.completed_length);
   const base::TimeDelta default_time_delta =
@@ -166,6 +165,7 @@
       suggestion->set_typed_count(i->typed_count);
     if (i->subtype_identifier > 0)
       suggestion->set_result_subtype_identifier(i->subtype_identifier);
+    suggestion->set_has_tab_match(i->has_tab_match);
   }
   for (ProvidersInfo::const_iterator i(log.providers_info.begin());
        i != log.providers_info.end(); ++i) {
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc
index f2a7e53..254405f 100644
--- a/components/omnibox/browser/omnibox_popup_model.cc
+++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -277,8 +277,8 @@
       return favicon;
   }
 
-  const auto& vector_icon_type =
-      AutocompleteMatch::TypeToVectorIcon(match.type, IsStarredMatch(match));
+  const auto& vector_icon_type = AutocompleteMatch::TypeToVectorIcon(
+      match.type, IsStarredMatch(match), match.has_tab_match);
   return edit_model_->client()->GetSizedIcon(vector_icon_type,
                                              vector_icon_color);
 }
diff --git a/components/omnibox/browser/omnibox_view.cc b/components/omnibox/browser/omnibox_view.cc
index 262319d..352606b 100644
--- a/components/omnibox/browser/omnibox_view.cc
+++ b/components/omnibox/browser/omnibox_view.cc
@@ -89,7 +89,7 @@
     return;
   // Unless user requests navigation, change disposition for this match type
   // so downstream will switch tabs.
-  if (match.type == AutocompleteMatchType::TAB_SEARCH) {
+  if (match.has_tab_match) {
     // "with-button" option inverts default action.
     bool invert = OmniboxFieldTrial::InTabSwitchSuggestionWithButtonTrial();
     if (disposition == WindowOpenDisposition::CURRENT_TAB &&
@@ -114,7 +114,7 @@
   return AutocompleteMatch::TypeToVectorIcon(
       model_ ? model_->CurrentTextType()
              : AutocompleteMatchType::URL_WHAT_YOU_TYPED,
-      /*is_bookmark=*/false);
+      /*is_bookmark=*/false, /*is_tab_match=*/false);
 }
 
 void OmniboxView::SetUserText(const base::string16& text) {
diff --git a/components/omnibox/browser/shortcuts_backend.cc b/components/omnibox/browser/shortcuts_backend.cc
index a55de4c..02f3019 100644
--- a/components/omnibox/browser/shortcuts_backend.cc
+++ b/components/omnibox/browser/shortcuts_backend.cc
@@ -124,9 +124,6 @@
 #if DCHECK_IS_ON()
   match.Validate();
 #endif  // DCHECK_IS_ON()
-  // TODO(crbug.com/46623): Let's think twice about saving these.
-  if (match.type == AutocompleteMatchType::TAB_SEARCH)
-    return;
   const base::string16 text_lowercase(base::i18n::ToLower(text));
   const base::Time now(base::Time::Now());
   for (ShortcutMap::const_iterator it(
diff --git a/components/policy/resources/policy_templates_et.xtb b/components/policy/resources/policy_templates_et.xtb
index d52df7f..7f9fff4 100644
--- a/components/policy/resources/policy_templates_et.xtb
+++ b/components/policy/resources/policy_templates_et.xtb
@@ -531,7 +531,7 @@
 <translation id="2529700525201305165">Piira kasutajaid, kes saavad logida sisse rakendusse <ph name="PRODUCT_NAME" /></translation>
 <translation id="2529880111512635313">Sunniviisiliselt installitud rakenduste ja laienduste loendi seadistamine</translation>
 <translation id="253135976343875019">Tegevusetuse hoiatuse viivitus vahelduvvoolutoite kasutamisel</translation>
-<translation id="2536283449105918306">Lubab kaitse vahekaardi all tehtavate toimingute eest</translation>
+<translation id="2536283449105918306">Lubab uute vahelehtede avamise vastase kaitse</translation>
 <translation id="2552966063069741410">Ajavöönd</translation>
 <translation id="2562339630163277285">Määrab otsingumootori URL-i, mida kasutatakse vahetute otsingutulemuste esitamiseks. URL peab sisaldama stringi <ph name="SEARCH_TERM_MARKER" />, mis asendatakse päringu tegemisel kasutaja sisestatud tekstiga.
 
@@ -2677,11 +2677,11 @@
 <translation id="9096086085182305205">Autentimisserveri lubatud nimekiri</translation>
 <translation id="9098553063150791878">HTTP autentimise reeglid</translation>
 <translation id="9105265795073104888">Androidi rakendustele muudetakse kättesaadavaks ainult puhverserveri seadistuse valikute alamkomplekt. Androidi rakenduste jaoks on puhverserveri kasutamine vabatahtlik. Te ei saa puhverserveri kasutamist sundida.</translation>
-<translation id="9110615239151047025">Lubab kaitse vahekaardi all tehtavate toimingute eest, mis blokeerib vahekaardi all tehtavate toimingutena tuvastatud navigeerimised.
+<translation id="9110615239151047025">Lubab uute vahelehtede avamise vastase kaitse, mis blokeerib uute vahelehtede avamisega seotud navigeerimised.
 
-      Vahekaardi all tehtavate toimingute selgituse leiate saidilt https://www.chromestatus.com/features/5675755719622656.
-      Kui selle reegli väärtuseks on määratud Tõene, blokeeritakse navigeerimised, mille teenus <ph name="PRODUCT_NAME" /> tuvastab vahekaardi all tehtavate toimingutena.
-      Kui selle reegli väärtuseks on määratud Väär, lubab teenus <ph name="PRODUCT_NAME" /> saitidele vahekaardi all tehtavate toimingutena tuvastatud navigeerimised.
+      Uute vahelehtede avamise selgituse leiate saidilt https://www.chromestatus.com/features/5675755719622656.
+      Kui selle reegli väärtuseks on määratud Tõene, blokeeritakse navigeerimised, mille teenus <ph name="PRODUCT_NAME" /> tuvastab uute vahelehtede avamisena.
+      Kui selle reegli väärtuseks on määratud Väär, lubab teenus <ph name="PRODUCT_NAME" /> saitidele uute vahelehtede avamise.
       Vaikimisi on selle reegli väärtuseks määratud Tõene.</translation>
 <translation id="9112727953998243860">Ettevõtte printerite konfiguratsioonifail</translation>
 <translation id="9112897538922695510">Lubab teil registreerida protokollitöötlejate loendi. See saab olla ainult soovitatud reegel. Atribuut |protocol| tuleb määrata skeemile (nagu „mailto”) ja atribuut |url| tuleb määrata skeemi käsitleva rakenduse URL-i mustrile. Muster võib sisaldada märgendit „%s”, mis asendatakse sellisel juhul käsitletava URL-iga.
diff --git a/components/policy/resources/policy_templates_lt.xtb b/components/policy/resources/policy_templates_lt.xtb
index f429cfb..d967af4 100644
--- a/components/policy/resources/policy_templates_lt.xtb
+++ b/components/policy/resources/policy_templates_lt.xtb
@@ -533,7 +533,7 @@
 <translation id="2529700525201305165">Riboti, kuriems naudotojams leidžiama prisijungti prie „<ph name="PRODUCT_NAME" />“</translation>
 <translation id="2529880111512635313">Konfigūruoti programų ir plėtinių, kuriuos įdiegti privaloma, sąrašą</translation>
 <translation id="253135976343875019">Neveikos įspėjimo delsa, kai naudojama kintamosios srovės energija</translation>
-<translation id="2536283449105918306">Įgalinama fone paleidžiamu skirtukų apsauga</translation>
+<translation id="2536283449105918306">Įgalinama fone paleidžiamų skirtukų apsauga</translation>
 <translation id="2552966063069741410">Laiko juosta</translation>
 <translation id="2562339630163277285">Nurodomas paieškos variklio, naudoto tiesioginiams rezultatams teikti, URL. URL turi būti eilutė <ph name="SEARCH_TERM_MARKER" />, kuri pateikiant užklausą bus pakeista naudotojo jau įvestu tekstu.
 
@@ -2690,7 +2690,7 @@
 <translation id="9096086085182305205">Tapatumo nustatymo serverio baltasis sąrašas</translation>
 <translation id="9098553063150791878">HTTP autentifikavimo politika</translation>
 <translation id="9105265795073104888">„Android“ programos gali pasiekti tik dalį tarpinio serverio konfigūravimo parinkčių. „Android“ programos gali pasirinkti naudoti tarpinį serverį. Negalite jų priversti naudoti tarpinio serverio.</translation>
-<translation id="9110615239151047025">Įgalinama fone paleidžiamu skirtukų apsauga. Taip užblokuojami naršymo veiksmai, kurie nustatomi kaip fone paleidžiami skirtukai.
+<translation id="9110615239151047025">Įgalinama fone paleidžiamų skirtukų apsauga. Taip užblokuojami naršymo veiksmai, kurie nustatomi kaip fone paleidžiami skirtukai.
 
       Fone paleidžiami skirtukai aprašyti adresu https://www.chromestatus.com/features/5675755719622656.
       Jei politika nustatyta į „True“, naršymo veiksmai, kuriuos „<ph name="PRODUCT_NAME" />“ laiko fone paleidžiamais skirtukais, bus užblokuoti.
diff --git a/components/printing/browser/print_manager_utils.cc b/components/printing/browser/print_manager_utils.cc
index 1257c7a..59b9ca8 100644
--- a/components/printing/browser/print_manager_utils.cc
+++ b/components/printing/browser/print_manager_utils.cc
@@ -8,7 +8,7 @@
 #include "components/printing/browser/features.h"
 #include "components/printing/browser/print_composite_client.h"
 #include "components/printing/common/print_messages.h"
-#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "printing/print_settings.h"
@@ -34,25 +34,7 @@
   // where OOPIF is used such as isolate-extensions, but should be good for
   // feature testing purpose. Eventually, we will remove this check and use pdf
   // compositor service by default for printing.
-
-  bool is_auxiliary_site_isolation_enabled;
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kIsolateOrigins)) {
-    is_auxiliary_site_isolation_enabled = true;
-  } else if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-                 switches::kDisableSiteIsolationTrials)) {
-    is_auxiliary_site_isolation_enabled = false;
-  } else {
-    // The features need to be checked last, because checking a feature
-    // activates the field trial and assigns the client either to a control or
-    // an experiment group.
-    is_auxiliary_site_isolation_enabled =
-        base::FeatureList::IsEnabled(::features::kIsolateOrigins) ||
-        base::FeatureList::IsEnabled(::features::kTopDocumentIsolation);
-  }
-
-  if (is_auxiliary_site_isolation_enabled ||
-      content::ContentBrowserClient::IsStrictSiteIsolationEnabled() ||
+  if (content::SiteIsolationPolicy::ShouldPdfCompositorBeEnabledForOopifs() ||
       base::FeatureList::IsEnabled(
           printing::features::kUsePdfCompositorServiceForPrint)) {
     PrintCompositeClient::CreateForWebContents(web_contents);
diff --git a/components/resources/default_100_percent/crash/favicon_sad_tab.png b/components/resources/default_100_percent/crash/favicon_sad_tab.png
index dcec70d8..38e51007 100644
--- a/components/resources/default_100_percent/crash/favicon_sad_tab.png
+++ b/components/resources/default_100_percent/crash/favicon_sad_tab.png
Binary files differ
diff --git a/components/resources/default_100_percent/favicon_history.png b/components/resources/default_100_percent/favicon_history.png
index 3af97be3..0de9a3f 100644
--- a/components/resources/default_100_percent/favicon_history.png
+++ b/components/resources/default_100_percent/favicon_history.png
Binary files differ
diff --git a/components/resources/default_100_percent/flags_ui/favicon_flags.png b/components/resources/default_100_percent/flags_ui/favicon_flags.png
index b27a223..0f6d8d0 100644
--- a/components/resources/default_100_percent/flags_ui/favicon_flags.png
+++ b/components/resources/default_100_percent/flags_ui/favicon_flags.png
Binary files differ
diff --git a/components/resources/default_200_percent/crash/favicon_sad_tab.png b/components/resources/default_200_percent/crash/favicon_sad_tab.png
index 9c434b9..6dd619d 100644
--- a/components/resources/default_200_percent/crash/favicon_sad_tab.png
+++ b/components/resources/default_200_percent/crash/favicon_sad_tab.png
Binary files differ
diff --git a/components/resources/default_200_percent/favicon_history.png b/components/resources/default_200_percent/favicon_history.png
index a07ed66e..126e8ddf 100644
--- a/components/resources/default_200_percent/favicon_history.png
+++ b/components/resources/default_200_percent/favicon_history.png
Binary files differ
diff --git a/components/resources/default_200_percent/flags_ui/favicon_flags.png b/components/resources/default_200_percent/flags_ui/favicon_flags.png
index 3b3d3722..d7da8a87 100644
--- a/components/resources/default_200_percent/flags_ui/favicon_flags.png
+++ b/components/resources/default_200_percent/flags_ui/favicon_flags.png
Binary files differ
diff --git a/components/resources/default_300_percent/crash/favicon_sad_tab.png b/components/resources/default_300_percent/crash/favicon_sad_tab.png
index 26221c6..8ca9ee8a 100644
--- a/components/resources/default_300_percent/crash/favicon_sad_tab.png
+++ b/components/resources/default_300_percent/crash/favicon_sad_tab.png
Binary files differ
diff --git a/components/resources/default_300_percent/favicon_history.png b/components/resources/default_300_percent/favicon_history.png
index c4c58862..0c174e1 100644
--- a/components/resources/default_300_percent/favicon_history.png
+++ b/components/resources/default_300_percent/favicon_history.png
Binary files differ
diff --git a/components/resources/default_300_percent/flags_ui/favicon_flags.png b/components/resources/default_300_percent/flags_ui/favicon_flags.png
index 14d8551..801b8604 100644
--- a/components/resources/default_300_percent/flags_ui/favicon_flags.png
+++ b/components/resources/default_300_percent/flags_ui/favicon_flags.png
Binary files differ
diff --git a/components/resources/sadtab.svg b/components/resources/sadtab.svg
index 9ce9ccb..6ff684b 100644
--- a/components/resources/sadtab.svg
+++ b/components/resources/sadtab.svg
@@ -1,4 +1,4 @@
 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48px" viewbox="0 0 48 48" fill="none">
-  <path stroke="#5a5a5a" stroke-width="3" stroke-linecap="square" d="M1.5 8.5 v34 h45 v-28 m-3-3 h-10 v-3 m-3-3 h-10 m15 6 h-18 v-3 m-3-3 h-10"/>
-  <path stroke="#5a5a5a" stroke-width="2" stroke-linecap="square" d="M12 35 h2 m2-2 h12 m2 2 h3 m2 2 h3 M11 21 l0 0 m0 4 h0 m4 0 h0 m0-4 h0 m-2 2 h0 M33 21 l0 0 m0 4 h0 m4 0 h0 m0-4 h0 m-2 2 h0"/>
+  <path stroke="#5f6368" stroke-width="3" stroke-linecap="square" d="M1.5 8.5 v34 h45 v-28 m-3-3 h-10 v-3 m-3-3 h-10 m15 6 h-18 v-3 m-3-3 h-10"/>
+  <path stroke="#5f6368" stroke-width="2" stroke-linecap="square" d="M12 35 h2 m2-2 h12 m2 2 h3 m2 2 h3 M11 21 l0 0 m0 4 h0 m4 0 h0 m0-4 h0 m-2 2 h0 M33 21 l0 0 m0 4 h0 m4 0 h0 m0-4 h0 m-2 2 h0"/>
 </svg>
diff --git a/components/services/heap_profiling/public/cpp/BUILD.gn b/components/services/heap_profiling/public/cpp/BUILD.gn
index dbc497ea..fdfc2dc 100644
--- a/components/services/heap_profiling/public/cpp/BUILD.gn
+++ b/components/services/heap_profiling/public/cpp/BUILD.gn
@@ -12,6 +12,8 @@
     "sender_pipe_posix.cc",
     "sender_pipe_win.cc",
     "stream.h",
+    "switches.cc",
+    "switches.h",
   ]
 
   public_deps = [
diff --git a/components/services/heap_profiling/public/cpp/switches.cc b/components/services/heap_profiling/public/cpp/switches.cc
new file mode 100644
index 0000000..de040ff
--- /dev/null
+++ b/components/services/heap_profiling/public/cpp/switches.cc
@@ -0,0 +1,26 @@
+// Copyright 2018 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/services/heap_profiling/public/cpp/switches.h"
+
+namespace heap_profiling {
+
+const char kMemlog[] = "memlog";
+const char kMemlogKeepSmallAllocations[] = "memlog-keep-small-allocations";
+const char kMemlogModeAll[] = "all";
+const char kMemlogModeAllRenderers[] = "all-renderers";
+const char kMemlogModeBrowser[] = "browser";
+const char kMemlogModeGpu[] = "gpu";
+const char kMemlogModeManual[] = "manual";
+const char kMemlogModeMinimal[] = "minimal";
+const char kMemlogModeRendererSampling[] = "renderer-sampling";
+const char kMemlogSampling[] = "memlog-sampling";
+const char kMemlogSamplingRate[] = "memlog-sampling-rate";
+const char kMemlogStackMode[] = "memlog-stack-mode";
+const char kMemlogStackModeMixed[] = "mixed";
+const char kMemlogStackModeNative[] = "native";
+const char kMemlogStackModeNativeWithThreadNames[] = "native-with-thread-names";
+const char kMemlogStackModePseudo[] = "pseudo";
+
+}  // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/switches.h b/components/services/heap_profiling/public/cpp/switches.h
new file mode 100644
index 0000000..e766e45
--- /dev/null
+++ b/components/services/heap_profiling/public/cpp/switches.h
@@ -0,0 +1,29 @@
+// Copyright 2018 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_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SWITCHES_H_
+#define COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SWITCHES_H_
+
+namespace heap_profiling {
+
+extern const char kMemlog[];
+extern const char kMemlogKeepSmallAllocations[];
+extern const char kMemlogModeAll[];
+extern const char kMemlogModeAllRenderers[];
+extern const char kMemlogModeBrowser[];
+extern const char kMemlogModeGpu[];
+extern const char kMemlogModeManual[];
+extern const char kMemlogModeMinimal[];
+extern const char kMemlogModeRendererSampling[];
+extern const char kMemlogSampling[];
+extern const char kMemlogSamplingRate[];
+extern const char kMemlogStackMode[];
+extern const char kMemlogStackModeMixed[];
+extern const char kMemlogStackModeNative[];
+extern const char kMemlogStackModeNativeWithThreadNames[];
+extern const char kMemlogStackModePseudo[];
+
+}  // namespace heap_profiling
+
+#endif  // COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SWITCHES_H_
diff --git a/components/strings/components_strings_mr.xtb b/components/strings/components_strings_mr.xtb
index 9822148..d094d73 100644
--- a/components/strings/components_strings_mr.xtb
+++ b/components/strings/components_strings_mr.xtb
@@ -141,7 +141,7 @@
 <translation id="1974060860693918893">प्रगत</translation>
 <translation id="1978555033938440688">फर्मवेयर आवृत्ती</translation>
 <translation id="2001146170449793414">{COUNT,plural, =1{आणि 1 अधिक}one{आणि # अधिक}other{आणि # अधिक}}</translation>
-<translation id="2003709556000175978">आता आपला पासवर्ड रिसेट करा</translation>
+<translation id="2003709556000175978">आता तुमचा पासवर्ड रीसेट करा</translation>
 <translation id="2025186561304664664">प्रॉक्सी स्वयंचलित ‍कॉन्फिगरेशनवर सेट करण्‍यात आली.</translation>
 <translation id="2030481566774242610">आपल्याला असे म्हणायचे होते <ph name="LINK" />?</translation>
 <translation id="2032962459168915086"><ph name="BEGIN_LINK" />प्रॉक्सी आणि फायरवॉल तपासणे<ph name="END_LINK" /></translation>
@@ -149,7 +149,7 @@
 <translation id="2064691555167957331">{COUNT,plural, =1{1 सूचना}one{# सूचना}other{# सूचना}}</translation>
 <translation id="2079545284768500474">पूर्ववत करा</translation>
 <translation id="20817612488360358">सिस्टम प्रॉक्सी सेटिंग्ज वापरण्‍यास सेट करण्‍यात आल्या परंतु एक सुस्पष्‍ट प्रॉक्सी कॉन्फिगरेशन देखील निर्दिष्‍ट करण्‍यात आले.</translation>
-<translation id="2084558088529668945">तुम्ही साइटवर एंटर केलेला पासवर्ड <ph name="ORG_NAME" /> ने व्यवस्थापित केलेला नाही. तुमचा पासवर्ड संरक्षित करण्यासाठी, अन्य अ‍ॅप्स आणि साइट तुमचा पासवर्ड पुन्हा वापरू नका.</translation>
+<translation id="2084558088529668945">तुम्ही साइटवर एंटर केलेला पासवर्ड <ph name="ORG_NAME" /> ने व्यवस्थापित केलेला नाही. तुमचा पासवर्ड संरक्षित करण्यासाठी, अन्य अ‍ॅप्स आणि साइटवर तुमचा पासवर्ड पुन्हा वापरू नका.</translation>
 <translation id="2091887806945687916">ध्वनी</translation>
 <translation id="2094505752054353250">डोमेन जुळत नाही</translation>
 <translation id="2096368010154057602">विभाग</translation>
diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc
index 9b985fb..496c9a9 100644
--- a/components/update_client/update_checker_unittest.cc
+++ b/components/update_client/update_checker_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/version.h"
@@ -898,4 +899,36 @@
   EXPECT_STREQ("this", component->action_run_.c_str());
 }
 
+TEST_F(UpdateCheckerTest, UpdatePauseResume) {
+  EXPECT_TRUE(post_interceptor_->ExpectRequest(
+      std::make_unique<PartialMatch>("updatecheck"),
+      test_file("updatecheck_reply_1.xml")));
+  post_interceptor_->url_job_request_ready_callback(base::BindOnce(
+      [](scoped_refptr<URLRequestPostInterceptor> post_interceptor) {
+        post_interceptor->Resume();
+      },
+      post_interceptor_));
+  post_interceptor_->Pause();
+
+  update_checker_ = UpdateChecker::Create(config_, metadata_.get());
+
+  IdToComponentPtrMap components;
+  components[kUpdateItemId] = MakeComponent();
+
+  update_checker_->CheckForUpdates(
+      update_context_->session_id, std::vector<std::string>{kUpdateItemId},
+      components, "", true,
+      base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
+                     base::Unretained(this)));
+  RunThreads();
+
+  const auto request = post_interceptor_->GetRequestBody(0);
+  EXPECT_NE(string::npos,
+            request.find(std::string("<app appid=\"") + kUpdateItemId +
+                         "\" version=\"0.9\" brand=\"TEST\" enabled=\"1\">"
+                         "<updatecheck/><ping r=\"-2\" "));
+  EXPECT_NE(string::npos,
+            request.find("<packages><package fp=\"fp1\"/></packages></app>"));
+}
+
 }  // namespace update_client
diff --git a/components/update_client/url_request_post_interceptor.cc b/components/update_client/url_request_post_interceptor.cc
index 447e46a..2bf72e1 100644
--- a/components/update_client/url_request_post_interceptor.cc
+++ b/components/update_client/url_request_post_interceptor.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -24,16 +25,25 @@
 namespace update_client {
 
 // Returns a canned response.
-class URLRequestMockJob : public net::URLRequestSimpleJob {
+class URLRequestPostInterceptor::URLRequestMockJob
+    : public net::URLRequestSimpleJob {
  public:
-  URLRequestMockJob(net::URLRequest* request,
+  URLRequestMockJob(scoped_refptr<URLRequestPostInterceptor> interceptor,
+                    net::URLRequest* request,
                     net::NetworkDelegate* network_delegate,
                     int response_code,
                     const std::string& response_body)
       : net::URLRequestSimpleJob(request, network_delegate),
+        interceptor_(interceptor),
         response_code_(response_code),
         response_body_(response_body) {}
 
+  void Start() override {
+    if (interceptor_->is_paused_)
+      return;
+    net::URLRequestSimpleJob::Start();
+  }
+
  protected:
   void GetResponseInfo(net::HttpResponseInfo* info) override {
     const std::string headers =
@@ -55,6 +65,8 @@
  private:
   ~URLRequestMockJob() override {}
 
+  scoped_refptr<URLRequestPostInterceptor> interceptor_;
+
   int response_code_;
   std::string response_body_;
   DISALLOW_COPY_AND_ASSIGN(URLRequestMockJob);
@@ -138,6 +150,25 @@
   base::queue<Expectation>().swap(expectations_);
 }
 
+void URLRequestPostInterceptor::Pause() {
+  base::AutoLock auto_lock(interceptor_lock_);
+  is_paused_ = true;
+}
+
+void URLRequestPostInterceptor::Resume() {
+  base::AutoLock auto_lock(interceptor_lock_);
+  is_paused_ = false;
+  io_task_runner_->PostTask(FROM_HERE,
+                            base::BindOnce(&URLRequestMockJob::Start,
+                                           base::Unretained(request_job_)));
+}
+
+void URLRequestPostInterceptor::url_job_request_ready_callback(
+    UrlJobRequestReadyCallback url_job_request_ready_callback) {
+  base::AutoLock auto_lock(interceptor_lock_);
+  url_job_request_ready_callback_ = std::move(url_job_request_ready_callback);
+}
+
 class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor {
  public:
   Delegate(const std::string& scheme,
@@ -214,8 +245,15 @@
         const std::string response_body(expectation.second.response_body);
         interceptor->expectations_.pop();
         ++interceptor->hit_count_;
-        return new URLRequestMockJob(request, network_delegate, response_code,
-                                     response_body);
+        interceptor->request_job_ =
+            new URLRequestMockJob(interceptor, request, network_delegate,
+                                  response_code, response_body);
+        if (interceptor->url_job_request_ready_callback_) {
+          io_task_runner_->PostTask(
+              FROM_HERE,
+              std::move(interceptor->url_job_request_ready_callback_));
+        }
+        return interceptor->request_job_;
       }
     }
 
diff --git a/components/update_client/url_request_post_interceptor.h b/components/update_client/url_request_post_interceptor.h
index 5b547fe..4355f6e4 100644
--- a/components/update_client/url_request_post_interceptor.h
+++ b/components/update_client/url_request_post_interceptor.h
@@ -12,6 +12,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/containers/queue.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -29,6 +30,8 @@
 
 namespace update_client {
 
+class URLRequestMockJob;
+
 // Intercepts requests to a file path, counts them, and captures the body of
 // the requests. Optionally, for each request, it can return a canned response
 // from a given file. The class maintains a queue of expectations, and returns
@@ -38,6 +41,11 @@
     : public base::RefCountedThreadSafe<URLRequestPostInterceptor> {
  public:
   using InterceptedRequest = std::pair<std::string, net::HttpRequestHeaders>;
+
+  // Called when the job associated with the url request which is intercepted
+  // by this object has been created.
+  using UrlJobRequestReadyCallback = base::OnceCallback<void()>;
+
   // Allows a generic string maching interface when setting up expectations.
   class RequestMatcher {
    public:
@@ -79,9 +87,26 @@
   // Resets the state of the interceptor so that new expectations can be set.
   void Reset();
 
-  class Delegate;
+  // Prevents the intercepted request from starting, as a way to simulate
+  // the effects of a very slow network. Call this function before the actual
+  // network request occurs.
+  void Pause();
+
+  // Allows a previously paused request to continue.
+  void Resume();
+
+  // Sets a callback to be invoked when the request job associated with
+  // an intercepted request is created. This allows the test execution to
+  // synchronize with network tasks running on the IO thread and avoid polling
+  // using idle run loops. A paused request can be resumed after this callback
+  // has been invoked.
+  void url_job_request_ready_callback(
+      UrlJobRequestReadyCallback url_job_request_ready_callback);
 
  private:
+  class Delegate;
+  class URLRequestMockJob;
+
   friend class URLRequestPostInterceptorFactory;
   friend class base::RefCountedThreadSafe<URLRequestPostInterceptor>;
 
@@ -118,6 +143,12 @@
   // Contains the expectations which this interceptor tries to match.
   base::queue<Expectation> expectations_;
 
+  URLRequestMockJob* request_job_ = nullptr;
+
+  bool is_paused_ = false;
+
+  UrlJobRequestReadyCallback url_job_request_ready_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(URLRequestPostInterceptor);
 };
 
diff --git a/components/viz/common/resources/resource.cc b/components/viz/common/resources/resource.cc
index 6869f53..42d3ae2 100644
--- a/components/viz/common/resources/resource.cc
+++ b/components/viz/common/resources/resource.cc
@@ -18,6 +18,7 @@
                    ResourceFormat format,
                    const gfx::ColorSpace& color_space)
     : locked_for_write(false),
+      locked_for_external_use(false),
       lost(false),
       marked_for_deletion(false),
       allocated(false),
diff --git a/components/viz/common/resources/resource.h b/components/viz/common/resources/resource.h
index 51a876e..82bef3a 100644
--- a/components/viz/common/resources/resource.h
+++ b/components/viz/common/resources/resource.h
@@ -109,6 +109,8 @@
   // When true, the resource is currently being written to. Used to prevent
   // misuse while the resource is being modified.
   bool locked_for_write : 1;
+  // When true, the resource is currently being used externally.
+  bool locked_for_external_use : 1;
   // When true the resource can not be used and must only be deleted. This is
   // passed along to the |release_callback|.
   bool lost : 1;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 8df88764..ab2fb1e 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -694,7 +694,6 @@
     "dom_storage/session_storage_namespace_impl.h",
     "download/byte_stream_input_stream.cc",
     "download/byte_stream_input_stream.h",
-    "download/download_item_factory.h",
     "download/download_item_utils.cc",
     "download/download_manager_impl.cc",
     "download/download_manager_impl.h",
@@ -1560,8 +1559,6 @@
     "shared_worker/shared_worker_service_impl.h",
     "site_instance_impl.cc",
     "site_instance_impl.h",
-    "site_isolation_policy.cc",
-    "site_isolation_policy.h",
     "speech/speech_recognition_dispatcher_host.cc",
     "speech/speech_recognition_dispatcher_host.h",
     "speech/speech_recognition_manager_impl.cc",
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index b6b9322fa5..3a6d098 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -83,7 +83,6 @@
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/service_manager/service_manager_context.h"
-#include "content/browser/site_isolation_policy.h"
 #include "content/browser/speech/speech_recognition_manager_impl.h"
 #include "content/browser/startup_task_runner.h"
 #include "content/browser/tracing/background_tracing_manager_impl.h"
@@ -99,6 +98,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/swap_metrics_driver.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
diff --git a/content/browser/browsing_instance.cc b/content/browser/browsing_instance.cc
index c7ed216..3758184 100644
--- a/content/browser/browsing_instance.cc
+++ b/content/browser/browsing_instance.cc
@@ -7,9 +7,9 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/site_isolation_policy.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 1ff1502..44dc90e 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -21,12 +21,12 @@
 #include "content/browser/bad_message.h"
 #include "content/browser/isolated_origin_util.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/site_isolation_policy.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/bindings_policy.h"
 #include "content/public/common/url_constants.h"
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 4fcc36fb..57c9997 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -36,7 +36,7 @@
 #include "components/download/public/common/download_file_factory.h"
 #include "components/download/public/common/download_file_impl.h"
 #include "components/download/public/common/download_task_runner.h"
-#include "components/download/public/common/parallel_download_utils.h"
+#include "components/download/public/common/parallel_download_configs.h"
 #include "content/browser/download/download_manager_impl.h"
 #include "content/browser/download/download_resource_handler.h"
 #include "content/browser/web_contents/web_contents_impl.h"
diff --git a/content/browser/download/download_item_factory.h b/content/browser/download/download_item_factory.h
deleted file mode 100644
index c088755..0000000
--- a/content/browser/download/download_item_factory.h
+++ /dev/null
@@ -1,85 +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.
-//
-// The DownloadItemFactory is used to produce different download::DownloadItems.
-// It is separate from the DownloadManager to allow download manager
-// unit tests to control the items produced.
-
-#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_FACTORY_H_
-#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_FACTORY_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "components/download/public/common/download_item.h"
-
-class GURL;
-
-namespace base {
-class FilePath;
-}  // namespace base
-
-namespace download {
-struct DownloadCreateInfo;
-class DownloadItemImpl;
-class DownloadItemImplDelegate;
-class DownloadRequestHandleInterface;
-}  // namespace download
-
-namespace content {
-
-class DownloadItemFactory {
-public:
-  virtual ~DownloadItemFactory() {}
-
-  virtual download::DownloadItemImpl* CreatePersistedItem(
-      download::DownloadItemImplDelegate* delegate,
-      const std::string& guid,
-      uint32_t download_id,
-      const base::FilePath& current_path,
-      const base::FilePath& target_path,
-      const std::vector<GURL>& url_chain,
-      const GURL& referrer_url,
-      const GURL& site_url,
-      const GURL& tab_url,
-      const GURL& tab_refererr_url,
-      const std::string& mime_type,
-      const std::string& original_mime_type,
-      base::Time start_time,
-      base::Time end_time,
-      const std::string& etag,
-      const std::string& last_modified,
-      int64_t received_bytes,
-      int64_t total_bytes,
-      const std::string& hash,
-      download::DownloadItem::DownloadState state,
-      download::DownloadDangerType danger_type,
-      download::DownloadInterruptReason interrupt_reason,
-      bool opened,
-      base::Time last_access_time,
-      bool transient,
-      const std::vector<download::DownloadItem::ReceivedSlice>&
-          received_slices) = 0;
-
-  virtual download::DownloadItemImpl* CreateActiveItem(
-      download::DownloadItemImplDelegate* delegate,
-      uint32_t download_id,
-      const download::DownloadCreateInfo& info) = 0;
-
-  virtual download::DownloadItemImpl* CreateSavePageItem(
-      download::DownloadItemImplDelegate* delegate,
-      uint32_t download_id,
-      const base::FilePath& path,
-      const GURL& url,
-      const std::string& mime_type,
-      std::unique_ptr<download::DownloadRequestHandleInterface>
-          request_handle) = 0;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_FACTORY_H_
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index c788efe..d8877e9 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -29,6 +29,7 @@
 #include "components/download/public/common/download_file.h"
 #include "components/download/public/common/download_file_factory.h"
 #include "components/download/public/common/download_interrupt_reasons.h"
+#include "components/download/public/common/download_item_factory.h"
 #include "components/download/public/common/download_item_impl.h"
 #include "components/download/public/common/download_request_handle_interface.h"
 #include "components/download/public/common/download_stats.h"
@@ -40,7 +41,6 @@
 #include "content/browser/byte_stream.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/download/byte_stream_input_stream.h"
-#include "content/browser/download/download_item_factory.h"
 #include "content/browser/download/download_resource_handler.h"
 #include "content/browser/download/download_utils.h"
 #include "content/browser/download/url_downloader.h"
@@ -255,7 +255,7 @@
           download_manager, std::move(downloader)));
 }
 
-class DownloadItemFactoryImpl : public DownloadItemFactory {
+class DownloadItemFactoryImpl : public download::DownloadItemFactory {
  public:
   DownloadItemFactoryImpl() {}
   ~DownloadItemFactoryImpl() override {}
@@ -835,9 +835,8 @@
   BeginDownloadInternal(std::move(params), nullptr, id, storage_partition);
 }
 
-
 void DownloadManagerImpl::SetDownloadItemFactoryForTesting(
-    std::unique_ptr<DownloadItemFactory> item_factory) {
+    std::unique_ptr<download::DownloadItemFactory> item_factory) {
   item_factory_ = std::move(item_factory);
 }
 
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index b97db191..13ae60ba 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -34,12 +34,12 @@
 
 namespace download {
 class DownloadFileFactory;
+class DownloadItemFactory;
 class DownloadItemImpl;
 class DownloadRequestHandleInterface;
 }
 
 namespace content {
-class DownloadItemFactory;
 class ResourceContext;
 class StoragePartitionImpl;
 class URLLoaderFactoryGetter;
@@ -145,7 +145,7 @@
 
   // For testing; specifically, accessed from TestFileErrorInjector.
   void SetDownloadItemFactoryForTesting(
-      std::unique_ptr<DownloadItemFactory> item_factory);
+      std::unique_ptr<download::DownloadItemFactory> item_factory);
   void SetDownloadFileFactoryForTesting(
       std::unique_ptr<download::DownloadFileFactory> file_factory);
   virtual download::DownloadFileFactory* GetDownloadFileFactoryForTesting();
@@ -282,7 +282,7 @@
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
 
   // Factory for creation of downloads items.
-  std::unique_ptr<DownloadItemFactory> item_factory_;
+  std::unique_ptr<download::DownloadItemFactory> item_factory_;
 
   // Factory for the creation of download files.
   std::unique_ptr<download::DownloadFileFactory> file_factory_;
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index 59340f3..ffa4b9d 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -28,14 +28,14 @@
 #include "components/download/public/common/download_file_factory.h"
 #include "components/download/public/common/download_interrupt_reasons.h"
 #include "components/download/public/common/download_item.h"
+#include "components/download/public/common/download_item_factory.h"
 #include "components/download/public/common/download_item_impl.h"
 #include "components/download/public/common/download_item_impl_delegate.h"
 #include "components/download/public/common/download_request_handle_interface.h"
 #include "components/download/public/common/mock_download_file.h"
+#include "components/download/public/common/mock_download_item_impl.h"
 #include "content/browser/byte_stream.h"
 #include "content/browser/download/byte_stream_input_stream.h"
-#include "content/browser/download/download_item_factory.h"
-#include "content/browser/download/mock_download_item_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/download_manager_delegate.h"
 #include "content/public/browser/storage_partition.h"
@@ -97,7 +97,7 @@
 MockDownloadManagerDelegate::~MockDownloadManagerDelegate() {}
 
 class MockDownloadItemFactory
-    : public DownloadItemFactory,
+    : public download::DownloadItemFactory,
       public base::SupportsWeakPtr<MockDownloadItemFactory> {
  public:
   MockDownloadItemFactory();
@@ -108,11 +108,11 @@
   // functionality if it's ever needed by consumers.
 
   // Returns NULL if no item of that id is present.
-  MockDownloadItemImpl* GetItem(int id);
+  download::MockDownloadItemImpl* GetItem(int id);
 
   // Remove and return an item made by the factory.
   // Generally used during teardown.
-  MockDownloadItemImpl* PopItem();
+  download::MockDownloadItemImpl* PopItem();
 
   // Should be called when the item of this id is removed so that
   // we don't keep dangling pointers.
@@ -165,7 +165,7 @@
       override;
 
  private:
-  std::map<uint32_t, MockDownloadItemImpl*> items_;
+  std::map<uint32_t, download::MockDownloadItemImpl*> items_;
   download::DownloadItemImplDelegate item_delegate_;
   bool has_observer_calls_;
 
@@ -177,19 +177,19 @@
 
 MockDownloadItemFactory::~MockDownloadItemFactory() {}
 
-MockDownloadItemImpl* MockDownloadItemFactory::GetItem(int id) {
+download::MockDownloadItemImpl* MockDownloadItemFactory::GetItem(int id) {
   if (items_.find(id) == items_.end())
     return nullptr;
   return items_[id];
 }
 
-MockDownloadItemImpl* MockDownloadItemFactory::PopItem() {
+download::MockDownloadItemImpl* MockDownloadItemFactory::PopItem() {
   if (items_.empty())
     return nullptr;
 
-  std::map<uint32_t, MockDownloadItemImpl*>::iterator first_item =
+  std::map<uint32_t, download::MockDownloadItemImpl*>::iterator first_item =
       items_.begin();
-  MockDownloadItemImpl* result = first_item->second;
+  download::MockDownloadItemImpl* result = first_item->second;
   items_.erase(first_item);
   return result;
 }
@@ -231,8 +231,8 @@
     bool transient,
     const std::vector<download::DownloadItem::ReceivedSlice>& received_slices) {
   DCHECK(items_.find(download_id) == items_.end());
-  MockDownloadItemImpl* result =
-      new StrictMock<MockDownloadItemImpl>(&item_delegate_);
+  download::MockDownloadItemImpl* result =
+      new StrictMock<download::MockDownloadItemImpl>(&item_delegate_);
   EXPECT_CALL(*result, GetId())
       .WillRepeatedly(Return(download_id));
   EXPECT_CALL(*result, GetGuid()).WillRepeatedly(ReturnRefOfCopy(guid));
@@ -246,8 +246,8 @@
     const download::DownloadCreateInfo& info) {
   DCHECK(items_.find(download_id) == items_.end());
 
-  MockDownloadItemImpl* result =
-      new StrictMock<MockDownloadItemImpl>(&item_delegate_);
+  download::MockDownloadItemImpl* result =
+      new StrictMock<download::MockDownloadItemImpl>(&item_delegate_);
   EXPECT_CALL(*result, GetId())
       .WillRepeatedly(Return(download_id));
   EXPECT_CALL(*result, GetGuid())
@@ -276,8 +276,8 @@
     std::unique_ptr<download::DownloadRequestHandleInterface> request_handle) {
   DCHECK(items_.find(download_id) == items_.end());
 
-  MockDownloadItemImpl* result =
-      new StrictMock<MockDownloadItemImpl>(&item_delegate_);
+  download::MockDownloadItemImpl* result =
+      new StrictMock<download::MockDownloadItemImpl>(&item_delegate_);
   EXPECT_CALL(*result, GetId())
       .WillRepeatedly(Return(download_id));
   items_[download_id] = result;
@@ -358,7 +358,7 @@
     browser_context_ = std::make_unique<TestBrowserContext>();
     download_manager_.reset(new DownloadManagerImpl(browser_context_.get()));
     download_manager_->SetDownloadItemFactoryForTesting(
-        std::unique_ptr<DownloadItemFactory>(
+        std::unique_ptr<download::DownloadItemFactory>(
             mock_download_item_factory_.get()));
     download_manager_->SetDownloadFileFactoryForTesting(
         std::unique_ptr<download::DownloadFileFactory>(
@@ -373,8 +373,8 @@
   }
 
   void TearDown() override {
-    while (MockDownloadItemImpl*
-           item = mock_download_item_factory_->PopItem()) {
+    while (download::MockDownloadItemImpl* item =
+               mock_download_item_factory_->PopItem()) {
       EXPECT_CALL(*item, GetState())
           .WillOnce(Return(download::DownloadItem::CANCELLED));
     }
@@ -390,7 +390,7 @@
   }
 
   // Returns download id.
-  MockDownloadItemImpl& AddItemToManager() {
+  download::MockDownloadItemImpl& AddItemToManager() {
     download::DownloadCreateInfo info;
 
     // Args are ignored except for download id, so everything else can be
@@ -399,7 +399,8 @@
     ++next_download_id_;
     download_manager_->CreateActiveItem(id, info);
     DCHECK(mock_download_item_factory_->GetItem(id));
-    MockDownloadItemImpl& item(*mock_download_item_factory_->GetItem(id));
+    download::MockDownloadItemImpl& item(
+        *mock_download_item_factory_->GetItem(id));
     // Satisfy expectation.  If the item is created in StartDownload(),
     // we call Start on it immediately, so we need to set that expectation
     // in the factory.
@@ -412,8 +413,9 @@
     return item;
   }
 
-  MockDownloadItemImpl& GetMockDownloadItem(int id) {
-    MockDownloadItemImpl* itemp = mock_download_item_factory_->GetItem(id);
+  download::MockDownloadItemImpl& GetMockDownloadItem(int id) {
+    download::MockDownloadItemImpl* itemp =
+        mock_download_item_factory_->GetItem(id);
 
     DCHECK(itemp);
     return *itemp;
@@ -526,7 +528,7 @@
 // blocks starting.
 TEST_F(DownloadManagerTest, DetermineDownloadTarget_True) {
   // Put a mock we have a handle to on the download manager.
-  MockDownloadItemImpl& item(AddItemToManager());
+  download::MockDownloadItemImpl& item(AddItemToManager());
   EXPECT_CALL(item, GetState())
       .WillRepeatedly(Return(download::DownloadItem::IN_PROGRESS));
 
@@ -540,7 +542,7 @@
 // allows starting.  This also tests OnDownloadTargetDetermined.
 TEST_F(DownloadManagerTest, DetermineDownloadTarget_False) {
   // Put a mock we have a handle to on the download manager.
-  MockDownloadItemImpl& item(AddItemToManager());
+  download::MockDownloadItemImpl& item(AddItemToManager());
 
   base::FilePath path(FILE_PATH_LITERAL("random_filepath.txt"));
   EXPECT_CALL(GetMockDownloadManagerDelegate(),
@@ -564,7 +566,7 @@
   for (uint32_t i = 0; i < 4; ++i)
     AddItemToManager();
 
-  MockDownloadItemImpl& item = GetMockDownloadItem(0);
+  download::MockDownloadItemImpl& item = GetMockDownloadItem(0);
   download::DownloadItem* result =
       download_manager_->GetDownloadByGuid(item.GetGuid());
   ASSERT_TRUE(result);
@@ -603,7 +605,7 @@
 TEST_F(DownloadManagerTest, RemoveDownloadsByURL) {
   base::Time now(base::Time::Now());
   for (uint32_t i = 0; i < 2; ++i) {
-    MockDownloadItemImpl& item(AddItemToManager());
+    download::MockDownloadItemImpl& item(AddItemToManager());
     EXPECT_CALL(item, GetStartTime()).WillRepeatedly(Return(now));
     EXPECT_CALL(item, GetState())
         .WillRepeatedly(Return(download::DownloadItem::COMPLETE));
diff --git a/content/browser/download/mock_download_item_impl.cc b/content/browser/download/mock_download_item_impl.cc
deleted file mode 100644
index bb18fc7..0000000
--- a/content/browser/download/mock_download_item_impl.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/download/mock_download_item_impl.h"
-
-namespace content {
-
-MockDownloadItemImpl::MockDownloadItemImpl(
-    download::DownloadItemImplDelegate* delegate)
-    : download::DownloadItemImpl(
-          delegate,
-          std::string("7d122682-55b5-4a47-a253-36cadc3e5bee"),
-          download::DownloadItem::kInvalidId,
-          base::FilePath(),
-          base::FilePath(),
-          std::vector<GURL>(),
-          GURL(),
-          GURL(),
-          GURL(),
-          GURL(),
-          "application/octet-stream",
-          "application/octet-stream",
-          base::Time(),
-          base::Time(),
-          std::string(),
-          std::string(),
-          0,
-          0,
-          std::string(),
-          download::DownloadItem::COMPLETE,
-          download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
-          download::DOWNLOAD_INTERRUPT_REASON_NONE,
-          false,
-          base::Time(),
-          true,
-          download::DownloadItem::ReceivedSlices()) {}
-
-MockDownloadItemImpl::~MockDownloadItemImpl() = default;
-
-}  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index e1a205e..c9a8e223 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -35,7 +35,6 @@
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/site_isolation_policy.h"
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
@@ -46,6 +45,7 @@
 #include "content/public/browser/render_process_host_observer.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/referrer.h"
 #include "content/public/common/url_constants.h"
diff --git a/content/browser/loader/cross_site_document_resource_handler.cc b/content/browser/loader/cross_site_document_resource_handler.cc
index 71b375a4..a6aedd72 100644
--- a/content/browser/loader/cross_site_document_resource_handler.cc
+++ b/content/browser/loader/cross_site_document_resource_handler.cc
@@ -22,10 +22,10 @@
 #include "content/browser/loader/detachable_resource_handler.h"
 #include "content/browser/loader/resource_request_info_impl.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/site_isolation_policy.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/resource_context.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_client.h"
 #include "net/base/io_buffer.h"
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index c7a9509..cf892d7 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -64,7 +64,6 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_navigation_handle_core.h"
 #include "content/browser/service_worker/service_worker_request_handler.h"
-#include "content/browser/site_isolation_policy.h"
 #include "content/browser/streams/stream.h"
 #include "content/browser/streams/stream_context.h"
 #include "content/browser/streams/stream_registry.h"
@@ -81,6 +80,7 @@
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/resource_throttle.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/stream_handle.h"
 #include "content/public/browser/stream_info.h"
 #include "content/public/common/browser_side_navigation_policy.h"
diff --git a/content/browser/payments/OWNERS b/content/browser/payments/OWNERS
index 81e0787..f601d5da 100644
--- a/content/browser/payments/OWNERS
+++ b/content/browser/payments/OWNERS
@@ -1,4 +1,5 @@
 jinho.bang@samsung.com
 rouslan@chromium.org
+gogerald@chromium.org
 
 # COMPONENT: UI>Browser>Payments
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 6e9c3c18..9c379aa 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -131,7 +131,6 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_dispatcher_host.h"
 #include "content/browser/site_instance_impl.h"
-#include "content/browser/site_isolation_policy.h"
 #include "content/browser/speech/speech_recognition_dispatcher_host.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/browser/streams/stream_context.h"
@@ -157,6 +156,7 @@
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/resource_context.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/common/bind_interface_helpers.h"
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/connection_filter.h"
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index 8da6612..1ab8078 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -8,7 +8,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/test_simple_task_runner.h"
@@ -832,9 +831,7 @@
 const std::string kScript("script.js");
 
 void RunNestedUntilIdle() {
-  base::MessageLoop::ScopedNestableTaskAllower allow(
-      base::MessageLoop::current());
-  base::RunLoop().RunUntilIdle();
+  base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
 }
 
 void OnIOComplete(int* rv_out, int rv) {
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index d8dea178..94d341b 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -15,10 +15,10 @@
 #include "content/browser/frame_host/debug_urls.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
-#include "content/browser/site_isolation_policy.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host_factory.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/web_ui_controller_factory.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 185e633..f97fe57 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -656,13 +656,14 @@
 }
 
 TEST_F(AuthenticatorImplTest, OversizedCredentialId) {
-  device::test::ScopedVirtualFidoDevice virtual_device_;
-  TestServiceManagerContext smc_;
+  device::test::ScopedVirtualFidoDevice scoped_virtual_device;
+  TestServiceManagerContext service_manager_context;
+
   // 255 is the maximum size of a U2F credential ID. We also test one greater
   // (256) to ensure that nothing untoward happens.
   const std::vector<size_t> kSizes = {255, 256};
 
-  for (size_t size : kSizes) {
+  for (const size_t size : kSizes) {
     SCOPED_TRACE(size);
 
     SimulateNavigation(GURL(kTestOrigin1));
@@ -675,7 +676,7 @@
 
     const bool should_be_valid = size < 256;
     if (should_be_valid) {
-      ASSERT_TRUE(virtual_device_.mutable_state()->InjectRegistration(
+      ASSERT_TRUE(scoped_virtual_device.mutable_state()->InjectRegistration(
           credential->id, kTestRelyingPartyId));
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
index c646bab..54d3833 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
@@ -26,12 +26,11 @@
 import org.chromium.content.browser.input.TextSuggestionHost;
 import org.chromium.content.browser.selection.SelectionPopupControllerImpl;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
-import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.ActionModeCallbackHelper;
 import org.chromium.content_public.browser.ContentViewCore;
 import org.chromium.content_public.browser.ContentViewCore.InternalAccessDelegate;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.device.gamepad.GamepadList;
 import org.chromium.ui.base.EventForwarder;
 import org.chromium.ui.base.ViewAndroidDelegate;
@@ -103,7 +102,7 @@
      *                    {@code null} if none exists.
      */
     public static ContentViewCoreImpl fromWebContents(WebContents webContents) {
-        return WebContentsUserData.fromWebContents(webContents, ContentViewCoreImpl.class, null);
+        return webContents.getOrSetUserData(ContentViewCoreImpl.class, null);
     }
 
     /**
@@ -152,8 +151,8 @@
     public static ContentViewCoreImpl create(Context context, String productVersion,
             WebContents webContents, ViewAndroidDelegate viewDelegate,
             InternalAccessDelegate internalDispatcher, WindowAndroid windowAndroid) {
-        ContentViewCoreImpl core = WebContentsUserData.fromWebContents(
-                webContents, ContentViewCoreImpl.class, UserDataFactoryLazyHolder.INSTANCE);
+        ContentViewCoreImpl core = webContents.getOrSetUserData(
+                ContentViewCoreImpl.class, UserDataFactoryLazyHolder.INSTANCE);
         assert core != null;
         assert !core.initialized();
         core.initialize(context, productVersion, viewDelegate, internalDispatcher, windowAndroid);
diff --git a/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java b/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java
index 4064578df..f80e80f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java
@@ -16,11 +16,11 @@
 import org.chromium.content.browser.selection.SelectionPopupControllerImpl;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.ContentViewCore.InternalAccessDelegate;
 import org.chromium.content_public.browser.GestureListenerManager;
 import org.chromium.content_public.browser.GestureStateListener;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.ui.base.GestureEventType;
 
 /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/JavascriptInjectorImpl.java b/content/public/android/java/src/org/chromium/content/browser/JavascriptInjectorImpl.java
index 9e8f966..cc27a8e9 100644
--- a/content/public/android/java/src/org/chromium/content/browser/JavascriptInjectorImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/JavascriptInjectorImpl.java
@@ -9,9 +9,9 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.JavascriptInjector;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 
 import java.lang.annotation.Annotation;
 import java.util.HashMap;
diff --git a/content/public/android/java/src/org/chromium/content/browser/JoystickHandler.java b/content/public/android/java/src/org/chromium/content/browser/JoystickHandler.java
index 8af332c..4822c87 100644
--- a/content/public/android/java/src/org/chromium/content/browser/JoystickHandler.java
+++ b/content/public/android/java/src/org/chromium/content/browser/JoystickHandler.java
@@ -8,9 +8,9 @@
 import android.view.MotionEvent;
 
 import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.ImeEventObserver;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.ui.base.EventForwarder;
 
 class JoystickHandler implements ImeEventObserver {
diff --git a/content/public/android/java/src/org/chromium/content/browser/PopupController.java b/content/public/android/java/src/org/chromium/content/browser/PopupController.java
index fe77c1e..caaad3bb 100644
--- a/content/public/android/java/src/org/chromium/content/browser/PopupController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/PopupController.java
@@ -7,8 +7,8 @@
 import org.chromium.content.browser.selection.SelectionPopupControllerImpl;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/content/public/android/java/src/org/chromium/content/browser/TapDisambiguator.java b/content/public/android/java/src/org/chromium/content/browser/TapDisambiguator.java
index 0973837..a7e15ea 100644
--- a/content/public/android/java/src/org/chromium/content/browser/TapDisambiguator.java
+++ b/content/public/android/java/src/org/chromium/content/browser/TapDisambiguator.java
@@ -14,10 +14,9 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.content.browser.PopupZoomer.OnTapListener;
 import org.chromium.content.browser.PopupZoomer.OnVisibilityChangedListener;
-import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.ImeEventObserver;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 
 /**
  * Class that handles tap disambiguation feature.  When a tap lands ambiguously
@@ -38,8 +37,8 @@
 
     public static TapDisambiguator create(
             Context context, WebContents webContents, ViewGroup containerView) {
-        TapDisambiguator tabDismabiguator = WebContentsUserData.fromWebContents(
-                webContents, TapDisambiguator.class, UserDataFactoryLazyHolder.INSTANCE);
+        TapDisambiguator tabDismabiguator = webContents.getOrSetUserData(
+                TapDisambiguator.class, UserDataFactoryLazyHolder.INSTANCE);
         assert tabDismabiguator != null;
         assert !tabDismabiguator.initialized();
 
@@ -48,7 +47,7 @@
     }
 
     public static TapDisambiguator fromWebContents(WebContents webContents) {
-        return WebContentsUserData.fromWebContents(webContents, TapDisambiguator.class, null);
+        return webContents.getOrSetUserData(TapDisambiguator.class, null);
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
index 70b296ac..7af133e9 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -34,11 +34,10 @@
 import org.chromium.content.browser.WindowEventObserver;
 import org.chromium.content.browser.accessibility.captioning.CaptioningController;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
-import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
 import org.chromium.content_public.browser.AccessibilitySnapshotNode;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.content_public.browser.WebContentsAccessibility;
 
 import java.util.ArrayList;
@@ -142,7 +141,7 @@
 
     public static WebContentsAccessibilityImpl create(Context context, ViewGroup containerView,
             WebContents webContents, String productVersion) {
-        WebContentsAccessibilityImpl wcax = WebContentsUserData.fromWebContents(webContents,
+        WebContentsAccessibilityImpl wcax = webContents.getOrSetUserData(
                 WebContentsAccessibilityImpl.class, UserDataFactoryLazyHolder.INSTANCE);
         assert wcax != null && !wcax.initialized();
         wcax.init(context, containerView, productVersion);
@@ -150,8 +149,7 @@
     }
 
     public static WebContentsAccessibilityImpl fromWebContents(WebContents webContents) {
-        return WebContentsUserData.fromWebContents(
-                webContents, WebContentsAccessibilityImpl.class, null);
+        return webContents.getOrSetUserData(WebContentsAccessibilityImpl.class, null);
     }
 
     protected WebContentsAccessibilityImpl(WebContents webContents) {
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
index cd43a0d..f29c6400 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
@@ -41,12 +41,11 @@
 import org.chromium.content.browser.WindowEventObserver;
 import org.chromium.content.browser.picker.InputDialogContainer;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
-import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.ImeEventObserver;
 import org.chromium.content_public.browser.InputMethodManagerWrapper;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.ui.base.ViewUtils;
 import org.chromium.ui.base.ime.TextInputType;
 
@@ -173,8 +172,8 @@
      */
     public static ImeAdapterImpl create(
             WebContents webContents, View containerView, InputMethodManagerWrapper wrapper) {
-        ImeAdapterImpl imeAdapter = WebContentsUserData.fromWebContents(
-                webContents, ImeAdapterImpl.class, UserDataFactoryLazyHolder.INSTANCE);
+        ImeAdapterImpl imeAdapter = webContents.getOrSetUserData(
+                ImeAdapterImpl.class, UserDataFactoryLazyHolder.INSTANCE);
         assert imeAdapter != null && !imeAdapter.initialized();
         imeAdapter.init(containerView, wrapper);
         return imeAdapter;
@@ -192,7 +191,7 @@
      *         {@link #create()} is not called yet.
      */
     public static ImeAdapterImpl fromWebContents(WebContents webContents) {
-        return WebContentsUserData.fromWebContents(webContents, ImeAdapterImpl.class, null);
+        return webContents.getOrSetUserData(ImeAdapterImpl.class, null);
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
index 1314048..8c4ff08 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
@@ -14,9 +14,8 @@
 import org.chromium.content.browser.PopupController.HideablePopup;
 import org.chromium.content.browser.accessibility.WebContentsAccessibilityImpl;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
-import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -60,8 +59,8 @@
      * @param view Container view.
      */
     public static SelectPopup create(Context context, WebContents webContents, View view) {
-        SelectPopup selectPopup = WebContentsUserData.fromWebContents(
-                webContents, SelectPopup.class, UserDataFactoryLazyHolder.INSTANCE);
+        SelectPopup selectPopup =
+                webContents.getOrSetUserData(SelectPopup.class, UserDataFactoryLazyHolder.INSTANCE);
         assert selectPopup != null && !selectPopup.initialized();
         selectPopup.init(context, view);
         return selectPopup;
@@ -75,7 +74,7 @@
      *         {@link #create()} is not called yet.
      */
     public static SelectPopup fromWebContents(WebContents webContents) {
-        return WebContentsUserData.fromWebContents(webContents, SelectPopup.class, null);
+        return webContents.getOrSetUserData(SelectPopup.class, null);
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java b/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java
index e9dcbe7..78b048a9 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java
@@ -15,9 +15,8 @@
 import org.chromium.content.browser.WindowAndroidChangedObserver;
 import org.chromium.content.browser.WindowEventObserver;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
-import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -54,8 +53,8 @@
      */
     public static TextSuggestionHost create(
             Context context, WebContents webContents, WindowAndroid windowAndroid, View view) {
-        TextSuggestionHost host = WebContentsUserData.fromWebContents(
-                webContents, TextSuggestionHost.class, UserDataFactoryLazyHolder.INSTANCE);
+        TextSuggestionHost host = webContents.getOrSetUserData(
+                TextSuggestionHost.class, UserDataFactoryLazyHolder.INSTANCE);
         assert host != null;
         assert !host.initialized();
         host.init(context, windowAndroid, view);
@@ -70,7 +69,7 @@
      *         {@link #create()} is not called yet.
      */
     public static TextSuggestionHost fromWebContents(WebContents webContents) {
-        return WebContentsUserData.fromWebContents(webContents, TextSuggestionHost.class, null);
+        return webContents.getOrSetUserData(TextSuggestionHost.class, null);
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
index be66428d..ad8e76a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
@@ -47,13 +47,12 @@
 import org.chromium.content.browser.WindowAndroidChangedObserver;
 import org.chromium.content.browser.WindowEventObserver;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
-import org.chromium.content.browser.webcontents.WebContentsUserData;
-import org.chromium.content.browser.webcontents.WebContentsUserData.UserDataFactory;
 import org.chromium.content_public.browser.ActionModeCallbackHelper;
 import org.chromium.content_public.browser.ImeEventObserver;
 import org.chromium.content_public.browser.SelectionClient;
 import org.chromium.content_public.browser.SelectionPopupController;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.MenuSourceType;
 import org.chromium.ui.base.WindowAndroid;
@@ -197,7 +196,7 @@
      */
     public static SelectionPopupControllerImpl create(
             Context context, WindowAndroid window, WebContents webContents, View view) {
-        SelectionPopupControllerImpl controller = WebContentsUserData.fromWebContents(webContents,
+        SelectionPopupControllerImpl controller = webContents.getOrSetUserData(
                 SelectionPopupControllerImpl.class, UserDataFactoryLazyHolder.INSTANCE);
         assert controller != null && !controller.initialized();
         controller.init(context, window, view, true);
@@ -212,8 +211,7 @@
      *         {@link #create()} is not called yet.
      */
     public static SelectionPopupControllerImpl fromWebContents(WebContents webContents) {
-        return WebContentsUserData.fromWebContents(
-                webContents, SelectionPopupControllerImpl.class, null);
+        return webContents.getOrSetUserData(SelectionPopupControllerImpl.class, null);
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index e843a7a..8b6e000 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -37,6 +37,7 @@
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.RenderFrameHost;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.content_public.browser.WebContentsInternals;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.ui.OverscrollRefreshHandler;
@@ -734,41 +735,37 @@
         return mRenderCoordinates;
     }
 
-    /**
-     * Sets {@link WebContentsUserData} object in {@code UserDataMap}.
-     * <p>
-     * Note: This should be only called by {@link WebContentsUserData}.
-     * @param key Key of the generic object to set (its class instance).
-     * @param data The wrapper {@link WebContentsUserData} of the generic object to store.
-     */
-    void setUserData(Class key, WebContentsUserData data) {
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getOrSetUserData(Class key, UserDataFactory<T> userDataFactory) {
         Map<Class, WebContentsUserData> userDataMap = getUserDataMap();
+
+        // Map can be null after WebView gets gc'ed on its way to destruction.
         if (userDataMap == null) {
             Log.e(TAG, "UserDataMap can't be found");
-            return;
+            return null;
         }
-        assert !userDataMap.containsKey(key); // Do not allow duplicated Data
-        userDataMap.put(key, data);
+
+        WebContentsUserData data = userDataMap.get(key);
+        if (data == null && userDataFactory != null) {
+            assert !userDataMap.containsKey(key); // Do not allow duplicated Data
+
+            T object = userDataFactory.create(this);
+            assert key.isInstance(object);
+            userDataMap.put(key, new WebContentsUserData(object));
+            // Retrieves from the map again to return null in case |setUserData| fails
+            // to store the object.
+            data = userDataMap.get(key);
+        }
+        // Casting Object to T is safe since we make sure the object was of type T upon creation.
+        return data != null ? (T) data.getObject() : null;
     }
 
     /**
-     * Gets {@link WebContentsUserData} object from {@code UserDataMap}.
-     * <p>
-     * Note: This should be only called by {@link WebContentsUserData}.
-     * @param key Key of the generic object wrapped in {@link WebContentsUserData}.
-     * @return The {@link WebContentUserData} wrapping the object associated with the key.
-     */
-    WebContentsUserData getUserData(Class key) {
-        Map<Class, WebContentsUserData> userDataMap = getUserDataMap();
-        return userDataMap != null ? userDataMap.get(key) : null;
-    }
-
-    /**
-     * Note: This should be only called by {@link WebContentsUserData}.
      * @return {@code UserDataMap} that contains internal user data. {@code null} if
      *         the map is already gc'ed.
      */
-    Map<Class, WebContentsUserData> getUserDataMap() {
+    private Map<Class, WebContentsUserData> getUserDataMap() {
         WebContentsInternals internals = mInternalsHolder.get();
         if (internals == null) return null;
         return ((WebContentsInternalsImpl) internals).userDataMap;
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsUserData.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsUserData.java
index 8686b08..d99acbf 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsUserData.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsUserData.java
@@ -5,8 +5,7 @@
 package org.chromium.content.browser.webcontents;
 
 import org.chromium.content_public.browser.WebContents;
-
-import java.util.Map;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 
 /**
  * Holds an object to be stored in {@code userDataMap} in {@link WebContents} for those
@@ -23,66 +22,28 @@
  * </code>
  */
 public final class WebContentsUserData {
-    /**
-     * Factory interface passed to {@link #fromWebContents()} for instantiation of
-     * class to be managed bu {@link WebContentsUserData}.
-     *
-     * Constructor method reference comes handy for class Foo to provide the factory.
-     * Use lazy initialization to avoid having to generate too many anonymous reference.
-     *
-     * <code>
-     * public class Foo {
-     *     static final class FoofactoryLazyHolder {
-     *         private static final UserDataFactory<Foo> INSTANCE = Foo::new;
-     *     }
-     *
-     *     static Foo fromWebContents(WebContents webContents) {
-     *         return WebContentsUserData.fromWebContents(
-     *                 webContents, Foo.class, FooFactoryLazyHolder.INSTANCE);
-     *     }
-     *     ....
-     * }
-     * </code>
-     *
-     * @param <T> Class to instantiate.
-     */
-    public interface UserDataFactory<T> { T create(WebContents webContents); }
-
     private final Object mObject;
 
-    private WebContentsUserData(Object object) {
+    WebContentsUserData(Object object) {
         mObject = object;
     }
 
+    Object getObject() {
+        return mObject;
+    }
+
     /**
      * Looks up the generic object of the given web contents.
      *
      * @param webContents The web contents for which to lookup the object.
      * @param key Class instance of the object used as the key.
-     * @param userDataFactory Factory that creates an object of the generic class. Create a new
-     * instance if the object is not available and the factory is non-null.
-     * @return The object (possibly null) of the given web contents.
+     * @param userDataFactory Factory that creates an object of the generic class. Creates a new
+     *        instance and returns it if not created yet.
+     * @return The object of the given web contents. Can be null if the object was not set
+     *         or the user data map is already garbage-collected.
      */
-    @SuppressWarnings("unchecked")
     public static <T> T fromWebContents(
             WebContents webContents, Class<T> key, UserDataFactory<T> userDataFactory) {
-        // Casting to WebContentsImpl is safe since it's the actual implementation.
-        WebContentsImpl webContentsImpl = (WebContentsImpl) webContents;
-        Map<Class, WebContentsUserData> userDataMap = webContentsImpl.getUserDataMap();
-
-        // Map can be null after WebView gets gc'ed on it wasy to destruction.
-        if (userDataMap == null) return null;
-
-        WebContentsUserData data = userDataMap.get(key);
-        if (data == null && userDataFactory != null) {
-            T object = userDataFactory.create(webContents);
-            assert key.isInstance(object);
-            webContentsImpl.setUserData(key, new WebContentsUserData(object));
-            // Retrieves from the map again to return null in case |setUserData| fails
-            // to store the object.
-            data = webContentsImpl.getUserData(key);
-        }
-        // Casting Object to T is safe since we make sure the object was of type T upon creation.
-        return data != null ? (T) data.mObject : null;
+        return ((WebContentsImpl) webContents).getOrSetUserData(key, userDataFactory);
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index 00fd5838..c933af4a 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -57,6 +57,30 @@
     }
 
     /**
+     * Factory interface passed to {@link #setUserData()} for instantiation of
+     * class as user data.
+     *
+     * Constructor method reference comes handy for class Foo to provide the factory.
+     * Use lazy initialization to avoid having to generate too many anonymous reference.
+     *
+     * <code>
+     * public class Foo {
+     *     static final class FoofactoryLazyHolder {
+     *         private static final UserDataFactory<Foo> INSTANCE = Foo::new;
+     *     }
+     *     ....
+     *
+     *     webContents.setUserData(Foo.class, FooFactoryLazyHolder.INSTANCE);
+     *
+     *     ....
+     * }
+     * </code>
+     *
+     * @param <T> Class to instantiate.
+     */
+    public interface UserDataFactory<T> { T create(WebContents webContents); }
+
+    /**
      * Sets holder of the objects used internally by WebContents for various features.
      * This transfers the ownership of the objects to the caller since they will have the same
      * lifecycle as that of the caller. The caller doesn't have to care about the objects inside
@@ -83,6 +107,17 @@
     boolean isDestroyed();
 
     /**
+     * Retrieves or stores a user data object for this WebContents.
+     * @param key Class instance of the object used as the key.
+     * @param userDataFactory Factory that creates an object of the generic class. A new object
+     *        is created if it hasn't been created and non-null factory is given.
+     * @return The created or retrieved user data object. Can be null if the object was
+     *         not created yet, or {@code userDataFactory} is null, or the internal data
+     *         storage is already garbage-collected.
+     */
+    public <T> T getOrSetUserData(Class key, UserDataFactory<T> userDataFactory);
+
+    /**
      * @return The navigation controller associated with this WebContents.
      */
     NavigationController getNavigationController();
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index ff8ab30..1beeb37 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -241,6 +241,8 @@
     "session_storage_usage_info.h",
     "shared_worker_service.h",
     "site_instance.h",
+    "site_isolation_policy.cc",
+    "site_isolation_policy.h",
     "speech_recognition_event_listener.h",
     "speech_recognition_manager.h",
     "speech_recognition_manager_delegate.h",
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index ab91454..97576b0b 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -11,7 +11,6 @@
 #include "base/guid.h"
 #include "base/logging.h"
 #include "build/build_config.h"
-#include "content/browser/site_isolation_policy.h"
 #include "content/public/browser/client_certificate_delegate.h"
 #include "content/public/browser/login_delegate.h"
 #include "content/public/browser/memory_coordinator_delegate.h"
@@ -186,11 +185,6 @@
   return false;
 }
 
-// static
-bool ContentBrowserClient::IsStrictSiteIsolationEnabled() {
-  return SiteIsolationPolicy::UseDedicatedProcessesForAllSites();
-}
-
 bool ContentBrowserClient::IsFileAccessAllowed(
     const base::FilePath& path,
     const base::FilePath& absolute_path,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 1281b1c2..72d06bf 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -367,14 +367,6 @@
   // See also https://crbug.com/825369
   virtual bool ShouldEnableStrictSiteIsolation();
 
-  // Allows //content embedders to check if --site-per-process has been enabled
-  // (via cmdline flag or via a field trial).
-  //
-  // TODO(lukasza, weili): https://crbug.com/824867: Remove this method after
-  // shipping OOPIF printing (the only caller is in
-  // components/printing/browser/print_manager_utils.cc).
-  static bool IsStrictSiteIsolationEnabled();
-
   // Indicates whether a file path should be accessible via file URL given a
   // request from a browser context which lives within |profile_path|.
   virtual bool IsFileAccessAllowed(const base::FilePath& path,
diff --git a/content/browser/site_isolation_policy.cc b/content/public/browser/site_isolation_policy.cc
similarity index 86%
rename from content/browser/site_isolation_policy.cc
rename to content/public/browser/site_isolation_policy.cc
index e924041e..5428cd9 100644
--- a/content/browser/site_isolation_policy.cc
+++ b/content/public/browser/site_isolation_policy.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/site_isolation_policy.h"
+#include "content/public/browser/site_isolation_policy.h"
 
 #include <algorithm>
 #include <iterator>
@@ -40,7 +40,8 @@
   // ContentBrowserClient consults a base::Feature, then it will activate the
   // field trial and assigns the client either to a control or an experiment
   // group - such assignment should be final.
-  return GetContentClient()->browser()->ShouldEnableStrictSiteIsolation();
+  return GetContentClient() &&
+         GetContentClient()->browser()->ShouldEnableStrictSiteIsolation();
 }
 
 // static
@@ -78,6 +79,9 @@
 
 // static
 bool SiteIsolationPolicy::AreIsolatedOriginsEnabled() {
+  // NOTE: Because it is possible for --isolate-origins to be isolating origins
+  // at a finer-than-site granularity, we do not suppress --isolate-origins when
+  // --site-per-process is also enabled.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kIsolateOrigins)) {
     return true;
@@ -95,6 +99,19 @@
 }
 
 // static
+
+bool SiteIsolationPolicy::ShouldPdfCompositorBeEnabledForOopifs() {
+  // TODO(weili): We only create pdf compositor client and use pdf compositor
+  // service when site-per-process or isolate-origins flag/feature is enabled,
+  // or top-document-isolation feature is enabled. This may not cover all cases
+  // where OOPIF is used such as isolate-extensions, but should be good for
+  // feature testing purpose. Eventually, we will remove this check and use pdf
+  // compositor service by default for printing.
+  return AreIsolatedOriginsEnabled() || IsTopDocumentIsolationEnabled() ||
+         UseDedicatedProcessesForAllSites();
+}
+
+// static
 std::vector<url::Origin>
 SiteIsolationPolicy::GetIsolatedOriginsFromEnvironment() {
   std::string cmdline_arg =
diff --git a/content/browser/site_isolation_policy.h b/content/public/browser/site_isolation_policy.h
similarity index 87%
rename from content/browser/site_isolation_policy.h
rename to content/public/browser/site_isolation_policy.h
index cfaa35d..06e13c0 100644
--- a/content/browser/site_isolation_policy.h
+++ b/content/public/browser/site_isolation_policy.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_SITE_ISOLATION_POLICY_H_
-#define CONTENT_BROWSER_SITE_ISOLATION_POLICY_H_
+#ifndef CONTENT_PUBLIC_BROWSER_SITE_ISOLATION_POLICY_H_
+#define CONTENT_PUBLIC_BROWSER_SITE_ISOLATION_POLICY_H_
 
 #include <vector>
 
@@ -43,6 +43,10 @@
   // Returns true if isolated origins feature is enabled.
   static bool AreIsolatedOriginsEnabled();
 
+  // Returns true if the PDF compositor should be enabled to allow out-of-
+  // process iframes (OOPIF's) to print properly.
+  static bool ShouldPdfCompositorBeEnabledForOopifs();
+
   // Returns the origins to isolate.  See also AreIsolatedOriginsEnabled.
   // This list applies globally to the whole browser in all profiles.
   static std::vector<url::Origin> GetIsolatedOrigins();
@@ -70,4 +74,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_SITE_ISOLATION_POLICY_H_
+#endif  // CONTENT_PUBLIC_BROWSER_SITE_ISOLATION_POLICY_H_
diff --git a/content/browser/site_isolation_policy_unittest.cc b/content/public/browser/site_isolation_policy_unittest.cc
similarity index 96%
rename from content/browser/site_isolation_policy_unittest.cc
rename to content/public/browser/site_isolation_policy_unittest.cc
index a60ec5d..a3ed6c1 100644
--- a/content/browser/site_isolation_policy_unittest.cc
+++ b/content/public/browser/site_isolation_policy_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/site_isolation_policy.h"
+#include "content/public/browser/site_isolation_policy.h"
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java
index 3075ef5..f2630a8d 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java
@@ -17,6 +17,7 @@
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.RenderFrameHost;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.ui.OverscrollRefreshHandler;
 import org.chromium.ui.base.EventForwarder;
@@ -54,6 +55,11 @@
     }
 
     @Override
+    public <T> T getOrSetUserData(Class key, UserDataFactory<T> userDataFactory) {
+        return null;
+    }
+
+    @Override
     public NavigationController getNavigationController() {
         return null;
     }
diff --git a/content/public/test/network_service_test_helper.cc b/content/public/test/network_service_test_helper.cc
index cfeb528..5b56be8a 100644
--- a/content/public/test/network_service_test_helper.cc
+++ b/content/public/test/network_service_test_helper.cc
@@ -20,6 +20,7 @@
 #include "net/cert/mock_cert_verifier.h"
 #include "net/cert/test_root_certs.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/http/transport_security_state.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/test_data_directory.h"
 #include "services/network/network_context.h"
@@ -94,6 +95,22 @@
     std::move(callback).Run();
   }
 
+  void SetShouldRequireCT(ShouldRequireCT required,
+                          SetShouldRequireCTCallback callback) override {
+    if (required == NetworkServiceTest::ShouldRequireCT::RESET) {
+      net::TransportSecurityState::SetShouldRequireCTForTesting(nullptr);
+      std::move(callback).Run();
+      return;
+    }
+
+    bool ct = true;
+    if (NetworkServiceTest::ShouldRequireCT::DONT_REQUIRE == required)
+      ct = false;
+
+    net::TransportSecurityState::SetShouldRequireCTForTesting(&ct);
+    std::move(callback).Run();
+  }
+
   void BindRequest(network::mojom::NetworkServiceTestRequest request) {
     bindings_.AddBinding(this, std::move(request));
   }
diff --git a/content/public/test/test_utils.cc b/content/public/test/test_utils.cc
index bf8a8d6..76d805d 100644
--- a/content/public/test/test_utils.cc
+++ b/content/public/test/test_utils.cc
@@ -28,6 +28,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/process_type.h"
@@ -194,8 +195,7 @@
 }
 
 bool AreAllSitesIsolatedForTesting() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kSitePerProcess);
+  return SiteIsolationPolicy::UseDedicatedProcessesForAllSites();
 }
 
 void IsolateAllSitesForTesting(base::CommandLine* command_line) {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 4b684a7b..baa231b 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -44,8 +44,6 @@
     "../browser/background_fetch/background_fetch_test_browser_context.h",
     "../browser/background_fetch/mock_background_fetch_delegate.cc",
     "../browser/background_fetch/mock_background_fetch_delegate.h",
-    "../browser/download/mock_download_item_impl.cc",
-    "../browser/download/mock_download_item_impl.h",
     "../browser/media/session/mock_media_session_observer.cc",
     "../browser/media/session/mock_media_session_observer.h",
     "../browser/service_worker/embedded_worker_test_helper.cc",
@@ -1482,7 +1480,6 @@
     "../browser/shared_worker/shared_worker_instance_unittest.cc",
     "../browser/shared_worker/shared_worker_service_impl_unittest.cc",
     "../browser/site_instance_impl_unittest.cc",
-    "../browser/site_isolation_policy_unittest.cc",
     "../browser/startup_task_runner_unittest.cc",
     "../browser/storage_partition_impl_map_unittest.cc",
     "../browser/storage_partition_impl_unittest.cc",
@@ -1553,6 +1550,7 @@
     "../common/throttling_url_loader_unittest.cc",
     "../common/unique_name_helper_unittest.cc",
     "../common/webplugininfo_unittest.cc",
+    "../public/browser/site_isolation_policy_unittest.cc",
 
     # TODO(jam): move these network/ tests to services/network.
     "../public/common/drop_data_unittest.cc",
diff --git a/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc b/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc
index fd59dd5..8d85992 100644
--- a/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc
+++ b/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/memory/shared_memory.h"
 #include "base/memory/shared_memory_handle.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/sync_socket.h"
@@ -82,11 +81,7 @@
   // New tasks might be posted while we are syncing, but in every iteration at
   // least one task will be run. 20 iterations should be enough for our code.
   for (int i = 0; i < 20; ++i) {
-    {
-      base::MessageLoop::ScopedNestableTaskAllower allower(
-          base::MessageLoop::current());
-      base::RunLoop().RunUntilIdle();
-    }
+    base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
     SyncWith(BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
     SyncWith(media::AudioManager::Get()->GetWorkerTaskRunner());
   }
diff --git a/device/BUILD.gn b/device/BUILD.gn
index c8d8df92..557e9438 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -75,6 +75,7 @@
     "fido/fido_request_handler_unittest.cc",
     "fido/get_assertion_handler_unittest.cc",
     "fido/get_assertion_task_unittest.cc",
+    "fido/make_credential_handler_unittest.cc",
     "fido/make_credential_task_unittest.cc",
     "fido/test_callback_receiver_unittest.cc",
     "fido/u2f_parsing_utils_unittest.cc",
diff --git a/device/fido/fake_hid_impl_for_testing.cc b/device/fido/fake_hid_impl_for_testing.cc
index f7984d5..24041b74 100644
--- a/device/fido/fake_hid_impl_for_testing.cc
+++ b/device/fido/fake_hid_impl_for_testing.cc
@@ -6,10 +6,19 @@
 
 #include <utility>
 
-#include "base/optional.h"
+#include "device/fido/u2f_parsing_utils.h"
 
 namespace device {
 
+namespace {
+
+MATCHER_P(IsCtapHidCommand, expected_command, "") {
+  return arg.size() >= 5 &&
+         arg[4] == (0x80 | static_cast<uint8_t>(expected_command));
+}
+
+}  // namespace
+
 MockHidConnection::MockHidConnection(
     device::mojom::HidDeviceInfoPtr device,
     device::mojom::HidConnectionRequest request,
@@ -45,6 +54,31 @@
   nonce_ = std::vector<uint8_t>(nonce.begin(), nonce.end());
 }
 
+void MockHidConnection::ExpectWriteHidInit() {
+  EXPECT_CALL(*this, WritePtr(::testing::_,
+                              IsCtapHidCommand(FidoHidDeviceCommand::kInit),
+                              ::testing::_))
+      .WillOnce(::testing::Invoke(
+          [&](auto&&, const std::vector<uint8_t>& buffer,
+              device::mojom::HidConnection::WriteCallback* cb) {
+            ASSERT_EQ(64u, buffer.size());
+            // First 7 bytes are 4 bytes of channel id, one byte representing
+            // HID command, 2 bytes for payload length.
+            SetNonce(base::make_span(buffer).subspan(7, 8));
+            std::move(*cb).Run(true);
+          }));
+}
+
+void MockHidConnection::ExpectHidWriteWithCommand(FidoHidDeviceCommand cmd) {
+  EXPECT_CALL(*this,
+              WritePtr(::testing::_, IsCtapHidCommand(cmd), ::testing::_))
+      .WillOnce(::testing::Invoke(
+          [&](auto&&, const std::vector<uint8_t>& buffer,
+              device::mojom::HidConnection::WriteCallback* cb) {
+            std::move(*cb).Run(true);
+          }));
+}
+
 bool FakeHidConnection::mock_connection_error_ = false;
 
 FakeHidConnection::FakeHidConnection(device::mojom::HidDeviceInfoPtr device)
diff --git a/device/fido/fake_hid_impl_for_testing.h b/device/fido/fake_hid_impl_for_testing.h
index 40427f1b..552adde 100644
--- a/device/fido/fake_hid_impl_for_testing.h
+++ b/device/fido/fake_hid_impl_for_testing.h
@@ -13,6 +13,7 @@
 #include "base/containers/span.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "device/fido/fido_constants.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -47,6 +48,9 @@
                          SendFeatureReportCallback callback) override;
   void SetNonce(base::span<uint8_t const> nonce);
 
+  void ExpectWriteHidInit();
+  void ExpectHidWriteWithCommand(FidoHidDeviceCommand cmd);
+
   const std::vector<uint8_t>& connection_channel_id() const {
     return connection_channel_id_;
   }
diff --git a/device/fido/fido_ble_device.h b/device/fido/fido_ble_device.h
index c46bc6f..427e7e86 100644
--- a/device/fido/fido_ble_device.h
+++ b/device/fido/fido_ble_device.h
@@ -69,7 +69,6 @@
   void StopTimeout();
   void OnTimeout();
 
-  State state_ = State::kInit;
   base::OneShotTimer timer_;
 
   std::unique_ptr<FidoBleConnection> connection_;
diff --git a/device/fido/fido_constants.cc b/device/fido/fido_constants.cc
index a8bb52c..354cb77 100644
--- a/device/fido/fido_constants.cc
+++ b/device/fido/fido_constants.cc
@@ -51,6 +51,8 @@
                                                     '_', 'V', '2'};
 
 const base::TimeDelta kDeviceTimeout = base::TimeDelta::FromSeconds(3);
+const base::TimeDelta kHidKeepAliveDelay =
+    base::TimeDelta::FromMilliseconds(100);
 
 const char kFormatKey[] = "fmt";
 const char kAttestationStatementKey[] = "attStmt";
diff --git a/device/fido/fido_constants.h b/device/fido/fido_constants.h
index b64034b..25dc23e 100644
--- a/device/fido/fido_constants.h
+++ b/device/fido/fido_constants.h
@@ -260,6 +260,11 @@
 // Maximum wait time before client error outs on device.
 COMPONENT_EXPORT(DEVICE_FIDO) extern const base::TimeDelta kDeviceTimeout;
 
+// Interval wait time before retrying reading on HID connection when
+// CTAPHID_KEEPALIVE message has been received.
+// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#ctaphid_keepalive-0x3b
+COMPONENT_EXPORT(DEVICE_FIDO) extern const base::TimeDelta kHidKeepAliveDelay;
+
 // String key values for attestation object as a response to MakeCredential
 // request.
 COMPONENT_EXPORT(DEVICE_FIDO) extern const char kFormatKey[];
diff --git a/device/fido/fido_hid_device.cc b/device/fido/fido_hid_device.cc
index 4f76c20f..935172a 100644
--- a/device/fido/fido_hid_device.cc
+++ b/device/fido/fido_hid_device.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/logging.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "crypto/random.h"
 #include "device/fido/fido_hid_message.h"
@@ -26,7 +27,6 @@
 FidoHidDevice::FidoHidDevice(device::mojom::HidDeviceInfoPtr device_info,
                              device::mojom::HidManager* hid_manager)
     : FidoDevice(),
-      state_(State::kInit),
       hid_manager_(hid_manager),
       device_info_(std::move(device_info)),
       weak_factory_(this) {}
@@ -61,9 +61,11 @@
       state_ = State::kBusy;
       ArmTimeout(repeating_callback);
       // Write message to the device.
+      const auto command_type = supported_protocol() == ProtocolVersion::kCtap
+                                    ? FidoHidDeviceCommand::kCbor
+                                    : FidoHidDeviceCommand::kMsg;
       WriteMessage(
-          FidoHidMessage::Create(channel_id_, FidoHidDeviceCommand::kMsg,
-                                 std::move(command)),
+          FidoHidMessage::Create(channel_id_, command_type, std::move(command)),
           true,
           base::BindOnce(&FidoHidDevice::MessageReceived,
                          weak_factory_.GetWeakPtr(), repeating_callback));
@@ -273,13 +275,34 @@
                                     std::unique_ptr<FidoHidMessage> message) {
   if (state_ == State::kDeviceError)
     return;
+
   timeout_callback_.Cancel();
-  if (!success) {
+  if (!success || !message) {
     state_ = State::kDeviceError;
     Transition(std::vector<uint8_t>(), std::move(callback));
     return;
   }
 
+  const auto cmd = message->cmd();
+  // If received HID packet has keep_alive as command type, re-read after delay.
+  if (supported_protocol() == ProtocolVersion::kCtap &&
+      cmd == FidoHidDeviceCommand::kKeepAlive) {
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&FidoHidDevice::OnKeepAlive, weak_factory_.GetWeakPtr(),
+                       std::move(callback)),
+        kHidKeepAliveDelay);
+    return;
+  }
+
+  if (cmd != FidoHidDeviceCommand::kMsg && cmd != FidoHidDeviceCommand::kCbor) {
+    DLOG(ERROR) << "Unexpected HID device command received.";
+    state_ = State::kDeviceError;
+    Transition(std::vector<uint8_t>(), std::move(callback));
+    return;
+  }
+
+  auto response = message->GetMessagePayload();
   state_ = State::kReady;
   base::WeakPtr<FidoHidDevice> self = weak_factory_.GetWeakPtr();
   std::move(callback).Run(
@@ -310,6 +333,15 @@
                               weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
+void FidoHidDevice::OnKeepAlive(DeviceCallback callback) {
+  auto repeating_callback =
+      base::AdaptCallbackForRepeating(std::move(callback));
+  ArmTimeout(repeating_callback);
+  ReadMessage(base::BindOnce(&FidoHidDevice::MessageReceived,
+                             weak_factory_.GetWeakPtr(),
+                             std::move(repeating_callback)));
+}
+
 void FidoHidDevice::OnWink(WinkCallback callback,
                            bool success,
                            std::unique_ptr<FidoHidMessage> response) {
diff --git a/device/fido/fido_hid_device.h b/device/fido/fido_hid_device.h
index 2dcfecf..db3dd14 100644
--- a/device/fido/fido_hid_device.h
+++ b/device/fido/fido_hid_device.h
@@ -92,16 +92,17 @@
                           bool success,
                           uint8_t report_id,
                           const base::Optional<std::vector<uint8_t>>& buf);
+  void OnKeepAlive(DeviceCallback callback);
   void OnWink(WinkCallback callback,
               bool success,
               std::unique_ptr<FidoHidMessage> response);
   void ArmTimeout(DeviceCallback callback);
   void OnTimeout(DeviceCallback callback);
+
   base::WeakPtr<FidoDevice> GetWeakPtr() override;
 
   uint32_t channel_id_ = kBroadcastChannel;
   uint8_t capabilities_ = 0;
-  State state_ = State::kInit;
 
   base::CancelableOnceClosure timeout_callback_;
   std::queue<std::pair<std::vector<uint8_t>, DeviceCallback>>
diff --git a/device/fido/fido_hid_device_unittest.cc b/device/fido/fido_hid_device_unittest.cc
index be65157..8c46041 100644
--- a/device/fido/fido_hid_device_unittest.cc
+++ b/device/fido/fido_hid_device_unittest.cc
@@ -16,6 +16,7 @@
 #include "device/fido/fido_constants.h"
 #include "device/fido/fido_hid_device.h"
 #include "device/fido/test_callback_receiver.h"
+#include "device/fido/u2f_parsing_utils.h"
 #include "device/fido/u2f_request.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
@@ -28,45 +29,53 @@
 
 using ::testing::_;
 using ::testing::Invoke;
-using ::testing::WithArg;
-using ::testing::WithArgs;
 
 namespace {
 
-std::string HexEncode(base::span<const uint8_t> in) {
-  return base::HexEncode(in.data(), in.size());
-}
+// HID_MSG(83), followed by payload length(0008), followed by 'U2F_V2', followed
+// by APDU response code(9000).
+constexpr uint8_t kMockVersionResponseSuffix[] = {
+    0x83, 0x00, 0x08, 0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, 0x90, 0x00};
 
-std::vector<uint8_t> HexDecode(base::StringPiece in) {
-  std::vector<uint8_t> out;
-  bool result = base::HexStringToBytes(in.as_string(), &out);
-  DCHECK(result);
-  return out;
-}
+// HID_KEEP_ALIVE(bb), followed by payload length(0001), followed by
+// status processing(01) byte.
+constexpr uint8_t kMockKeepAliveResponseSuffix[] = {0xbb, 0x00, 0x01, 0x01};
 
-// Converts hex encoded StringPiece to byte vector and pads zero to fit HID
-// packet size.
-std::vector<uint8_t> MakePacket(base::StringPiece hex) {
-  std::vector<uint8_t> out = HexDecode(hex);
-  out.resize(64);
-  return out;
-}
+// 4 byte broadcast channel id(ffffffff), followed by an HID_INIT command(86),
+// followed by a fixed size payload length(11). 8 byte nonce and 4 byte channel
+// ID must be appended to create a well formed  HID_INIT packet.
+constexpr uint8_t kInitResponsePrefix[] = {
+    0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11,
+};
 
 // Returns HID_INIT request to send to device with mock connection.
-std::vector<uint8_t> CreateMockInitResponse(std::vector<uint8_t> nonce,
-                                            std::vector<uint8_t> channel_id) {
-  // 4 bytes of broadcast channel identifier(ffffffff), followed by
-  // HID_INIT command(86) and 2 byte payload length(11).
-  return MakePacket("ffffffff860011" + HexEncode(nonce) +
-                    HexEncode(channel_id));
+std::vector<uint8_t> CreateMockInitResponse(
+    base::span<const uint8_t> nonce,
+    base::span<const uint8_t> channel_id) {
+  auto init_response = u2f_parsing_utils::Materialize(kInitResponsePrefix);
+  u2f_parsing_utils::Append(&init_response, nonce);
+  u2f_parsing_utils::Append(&init_response, channel_id);
+  init_response.resize(64);
+  return init_response;
+}
+
+// Returns HID keep alive message encoded into HID packet format.
+std::vector<uint8_t> GetKeepAliveHidMessage(
+    base::span<const uint8_t> channel_id) {
+  auto response = u2f_parsing_utils::Materialize(channel_id);
+  u2f_parsing_utils::Append(&response, kMockKeepAliveResponseSuffix);
+  response.resize(64);
+  return response;
 }
 
 // Returns "U2F_v2" as a mock response to version request with given channel id.
-std::vector<uint8_t> CreateMockVersionResponse(
-    std::vector<uint8_t> channel_id) {
-  // HID_MSG command(83), followed by payload length(0008), followed by
-  // hex encoded "U2F_V2" and  NO_ERROR response code(9000).
-  return MakePacket(HexEncode(channel_id) + "8300085532465f56329000");
+std::vector<uint8_t> CreateMockResponse(
+    base::span<const uint8_t> channel_id,
+    base::span<const uint8_t> response_buffer) {
+  auto response = u2f_parsing_utils::Materialize(channel_id);
+  u2f_parsing_utils::Append(&response, response_buffer);
+  response.resize(64);
+  return response;
 }
 
 // Returns U2F_V2 version response formatted in APDU response encoding.
@@ -127,19 +136,16 @@
 
 class FidoHidDeviceTest : public ::testing::Test {
  public:
-  FidoHidDeviceTest()
-      : scoped_task_environment_(
-            base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
-
   void SetUp() override {
     fake_hid_manager_ = std::make_unique<FakeHidManager>();
     fake_hid_manager_->AddBinding2(mojo::MakeRequest(&hid_manager_));
   }
 
  protected:
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
   device::mojom::HidManagerPtr hid_manager_;
   std::unique_ptr<FakeHidManager> fake_hid_manager_;
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
 TEST_F(FidoHidDeviceTest, TestConnectionFailure) {
@@ -223,65 +229,55 @@
 }
 
 TEST_F(FidoHidDeviceTest, TestRetryChannelAllocation) {
-  const std::vector<uint8_t> kIncorrectNonce = {0x00, 0x00, 0x00, 0x00,
-                                                0x00, 0x00, 0x00, 0x00};
+  constexpr uint8_t kIncorrectNonce[] = {0x00, 0x00, 0x00, 0x00,
+                                         0x00, 0x00, 0x00, 0x00};
 
-  const std::vector<uint8_t> kChannelId = {0x01, 0x02, 0x03, 0x04};
+  constexpr uint8_t kChannelId[] = {0x01, 0x02, 0x03, 0x04};
 
   auto hid_device = TestHidDevice();
 
   // Replace device HID connection with custom client connection bound to mock
   // server-side mojo connection.
   device::mojom::HidConnectionPtr connection_client;
-  MockHidConnection mock_connection(
-      hid_device.Clone(), mojo::MakeRequest(&connection_client), kChannelId);
+  MockHidConnection mock_connection(hid_device.Clone(),
+                                    mojo::MakeRequest(&connection_client),
+                                    u2f_parsing_utils::Materialize(kChannelId));
 
-  // Delegate custom functions to be invoked for mock hid connection.
-  EXPECT_CALL(mock_connection, WritePtr(_, _, _))
-      // HID_INIT request to authenticator for channel allocation.
-      .WillOnce(WithArgs<1, 2>(
-          Invoke([&](const std::vector<uint8_t>& buffer,
-                     device::mojom::HidConnection::WriteCallback* cb) {
-            mock_connection.SetNonce(base::make_span(buffer).subspan(7, 8));
-            std::move(*cb).Run(true);
-          })))
+  // Initial write for establishing a channel ID.
+  mock_connection.ExpectWriteHidInit();
 
-      // HID_MSG request to authenticator for version request.
-      .WillOnce(WithArgs<2>(
-          Invoke([](device::mojom::HidConnection::WriteCallback* cb) {
-            std::move(*cb).Run(true);
-          })));
+  // HID_MSG request to authenticator for version request.
+  mock_connection.ExpectHidWriteWithCommand(FidoHidDeviceCommand::kMsg);
 
   EXPECT_CALL(mock_connection, ReadPtr(_))
-      // First response to HID_INIT request with incorrect nonce.
-      .WillOnce(WithArg<0>(
-          Invoke([kIncorrectNonce, &mock_connection](
-                     device::mojom::HidConnection::ReadCallback* cb) {
+      // First response to HID_INIT request with an incorrect nonce.
+      .WillOnce(
+          Invoke([kIncorrectNonce, &mock_connection](auto* cb) {
             std::move(*cb).Run(
                 true, 0,
                 CreateMockInitResponse(
                     kIncorrectNonce, mock_connection.connection_channel_id()));
-          })))
-      // Second response to HID_INIT request with correct nonce.
-      .WillOnce(WithArg<0>(Invoke(
+          }))
+      // Second response to HID_INIT request with a correct nonce.
+      .WillOnce(Invoke(
           [&mock_connection](device::mojom::HidConnection::ReadCallback* cb) {
             std::move(*cb).Run(true, 0,
                                CreateMockInitResponse(
                                    mock_connection.nonce(),
                                    mock_connection.connection_channel_id()));
-          })))
+          }))
       // Version response from the authenticator.
-      .WillOnce(WithArg<0>(Invoke(
+      .WillOnce(Invoke(
           [&mock_connection](device::mojom::HidConnection::ReadCallback* cb) {
-            std::move(*cb).Run(true, 0,
-                               CreateMockVersionResponse(
-                                   mock_connection.connection_channel_id()));
-          })));
+            std::move(*cb).Run(
+                true, 0,
+                CreateMockResponse(mock_connection.connection_channel_id(),
+                                   kMockVersionResponseSuffix));
+          }));
 
   // Add device and set mock connection to fake hid manager.
   fake_hid_manager_->AddDeviceAndSetConnection(std::move(hid_device),
                                                std::move(connection_client));
-
   FidoDeviceEnumerateCallbackReceiver receiver(hid_manager_.get());
   hid_manager_->GetDevices(receiver.callback());
   receiver.WaitForCallback();
@@ -301,4 +297,139 @@
   EXPECT_THAT(*result, testing::ElementsAreArray(GetValidU2fVersionResponse()));
 }
 
+TEST_F(FidoHidDeviceTest, TestKeepAliveMessage) {
+  constexpr uint8_t kChannelId[] = {0x01, 0x02, 0x03, 0x04};
+
+  auto hid_device = TestHidDevice();
+
+  // Replace device HID connection with custom client connection bound to mock
+  // server-side mojo connection.
+  device::mojom::HidConnectionPtr connection_client;
+  MockHidConnection mock_connection(hid_device.Clone(),
+                                    mojo::MakeRequest(&connection_client),
+                                    u2f_parsing_utils::Materialize(kChannelId));
+
+  // Initial write for establishing channel ID.
+  mock_connection.ExpectWriteHidInit();
+
+  // HID_CBOR request to authenticator.
+  mock_connection.ExpectHidWriteWithCommand(FidoHidDeviceCommand::kCbor);
+
+  EXPECT_CALL(mock_connection, ReadPtr(_))
+      // Response to HID_INIT request.
+      .WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
+        std::move(*cb).Run(
+            true, 0,
+            CreateMockInitResponse(mock_connection.nonce(),
+                                   mock_connection.connection_channel_id()));
+      }))
+      // // Keep alive message sent from the authenticator.
+      .WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
+        std::move(*cb).Run(
+            true, 0,
+            GetKeepAliveHidMessage(mock_connection.connection_channel_id()));
+      }))
+      // Repeated Read() invocation due to keep alive message. Sends a dummy
+      // response that corresponds to U2F version response.
+      .WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
+        auto almost_time_out =
+            kDeviceTimeout - base::TimeDelta::FromMicroseconds(1);
+        scoped_task_environment_.FastForwardBy(almost_time_out);
+
+        std::move(*cb).Run(
+            true, 0,
+            CreateMockResponse(mock_connection.connection_channel_id(),
+                               kMockVersionResponseSuffix));
+      }));
+
+  // Add device and set mock connection to fake hid manager.
+  fake_hid_manager_->AddDeviceAndSetConnection(std::move(hid_device),
+                                               std::move(connection_client));
+
+  FidoDeviceEnumerateCallbackReceiver receiver(hid_manager_.get());
+  hid_manager_->GetDevices(receiver.callback());
+  receiver.WaitForCallback();
+
+  std::vector<std::unique_ptr<FidoHidDevice>> u2f_devices =
+      receiver.TakeReturnedDevicesFiltered();
+  ASSERT_EQ(1u, u2f_devices.size());
+  auto& device = u2f_devices.front();
+
+  // Keep alive message handling is only supported for CTAP HID device.
+  device->set_supported_protocol(ProtocolVersion::kCtap);
+  TestDeviceCallbackReceiver cb;
+  device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(false),
+                         cb.callback());
+  cb.WaitForCallback();
+  const auto result = std::get<0>(*cb.result());
+  ASSERT_TRUE(result);
+  EXPECT_THAT(*result, testing::ElementsAreArray(GetValidU2fVersionResponse()));
+}
+
+TEST_F(FidoHidDeviceTest, TestDeviceTimeoutAfterKeepAliveMessage) {
+  constexpr uint8_t kChannelId[] = {0x01, 0x02, 0x03, 0x04};
+
+  auto hid_device = TestHidDevice();
+
+  // Replace device HID connection with custom client connection bound to mock
+  // server-side mojo connection.
+  device::mojom::HidConnectionPtr connection_client;
+  MockHidConnection mock_connection(hid_device.Clone(),
+                                    mojo::MakeRequest(&connection_client),
+                                    u2f_parsing_utils::Materialize(kChannelId));
+
+  // Initial write for establishing channel ID.
+  mock_connection.ExpectWriteHidInit();
+
+  // HID_CBOR request to authenticator.
+  mock_connection.ExpectHidWriteWithCommand(FidoHidDeviceCommand::kCbor);
+
+  EXPECT_CALL(mock_connection, ReadPtr(_))
+      // Response to HID_INIT request.
+      .WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
+        std::move(*cb).Run(
+            true, 0,
+            CreateMockInitResponse(mock_connection.nonce(),
+                                   mock_connection.connection_channel_id()));
+      }))
+      // // Keep alive message sent from the authenticator.
+      .WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
+        std::move(*cb).Run(
+            true, 0,
+            GetKeepAliveHidMessage(mock_connection.connection_channel_id()));
+      }))
+      // Repeated Read() invocation due to keep alive message. The callback
+      // is invoked only after 3 seconds, which should cause device to timeout.
+      .WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
+        scoped_task_environment_.FastForwardBy(kDeviceTimeout);
+        std::move(*cb).Run(
+            true, 0,
+            CreateMockResponse(mock_connection.connection_channel_id(),
+                               kMockVersionResponseSuffix));
+      }));
+
+  // Add device and set mock connection to fake hid manager.
+  fake_hid_manager_->AddDeviceAndSetConnection(std::move(hid_device),
+                                               std::move(connection_client));
+
+  FidoDeviceEnumerateCallbackReceiver receiver(hid_manager_.get());
+  hid_manager_->GetDevices(receiver.callback());
+  receiver.WaitForCallback();
+
+  std::vector<std::unique_ptr<FidoHidDevice>> u2f_devices =
+      receiver.TakeReturnedDevicesFiltered();
+  ASSERT_EQ(1u, u2f_devices.size());
+  auto& device = u2f_devices.front();
+
+  // Keep alive message handling is only supported for CTAP HID device.
+  device->set_supported_protocol(ProtocolVersion::kCtap);
+  TestDeviceCallbackReceiver cb;
+  device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(false),
+                         cb.callback());
+  cb.WaitForCallback();
+  const auto result = std::get<0>(*cb.result());
+  EXPECT_FALSE(result);
+  EXPECT_EQ(FidoDevice::State::kDeviceError, device->state());
+}
+
 }  // namespace device
diff --git a/device/fido/fido_request_handler.h b/device/fido/fido_request_handler.h
index ff13b54..2e8705d 100644
--- a/device/fido/fido_request_handler.h
+++ b/device/fido/fido_request_handler.h
@@ -10,7 +10,6 @@
 #include <utility>
 
 #include "base/callback.h"
-#include "base/component_export.h"
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "base/optional.h"
@@ -23,8 +22,7 @@
 // Handles receiving response form potentially multiple connected authenticators
 // and relaying response to the relying party.
 template <class Response>
-class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandler
-    : public FidoRequestHandlerBase {
+class FidoRequestHandler : public FidoRequestHandlerBase {
  public:
   using CompletionCallback =
       base::OnceCallback<void(FidoReturnCode status_code,
diff --git a/device/fido/fido_request_handler_base.cc b/device/fido/fido_request_handler_base.cc
index 98f18f1..a8ec82c6 100644
--- a/device/fido/fido_request_handler_base.cc
+++ b/device/fido/fido_request_handler_base.cc
@@ -52,6 +52,10 @@
 void FidoRequestHandlerBase::DeviceAdded(FidoDiscovery* discovery,
                                          FidoDevice* device) {
   DCHECK(!base::ContainsKey(ongoing_tasks(), device->GetId()));
+  // All devices are initially assumed to support CTAP protocol and thus
+  // AuthenticatorGetInfo command is sent to all connected devices. If device
+  // errors out, then it is assumed to support U2F protocol.
+  device->set_supported_protocol(ProtocolVersion::kCtap);
   ongoing_tasks_.emplace(device->GetId(), CreateTaskForNewDevice(device));
 }
 
diff --git a/device/fido/fido_request_handler_unittest.cc b/device/fido/fido_request_handler_unittest.cc
index 9b4cda7a..0998bcd 100644
--- a/device/fido/fido_request_handler_unittest.cc
+++ b/device/fido/fido_request_handler_unittest.cc
@@ -4,17 +4,18 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/test/scoped_task_environment.h"
-#include "device/fido/authenticator_make_credential_response.h"
-#include "device/fido/ctap_make_credential_request.h"
 #include "device/fido/fake_fido_discovery.h"
 #include "device/fido/fido_constants.h"
+#include "device/fido/fido_device.h"
+#include "device/fido/fido_request_handler.h"
 #include "device/fido/fido_response_test_data.h"
-#include "device/fido/make_credential_request_handler.h"
+#include "device/fido/fido_task.h"
 #include "device/fido/mock_fido_device.h"
 #include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/u2f_transport_protocol.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -24,14 +25,82 @@
 
 namespace {
 
-constexpr uint8_t kClientDataHash[] = {0x01, 0x02, 0x03};
-constexpr uint8_t kUserId[] = {0x01, 0x02, 0x03};
-constexpr char kRpId[] = "google.com";
+using FakeTaskCallback =
+    base::OnceCallback<void(CtapDeviceResponseCode status_code,
+                            base::Optional<std::vector<uint8_t>>)>;
+using FakeHandlerCallback = base::OnceCallback<void(
+    FidoReturnCode status_code,
+    base::Optional<std::vector<uint8_t>> response_data)>;
+using FakeHandlerCallbackReceiver =
+    test::StatusAndValueCallbackReceiver<FidoReturnCode,
+                                         base::Optional<std::vector<uint8_t>>>;
 
-using TestMakeCredentialRequestCallback =
-    ::device::test::StatusAndValueCallbackReceiver<
-        FidoReturnCode,
-        base::Optional<AuthenticatorMakeCredentialResponse>>;
+// Fake FidoTask implementation that treats all response from FidoDevice as
+// success if the response is a non-empty vector and sends an empty byte array
+// to the device when StartTask() is invoked.
+class FakeFidoTask : public FidoTask {
+ public:
+  FakeFidoTask(FidoDevice* device, FakeTaskCallback callback)
+      : FidoTask(device), callback_(std::move(callback)), weak_factory_(this) {}
+  ~FakeFidoTask() override = default;
+
+  void StartTask() override {
+    device()->DeviceTransact(std::vector<uint8_t>(),
+                             base::BindOnce(&FakeFidoTask::CompletionCallback,
+                                            weak_factory_.GetWeakPtr()));
+  }
+
+  // Fake callback that treats all response with non-empty |device_response| as
+  // a successful response, empty (not base::nullopt) response as an UP-verified
+  // error, and base::nullopt as a device processing error.
+  // TODO(hongjunchoi): Change criteria for deciding when to return success,
+  // UP-verified error, or processing error for readability.
+  void CompletionCallback(
+      base::Optional<std::vector<uint8_t>> device_response) {
+    if (!device_response) {
+      std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther,
+                               base::nullopt);
+      return;
+    }
+
+    device_response->empty()
+        ? std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrNotAllowed,
+                                   base::nullopt)
+        : std::move(callback_).Run(CtapDeviceResponseCode::kSuccess,
+                                   std::vector<uint8_t>());
+  }
+
+ private:
+  FakeTaskCallback callback_;
+  base::WeakPtrFactory<FakeFidoTask> weak_factory_;
+};
+
+class FakeFidoRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> {
+ public:
+  FakeFidoRequestHandler(const base::flat_set<U2fTransportProtocol>& protocols,
+                         FakeHandlerCallback callback)
+      : FidoRequestHandler(nullptr /* connector */,
+                           protocols,
+                           std::move(callback)),
+        weak_factory_(this) {}
+  ~FakeFidoRequestHandler() override = default;
+
+  std::unique_ptr<FidoTask> CreateTaskForNewDevice(
+      FidoDevice* device) override {
+    return std::make_unique<FakeFidoTask>(
+        device, base::BindOnce(&FakeFidoRequestHandler::OnDeviceResponse,
+                               weak_factory_.GetWeakPtr(), device));
+  }
+
+ private:
+  FakeHandlerCallback callback_;
+  base::WeakPtrFactory<FakeFidoRequestHandler> weak_factory_;
+};
+
+std::vector<uint8_t> CreateFakeSuccessDeviceResponse() {
+  return std::vector<uint8_t>{
+      base::strict_cast<uint8_t>(CtapDeviceResponseCode::kSuccess)};
+}
 
 }  // namespace
 
@@ -41,47 +110,34 @@
     discovery_ = scoped_fake_discovery_factory_.ForgeNextHidDiscovery();
   }
 
-  std::unique_ptr<MakeCredentialRequestHandler> CreateMakeCredentialHandler() {
+  std::unique_ptr<FakeFidoRequestHandler> CreateFakeHandler() {
     ForgeNextHidDiscovery();
-    PublicKeyCredentialRpEntity rp(kRpId);
-    PublicKeyCredentialUserEntity user(u2f_parsing_utils::Materialize(kUserId));
-    PublicKeyCredentialParams credential_params({{kU2fCredentialType}});
-
-    auto request_parameter = CtapMakeCredentialRequest(
-        u2f_parsing_utils::Materialize(kClientDataHash), std::move(rp),
-        std::move(user), std::move(credential_params));
-
-    return std::make_unique<MakeCredentialRequestHandler>(
-        nullptr,
+    return std::make_unique<FakeFidoRequestHandler>(
         base::flat_set<U2fTransportProtocol>(
             {U2fTransportProtocol::kUsbHumanInterfaceDevice}),
-        std::move(request_parameter), AuthenticatorSelectionCriteria(),
         cb_.callback());
   }
 
   test::FakeFidoDiscovery* discovery() const { return discovery_; }
-  TestMakeCredentialRequestCallback& callback() { return cb_; }
+  FakeHandlerCallbackReceiver& callback() { return cb_; }
 
  protected:
   base::test::ScopedTaskEnvironment scoped_task_environment_{
       base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
   test::ScopedFakeFidoDiscoveryFactory scoped_fake_discovery_factory_;
   test::FakeFidoDiscovery* discovery_;
-  TestMakeCredentialRequestCallback cb_;
+  FakeHandlerCallbackReceiver cb_;
 };
 
-TEST_F(FidoRequestHandlerTest, TestMakeCredentialRequestHandler) {
-  auto request_handler = CreateMakeCredentialHandler();
+TEST_F(FidoRequestHandlerTest, TestSingleDeviceSuccess) {
+  auto request_handler = CreateFakeHandler();
   discovery()->WaitForCallToStartAndSimulateSuccess();
 
   auto device = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0"));
-  device->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorGetInfo,
-      test_data::kTestAuthenticatorGetInfoResponse);
-  device->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorMakeCredential,
-      test_data::kTestMakeCredentialResponse);
+  // Device returns success (non-empty vector) response.
+  device->ExpectRequestAndRespondWith(std::vector<uint8_t>(),
+                                      CreateFakeSuccessDeviceResponse());
 
   discovery()->AddDevice(std::move(device));
   callback().WaitForCallback();
@@ -93,24 +149,22 @@
 // cancel request has been sent either from the user or from the relying party
 // (i.e. FidoRequestHandler object is destroyed.) Upon destruction, cancel
 // command must be invoked to all connected authenticators.
-TEST_F(FidoRequestHandlerTest, TestCancelRequest) {
-  auto request_handler = CreateMakeCredentialHandler();
+TEST_F(FidoRequestHandlerTest, TestAuthenticatorHandlerReset) {
+  auto request_handler = CreateFakeHandler();
   discovery()->WaitForCallToStartAndSimulateSuccess();
 
   auto device0 = std::make_unique<MockFidoDevice>();
   device0->set_supported_protocol(ProtocolVersion::kCtap);
   EXPECT_CALL(*device0, GetId()).WillRepeatedly(testing::Return("device0"));
-  device0->ExpectCtap2CommandWithoutResponse(
-      CtapRequestCommand::kAuthenticatorGetInfo);
-  device0->ExpectCtap2CommandWithoutResponse(
+  device0->ExpectRequestAndDoNotRespond(std::vector<uint8_t>());
+  device0->ExpectCtap2CommandAndDoNotRespond(
       CtapRequestCommand::kAuthenticatorCancel);
 
   auto device1 = std::make_unique<MockFidoDevice>();
   device1->set_supported_protocol(ProtocolVersion::kCtap);
   EXPECT_CALL(*device1, GetId()).WillRepeatedly(testing::Return("device1"));
-  device1->ExpectCtap2CommandWithoutResponse(
-      CtapRequestCommand::kAuthenticatorGetInfo);
-  device1->ExpectCtap2CommandWithoutResponse(
+  device1->ExpectRequestAndDoNotRespond(std::vector<uint8_t>());
+  device1->ExpectCtap2CommandAndDoNotRespond(
       CtapRequestCommand::kAuthenticatorCancel);
 
   discovery()->AddDevice(std::move(device0));
@@ -122,29 +176,24 @@
 // Test a scenario where 2 devices are connected and a response is received from
 // only a single device(device1) and the remaining device hangs.
 TEST_F(FidoRequestHandlerTest, TestRequestWithMultipleDevices) {
-  auto request_handler = CreateMakeCredentialHandler();
+  auto request_handler = CreateFakeHandler();
   discovery()->WaitForCallToStartAndSimulateSuccess();
 
   // Represents a connected device that hangs without a response.
   auto device0 = std::make_unique<MockFidoDevice>();
+  device0->set_supported_protocol(ProtocolVersion::kCtap);
   EXPECT_CALL(*device0, GetId()).WillRepeatedly(testing::Return("device0"));
-  device0->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorGetInfo,
-      test_data::kTestAuthenticatorGetInfoResponse);
-  device0->ExpectCtap2CommandWithoutResponse(
-      CtapRequestCommand::kAuthenticatorMakeCredential);
-  device0->ExpectCtap2CommandWithoutResponse(
+  // Device is unresponsive and cancel command is invoked afterwards.
+  device0->ExpectRequestAndDoNotRespond(std::vector<uint8_t>());
+  device0->ExpectCtap2CommandAndDoNotRespond(
       CtapRequestCommand::kAuthenticatorCancel);
 
   // Represents a connected device that response successfully.
   auto device1 = std::make_unique<MockFidoDevice>();
+  device1->set_supported_protocol(ProtocolVersion::kCtap);
   EXPECT_CALL(*device1, GetId()).WillRepeatedly(testing::Return("device1"));
-  device1->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorGetInfo,
-      test_data::kTestAuthenticatorGetInfoResponse);
-  device1->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorMakeCredential,
-      test_data::kTestMakeCredentialResponse);
+  device1->ExpectRequestAndRespondWith(std::vector<uint8_t>(),
+                                       CreateFakeSuccessDeviceResponse());
 
   discovery()->AddDevice(std::move(device0));
   discovery()->AddDevice(std::move(device1));
@@ -154,37 +203,35 @@
   EXPECT_EQ(FidoReturnCode::kSuccess, callback().status());
 }
 
-// Test a scenario where 2 devices respond successfully with small time delay.
-// Only the first received response should be passed on to the relying party,
-// and cancel request should be sent to the other authenticator.
+// Test a scenario where 2 devices respond successfully with small time
+// delay. Only the first received response should be passed on to the relying
+// party, and cancel request should be sent to the other authenticator.
 TEST_F(FidoRequestHandlerTest, TestRequestWithMultipleSuccessResponses) {
-  auto request_handler = CreateMakeCredentialHandler();
+  auto request_handler = CreateFakeHandler();
   discovery()->WaitForCallToStartAndSimulateSuccess();
 
   // Represents a connected device that responds successfully after small time
   // delay.
   auto device0 = std::make_unique<MockFidoDevice>();
+  device0->set_supported_protocol(ProtocolVersion::kCtap);
   EXPECT_CALL(*device0, GetId()).WillRepeatedly(testing::Return("device0"));
-  device0->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorGetInfo,
-      test_data::kTestAuthenticatorGetInfoResponse);
-  device0->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorMakeCredential,
-      test_data::kTestMakeCredentialResponse,
-      base::TimeDelta::FromMicroseconds(1));
+  // Device responds successfully after short delay.
+  device0->ExpectRequestAndRespondWith(std::vector<uint8_t>(),
+                                       CreateFakeSuccessDeviceResponse(),
+                                       base::TimeDelta::FromMicroseconds(1));
 
   // Represents a device that returns a success response after a longer time
   // delay.
   auto device1 = std::make_unique<MockFidoDevice>();
+  device1->set_supported_protocol(ProtocolVersion::kCtap);
+
   EXPECT_CALL(*device1, GetId()).WillRepeatedly(testing::Return("device1"));
-  device1->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorGetInfo,
-      test_data::kTestAuthenticatorGetInfoResponse);
-  device1->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorMakeCredential,
-      test_data::kTestMakeCredentialResponse,
-      base::TimeDelta::FromMicroseconds(10));
-  device1->ExpectCtap2CommandWithoutResponse(
+  // Returns success response after long delay.
+  device1->ExpectRequestAndRespondWith(std::vector<uint8_t>(),
+                                       CreateFakeSuccessDeviceResponse(),
+                                       base::TimeDelta::FromMicroseconds(10));
+  // Cancel command is invoked after receiving response from |device0|.
+  device1->ExpectCtap2CommandAndDoNotRespond(
       CtapRequestCommand::kAuthenticatorCancel);
 
   discovery()->AddDevice(std::move(device0));
@@ -203,45 +250,35 @@
 // failures, the first received response should be passed on to the relying
 // party and cancel command should be sent to the remaining device.
 TEST_F(FidoRequestHandlerTest, TestRequestWithMultipleFailureResponses) {
-  auto request_handler = CreateMakeCredentialHandler();
+  auto request_handler = CreateFakeHandler();
   discovery()->WaitForCallToStartAndSimulateSuccess();
 
   // Represents a connected device that immediately responds with processing
   // error.
   auto device0 = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device0, GetId()).WillRepeatedly(testing::Return("device0"));
-  device0->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorGetInfo,
-      test_data::kTestAuthenticatorGetInfoResponse);
-  device0->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorMakeCredential, base::nullopt);
+  // Responds with base::nullopt which represents a processing error.
+  device0->ExpectRequestAndRespondWith(std::vector<uint8_t>(), base::nullopt);
 
   // Represents a device that returns UP verified failure response after a small
   // time delay.
   auto device1 = std::make_unique<MockFidoDevice>();
   EXPECT_CALL(*device1, GetId()).WillRepeatedly(testing::Return("device1"));
-  device1->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorGetInfo,
-      test_data::kTestAuthenticatorGetInfoResponse);
-  device1->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorMakeCredential,
-      std::vector<uint8_t>{base::strict_cast<uint8_t>(
-          CtapDeviceResponseCode::kCtap2ErrInvalidCredential)},
-      base::TimeDelta::FromMicroseconds(1));
+  device1->ExpectRequestAndRespondWith(
+      std::vector<uint8_t>(),
+      // Responds with an empty vector that represents a UP-verified error.
+      std::vector<uint8_t>(), base::TimeDelta::FromMicroseconds(1));
 
   // Represents a device that returns UP verified failure response after a big
   // time delay.
   auto device2 = std::make_unique<MockFidoDevice>();
+  device2->set_supported_protocol(ProtocolVersion::kCtap);
   EXPECT_CALL(*device2, GetId()).WillRepeatedly(testing::Return("device2"));
-  device2->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorGetInfo,
-      test_data::kTestAuthenticatorGetInfoResponse);
-  device2->ExpectCtap2CommandAndRespondWith(
-      CtapRequestCommand::kAuthenticatorMakeCredential,
-      std::vector<uint8_t>{base::strict_cast<uint8_t>(
-          CtapDeviceResponseCode::kCtap2ErrInvalidCredential)},
-      base::TimeDelta::FromMicroseconds(10));
-  device2->ExpectCtap2CommandWithoutResponse(
+  device2->ExpectRequestAndRespondWith(
+      std::vector<uint8_t>(),
+      // Responds with an empty vector that represents a UP-verified error.
+      std::vector<uint8_t>(), base::TimeDelta::FromMicroseconds(10));
+  device2->ExpectCtap2CommandAndDoNotRespond(
       CtapRequestCommand::kAuthenticatorCancel);
 
   discovery()->AddDevice(std::move(device0));
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc
index ead5028e..49b9901 100644
--- a/device/fido/get_assertion_handler_unittest.cc
+++ b/device/fido/get_assertion_handler_unittest.cc
@@ -25,10 +25,9 @@
 constexpr uint8_t kClientDataHash[] = {0x01, 0x02, 0x03};
 constexpr char kRpId[] = "google.com";
 
-using TestGetAssertionRequestCallback =
-    ::device::test::StatusAndValueCallbackReceiver<
-        FidoReturnCode,
-        base::Optional<AuthenticatorGetAssertionResponse>>;
+using TestGetAssertionRequestCallback = test::StatusAndValueCallbackReceiver<
+    FidoReturnCode,
+    base::Optional<AuthenticatorGetAssertionResponse>>;
 
 }  // namespace
 
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc
new file mode 100644
index 0000000..e861ffee
--- /dev/null
+++ b/device/fido/make_credential_handler_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <utility>
+
+#include "base/test/scoped_task_environment.h"
+#include "device/fido/authenticator_make_credential_response.h"
+#include "device/fido/authenticator_selection_criteria.h"
+#include "device/fido/ctap_make_credential_request.h"
+#include "device/fido/fake_fido_discovery.h"
+#include "device/fido/fido_constants.h"
+#include "device/fido/fido_device.h"
+#include "device/fido/fido_response_test_data.h"
+#include "device/fido/make_credential_request_handler.h"
+#include "device/fido/mock_fido_device.h"
+#include "device/fido/test_callback_receiver.h"
+#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/u2f_transport_protocol.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+
+namespace device {
+
+namespace {
+
+constexpr uint8_t kClientDataHash[] = {0x01, 0x02, 0x03};
+constexpr uint8_t kUserId[] = {0x01, 0x02, 0x03};
+constexpr char kRpId[] = "google.com";
+
+using TestMakeCredentialRequestCallback = test::StatusAndValueCallbackReceiver<
+    FidoReturnCode,
+    base::Optional<AuthenticatorMakeCredentialResponse>>;
+
+}  // namespace
+
+class FidoMakeCredentialHandlerTest : public ::testing::Test {
+ public:
+  void ForgeNextHidDiscovery() {
+    discovery_ = scoped_fake_discovery_factory_.ForgeNextHidDiscovery();
+  }
+
+  std::unique_ptr<MakeCredentialRequestHandler> CreateMakeCredentialHandler() {
+    ForgeNextHidDiscovery();
+    PublicKeyCredentialRpEntity rp(kRpId);
+    PublicKeyCredentialUserEntity user(u2f_parsing_utils::Materialize(kUserId));
+    PublicKeyCredentialParams credential_params({{kU2fCredentialType}});
+
+    auto request_parameter = CtapMakeCredentialRequest(
+        u2f_parsing_utils::Materialize(kClientDataHash), std::move(rp),
+        std::move(user), std::move(credential_params));
+
+    return std::make_unique<MakeCredentialRequestHandler>(
+        nullptr,
+        base::flat_set<U2fTransportProtocol>(
+            {U2fTransportProtocol::kUsbHumanInterfaceDevice}),
+        std::move(request_parameter), AuthenticatorSelectionCriteria(),
+        cb_.callback());
+  }
+
+  test::FakeFidoDiscovery* discovery() const { return discovery_; }
+  TestMakeCredentialRequestCallback& callback() { return cb_; }
+
+ protected:
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
+  test::ScopedFakeFidoDiscoveryFactory scoped_fake_discovery_factory_;
+  test::FakeFidoDiscovery* discovery_;
+  TestMakeCredentialRequestCallback cb_;
+};
+
+TEST_F(FidoMakeCredentialHandlerTest, TestMakeCredentialRequestHandler) {
+  auto request_handler = CreateMakeCredentialHandler();
+  discovery()->WaitForCallToStartAndSimulateSuccess();
+
+  auto device = std::make_unique<MockFidoDevice>();
+  EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0"));
+  device->ExpectCtap2CommandAndRespondWith(
+      CtapRequestCommand::kAuthenticatorGetInfo,
+      test_data::kTestAuthenticatorGetInfoResponse);
+  device->ExpectCtap2CommandAndRespondWith(
+      CtapRequestCommand::kAuthenticatorMakeCredential,
+      test_data::kTestMakeCredentialResponse);
+
+  discovery()->AddDevice(std::move(device));
+  callback().WaitForCallback();
+  EXPECT_EQ(FidoReturnCode::kSuccess, callback().status());
+  EXPECT_TRUE(request_handler->is_complete());
+}
+
+// Test a scenario where the connected authenticator is a U2F device. Request
+// be silently dropped and request should remain in incomplete state.
+TEST_F(FidoMakeCredentialHandlerTest,
+       TestMakeCredentialIncorrectGetInfoResponse) {
+  auto request_handler = CreateMakeCredentialHandler();
+  discovery()->WaitForCallToStartAndSimulateSuccess();
+
+  auto device = std::make_unique<MockFidoDevice>();
+  EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0"));
+  device->ExpectCtap2CommandAndRespondWith(
+      CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt);
+
+  discovery()->AddDevice(std::move(device));
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  EXPECT_FALSE(request_handler->is_complete());
+}
+
+}  // namespace device
diff --git a/device/fido/mock_fido_device.cc b/device/fido/mock_fido_device.cc
index 37afeca..673ac28 100644
--- a/device/fido/mock_fido_device.cc
+++ b/device/fido/mock_fido_device.cc
@@ -16,8 +16,9 @@
 
 namespace device {
 
+// Matcher to compare the fist byte of the incoming requests.
 MATCHER_P(IsCtap2Command, expected_command, "") {
-  return !arg.empty() && (arg[0] == static_cast<uint8_t>(expected_command));
+  return !arg.empty() && arg[0] == base::strict_cast<uint8_t>(expected_command);
 }
 
 MockFidoDevice::MockFidoDevice() : weak_factory_(this) {}
@@ -51,28 +52,6 @@
 }
 
 // static
-void MockFidoDevice::NoErrorGetInfo(const std::vector<uint8_t>& command,
-                                    DeviceCallback& cb) {
-  std::move(cb).Run(std::vector<uint8_t>(
-      std::begin(test_data::kTestAuthenticatorGetInfoResponse),
-      std::end(test_data::kTestAuthenticatorGetInfoResponse)));
-}
-
-// static
-void MockFidoDevice::CtapDeviceError(const std::vector<uint8_t>& command,
-                                     DeviceCallback& cb) {
-  std::move(cb).Run(base::nullopt);
-}
-
-// static
-void MockFidoDevice::NoErrorMakeCredential(const std::vector<uint8_t>& command,
-                                           DeviceCallback& cb) {
-  std::move(cb).Run(
-      std::vector<uint8_t>(std::begin(test_data::kTestMakeCredentialResponse),
-                           std::end(test_data::kTestMakeCredentialResponse)));
-}
-
-// static
 void MockFidoDevice::NoErrorSign(const std::vector<uint8_t>& command,
                                  DeviceCallback& cb) {
   std::move(cb).Run(
@@ -135,15 +114,39 @@
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, base::BindOnce(std::move(cb), std::move(data)), delay);
   };
+
   EXPECT_CALL(*this, DeviceTransactPtr(IsCtap2Command(command), ::testing::_))
       .WillOnce(::testing::WithArg<1>(::testing::Invoke(send_response)));
 }
 
-void MockFidoDevice::ExpectCtap2CommandWithoutResponse(
+void MockFidoDevice::ExpectRequestAndRespondWith(
+    base::span<const uint8_t> request,
+    base::Optional<base::span<const uint8_t>> response,
+    base::TimeDelta delay) {
+  auto data = u2f_parsing_utils::MaterializeOrNull(response);
+  auto send_response = [ data(std::move(data)), delay ](DeviceCallback & cb) {
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::BindOnce(std::move(cb), std::move(data)), delay);
+  };
+
+  auto request_as_vector = u2f_parsing_utils::Materialize(request);
+  EXPECT_CALL(*this,
+              DeviceTransactPtr(std::move(request_as_vector), ::testing::_))
+      .WillOnce(::testing::WithArg<1>(::testing::Invoke(send_response)));
+}
+
+void MockFidoDevice::ExpectCtap2CommandAndDoNotRespond(
     CtapRequestCommand command) {
   EXPECT_CALL(*this, DeviceTransactPtr(IsCtap2Command(command), ::testing::_));
 }
 
+void MockFidoDevice::ExpectRequestAndDoNotRespond(
+    base::span<const uint8_t> request) {
+  auto request_as_vector = u2f_parsing_utils::Materialize(request);
+  EXPECT_CALL(*this,
+              DeviceTransactPtr(std::move(request_as_vector), ::testing::_));
+}
+
 base::WeakPtr<FidoDevice> MockFidoDevice::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
 }
diff --git a/device/fido/mock_fido_device.h b/device/fido/mock_fido_device.h
index d96a691..3f0fed3f 100644
--- a/device/fido/mock_fido_device.h
+++ b/device/fido/mock_fido_device.h
@@ -45,12 +45,6 @@
                            DeviceCallback& cb);
   static void WrongData(const std::vector<uint8_t>& command,
                         DeviceCallback& cb);
-  static void NoErrorGetInfo(const std::vector<uint8_t>& command,
-                             DeviceCallback& cb);
-  static void CtapDeviceError(const std::vector<uint8_t>& command,
-                              DeviceCallback& cb);
-  static void NoErrorMakeCredential(const std::vector<uint8_t>& command,
-                                    DeviceCallback& cb);
   static void NoErrorSign(const std::vector<uint8_t>& command,
                           DeviceCallback& cb);
   static void NoErrorRegister(const std::vector<uint8_t>& command,
@@ -68,7 +62,12 @@
       CtapRequestCommand command,
       base::Optional<base::span<const uint8_t>> response,
       base::TimeDelta delay = base::TimeDelta());
-  void ExpectCtap2CommandWithoutResponse(CtapRequestCommand command);
+  void ExpectRequestAndRespondWith(
+      base::span<const uint8_t> request,
+      base::Optional<base::span<const uint8_t>> response,
+      base::TimeDelta delay = base::TimeDelta());
+  void ExpectCtap2CommandAndDoNotRespond(CtapRequestCommand command);
+  void ExpectRequestAndDoNotRespond(base::span<const uint8_t> request);
 
   base::WeakPtr<FidoDevice> GetWeakPtr() override;
 
diff --git a/device/fido/virtual_fido_device.h b/device/fido/virtual_fido_device.h
index b651e70..cfaacf6 100644
--- a/device/fido/virtual_fido_device.h
+++ b/device/fido/virtual_fido_device.h
@@ -69,7 +69,7 @@
     // typically be a domain, e.g. "example.com").
     //
     // Returns true on success. Will fail if there already exists a credential
-    // with the given ID.
+    // with the given ID or if private-key generation fails.
     bool InjectRegistration(const std::vector<uint8_t>& credential_id,
                             const std::string& relying_party_id);
 
diff --git a/docs/windows_build_instructions.md b/docs/windows_build_instructions.md
index 793c13bef..40a620f 100644
--- a/docs/windows_build_instructions.md
+++ b/docs/windows_build_instructions.md
@@ -178,17 +178,37 @@
 
 The generated solution will contain several thousand projects and will be very
 slow to load. Use the `--filters` argument to restrict generating project files
-for only the code you're interested in, although this will also limit what
-files appear in the project explorer. A minimal solution that will let you
-compile and run Chrome in the IDE but will not show any source files is:
+for only the code you're interested in. Although this will also limit what
+files appear in the project explorer, debugging will still work and you can
+set breakpoints in files that you open manually. A minimal solution that will
+let you compile and run Chrome in the IDE but will not show any source files
+is:
 
 ```
-$ gn gen --ide=vs --filters=//chrome out\Default
+$ gn gen --ide=vs --filters=//chrome --no-deps out\Default
 ```
 
+You can selectively add other directories you care about to the filter like so:
+`--filters=//chrome;//third_party/WebKit/*;//gpu/*`.
+
 There are other options for controlling how the solution is generated, run `gn
 help gen` for the current documentation.
 
+By default when you start debugging in Visual Studio the debugger will only
+attach to the main browser process. To debug all of Chrome, install
+[Microsoft's Child Process Debugging Power Tool](https://blogs.msdn.microsoft.com/devops/2014/11/24/introducing-the-child-process-debugging-power-tool/).
+You will also need to run Visual Studio as administrator, or it will silently
+fail to attach to some of Chrome's child processes.
+
+It is also possible to debug and develop Chrome in Visual Studio without a
+solution file. Simply "open" your chrome.exe binary with
+`File->Open->Project/Solution`, or from a Visual Studio command prompt like
+so: `devenv /debugexe out\Debug\chrome.exe <your arguments>`. Many of Visual
+Studio's code editing features will not work in this configuration, but by
+installing the [VsChromium Visual Studio Extension](https://chromium.github.io/vs-chromium/)
+you can get the source code to appear in the solution explorer window along
+with other useful features such as code search.
+
 ### Faster builds
 
 * Reduce file system overhead by excluding build directories from
diff --git a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
index a4afe89..fc0f5582 100644
--- a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
+++ b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
@@ -299,8 +299,8 @@
     WebViewInternalCaptureVisibleRegionFunction()
     : is_guest_transparent_(false) {}
 
-bool WebViewInternalCaptureVisibleRegionFunction::RunAsyncSafe(
-    WebViewGuest* guest) {
+ExtensionFunction::ResponseAction
+WebViewInternalCaptureVisibleRegionFunction::Run() {
   using api::extension_types::ImageDetails;
 
   std::unique_ptr<web_view_internal::CaptureVisibleRegion::Params> params(
@@ -314,16 +314,18 @@
     image_details = ImageDetails::FromValue(*spec);
   }
 
-  is_guest_transparent_ = guest->allow_transparency();
+  is_guest_transparent_ = guest_->allow_transparency();
   const CaptureResult capture_result = CaptureAsync(
-      guest->web_contents(), image_details.get(),
+      guest_->web_contents(), image_details.get(),
       base::BindOnce(
           &WebViewInternalCaptureVisibleRegionFunction::CopyFromSurfaceComplete,
           this));
-  if (capture_result == OK)
-    return true;
-  SetErrorMessage(capture_result);
-  return false;
+  if (capture_result == OK) {
+    // CaptureAsync may have responded synchronously.
+    return did_respond() ? AlreadyResponded() : RespondLater();
+  }
+
+  return RespondNow(Error(GetErrorMessage(capture_result)));
 }
 bool WebViewInternalCaptureVisibleRegionFunction::IsScreenshotEnabled() const {
   // TODO(wjmaclean): Is it ok to always return true here?
@@ -342,17 +344,15 @@
     return;
   }
 
-  SetResult(std::make_unique<base::Value>(base64_result));
-  SendResponse(true);
+  Respond(OneArgument(std::make_unique<base::Value>(base64_result)));
 }
 
 void WebViewInternalCaptureVisibleRegionFunction::OnCaptureFailure(
     CaptureResult result) {
-  SetErrorMessage(result);
-  SendResponse(false);
+  Respond(Error(GetErrorMessage(result)));
 }
 
-void WebViewInternalCaptureVisibleRegionFunction::SetErrorMessage(
+std::string WebViewInternalCaptureVisibleRegionFunction::GetErrorMessage(
     CaptureResult result) {
   const char* reason_description = "internal error";
   switch (result) {
@@ -371,11 +371,11 @@
       break;
     case OK:
       NOTREACHED()
-          << "SetErrorMessage should not be called with a successful result";
-      return;
+          << "GetErrorMessage should not be called with a successful result";
+      return "";
   }
-  error_ = ErrorUtils::FormatErrorMessage("Failed to capture webview: *",
-                                          reason_description);
+  return ErrorUtils::FormatErrorMessage("Failed to capture webview: *",
+                                        reason_description);
 }
 
 ExtensionFunction::ResponseAction WebViewInternalNavigateFunction::Run() {
diff --git a/extensions/browser/api/guest_view/web_view/web_view_internal_api.h b/extensions/browser/api/guest_view/web_view/web_view_internal_api.h
index 4f73e4f8e..cf960bff 100644
--- a/extensions/browser/api/guest_view/web_view/web_view_internal_api.h
+++ b/extensions/browser/api/guest_view/web_view/web_view_internal_api.h
@@ -49,7 +49,7 @@
 };
 
 class WebViewInternalCaptureVisibleRegionFunction
-    : public LegacyWebViewInternalExtensionFunction,
+    : public WebViewInternalExtensionFunction,
       public WebContentsCaptureClient {
  public:
   DECLARE_EXTENSION_FUNCTION("webViewInternal.captureVisibleRegion",
@@ -59,17 +59,17 @@
  protected:
   ~WebViewInternalCaptureVisibleRegionFunction() override {}
 
- private:
-  // LegacyWebViewInternalExtensionFunction implementation.
-  bool RunAsyncSafe(WebViewGuest* guest) override;
+  // UIThreadExtensionFunction:
+  ResponseAction Run() override;
 
+ private:
   // extensions::WebContentsCaptureClient:
   bool IsScreenshotEnabled() const override;
   bool ClientAllowsTransparency() override;
   void OnCaptureSuccess(const SkBitmap& bitmap) override;
   void OnCaptureFailure(CaptureResult result) override;
 
-  void SetErrorMessage(CaptureResult result);
+  std::string GetErrorMessage(CaptureResult result);
 
   bool is_guest_transparent_;
 
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 968d88e9..7cd187a 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1295,6 +1295,10 @@
   DECLARATIVENETREQUEST_REMOVEWHITELISTEDPAGES,
   DECLARATIVENETREQUEST_GETWHITELISTEDPAGES,
   DEVELOPERPRIVATE_INSTALLDROPPEDFILE,
+  AUTOMATIONINTERNAL_ENABLEFRAME,
+  AUTOMATIONINTERNAL_QUERYSELECTOR,
+  DEBUGGER_GETTARGETS,
+  NOTIFICATIONS_GETPERMISSIONLEVEL,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/extension_function_registry.h b/extensions/browser/extension_function_registry.h
index a1d1d834..93b5411 100644
--- a/extensions/browser/extension_function_registry.h
+++ b/extensions/browser/extension_function_registry.h
@@ -42,6 +42,7 @@
     extensions::functions::HistogramValue histogram_value_ =
         extensions::functions::UNKNOWN;
   };
+  using FactoryMap = std::map<std::string, FactoryEntry>;
 
   static ExtensionFunctionRegistry& GetInstance();
   ExtensionFunctionRegistry();
@@ -63,8 +64,9 @@
                           T::histogram_value()));
   }
 
+  const FactoryMap& GetFactoriesForTesting() const { return factories_; }
+
  private:
-  typedef std::map<std::string, FactoryEntry> FactoryMap;
   FactoryMap factories_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionFunctionRegistry);
diff --git a/gpu/OWNERS b/gpu/OWNERS
index cb1b32e..6291e491 100644
--- a/gpu/OWNERS
+++ b/gpu/OWNERS
@@ -1,3 +1,4 @@
+backer@chromium.org
 ericrk@chromium.org
 kbr@chromium.org
 piman@chromium.org
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index c2d523c..616b12e 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -438,6 +438,12 @@
     short_name: "64"
   }
   builders: {
+    name: "buildbot/chromium.fyi/Linux deterministic (dbg)"
+    name: "buildbucket/luci.chromium.ci/Deterministic Linux (dbg)"
+    category: "chromium.linux|debug"
+    short_name: "det"
+  }
+  builders: {
     name: "buildbucket/luci.chromium.ci/Deterministic Linux"
     category: "chromium.linux"
     short_name: "det"
@@ -1815,6 +1821,36 @@
     short_name: "ci"
   }
 
+  builders: {
+    name: "buildbot/chromium.fyi/Linux deterministic (dbg)"
+    category: "chromium.linux|debug"
+    short_name: "bb"
+  }
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Deterministic Linux (dbg)"
+    category: "chromium.linux|debug"
+    short_name: "ci"
+  }
+  builders: {
+    name: "buildbot/chromium.fyi/Android deterministic"
+    category: "chromium.android|release"
+    short_name: "bb"
+  }
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Deterministic Android"
+    category: "chromium.android|release"
+    short_name: "ci"
+  }
+  builders: {
+    name: "buildbot/chromium.fyi/Android deterministic (dbg)"
+    category: "chromium.android|debug"
+    short_name: "bb"
+  }
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Deterministic Android (dbg)"
+    category: "chromium.android|debug"
+    short_name: "ci"
+  }
 }
 
 consoles: {
@@ -2071,6 +2107,18 @@
     short_name: "64"
   }
   builders: {
+    name: "buildbot/chromium.fyi/Android deterministic"
+    name: "buildbucket/luci.chromium.ci/Deterministic Android"
+    category: "builder|det"
+    short_name: "rel"
+  }
+  builders: {
+    name: "buildbot/chromium.fyi/Android deterministic (dbg)"
+    name: "buildbucket/luci.chromium.ci/Deterministic Android (dbg)"
+    category: "builder|det"
+    short_name: "dbg"
+  }
+  builders: {
     name: "buildbot/chromium.android/KitKat Phone Tester (dbg)"
     category: "tester|phone"
     short_name: "K"
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_cs.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_cs.xtb
index 7b2b647d..808ace6 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_cs.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_cs.xtb
@@ -16,7 +16,7 @@
 <translation id="3148688391461398285">Získejte v Chromu lepší funkce založené na poloze.</translation>
 <translation id="3167189358072330585">Váš účet v prohlížeči Google Chrome nefunguje. Kontaktujte administrátora domény nebo se přihlaste pomocí běžného účtu Google.</translation>
 <translation id="3196546062792660320">Chrome vám šetří čas tím, že vaše účty přenáší na web. Účty můžete přidat nebo odstranit v Nastavení.</translation>
-<translation id="3282568296779691940">Přihlášení do Chrome</translation>
+<translation id="3282568296779691940">Přihlásit se do Chromu</translation>
 <translation id="3345341804167540816">Používejte Chrome všude</translation>
 <translation id="3678774398092457402">Chcete, aby aplikace Chrome uložila vaše heslo pro tento web?</translation>
 <translation id="384394811301901750">Google Chrome nyní nemůže použít fotoaparát</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_de.xtb b/ios/chrome/app/strings/resources/ios_strings_de.xtb
index e83ad7b..d973c29 100644
--- a/ios/chrome/app/strings/resources/ios_strings_de.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_de.xtb
@@ -215,7 +215,7 @@
 <translation id="5062321486222145940">Google Drive installieren</translation>
 <translation id="5083464117946352670">Fehler bei Bestimmung der Dateigröße</translation>
 <translation id="5094827893301452931">Tweet gepostet</translation>
-<translation id="5173593619615111996">Alle Inkognitotabs schließen</translation>
+<translation id="5173593619615111996">Alle Inkognito-Tabs schließen</translation>
 <translation id="5181140330217080051">Download wird ausgeführt...</translation>
 <translation id="5186185447130319458">Privat</translation>
 <translation id="5190835502935405962">Lesezeichenleiste</translation>
@@ -286,7 +286,7 @@
 <translation id="6342069812937806050">Abgeschlossen</translation>
 <translation id="6344783595350022745">Text entfernen</translation>
 <translation id="6346549652287021269">Neuen Download starten?</translation>
-<translation id="6362362396625799311">Keine Inkognitotabs</translation>
+<translation id="6362362396625799311">Keine Inkognito-Tabs</translation>
 <translation id="6374469231428023295">Erneut versuchen</translation>
 <translation id="6380866119319257197">Wenn Sie Ihre Passphrase vergessen oder diese Einstellung ändern möchten, <ph name="BEGIN_LINK" />setzen Sie die Synchronisierung zurück<ph name="END_LINK" /></translation>
 <translation id="6389470377220713856">Name auf Karte</translation>
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.cc b/ios/chrome/browser/ui/omnibox/omnibox_util.cc
index 18958e05..af1423bf 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_util.cc
+++ b/ios/chrome/browser/ui/omnibox/omnibox_util.cc
@@ -28,7 +28,7 @@
     case AutocompleteMatchType::HISTORY_TITLE:
     case AutocompleteMatchType::HISTORY_URL:
     case AutocompleteMatchType::SEARCH_HISTORY:
-    case AutocompleteMatchType::TAB_SEARCH:
+    case AutocompleteMatchType::TAB_SEARCH_DEPRECATED:
       return is_incognito ? IDR_IOS_OMNIBOX_HISTORY_INCOGNITO
                           : IDR_IOS_OMNIBOX_HISTORY;
     case AutocompleteMatchType::CONTACT_DEPRECATED:
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
index d5f11d5..a5b5fb14 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -31,8 +31,8 @@
 #include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
 #import "ios/chrome/browser/ui/settings/sync_utils/sync_presenter.h"
 #import "ios/chrome/browser/ui/signin_interaction/public/signin_presenter.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_signin_promo_item.h"
-#import "ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
 #include "ios/chrome/browser/ui/ui_util.h"
@@ -178,8 +178,9 @@
   [model addSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs];
   [model setSectionIdentifier:SectionIdentifierRecentlyClosedTabs
                  collapsedKey:kRecentlyClosedCollapsedKey];
-  TableViewTextHeaderFooterItem* header = [[TableViewTextHeaderFooterItem alloc]
-      initWithType:ItemTypeRecentlyClosedHeader];
+  TableViewDisclosureHeaderFooterItem* header =
+      [[TableViewDisclosureHeaderFooterItem alloc]
+          initWithType:ItemTypeRecentlyClosedHeader];
   header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_RECENTLY_CLOSED);
   [model setHeader:header
       forSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs];
@@ -283,8 +284,8 @@
     NSString* sessionCollapsedKey = base::SysUTF8ToNSString(session->tag);
     [model setSectionIdentifier:sessionIdentifier
                    collapsedKey:sessionCollapsedKey];
-    TableViewTextHeaderFooterItem* header =
-        [[TableViewTextHeaderFooterItem alloc]
+    TableViewDisclosureHeaderFooterItem* header =
+        [[TableViewDisclosureHeaderFooterItem alloc]
             initWithType:ItemTypeSessionHeader];
     header.text = base::SysUTF8ToNSString(session->name);
     header.subtitleText = l10n_util::GetNSStringF(
@@ -374,8 +375,9 @@
   [model addSectionWithIdentifier:SectionIdentifierOtherDevices];
   [model setSectionIdentifier:SectionIdentifierOtherDevices
                  collapsedKey:kOtherDeviceCollapsedKey];
-  TableViewTextHeaderFooterItem* header = [[TableViewTextHeaderFooterItem alloc]
-      initWithType:ItemTypeRecentlyClosedHeader];
+  TableViewDisclosureHeaderFooterItem* header =
+      [[TableViewDisclosureHeaderFooterItem alloc]
+          initWithType:ItemTypeRecentlyClosedHeader];
   header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OTHER_DEVICES);
   [model setHeader:header
       forSectionWithIdentifier:SectionIdentifierOtherDevices];
@@ -776,8 +778,9 @@
         sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier];
     UITableViewHeaderFooterView* headerView =
         [self.tableView headerViewForSection:section];
-    TableViewTextHeaderFooterView* headerTextView =
-        base::mac::ObjCCastStrict<TableViewTextHeaderFooterView>(headerView);
+    TableViewDisclosureHeaderFooterView* headerTextView =
+        base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>(
+            headerView);
     [headerTextView animateHighlight];
   }
 }
@@ -832,8 +835,9 @@
         sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier];
     UITableViewHeaderFooterView* headerView =
         [self.tableView headerViewForSection:section];
-    TableViewTextHeaderFooterView* headerTextView =
-        base::mac::ObjCCastStrict<TableViewTextHeaderFooterView>(headerView);
+    TableViewDisclosureHeaderFooterView* headerTextView =
+        base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>(
+            headerView);
     [headerTextView animateHighlight];
 
     web::ContextMenuParams params;
diff --git a/ios/chrome/browser/ui/table_view/cells/BUILD.gn b/ios/chrome/browser/ui/table_view/cells/BUILD.gn
index 2a96d36..066b1aaf 100644
--- a/ios/chrome/browser/ui/table_view/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/table_view/cells/BUILD.gn
@@ -4,6 +4,10 @@
 
 source_set("cells") {
   sources = [
+    "table_view_cells_constants.h",
+    "table_view_cells_constants.mm",
+    "table_view_disclosure_header_footer_item.h",
+    "table_view_disclosure_header_footer_item.mm",
     "table_view_header_footer_item.h",
     "table_view_header_footer_item.mm",
     "table_view_item.h",
@@ -19,7 +23,9 @@
   ]
 
   deps = [
+    "resources:table_view_cell_chevron",
     "//base",
+    "//ios/chrome/browser/ui:ui_util",
     "//ios/chrome/browser/ui/authentication:authentication_ui",
     "//ios/chrome/browser/ui/list_model",
     "//ios/chrome/browser/ui/table_view:styler",
diff --git a/ios/chrome/browser/ui/table_view/cells/resources/table_view_cell_chevron.imageset/Contents.json b/ios/chrome/browser/ui/table_view/cells/resources/table_view_cell_chevron.imageset/Contents.json
index cc4e11e8a..45fe89faa 100644
--- a/ios/chrome/browser/ui/table_view/cells/resources/table_view_cell_chevron.imageset/Contents.json
+++ b/ios/chrome/browser/ui/table_view/cells/resources/table_view_cell_chevron.imageset/Contents.json
@@ -8,12 +8,12 @@
         {
             "idiom": "universal",
             "scale": "2x",
-            "filename": "table_view_cell_chevron_@2x.png"
+            "filename": "table_view_cell_chevron@2x.png"
         },
         {
             "idiom": "universal",
             "scale": "3x",
-            "filename": "table_view_cell_chevron_@3x.png"
+            "filename": "table_view_cell_chevron@3x.png"
         }
     ],
     "info": {
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h b/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h
new file mode 100644
index 0000000..d5a03cf
--- /dev/null
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_CELLS_CONSTANTS_H_
+#define IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_CELLS_CONSTANTS_H_
+
+#import <UIKit/UIKit.h>
+
+// The spacing between views inside of a cell.
+extern const CGFloat kTableViewCellViewSpacing;
+
+// The vertical spacing between text labels in a stackView.
+extern const CGFloat kTableViewVerticalLabelStackSpacing;
+
+// Animation Duration for highlighting selected section header.
+extern const CGFloat kTableViewCellSelectionAnimationDuration;
+
+// Color and alpha used to highlight a cell with a middle gray color to
+// represent a user tap.
+extern const CGFloat kTableViewHighlightedCellColor;
+extern const CGFloat kTableViewHighlightedCellColorAlpha;
+
+#endif  // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_CELLS_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.mm b/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.mm
new file mode 100644
index 0000000..6a4df52
--- /dev/null
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.mm
@@ -0,0 +1,15 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+const CGFloat kTableViewCellViewSpacing = 16.0;
+const CGFloat kTableViewVerticalLabelStackSpacing = 2.0;
+const CGFloat kTableViewCellSelectionAnimationDuration = 0.15;
+const CGFloat kTableViewHighlightedCellColor = 0xA6A6A6;
+const CGFloat kTableViewHighlightedCellColorAlpha = 0.5;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h
new file mode 100644
index 0000000..18b6c6b
--- /dev/null
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_DISCLOSURE_HEADER_FOOTER_ITEM_H_
+#define IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_DISCLOSURE_HEADER_FOOTER_ITEM_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h"
+
+// TableViewDisclosureHeaderFooterItem contains the model data for a
+// TableViewDisclosureHeaderFooterView.
+@interface TableViewDisclosureHeaderFooterItem : TableViewHeaderFooterItem
+// Title of Header.
+@property(nonatomic, readwrite, strong) NSString* text;
+// Header subtitle displayed as a smaller font under title.
+@property(nonatomic, readwrite, strong) NSString* subtitleText;
+@end
+
+// UITableViewHeaderFooterView that displays a text label, subtitle, and a
+// disclosure accessory view.
+@interface TableViewDisclosureHeaderFooterView : UITableViewHeaderFooterView
+// Shows the text of the TableViewDisclosureHeaderFooterItem.
+@property(nonatomic, readwrite, strong) UILabel* titleLabel;
+// Shows the subtitleText of the TableViewDisclosureHeaderFooterItem.
+@property(nonatomic, readwrite, strong) UILabel* subtitleLabel;
+// Animates a change in the backgroundView color and then changes it back to the
+// original backGround color in order to simulate a selection highlight.
+- (void)animateHighlight;
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_DISCLOSURE_HEADER_FOOTER_ITEM_H_
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
new file mode 100644
index 0000000..4a6eba6
--- /dev/null
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.mm
@@ -0,0 +1,137 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h"
+
+#include "base/mac/foundation_util.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
+#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation TableViewDisclosureHeaderFooterItem
+@synthesize subtitleText = _subtitleText;
+@synthesize text = _text;
+
+- (instancetype)initWithType:(NSInteger)type {
+  self = [super initWithType:type];
+  if (self) {
+    self.cellClass = [TableViewDisclosureHeaderFooterView class];
+  }
+  return self;
+}
+
+- (void)configureHeaderFooterView:(UITableViewHeaderFooterView*)headerFooter
+                       withStyler:(ChromeTableViewStyler*)styler {
+  [super configureHeaderFooterView:headerFooter withStyler:styler];
+
+  // Set the contentView backgroundColor, not the header's.
+  headerFooter.contentView.backgroundColor = styler.tableViewBackgroundColor;
+
+  TableViewDisclosureHeaderFooterView* header =
+      base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>(
+          headerFooter);
+  header.titleLabel.text = self.text;
+  header.subtitleLabel.text = self.subtitleText;
+}
+
+@end
+
+#pragma mark - TableViewDisclosureHeaderFooterView
+
+@interface TableViewDisclosureHeaderFooterView ()
+// Animator that handles all cell animations.
+@property(strong, nonatomic) UIViewPropertyAnimator* cellAnimator;
+@end
+
+@implementation TableViewDisclosureHeaderFooterView
+@synthesize cellAnimator = _cellAnimator;
+@synthesize subtitleLabel = _subtitleLabel;
+@synthesize titleLabel = _titleLabel;
+
+- (instancetype)initWithReuseIdentifier:(NSString*)reuseIdentifier {
+  self = [super initWithReuseIdentifier:reuseIdentifier];
+  if (self) {
+    // Labels, set font sizes using dynamic type.
+    _titleLabel = [[UILabel alloc] init];
+    _titleLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
+    _subtitleLabel = [[UILabel alloc] init];
+    _subtitleLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
+    _subtitleLabel.textColor = [UIColor lightGrayColor];
+
+    // Vertical StackView.
+    UIStackView* verticalStack = [[UIStackView alloc]
+        initWithArrangedSubviews:@[ _titleLabel, _subtitleLabel ]];
+    verticalStack.axis = UILayoutConstraintAxisVertical;
+    verticalStack.spacing = kTableViewVerticalLabelStackSpacing;
+
+    // Disclosure ImageView.
+    UIImageView* disclosureImageView = [[UIImageView alloc]
+        initWithImage:[UIImage imageNamed:@"table_view_cell_chevron"]];
+    [disclosureImageView
+        setContentHuggingPriority:UILayoutPriorityDefaultHigh
+                          forAxis:UILayoutConstraintAxisHorizontal];
+
+    // Horizontal StackView.
+    UIStackView* horizontalStack = [[UIStackView alloc]
+        initWithArrangedSubviews:@[ verticalStack, disclosureImageView ]];
+    horizontalStack.axis = UILayoutConstraintAxisHorizontal;
+    horizontalStack.spacing = kTableViewCellViewSpacing;
+    horizontalStack.translatesAutoresizingMaskIntoConstraints = NO;
+    horizontalStack.alignment = UIStackViewAlignmentCenter;
+
+    // Add subviews to View Hierarchy.
+    [self.contentView addSubview:horizontalStack];
+
+    // Set and activate constraints.
+    [NSLayoutConstraint activateConstraints:@[
+      // Horizontal Stack Constraints.
+      [horizontalStack.leadingAnchor
+          constraintEqualToAnchor:self.contentView.leadingAnchor
+                         constant:kTableViewCellViewSpacing],
+      [horizontalStack.trailingAnchor
+          constraintEqualToAnchor:self.contentView.trailingAnchor
+                         constant:-kTableViewCellViewSpacing],
+      [horizontalStack.topAnchor
+          constraintGreaterThanOrEqualToAnchor:self.contentView.topAnchor
+                                      constant:kTableViewCellViewSpacing],
+      [horizontalStack.bottomAnchor
+          constraintLessThanOrEqualToAnchor:self.contentView.bottomAnchor
+                                   constant:-kTableViewCellViewSpacing],
+      [horizontalStack.centerYAnchor
+          constraintEqualToAnchor:self.contentView.centerYAnchor]
+    ]];
+  }
+  return self;
+}
+
+- (void)animateHighlight {
+  UIColor* originalBackgroundColor = self.contentView.backgroundColor;
+  self.cellAnimator = [[UIViewPropertyAnimator alloc]
+      initWithDuration:kTableViewCellSelectionAnimationDuration
+                 curve:UIViewAnimationCurveLinear
+            animations:^{
+              self.contentView.backgroundColor =
+                  UIColorFromRGB(kTableViewHighlightedCellColor,
+                                 kTableViewHighlightedCellColorAlpha);
+            }];
+  __weak TableViewDisclosureHeaderFooterView* weakSelf = self;
+  [self.cellAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
+    weakSelf.contentView.backgroundColor = originalBackgroundColor;
+  }];
+  [self.cellAnimator startAnimation];
+}
+
+- (void)prepareForReuse {
+  [super prepareForReuse];
+  if (self.cellAnimator.isRunning)
+    [self.cellAnimator stopAnimation:YES];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
index fce23640..0fd8767 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.mm
@@ -5,19 +5,14 @@
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h"
 
 #include "base/mac/foundation_util.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-namespace {
-// The inner insets of the View content.
-const CGFloat kMargin = 16;
-
-// The vertical spacing between text labels.
-const CGFloat kVerticalSpacing = 2.0;
-}
 
 @implementation TableViewTextHeaderFooterItem
 @synthesize subtitleText = _subtitleText;
@@ -76,7 +71,7 @@
     UIStackView* verticalStack = [[UIStackView alloc]
         initWithArrangedSubviews:@[ _textLabel, _subtitleLabel ]];
     verticalStack.axis = UILayoutConstraintAxisVertical;
-    verticalStack.spacing = kVerticalSpacing;
+    verticalStack.spacing = kTableViewVerticalLabelStackSpacing;
     verticalStack.translatesAutoresizingMaskIntoConstraints = NO;
 
     // Container View.
@@ -92,16 +87,16 @@
       // Container Constraints.
       [containerView.leadingAnchor
           constraintEqualToAnchor:self.contentView.leadingAnchor
-                         constant:kMargin],
+                         constant:kTableViewCellViewSpacing],
       [containerView.trailingAnchor
           constraintEqualToAnchor:self.contentView.trailingAnchor
-                         constant:-kMargin],
+                         constant:-kTableViewCellViewSpacing],
       [containerView.topAnchor
           constraintGreaterThanOrEqualToAnchor:self.contentView.topAnchor
-                                      constant:kMargin],
+                                      constant:kTableViewCellViewSpacing],
       [containerView.bottomAnchor
           constraintLessThanOrEqualToAnchor:self.contentView.bottomAnchor
-                                   constant:-kMargin],
+                                   constant:-kTableViewCellViewSpacing],
       [containerView.centerYAnchor
           constraintEqualToAnchor:self.contentView.centerYAnchor],
       // Vertical StackView Constraints.
@@ -120,11 +115,12 @@
 - (void)animateHighlight {
   UIColor* originalBackgroundColor = self.contentView.backgroundColor;
   self.cellAnimator = [[UIViewPropertyAnimator alloc]
-      initWithDuration:0.15
+      initWithDuration:kTableViewCellSelectionAnimationDuration
                  curve:UIViewAnimationCurveLinear
             animations:^{
               self.contentView.backgroundColor =
-                  [[UIColor lightGrayColor] colorWithAlphaComponent:0.5];
+                  UIColorFromRGB(kTableViewHighlightedCellColor,
+                                 kTableViewHighlightedCellColorAlpha);
             }];
   __weak TableViewTextHeaderFooterView* weakSelf = self;
   [self.cellAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
diff --git a/ios/web_view/shell/shell_autofill_delegate.m b/ios/web_view/shell/shell_autofill_delegate.m
index db8cda6..b8a9f727 100644
--- a/ios/web_view/shell/shell_autofill_delegate.m
+++ b/ios/web_view/shell/shell_autofill_delegate.m
@@ -38,7 +38,7 @@
 
 - (void)autofillController:(CWVAutofillController*)autofillController
     didFocusOnFieldWithName:(NSString*)fieldName
-             withIdentifier:(NSString*)fieldIdentifier
+            fieldIdentifier:(NSString*)fieldIdentifier
                    formName:(NSString*)formName
                       value:(NSString*)value {
   _autofillController = autofillController;
@@ -82,6 +82,7 @@
 
 - (void)autofillController:(CWVAutofillController*)autofillController
     didInputInFieldWithName:(NSString*)fieldName
+            fieldIdentifier:(NSString*)fieldIdentifier
                    formName:(NSString*)formName
                       value:(NSString*)value {
   // Not implemented.
@@ -89,6 +90,7 @@
 
 - (void)autofillController:(CWVAutofillController*)autofillController
     didBlurOnFieldWithName:(NSString*)fieldName
+           fieldIdentifier:(NSString*)fieldIdentifier
                   formName:(NSString*)formName
                      value:(NSString*)value {
   [_alertController dismissViewControllerAnimated:YES completion:nil];
@@ -96,6 +98,13 @@
   _autofillController = nil;
 }
 
+- (void)autofillController:(CWVAutofillController*)autofillController
+     didSubmitFormWithName:(NSString*)formName
+             userInitiated:(BOOL)userInitiated
+               isMainFrame:(BOOL)isMainFrame {
+  // Not implemented.
+}
+
 #pragma mark - Private Methods
 
 - (UIAlertController*)newAlertController {
diff --git a/ipc/ipc_mojo_bootstrap_unittest.cc b/ipc/ipc_mojo_bootstrap_unittest.cc
index 0912a78..b12b978 100644
--- a/ipc/ipc_mojo_bootstrap_unittest.cc
+++ b/ipc/ipc_mojo_bootstrap_unittest.cc
@@ -4,27 +4,18 @@
 
 #include "ipc/ipc_mojo_bootstrap.h"
 
-#include <stdint.h>
+#include <cstdint>
 #include <memory>
+#include <utility>
 
-#include "base/base_paths.h"
-#include "base/files/file.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
 #include "ipc/ipc.mojom.h"
 #include "ipc/ipc_test_base.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/test/mojo_test_base.h"
 #include "mojo/edk/test/multiprocess_test_helper.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 
-#if defined(OS_POSIX)
-#include "base/file_descriptor_posix.h"
-#endif
-
 namespace {
 
 constexpr int32_t kTestServerPid = 42;
@@ -65,7 +56,10 @@
       MessageExpectation message_expectation = MessageExpectation::kNotExpected)
       : binding_(this, std::move(request)),
         on_peer_pid_set_(on_peer_pid_set),
-        message_expectation_(message_expectation) {}
+        message_expectation_(message_expectation) {
+    binding_.set_connection_error_handler(disconnect_run_loop_.QuitClosure());
+  }
+
   ~PeerPidReceiver() override {
     bool expected_message =
         message_expectation_ != MessageExpectation::kNotExpected;
@@ -97,19 +91,15 @@
 
   int32_t peer_pid() const { return peer_pid_; }
 
-  void RunUntilDisconnect() {
-    base::RunLoop run_loop;
-    binding_.set_connection_error_handler(run_loop.QuitClosure());
-    run_loop.Run();
-  }
+  void RunUntilDisconnect() { disconnect_run_loop_.Run(); }
 
  private:
   mojo::AssociatedBinding<IPC::mojom::Channel> binding_;
   const base::Closure on_peer_pid_set_;
   MessageExpectation message_expectation_;
   int32_t peer_pid_ = -1;
-
   bool received_message_ = false;
+  base::RunLoop disconnect_run_loop_;
 
   DISALLOW_COPY_AND_ASSIGN(PeerPidReceiver);
 };
@@ -165,8 +155,7 @@
   return 0;
 }
 
-// TODO(https://crbug.com/826450): Fix flakiness and re-enable.
-TEST_F(IPCMojoBootstrapTest, DISABLED_ReceiveEmptyMessage) {
+TEST_F(IPCMojoBootstrapTest, ReceiveEmptyMessage) {
   base::MessageLoop message_loop;
   Connection connection(
       IPC::MojoBootstrap::Create(
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h
index a122a426..f0bd390 100644
--- a/media/base/video_frame_metadata.h
+++ b/media/base/video_frame_metadata.h
@@ -34,6 +34,7 @@
 
     // Some VideoFrames have an indication of the color space used.  Use
     // GetInteger()/SetInteger() and ColorSpace enumeration.
+    // Reading this metadata is deprecated, use frame->ColorSpace() instead.
     COLOR_SPACE,
 
     // Indicates that this frame must be copied to a new texture before use,
diff --git a/media/base/video_types.h b/media/base/video_types.h
index 793d9ff6..5bfd8f5 100644
--- a/media/base/video_types.h
+++ b/media/base/video_types.h
@@ -73,6 +73,7 @@
 
 // Color space or color range used for the pixels.
 // Logged to UMA, so never reuse values. Leave gaps if necessary.
+// This enum is deprecated, use VideoColorSpace or gfx::ColorSpace instead.
 enum ColorSpace {
   COLOR_SPACE_UNSPECIFIED = 0,  // In general this is Rec601.
   // The JPEG color space is the combination of Rec.601 and full range colors
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 5ae1817b..7c85f49 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -266,7 +266,10 @@
   void ActivateViewportIntersectionMonitoring(bool activate) override;
   void UpdateRemotePlaybackCompatibility(bool is_compatible) override;
 
-  // Test helper methods for exercising media suspension.
+  // Test helper methods for exercising media suspension. Once called, when
+  // |target_state| is reached or exceeded the stale flag will be set when
+  // computing the play state, which will trigger suspend if the player is
+  // paused; see UpdatePlayState_ComputePlayState() for the exact details.
   void ForceStaleStateForTesting(ReadyState target_state) override;
   bool IsSuspendedForTesting() override;
 
diff --git a/media/filters/aom_video_decoder.cc b/media/filters/aom_video_decoder.cc
index 09486b8..594e562 100644
--- a/media/filters/aom_video_decoder.cc
+++ b/media/filters/aom_video_decoder.cc
@@ -96,13 +96,6 @@
           return PIXEL_FORMAT_UNKNOWN;
       }
 
-    case AOM_IMG_FMT_I440:
-    case AOM_IMG_FMT_I44016:
-      // TODO(dalecurtis): We'll need to add support for these to handle the
-      // full range of expected AOM content.
-      NOTIMPLEMENTED();
-      break;
-
     default:
       break;
   }
diff --git a/media/gpu/h264_decoder.cc b/media/gpu/h264_decoder.cc
index 0983951..ebc7e2b 100644
--- a/media/gpu/h264_decoder.cc
+++ b/media/gpu/h264_decoder.cc
@@ -110,55 +110,11 @@
 }
 
 bool H264Decoder::InitCurrPicture(const H264SliceHeader* slice_hdr) {
-  DCHECK(curr_pic_.get());
-
-  curr_pic_->idr = slice_hdr->idr_pic_flag;
-  if (curr_pic_->idr)
-    curr_pic_->idr_pic_id = slice_hdr->idr_pic_id;
-
-  if (slice_hdr->field_pic_flag) {
-    curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM
-                                                    : H264Picture::FIELD_TOP;
-  } else {
-    curr_pic_->field = H264Picture::FIELD_NONE;
-  }
-
-  if (curr_pic_->field != H264Picture::FIELD_NONE) {
-    DVLOG(1) << "Interlaced video not supported.";
+  if (!FillH264PictureFromSliceHeader(parser_.GetSPS(curr_sps_id_), *slice_hdr,
+                                      curr_pic_.get())) {
     return false;
   }
 
-  curr_pic_->nal_ref_idc = slice_hdr->nal_ref_idc;
-  curr_pic_->ref = slice_hdr->nal_ref_idc != 0;
-  // This assumes non-interlaced stream.
-  curr_pic_->frame_num = curr_pic_->pic_num = slice_hdr->frame_num;
-
-  DCHECK_NE(curr_sps_id_, -1);
-  const H264SPS* sps = parser_.GetSPS(curr_sps_id_);
-  if (!sps)
-    return false;
-
-  curr_pic_->pic_order_cnt_type = sps->pic_order_cnt_type;
-  switch (curr_pic_->pic_order_cnt_type) {
-    case 0:
-      curr_pic_->pic_order_cnt_lsb = slice_hdr->pic_order_cnt_lsb;
-      curr_pic_->delta_pic_order_cnt_bottom =
-          slice_hdr->delta_pic_order_cnt_bottom;
-      break;
-
-    case 1:
-      curr_pic_->delta_pic_order_cnt0 = slice_hdr->delta_pic_order_cnt0;
-      curr_pic_->delta_pic_order_cnt1 = slice_hdr->delta_pic_order_cnt1;
-      break;
-
-    case 2:
-      break;
-
-    default:
-      NOTREACHED();
-      return false;
-  }
-
   if (!CalculatePicOrderCounts(curr_pic_))
     return false;
 
@@ -1200,53 +1156,12 @@
   return true;
 }
 
-bool H264Decoder::IsNewPrimaryCodedPicture(
-    const H264SliceHeader* slice_hdr) const {
-  if (!curr_pic_)
-    return true;
-
-  // 7.4.1.2.4, assumes non-interlaced.
-  if (slice_hdr->frame_num != curr_pic_->frame_num ||
-      slice_hdr->pic_parameter_set_id != curr_pps_id_ ||
-      slice_hdr->nal_ref_idc != curr_pic_->nal_ref_idc ||
-      slice_hdr->idr_pic_flag != curr_pic_->idr ||
-      (slice_hdr->idr_pic_flag &&
-       (slice_hdr->idr_pic_id != curr_pic_->idr_pic_id ||
-        // If we have two consecutive IDR slices, and the second one has
-        // first_mb_in_slice == 0, treat it as a new picture.
-        // Per spec, idr_pic_id should not be equal in this case (and we should
-        // have hit the condition above instead, see spec 7.4.3 on idr_pic_id),
-        // but some encoders neglect changing idr_pic_id for two consecutive
-        // IDRs. Work around this by checking if the next slice contains the
-        // zeroth macroblock, i.e. data that belongs to the next picture.
-        slice_hdr->first_mb_in_slice == 0)))
-    return true;
-
-  const H264SPS* sps = parser_.GetSPS(curr_sps_id_);
-  if (!sps)
-    return false;
-
-  if (sps->pic_order_cnt_type == curr_pic_->pic_order_cnt_type) {
-    if (curr_pic_->pic_order_cnt_type == 0) {
-      if (slice_hdr->pic_order_cnt_lsb != curr_pic_->pic_order_cnt_lsb ||
-          slice_hdr->delta_pic_order_cnt_bottom !=
-              curr_pic_->delta_pic_order_cnt_bottom)
-        return true;
-    } else if (curr_pic_->pic_order_cnt_type == 1) {
-      if (slice_hdr->delta_pic_order_cnt0 != curr_pic_->delta_pic_order_cnt0 ||
-          slice_hdr->delta_pic_order_cnt1 != curr_pic_->delta_pic_order_cnt1)
-        return true;
-    }
-  }
-
-  return false;
-}
-
 bool H264Decoder::PreprocessCurrentSlice() {
   const H264SliceHeader* slice_hdr = curr_slice_hdr_.get();
   DCHECK(slice_hdr);
 
-  if (IsNewPrimaryCodedPicture(slice_hdr)) {
+  if (IsNewPrimaryCodedPicture(curr_pic_.get(), curr_pps_id_,
+                               parser_.GetSPS(curr_sps_id_), *slice_hdr)) {
     // New picture, so first finish the previous one before processing it.
     if (!FinishPrevFrameIfPresent())
       return false;
@@ -1458,4 +1373,101 @@
   return dpb_.max_num_pics() + kPicsInPipeline;
 }
 
+// static
+bool H264Decoder::FillH264PictureFromSliceHeader(
+    const H264SPS* sps,
+    const H264SliceHeader& slice_hdr,
+    H264Picture* pic) {
+  DCHECK(pic);
+
+  pic->idr = slice_hdr.idr_pic_flag;
+  if (pic->idr)
+    pic->idr_pic_id = slice_hdr.idr_pic_id;
+
+  if (slice_hdr.field_pic_flag) {
+    pic->field = slice_hdr.bottom_field_flag ? H264Picture::FIELD_BOTTOM
+                                             : H264Picture::FIELD_TOP;
+  } else {
+    pic->field = H264Picture::FIELD_NONE;
+  }
+
+  if (pic->field != H264Picture::FIELD_NONE) {
+    DVLOG(1) << "Interlaced video not supported.";
+    return false;
+  }
+
+  pic->nal_ref_idc = slice_hdr.nal_ref_idc;
+  pic->ref = slice_hdr.nal_ref_idc != 0;
+  // This assumes non-interlaced stream.
+  pic->frame_num = pic->pic_num = slice_hdr.frame_num;
+
+  if (!sps)
+    return false;
+
+  pic->pic_order_cnt_type = sps->pic_order_cnt_type;
+  switch (pic->pic_order_cnt_type) {
+    case 0:
+      pic->pic_order_cnt_lsb = slice_hdr.pic_order_cnt_lsb;
+      pic->delta_pic_order_cnt_bottom = slice_hdr.delta_pic_order_cnt_bottom;
+      break;
+
+    case 1:
+      pic->delta_pic_order_cnt0 = slice_hdr.delta_pic_order_cnt0;
+      pic->delta_pic_order_cnt1 = slice_hdr.delta_pic_order_cnt1;
+      break;
+
+    case 2:
+      break;
+
+    default:
+      NOTREACHED();
+      return false;
+  }
+  return true;
+}
+
+// static
+bool H264Decoder::IsNewPrimaryCodedPicture(const H264Picture* curr_pic,
+                                           int curr_pps_id,
+                                           const H264SPS* sps,
+                                           const H264SliceHeader& slice_hdr) {
+  if (!curr_pic)
+    return true;
+
+  // 7.4.1.2.4, assumes non-interlaced.
+  if (slice_hdr.frame_num != curr_pic->frame_num ||
+      slice_hdr.pic_parameter_set_id != curr_pps_id ||
+      slice_hdr.nal_ref_idc != curr_pic->nal_ref_idc ||
+      slice_hdr.idr_pic_flag != curr_pic->idr ||
+      (slice_hdr.idr_pic_flag &&
+       (slice_hdr.idr_pic_id != curr_pic->idr_pic_id ||
+        // If we have two consecutive IDR slices, and the second one has
+        // first_mb_in_slice == 0, treat it as a new picture.
+        // Per spec, idr_pic_id should not be equal in this case (and we should
+        // have hit the condition above instead, see spec 7.4.3 on idr_pic_id),
+        // but some encoders neglect changing idr_pic_id for two consecutive
+        // IDRs. Work around this by checking if the next slice contains the
+        // zeroth macroblock, i.e. data that belongs to the next picture.
+        slice_hdr.first_mb_in_slice == 0)))
+    return true;
+
+  if (!sps)
+    return false;
+
+  if (sps->pic_order_cnt_type == curr_pic->pic_order_cnt_type) {
+    if (curr_pic->pic_order_cnt_type == 0) {
+      if (slice_hdr.pic_order_cnt_lsb != curr_pic->pic_order_cnt_lsb ||
+          slice_hdr.delta_pic_order_cnt_bottom !=
+              curr_pic->delta_pic_order_cnt_bottom)
+        return true;
+    } else if (curr_pic->pic_order_cnt_type == 1) {
+      if (slice_hdr.delta_pic_order_cnt0 != curr_pic->delta_pic_order_cnt0 ||
+          slice_hdr.delta_pic_order_cnt1 != curr_pic->delta_pic_order_cnt1)
+        return true;
+    }
+  }
+
+  return false;
+}
+
 }  // namespace media
diff --git a/media/gpu/h264_decoder.h b/media/gpu/h264_decoder.h
index b0c5b46..40d274c 100644
--- a/media/gpu/h264_decoder.h
+++ b/media/gpu/h264_decoder.h
@@ -112,6 +112,18 @@
   gfx::Size GetPicSize() const override;
   size_t GetRequiredNumOfPictures() const override;
 
+  // Return true if we need to start a new picture.
+  static bool IsNewPrimaryCodedPicture(const H264Picture* curr_pic,
+                                       int curr_pps_id,
+                                       const H264SPS* sps,
+                                       const H264SliceHeader& slice_hdr);
+
+  // Fill a H264Picture in |pic| from given |sps| and |slice_hdr|. Return false
+  // when there is an error.
+  static bool FillH264PictureFromSliceHeader(const H264SPS* sps,
+                                             const H264SliceHeader& slice_hdr,
+                                             H264Picture* pic);
+
  private:
   // We need to keep at most kDPBMaxSize pictures in DPB for
   // reference/to display later and an additional one for the one currently
@@ -140,9 +152,6 @@
   // Process current slice as a slice of the current picture.
   bool ProcessCurrentSlice();
 
-  // Return true if we need to start a new picture.
-  bool IsNewPrimaryCodedPicture(const H264SliceHeader* slice_hdr) const;
-
   // Initialize the current picture according to data in |slice_hdr|.
   bool InitCurrPicture(const H264SliceHeader* slice_hdr);
 
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index 24724e217..2cd08a8 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -48,6 +48,8 @@
 #include "media/filters/ivf_parser.h"
 #include "media/gpu/buildflags.h"
 #include "media/gpu/gpu_video_encode_accelerator_factory.h"
+#include "media/gpu/h264_decoder.h"
+#include "media/gpu/h264_dpb.h"
 #include "media/gpu/video_accelerator_unittest_helpers.h"
 #include "media/video/fake_video_encode_accelerator.h"
 #include "media/video/h264_parser.h"
@@ -555,16 +557,24 @@
       : StreamValidator(frame_cb),
         seen_sps_(false),
         seen_pps_(false),
-        seen_idr_(false) {}
+        seen_idr_(false),
+        curr_pic_(new H264Picture) {}
 
   void ProcessStreamBuffer(const uint8_t* stream, size_t size) override;
 
  private:
+  bool IsNewPicture(const H264SliceHeader& slice_hdr);
+  bool UpdateCurrentPicture(const H264SliceHeader& slice_hdr);
+
   // Set to true when encoder provides us with the corresponding NALU type.
   bool seen_sps_;
   bool seen_pps_;
   bool seen_idr_;
 
+  scoped_refptr<H264Picture> curr_pic_;
+  int curr_sps_id_ = -1;
+  int curr_pps_id_ = -1;
+
   H264Parser h264_parser_;
 };
 
@@ -592,9 +602,14 @@
         FALLTHROUGH;
       case H264NALU::kNonIDRSlice: {
         ASSERT_TRUE(seen_idr_);
-        seen_sps_ = seen_pps_ = false;
-        if (!frame_cb_.Run(keyframe))
-          return;
+        H264SliceHeader slice_hdr;
+        ASSERT_EQ(H264Parser::kOk,
+                  h264_parser_.ParseSliceHeader(nalu, &slice_hdr));
+        if (IsNewPicture(slice_hdr)) {
+          if (!frame_cb_.Run(keyframe))
+            return;
+          ASSERT_TRUE(UpdateCurrentPicture(slice_hdr));
+        }
         break;
       }
 
@@ -619,6 +634,37 @@
   }
 }
 
+bool H264Validator::IsNewPicture(const H264SliceHeader& slice_hdr) {
+  if (!curr_pic_)
+    return true;
+  return H264Decoder::IsNewPrimaryCodedPicture(
+      curr_pic_.get(), curr_pps_id_, h264_parser_.GetSPS(curr_sps_id_),
+      slice_hdr);
+}
+
+bool H264Validator::UpdateCurrentPicture(const H264SliceHeader& slice_hdr) {
+  curr_pps_id_ = slice_hdr.pic_parameter_set_id;
+  const H264PPS* pps = h264_parser_.GetPPS(curr_pps_id_);
+  if (!pps) {
+    LOG(ERROR) << "Cannot parse pps.";
+    return false;
+  }
+
+  curr_sps_id_ = pps->seq_parameter_set_id;
+  const H264SPS* sps = h264_parser_.GetSPS(curr_sps_id_);
+  if (!sps) {
+    LOG(ERROR) << "Cannot parse sps.";
+    return false;
+  }
+
+  if (!H264Decoder::FillH264PictureFromSliceHeader(sps, slice_hdr,
+                                                   curr_pic_.get())) {
+    LOG(FATAL) << "Cannot initialize current frame.";
+    return false;
+  }
+  return true;
+}
+
 class VP8Validator : public StreamValidator {
  public:
   explicit VP8Validator(const FrameFoundCallback& frame_cb)
@@ -2575,6 +2621,13 @@
                                                           false,
                                                           false,
                                                           false)));
+
+INSTANTIATE_TEST_CASE_P(
+    VerifyTimestamp,
+    VideoEncodeAcceleratorTest,
+    ::testing::Values(
+        std::make_tuple(1, false, 0, false, false, false, false, false, true)));
+
 #if defined(OS_WIN)
 INSTANTIATE_TEST_CASE_P(
     ForceBitrate,
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
index 3948362..1f7de8a 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -253,13 +253,6 @@
   hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
   RETURN_ON_HR_FAILURE(hr, "Couldn't set ProcessMessage", false);
 
-  // Pin all client callbacks to the main task runner initially. It can be
-  // reassigned by TryToSetupEncodeOnSeparateThread().
-  if (!encode_client_task_runner_) {
-    encode_client_task_runner_ = main_client_task_runner_;
-    encode_client_ = main_client_;
-  }
-
   main_client_task_runner_->PostTask(
       FROM_HERE, base::Bind(&Client::RequireBitstreamBuffers, main_client_,
                             kNumInputBuffers, input_visible_size_,
@@ -271,7 +264,7 @@
     const scoped_refptr<VideoFrame>& frame,
     bool force_keyframe) {
   DVLOG(3) << __func__;
-  DCHECK(encode_client_task_runner_->BelongsToCurrentThread());
+  DCHECK(main_client_task_runner_->BelongsToCurrentThread());
 
   encoder_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&MediaFoundationVideoEncodeAccelerator::EncodeTask,
@@ -282,7 +275,7 @@
 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBuffer(
     const BitstreamBuffer& buffer) {
   DVLOG(3) << __func__ << ": buffer size=" << buffer.size();
-  DCHECK(encode_client_task_runner_->BelongsToCurrentThread());
+  DCHECK(main_client_task_runner_->BelongsToCurrentThread());
 
   if (buffer.size() < bitstream_buffer_size_) {
     DLOG(ERROR) << "Output BitstreamBuffer isn't big enough: " << buffer.size()
@@ -313,7 +306,7 @@
     uint32_t framerate) {
   DVLOG(3) << __func__ << ": bitrate=" << bitrate
            << ": framerate=" << framerate;
-  DCHECK(encode_client_task_runner_->BelongsToCurrentThread());
+  DCHECK(main_client_task_runner_->BelongsToCurrentThread());
 
   encoder_thread_task_runner_->PostTask(
       FROM_HERE,
@@ -340,16 +333,6 @@
   delete this;
 }
 
-bool MediaFoundationVideoEncodeAccelerator::TryToSetupEncodeOnSeparateThread(
-    const base::WeakPtr<Client>& encode_client,
-    const scoped_refptr<base::SingleThreadTaskRunner>& encode_task_runner) {
-  DVLOG(3) << __func__;
-  DCHECK(main_client_task_runner_->BelongsToCurrentThread());
-  encode_client_ = encode_client;
-  encode_client_task_runner_ = encode_task_runner;
-  return true;
-}
-
 // static
 bool MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization() {
   bool result = true;
@@ -553,7 +536,8 @@
 void MediaFoundationVideoEncodeAccelerator::NotifyError(
     VideoEncodeAccelerator::Error error) {
   DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread() ||
-         encode_client_task_runner_->BelongsToCurrentThread());
+         main_client_task_runner_->BelongsToCurrentThread());
+
   main_client_task_runner_->PostTask(
       FROM_HERE, base::Bind(&Client::NotifyError, main_client_, error));
 }
@@ -694,8 +678,8 @@
     memcpy(buffer_ref->shm->memory(), scoped_buffer.get(), size);
   }
 
-  encode_client_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&Client::BitstreamBufferReady, encode_client_,
+  main_client_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&Client::BitstreamBufferReady, main_client_,
                             buffer_ref->id, size, keyframe, timestamp));
 
   // Keep calling ProcessOutput recursively until MF_E_TRANSFORM_NEED_MORE_INPUT
@@ -729,9 +713,9 @@
 
   memcpy(buffer_ref->shm->memory(), encode_output->memory(),
          encode_output->size());
-  encode_client_task_runner_->PostTask(
+  main_client_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&Client::BitstreamBufferReady, encode_client_, buffer_ref->id,
+      base::Bind(&Client::BitstreamBufferReady, main_client_, buffer_ref->id,
                  encode_output->size(), encode_output->keyframe,
                  encode_output->capture_timestamp));
 }
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
index e7abe4c..48b8ff0 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
@@ -26,9 +26,8 @@
 // Media Foundation implementation of the VideoEncodeAccelerator interface for
 // Windows.
 // This class saves the task runner on which it is constructed and runs client
-// callbacks using that same task runner. If TryToSetupEncodeOnSeparateThread()
-// is called, it uses the given |encode_task_runner| instead to return encoded
-// data. This class has DCHECKs to makes sure that methods are called in the
+// callbacks using that same task runner.
+// This class has DCHECKs to makes sure that methods are called in the
 // correct task runners. It starts an internal encoder thread on which
 // VideoEncodeAccelerator implementation tasks are posted.
 class MEDIA_GPU_EXPORT MediaFoundationVideoEncodeAccelerator
@@ -52,10 +51,6 @@
   void RequestEncodingParametersChange(uint32_t bitrate,
                                        uint32_t framerate) override;
   void Destroy() override;
-  bool TryToSetupEncodeOnSeparateThread(
-      const base::WeakPtr<Client>& encode_client,
-      const scoped_refptr<base::SingleThreadTaskRunner>& encode_task_runner)
-      override;
 
   // Preload dlls required for encoding. Returns true if all required dlls are
   // correctly loaded.
@@ -99,7 +94,7 @@
       std::unique_ptr<BitstreamBufferRef> buffer_ref);
 
   // Copies EncodeOutput into a BitstreamBuffer and returns it to the
-  // |encode_client_|.
+  // |main_client_|.
   void ReturnBitstreamBuffer(
       std::unique_ptr<EncodeOutput> encode_output,
       std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef>
@@ -153,12 +148,6 @@
   std::unique_ptr<base::WeakPtrFactory<Client>> main_client_weak_factory_;
   scoped_refptr<base::SingleThreadTaskRunner> main_client_task_runner_;
 
-  // Used to run client callback BitstreamBufferReady() on
-  // |encode_client_task_runner_| if given by
-  // TryToSetupEncodeOnSeparateThread().
-  base::WeakPtr<Client> encode_client_;
-  scoped_refptr<base::SingleThreadTaskRunner> encode_client_task_runner_;
-
   // This thread services tasks posted from the VEA API entry points by the
   // GPU child thread and CompressionCallback() posted from device thread.
   base::Thread encoder_thread_;
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index d360576b..8b06e2a 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -8,6 +8,7 @@
   "//chrome/common/importer/typemaps.gni",
   "//chrome/common/media_router/mojo/typemaps.gni",
   "//chrome/typemaps.gni",
+  "//chromeos/services/device_sync/public/mojom/typemaps.gni",
   "//components/arc/common/typemaps.gni",
   "//components/metrics/public/cpp/typemaps.gni",
   "//components/sync/mojo/typemaps.gni",
diff --git a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
index 65f090a..badaaf5c 100644
--- a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
+++ b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
@@ -213,8 +213,11 @@
     }
 
     /**
-     * Gets the SSID of the currently associated WiFi access point if there is one. Otherwise,
-     * returns empty string.
+     * Gets the SSID of the currently associated WiFi access point if there is one, and it is
+     * available. SSID may not be available if the app does not have permissions to access it. On
+     * Android M+, the app accessing SSID needs to have ACCESS_COARSE_LOCATION or
+     * ACCESS_FINE_LOCATION. If there is no WiFi access point or its SSID is unavailable, an empty
+     * string is returned.
      */
     @CalledByNative
     public static String getWifiSSID() {
@@ -224,7 +227,9 @@
             final WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
             if (wifiInfo != null) {
                 final String ssid = wifiInfo.getSSID();
-                if (ssid != null) {
+                // On Android M+, the platform APIs may return "<unknown ssid>" as the SSID if the
+                // app does not have sufficient permissions. In that case, return an empty string.
+                if (ssid != null && !ssid.equals("<unknown ssid>")) {
                     return ssid;
                 }
             }
diff --git a/net/android/network_library.h b/net/android/network_library.h
index ce5afd16..651600d1 100644
--- a/net/android/network_library.h
+++ b/net/android/network_library.h
@@ -77,8 +77,11 @@
 // Marshmallow and later versions. Returns false on earlier versions.
 NET_EXPORT bool GetIsCaptivePortal();
 
-// Gets the SSID of the currently associated WiFi access point if there is one.
-// Otherwise, returns empty string.
+// Gets the SSID of the currently associated WiFi access point if there is one,
+// and it is available. SSID may not be available if the app does not have
+// permissions to access it. On Android M+, the app accessing SSID needs to have
+// ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION. If there is no WiFi access
+// point or its SSID is unavailable, an empty string is returned.
 NET_EXPORT_PRIVATE std::string GetWifiSSID();
 
 // Gets the DNS servers and puts them in |dns_servers|.
diff --git a/net/base/network_interfaces.h b/net/base/network_interfaces.h
index d3d9f4e..538adb2 100644
--- a/net/base/network_interfaces.h
+++ b/net/base/network_interfaces.h
@@ -86,8 +86,11 @@
 NET_EXPORT bool GetNetworkList(NetworkInterfaceList* networks,
                                int policy);
 
-// Gets the SSID of the currently associated WiFi access point if there is one.
-// Otherwise, returns empty string.
+// Gets the SSID of the currently associated WiFi access point if there is one,
+// and it is available. SSID may not be available if the app does not have
+// permissions to access it. On Android M+, the app accessing SSID needs to have
+// ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION. If there is no WiFi access
+// point or its SSID is unavailable, an empty string is returned.
 // Currently only implemented on Linux, ChromeOS, Android and Windows.
 NET_EXPORT std::string GetWifiSSID();
 
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index cfd6728..87a81db5 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -1057,13 +1057,6 @@
             base::Bind(&NetLogHttpStreamProtoCallback, negotiated_protocol_));
         if (negotiated_protocol_ == kProtoHTTP2) {
           if (is_websocket_) {
-            // If request is WebSocket with no proxy, then HTTP/2 must not have
-            // been advertised in the TLS handshake.  The TLS layer must not
-            // have accepted the server choosing HTTP/2.
-            // TODO(bnc): Change to DCHECK once https://crbug.com/819101 is
-            // fixed.
-            CHECK(!proxy_info_.is_direct());
-
             // WebSocket is not supported over a fresh HTTP/2 connection.
             return ERR_NOT_IMPLEMENTED;
           }
diff --git a/net/spdy/chromium/spdy_network_transaction_unittest.cc b/net/spdy/chromium/spdy_network_transaction_unittest.cc
index 080b765..b427ee87 100644
--- a/net/spdy/chromium/spdy_network_transaction_unittest.cc
+++ b/net/spdy/chromium/spdy_network_transaction_unittest.cc
@@ -7217,6 +7217,47 @@
   helper.VerifyDataConsumed();
 }
 
+TEST_F(SpdyNetworkTransactionTest, WebSocketNegotiatesHttp2) {
+  HttpRequestInfo request;
+  request.method = "GET";
+  request.url = GURL("wss://www.example.org/");
+  request.traffic_annotation =
+      net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+  EXPECT_TRUE(HostPortPair::FromURL(request_.url)
+                  .Equals(HostPortPair::FromURL(request.url)));
+  request.extra_headers.SetHeader("Connection", "Upgrade");
+  request.extra_headers.SetHeader("Upgrade", "websocket");
+  request.extra_headers.SetHeader("Origin", "http://www.example.org");
+  request.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
+
+  NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
+  helper.RunPreTestSetup();
+
+  StaticSocketDataProvider data(nullptr, 0, nullptr, 0);
+
+  auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
+  // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
+  ssl_provider->next_protos_expected_in_ssl_config = NextProtoVector{};
+  // Force socket to use HTTP/1.1, the default protocol without ALPN.
+  ssl_provider->next_proto = kProtoHTTP2;
+  ssl_provider->ssl_info.cert =
+      ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+  helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
+
+  HttpNetworkTransaction* trans = helper.trans();
+  TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
+  trans->SetWebSocketHandshakeStreamCreateHelper(
+      &websocket_stream_create_helper);
+
+  TestCompletionCallback callback;
+  int rv = trans->Start(&request, callback.callback(), log_);
+  ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+  rv = callback.WaitForResult();
+  ASSERT_THAT(rv, IsError(ERR_NOT_IMPLEMENTED));
+
+  helper.VerifyDataConsumed();
+}
+
 // Plaintext WebSocket over HTTP/2 is not implemented, see
 // https://crbug.com/684681.
 TEST_F(SpdyNetworkTransactionTest, PlaintextWebSocketOverHttp2Proxy) {
diff --git a/notification_helper/BUILD.gn b/notification_helper/BUILD.gn
index f74d202..7068bf82 100644
--- a/notification_helper/BUILD.gn
+++ b/notification_helper/BUILD.gn
@@ -72,7 +72,6 @@
     "//base/test:test_support",
     "//chrome/install_static:install_static_util",
     "//chrome/install_static/test:test_support",
-    "//chrome/installer/setup:lib",
     "//chrome/installer/util:with_no_strings",
     "//testing/gtest",
   ]
diff --git a/notification_helper/DEPS b/notification_helper/DEPS
index df7fb84..6769e27a 100644
--- a/notification_helper/DEPS
+++ b/notification_helper/DEPS
@@ -4,7 +4,6 @@
   "+chrome/common/chrome_switches.h",
   "+chrome/common/chrome_version.h",
   "+chrome/install_static",
-  "+chrome/installer/setup",
   "+chrome/installer/util",
   "+components/crash/content/app/crashpad.h",
   "+components/crash/content/app/crash_reporter_client.h",
diff --git a/notification_helper/notification_helper_process_unittest.cc b/notification_helper/notification_helper_process_unittest.cc
index e82c4165..5e31556 100644
--- a/notification_helper/notification_helper_process_unittest.cc
+++ b/notification_helper/notification_helper_process_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/win/scoped_winrt_initializer.h"
 #include "base/win/windows_types.h"
 #include "chrome/install_static/install_util.h"
-#include "chrome/installer/setup/setup_util.h"
 #include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/registry_key_backup.h"
 #include "chrome/installer/util/util_constants.h"
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index be4dcf33..99d88b3e 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -37,6 +37,8 @@
     "group_member.h",
     "in_process_audio_manager_accessor.cc",
     "in_process_audio_manager_accessor.h",
+    "output_controller.cc",
+    "output_controller.h",
     "output_stream.cc",
     "output_stream.h",
     "owning_audio_manager_accessor.cc",
@@ -47,6 +49,8 @@
     "service_factory.h",
     "stream_factory.cc",
     "stream_factory.h",
+    "sync_reader.cc",
+    "sync_reader.h",
     "system_info.cc",
     "system_info.h",
   ]
@@ -65,7 +69,9 @@
   sources = [
     "debug_recording_unittest.cc",
     "group_coordinator_unittest.cc",
+    "output_controller_unittest.cc",
     "output_stream_unittest.cc",
+    "sync_reader_unittest.cc",
     "test/audio_system_to_service_adapter_test.cc",
     "test/debug_recording_session_unittest.cc",
     "test/in_process_service_test.cc",
diff --git a/services/audio/output_controller.cc b/services/audio/output_controller.cc
new file mode 100644
index 0000000..e7a3d7c
--- /dev/null
+++ b/services/audio/output_controller.cc
@@ -0,0 +1,599 @@
+// 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 "services/audio/output_controller.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/task_runner_util.h"
+#include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_event.h"
+#include "media/base/audio_timestamp_helper.h"
+
+using base::TimeDelta;
+
+namespace audio {
+
+namespace {
+
+// Time in seconds between two successive measurements of audio power levels.
+constexpr int kPowerMonitorLogIntervalSeconds = 15;
+
+// Used to log the result of rendering startup.
+// Elements in this enum should not be deleted or rearranged; the only
+// permitted operation is to add new elements before
+// STREAM_CREATION_RESULT_MAX and update STREAM_CREATION_RESULT_MAX.
+enum StreamCreationResult {
+  STREAM_CREATION_OK = 0,
+  STREAM_CREATION_CREATE_FAILED = 1,
+  STREAM_CREATION_OPEN_FAILED = 2,
+  STREAM_CREATION_RESULT_MAX = STREAM_CREATION_OPEN_FAILED,
+};
+
+void LogStreamCreationResult(bool for_device_change,
+                             StreamCreationResult result) {
+  if (for_device_change) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "Media.AudioOutputController.ProxyStreamCreationResultForDeviceChange",
+        result, STREAM_CREATION_RESULT_MAX + 1);
+  } else {
+    UMA_HISTOGRAM_ENUMERATION(
+        "Media.AudioOutputController.ProxyStreamCreationResult", result,
+        STREAM_CREATION_RESULT_MAX + 1);
+  }
+}
+
+}  // namespace
+
+OutputController::ErrorStatisticsTracker::ErrorStatisticsTracker()
+    : start_time_(base::TimeTicks::Now()), on_more_io_data_called_(0) {
+  // WedgeCheck() will look to see if |on_more_io_data_called_| is true after
+  // the timeout expires and log this as a UMA stat. If the stream is
+  // paused/closed before the timer fires, nothing is logged.
+  wedge_timer_.Start(FROM_HERE, TimeDelta::FromSeconds(5), this,
+                     &ErrorStatisticsTracker::WedgeCheck);
+}
+
+OutputController::ErrorStatisticsTracker::~ErrorStatisticsTracker() {
+  UMA_HISTOGRAM_LONG_TIMES("Media.OutputStreamDuration",
+                           base::TimeTicks::Now() - start_time_);
+  UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputController.CallbackError",
+                        error_during_callback_);
+}
+
+void OutputController::ErrorStatisticsTracker::RegisterError() {
+  error_during_callback_ = true;
+}
+
+void OutputController::ErrorStatisticsTracker::OnMoreDataCalled() {
+  // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
+  // may have already fired if OnMoreData() took an abnormal amount of time).
+  // Since this thread is the only writer of |on_more_io_data_called_| once the
+  // thread starts, it's safe to compare and then increment.
+  if (on_more_io_data_called_.IsZero())
+    on_more_io_data_called_.Increment();
+}
+
+void OutputController::ErrorStatisticsTracker::WedgeCheck() {
+  UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess",
+                        on_more_io_data_called_.IsOne());
+}
+
+OutputController::OutputController(media::AudioManager* audio_manager,
+                                   EventHandler* handler,
+                                   const media::AudioParameters& params,
+                                   const std::string& output_device_id,
+                                   const base::UnguessableToken& group_id,
+                                   SyncReader* sync_reader)
+    : audio_manager_(audio_manager),
+      params_(params),
+      handler_(handler),
+      task_runner_(audio_manager->GetTaskRunner()),
+      output_device_id_(output_device_id),
+      group_id_(group_id),
+      stream_(NULL),
+      diverting_to_stream_(NULL),
+      should_duplicate_(0),
+      volume_(1.0),
+      state_(kEmpty),
+      sync_reader_(sync_reader),
+      power_monitor_(
+          params.sample_rate(),
+          TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
+      weak_factory_for_stream_(this) {
+  DCHECK(audio_manager);
+  DCHECK(handler_);
+  DCHECK(sync_reader_);
+  DCHECK(task_runner_.get());
+}
+
+OutputController::~OutputController() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK_EQ(kClosed, state_);
+  DCHECK_EQ(nullptr, stream_);
+  DCHECK(duplication_targets_.empty());
+}
+
+bool OutputController::Create(bool is_for_device_change) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
+  TRACE_EVENT0("audio", "OutputController::Create");
+  handler_->OnLog(is_for_device_change
+                      ? "OutputController::Create (for device change)"
+                      : "OutputController::Create");
+
+  // Close() can be called before Create() is executed.
+  if (state_ == kClosed)
+    return false;
+
+  StopCloseAndClearStream();  // Calls RemoveOutputDeviceChangeListener().
+  DCHECK_EQ(kEmpty, state_);
+
+  stream_ = diverting_to_stream_ ? diverting_to_stream_
+                                 : audio_manager_->MakeAudioOutputStreamProxy(
+                                       params_, output_device_id_);
+  if (!stream_) {
+    state_ = kError;
+    LogStreamCreationResult(is_for_device_change,
+                            STREAM_CREATION_CREATE_FAILED);
+    handler_->OnControllerError();
+    return false;
+  }
+
+  weak_this_for_stream_ = weak_factory_for_stream_.GetWeakPtr();
+  if (!stream_->Open()) {
+    StopCloseAndClearStream();
+    LogStreamCreationResult(is_for_device_change, STREAM_CREATION_OPEN_FAILED);
+    state_ = kError;
+    handler_->OnControllerError();
+    return false;
+  }
+
+  LogStreamCreationResult(is_for_device_change, STREAM_CREATION_OK);
+
+  // Everything started okay, so re-register for state change callbacks if
+  // stream_ was created via AudioManager.
+  if (stream_ != diverting_to_stream_)
+    audio_manager_->AddOutputDeviceChangeListener(this);
+
+  // We have successfully opened the stream. Set the initial volume.
+  stream_->SetVolume(volume_);
+
+  // Finally set the state to kCreated.
+  state_ = kCreated;
+
+  // TODO(crbug/824019): This should be done much earlier. For now, just
+  // preserve the "legacy mirroring" order-of-operations until the new mirroring
+  // impl is in-place.
+  if (!diverter_)
+    diverter_.emplace(this);
+
+  return true;
+}
+
+void OutputController::Play() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
+  TRACE_EVENT0("audio", "OutputController::Play");
+  handler_->OnLog("OutputController::Play");
+
+  // We can start from created or paused state.
+  if (state_ != kCreated && state_ != kPaused)
+    return;
+
+  // Ask for first packet.
+  sync_reader_->RequestMoreData(base::TimeDelta(), base::TimeTicks(), 0);
+
+  state_ = kPlaying;
+
+  if (will_monitor_audio_levels()) {
+    last_audio_level_log_time_ = base::TimeTicks::Now();
+  }
+
+  stats_tracker_.emplace();
+
+  stream_->Start(this);
+
+  handler_->OnControllerPlaying();
+}
+
+void OutputController::StopStream() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  if (state_ == kPlaying) {
+    stream_->Stop();
+    stats_tracker_.reset();
+
+    if (will_monitor_audio_levels()) {
+      LogAudioPowerLevel("StopStream");
+    }
+
+    // A stopped stream is silent, and power_montior_.Scan() is no longer being
+    // called; so we must reset the power monitor.
+    power_monitor_.Reset();
+
+    state_ = kPaused;
+  }
+}
+
+void OutputController::Pause() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
+  TRACE_EVENT0("audio", "OutputController::Pause");
+  handler_->OnLog("OutputController::Pause");
+
+  StopStream();
+
+  if (state_ != kPaused)
+    return;
+
+  // Let the renderer know we've stopped.  Necessary to let PPAPI clients know
+  // audio has been shutdown.  TODO(dalecurtis): This stinks.  PPAPI should have
+  // a better way to know when it should exit PPB_Audio_Shared::Run().
+  sync_reader_->RequestMoreData(base::TimeDelta::Max(), base::TimeTicks(), 0);
+
+  handler_->OnControllerPaused();
+}
+
+void OutputController::Close() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
+  TRACE_EVENT0("audio", "OutputController::Close");
+  handler_->OnLog("OutputController::Close");
+
+  if (state_ != kClosed) {
+    StopCloseAndClearStream();
+    sync_reader_->Close();
+    diverter_ = base::nullopt;
+    for (media::AudioPushSink* sink : duplication_targets_)
+      sink->Close();
+    duplication_targets_.clear();
+    state_ = kClosed;
+  }
+}
+
+void OutputController::SetVolume(double volume) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // Saves the volume to a member first. We may not be able to set the volume
+  // right away but when the stream is created we'll set the volume.
+  volume_ = volume;
+
+  switch (state_) {
+    case kCreated:
+    case kPlaying:
+    case kPaused:
+      stream_->SetVolume(volume_);
+      break;
+    default:
+      return;
+  }
+}
+
+void OutputController::ReportError() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  TRACE_EVENT0("audio", "OutputController::ReportError");
+  DLOG(ERROR) << "OutputController::ReportError";
+  if (state_ != kClosed) {
+    if (stats_tracker_)
+      stats_tracker_->RegisterError();
+    handler_->OnControllerError();
+  }
+}
+
+int OutputController::OnMoreData(base::TimeDelta delay,
+                                 base::TimeTicks delay_timestamp,
+                                 int prior_frames_skipped,
+                                 media::AudioBus* dest) {
+  TRACE_EVENT_BEGIN1("audio", "OutputController::OnMoreData", "frames skipped",
+                     prior_frames_skipped);
+
+  stats_tracker_->OnMoreDataCalled();
+
+  sync_reader_->Read(dest);
+
+  const int frames =
+      dest->is_bitstream_format() ? dest->GetBitstreamFrames() : dest->frames();
+  delay +=
+      media::AudioTimestampHelper::FramesToTime(frames, params_.sample_rate());
+
+  sync_reader_->RequestMoreData(delay, delay_timestamp, prior_frames_skipped);
+
+  if (should_duplicate_.IsOne()) {
+    const base::TimeTicks reference_time = delay_timestamp + delay;
+    std::unique_ptr<media::AudioBus> copy(media::AudioBus::Create(params_));
+    dest->CopyTo(copy.get());
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&OutputController::BroadcastDataToDuplicationTargets,
+                       weak_this_for_stream_, std::move(copy), reference_time));
+  }
+
+  if (will_monitor_audio_levels()) {
+    // Note: this code path should never be hit when using bitstream streams.
+    // Scan doesn't expect compressed audio, so it may go out of bounds trying
+    // to read |frames| frames of PCM data.
+    CHECK(!params_.IsBitstreamFormat());
+    power_monitor_.Scan(*dest, frames);
+
+    const auto now = base::TimeTicks::Now();
+    if ((now - last_audio_level_log_time_).InSeconds() >
+        kPowerMonitorLogIntervalSeconds) {
+      LogAudioPowerLevel("OnMoreData");
+      last_audio_level_log_time_ = now;
+    }
+  }
+
+  TRACE_EVENT_END2("audio", "OutputController::OnMoreData", "timestamp (ms)",
+                   (delay_timestamp - base::TimeTicks()).InMillisecondsF(),
+                   "delay (ms)", delay.InMillisecondsF());
+  return frames;
+}
+
+void OutputController::BroadcastDataToDuplicationTargets(
+    std::unique_ptr<media::AudioBus> audio_bus,
+    base::TimeTicks reference_time) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  TRACE_EVENT1("audio", "OutputController::BroadcastDataToDuplicationTargets",
+               "reference_time (ms)",
+               (reference_time - base::TimeTicks()).InMillisecondsF());
+  if (state_ != kPlaying || duplication_targets_.empty())
+    return;
+
+  // Note: Do not need to acquire lock since this is running on the same thread
+  // as where the set is modified.
+  for (auto target = std::next(duplication_targets_.begin(), 1);
+       target != duplication_targets_.end(); ++target) {
+    std::unique_ptr<media::AudioBus> copy(media::AudioBus::Create(params_));
+    audio_bus->CopyTo(copy.get());
+    (*target)->OnData(std::move(copy), reference_time);
+  }
+
+  (*duplication_targets_.begin())->OnData(std::move(audio_bus), reference_time);
+}
+
+void OutputController::LogAudioPowerLevel(const char* call_name) {
+  std::pair<float, bool> power_and_clip =
+      power_monitor_.ReadCurrentPowerAndClip();
+  handler_->OnLog(
+      base::StringPrintf("OutputController::%s: average audio level=%.2f dBFS",
+                         call_name, power_and_clip.first));
+}
+
+void OutputController::OnError() {
+  // Handle error on the audio controller thread.  We defer errors for one
+  // second in case they are the result of a device change; delay chosen to
+  // exceed duration of device changes which take a few hundred milliseconds.
+  task_runner_->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&OutputController::ReportError, weak_this_for_stream_),
+      base::TimeDelta::FromSeconds(1));
+}
+
+void OutputController::StopCloseAndClearStream() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  // Allow calling unconditionally and bail if we don't have a stream_ to close.
+  if (stream_) {
+    // Ensure any pending tasks, specific to the stream_, are canceled.
+    weak_factory_for_stream_.InvalidateWeakPtrs();
+
+    // De-register from state change callbacks if stream_ was created via
+    // AudioManager.
+    if (stream_ != diverting_to_stream_)
+      audio_manager_->RemoveOutputDeviceChangeListener(this);
+
+    StopStream();
+    stream_->Close();
+    stats_tracker_.reset();
+
+    if (stream_ == diverting_to_stream_)
+      diverting_to_stream_ = NULL;
+    stream_ = NULL;
+  }
+
+  state_ = kEmpty;
+}
+
+void OutputController::OnDeviceChange() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
+  TRACE_EVENT0("audio", "OutputController::OnDeviceChange");
+
+  auto state_to_string = [](State state) {
+    switch (state) {
+      case kEmpty:
+        return "empty";
+      case kCreated:
+        return "created";
+      case kPlaying:
+        return "playing";
+      case kPaused:
+        return "paused";
+      case kClosed:
+        return "closed";
+      case kError:
+        return "error";
+    }
+    return "unknown";
+  };
+
+  handler_->OnLog(
+      base::StringPrintf("OutputController::OnDeviceChange while in state: %s",
+                         state_to_string(state_)));
+
+  // TODO(dalecurtis): Notify the renderer side that a device change has
+  // occurred.  Currently querying the hardware information here will lead to
+  // crashes on OSX.  See http://crbug.com/158170.
+
+  // Recreate the stream (Create() will first shut down an existing stream).
+  // Exit if we ran into an error.
+  const State original_state = state_;
+  Create(true);
+  if (!stream_ || state_ == kError)
+    return;
+
+  // Get us back to the original state or an equivalent state.
+  switch (original_state) {
+    case kPlaying:
+      Play();
+      return;
+    case kCreated:
+    case kPaused:
+      // From the outside these two states are equivalent.
+      return;
+    default:
+      NOTREACHED() << "Invalid original state.";
+  }
+}
+
+OutputController::ThreadHoppingDiverter::ThreadHoppingDiverter(
+    OutputController* controller)
+    : controller_(controller), weak_this_(AsWeakPtr()) {
+  controller_->audio_manager_->AddDiverter(controller_->group_id_, this);
+}
+
+OutputController::ThreadHoppingDiverter::~ThreadHoppingDiverter() {
+  controller_->audio_manager_->RemoveDiverter(this);
+}
+
+const media::AudioParameters&
+OutputController::ThreadHoppingDiverter::GetAudioParameters() {
+  return controller_->params_;
+}
+
+void OutputController::ThreadHoppingDiverter::StartDiverting(
+    media::AudioOutputStream* to_stream) {
+  controller_->task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(
+                     [](base::WeakPtr<ThreadHoppingDiverter> weak_self,
+                        media::AudioOutputStream* to_stream) {
+                       if (auto* self = weak_self.get()) {
+                         self->controller_->DoStartDiverting(to_stream);
+                       } else {
+                         // The OutputController went away. Close the stream
+                         // here to avoid leaks.
+                         to_stream->Close();
+                       }
+                     },
+                     weak_this_, to_stream));
+}
+
+void OutputController::ThreadHoppingDiverter::StopDiverting() {
+  controller_->task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(
+                     [](base::WeakPtr<ThreadHoppingDiverter> weak_self) {
+                       if (auto* self = weak_self.get()) {
+                         self->controller_->DoStopDiverting();
+                       } else {
+                         // The OutputController went away, but it will have
+                         // closed the stream perforce.
+                       }
+                     },
+                     weak_this_));
+}
+
+void OutputController::ThreadHoppingDiverter::StartDuplicating(
+    media::AudioPushSink* sink) {
+  controller_->task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(
+                     [](base::WeakPtr<ThreadHoppingDiverter> weak_self,
+                        media::AudioPushSink* sink) {
+                       if (auto* self = weak_self.get()) {
+                         self->controller_->DoStartDuplicating(sink);
+                       } else {
+                         // The OutputController went away. Close the sink here
+                         // to avoid leaks.
+                         sink->Close();
+                       }
+                     },
+                     weak_this_, sink));
+}
+
+void OutputController::ThreadHoppingDiverter::StopDuplicating(
+    media::AudioPushSink* sink) {
+  controller_->task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(
+                     [](base::WeakPtr<ThreadHoppingDiverter> weak_self,
+                        media::AudioPushSink* sink) {
+                       if (auto* self = weak_self.get()) {
+                         self->controller_->DoStopDuplicating(sink);
+                       } else {
+                         // The OutputController went away, but it will have
+                         // closed the sink perforce.
+                       }
+                     },
+                     weak_this_, sink));
+}
+
+void OutputController::DoStartDiverting(media::AudioOutputStream* to_stream) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  if (state_ == kClosed) {
+    to_stream->Close();
+    return;
+  }
+
+  DCHECK(!diverting_to_stream_);
+  diverting_to_stream_ = to_stream;
+  // Note: OnDeviceChange() will engage the "re-create" process, which will
+  // detect and use the alternate AudioOutputStream rather than create a new one
+  // via AudioManager.
+  OnDeviceChange();
+}
+
+void OutputController::DoStopDiverting() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  if (state_ == kClosed)
+    return;
+
+  // Note: OnDeviceChange() will cause the existing stream (the consumer of the
+  // diverted audio data) to be closed, and diverting_to_stream_ will be set
+  // back to NULL.
+  OnDeviceChange();
+  DCHECK(!diverting_to_stream_);
+}
+
+void OutputController::DoStartDuplicating(media::AudioPushSink* sink) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  if (state_ == kClosed) {
+    sink->Close();
+    return;
+  }
+
+  if (duplication_targets_.empty())
+    should_duplicate_.Increment();
+
+  duplication_targets_.insert(sink);
+}
+
+void OutputController::DoStopDuplicating(media::AudioPushSink* sink) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  if (state_ == kClosed)
+    return;
+
+  sink->Close();
+
+  duplication_targets_.erase(sink);
+  if (duplication_targets_.empty()) {
+    const bool is_nonzero = should_duplicate_.Decrement();
+    DCHECK(!is_nonzero);
+  }
+}
+
+std::pair<float, bool> OutputController::ReadCurrentPowerAndClip() {
+  DCHECK(will_monitor_audio_levels());
+  return power_monitor_.ReadCurrentPowerAndClip();
+}
+
+}  // namespace audio
diff --git a/services/audio/output_controller.h b/services/audio/output_controller.h
new file mode 100644
index 0000000..3ff641c
--- /dev/null
+++ b/services/audio/output_controller.h
@@ -0,0 +1,308 @@
+// 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 SERVICES_AUDIO_OUTPUT_CONTROLLER_H_
+#define SERVICES_AUDIO_OUTPUT_CONTROLLER_H_
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/atomic_ref_count.h"
+#include "base/callback.h"
+#include "base/containers/flat_set.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "base/unguessable_token.h"
+#include "build/build_config.h"
+#include "media/audio/audio_io.h"
+#include "media/audio/audio_manager.h"
+#include "media/audio/audio_power_monitor.h"
+#include "media/audio/audio_source_diverter.h"
+
+// An OutputController controls an AudioOutputStream and provides data to this
+// output stream. It executes audio operations like play, pause, stop, etc. on
+// the audio manager thread, while the audio data flow occurs on the platform's
+// realtime audio thread.
+//
+// Here is a state transition diagram for the OutputController:
+//
+//   *[ Empty ]  -->  [ Created ]  -->  [ Playing ]  -------.
+//        |                |               |    ^           |
+//        |                |               |    |           |
+//        |                |               |    |           v
+//        |                |               |    `-----  [ Paused ]
+//        |                |               |                |
+//        |                v               v                |
+//        `----------->  [      Closed       ]  <-----------'
+//
+// * Initial state
+//
+// At any time after reaching the Created state but before Closed, the
+// OutputController may be notified of a device change via OnDeviceChange().  As
+// the OnDeviceChange() is processed, state transitions will occur, ultimately
+// ending up in an equivalent pre-call state.  E.g., if the state was Paused,
+// the new state will be Created, since these states are all functionally
+// equivalent and require a Play() call to continue to the next state.
+//
+// The AudioOutputStream can request data from the OutputController via the
+// AudioSourceCallback interface. OutputController uses the SyncReader passed to
+// it via construction to synchronously fulfill this read request.
+
+namespace audio {
+
+class OutputController : public media::AudioOutputStream::AudioSourceCallback,
+                         public media::AudioManager::AudioDeviceListener {
+ public:
+  // An event handler that receives events from the OutputController. The
+  // following methods are called on the audio manager thread.
+  class EventHandler {
+   public:
+    virtual void OnControllerPlaying() = 0;
+    virtual void OnControllerPaused() = 0;
+    virtual void OnControllerError() = 0;
+    virtual void OnLog(base::StringPiece message) = 0;
+
+   protected:
+    virtual ~EventHandler() {}
+  };
+
+  // A synchronous reader interface used by OutputController for synchronous
+  // reading.
+  // TODO(crogers): find a better name for this class and the Read() method
+  // now that it can handle synchronized I/O.
+  class SyncReader {
+   public:
+    virtual ~SyncReader() {}
+
+    // This is used by SyncReader to prepare more data and perform
+    // synchronization. Also inform about output delay at a certain moment and
+    // if any frames have been skipped by the renderer (typically the OS). The
+    // renderer source can handle this appropriately depending on the type of
+    // source. An ordinary file playout would ignore this.
+    virtual void RequestMoreData(base::TimeDelta delay,
+                                 base::TimeTicks delay_timestamp,
+                                 int prior_frames_skipped) = 0;
+
+    // Attempts to completely fill |dest|, zeroing |dest| if the request can not
+    // be fulfilled (due to timeout).
+    virtual void Read(media::AudioBus* dest) = 0;
+
+    // Close this synchronous reader.
+    virtual void Close() = 0;
+  };
+
+  // |audio_manager| and |handler| must outlive OutputController.  The
+  // |output_device_id| can be either empty (default device) or specify a
+  // specific hardware device for audio output.
+  OutputController(media::AudioManager* audio_manager,
+                   EventHandler* handler,
+                   const media::AudioParameters& params,
+                   const std::string& output_device_id,
+                   const base::UnguessableToken& group_id,
+                   SyncReader* sync_reader);
+  ~OutputController() override;
+
+  // Indicates whether audio power level analysis will be performed.  If false,
+  // ReadCurrentPowerAndClip() can not be called.
+  static constexpr bool will_monitor_audio_levels() {
+#if defined(OS_ANDROID) || defined(OS_IOS)
+    return false;
+#else
+    return true;
+#endif
+  }
+
+  // Methods to control playback of the stream.
+
+  // Creates the audio output stream. This must be called before Play(). Returns
+  // true if successful, and Play() may commence.
+  bool Create(bool is_for_device_change);
+
+  // Starts the playback of this audio output stream.
+  void Play();
+
+  // Pause this audio output stream.
+  void Pause();
+
+  // Closes the audio output stream synchronously. Stops the stream first, if
+  // necessary. After this method returns, this OutputController can be
+  // destroyed by its owner.
+  void Close();
+
+  // Sets the volume of the audio output stream.
+  void SetVolume(double volume);
+
+  // AudioSourceCallback implementation.
+  int OnMoreData(base::TimeDelta delay,
+                 base::TimeTicks delay_timestamp,
+                 int prior_frames_skipped,
+                 media::AudioBus* dest) override;
+  void OnError() override;
+
+  // AudioDeviceListener implementation.  When called OutputController will
+  // shutdown the existing |stream_|, create a new stream, and then transition
+  // back to an equivalent state prior to being called.
+  void OnDeviceChange() override;
+
+  // Accessor for AudioPowerMonitor::ReadCurrentPowerAndClip().  See comments in
+  // audio_power_monitor.h for usage.  This may be called on any thread.
+  std::pair<float, bool> ReadCurrentPowerAndClip();
+
+ protected:
+  // Internal state of the source.
+  enum State {
+    kEmpty,
+    kCreated,
+    kPlaying,
+    kPaused,
+    kClosed,
+    kError,
+  };
+
+  // Time constant for AudioPowerMonitor.  See AudioPowerMonitor ctor comments
+  // for semantics.  This value was arbitrarily chosen, but seems to work well.
+  enum { kPowerMeasurementTimeConstantMillis = 10 };
+
+ private:
+  // Used to store various stats about a stream. The lifetime of this object is
+  // from play until pause. The underlying physical stream may be changed when
+  // resuming playback, hence separate stats are logged for each play/pause
+  // cycle.
+  class ErrorStatisticsTracker {
+   public:
+    ErrorStatisticsTracker();
+
+    // Note: the destructor takes care of logging all of the stats.
+    ~ErrorStatisticsTracker();
+
+    // Called to indicate an error callback was fired for the stream.
+    void RegisterError();
+
+    // This function should be called from the stream callback thread.
+    void OnMoreDataCalled();
+
+   private:
+    void WedgeCheck();
+
+    const base::TimeTicks start_time_;
+
+    bool error_during_callback_ = false;
+
+    // Flags when we've asked for a stream to start but it never did.
+    base::AtomicRefCount on_more_io_data_called_;
+    base::OneShotTimer wedge_timer_;
+  };
+
+  // Provides a thread-safe AudioSourceDiverter proxy, sitting in front of the
+  // simpler threading model of this OutputController.
+  // TODO(crbug/824019): Remove this legacy functionality.
+  class ThreadHoppingDiverter
+      : public base::SupportsWeakPtr<ThreadHoppingDiverter>,
+        public media::AudioSourceDiverter {
+   public:
+    explicit ThreadHoppingDiverter(OutputController* controller);
+    ~ThreadHoppingDiverter() final;
+
+    // AudioSourceDiverter implementation.
+    const media::AudioParameters& GetAudioParameters() final;
+    void StartDiverting(media::AudioOutputStream* to_stream) final;
+    void StopDiverting() final;
+    void StartDuplicating(media::AudioPushSink* sink) final;
+    void StopDuplicating(media::AudioPushSink* sink) final;
+
+   private:
+    OutputController* const controller_;
+    const base::WeakPtr<ThreadHoppingDiverter> weak_this_;
+  };
+
+  // Start/StopDiverting() and Start/StopDuplicating() trampoline to these
+  // methods through |task_runner_|.
+  // TODO(crbug/824019): Remove this legacy functionality.
+  void DoStartDiverting(media::AudioOutputStream* to_stream);
+  void DoStopDiverting();
+  void DoStartDuplicating(media::AudioPushSink* sink);
+  void DoStopDuplicating(media::AudioPushSink* sink);
+
+  // Notifies the EventHandler that an error has occurred.
+  void ReportError();
+
+  // Helper method that stops the physical stream.
+  void StopStream();
+
+  // Helper method that stops, closes, and NULLs |*stream_|.
+  void StopCloseAndClearStream();
+
+  // Send audio data to each duplication target.
+  void BroadcastDataToDuplicationTargets(
+      std::unique_ptr<media::AudioBus> audio_bus,
+      base::TimeTicks reference_time);
+
+  // Log the current average power level measured by power_monitor_.
+  void LogAudioPowerLevel(const char* call_name);
+
+  media::AudioManager* const audio_manager_;
+  const media::AudioParameters params_;
+  EventHandler* const handler_;
+
+  // The task runner for the audio manager. All control methods should be called
+  // via tasks run by this TaskRunner.
+  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  // Specifies the device id of the output device to open or empty for the
+  // default output device.
+  const std::string output_device_id_;
+
+  // A token indicating membership in a group of output controllers/streams.
+  const base::UnguessableToken group_id_;
+
+  media::AudioOutputStream* stream_;
+
+  // When non-NULL, audio is being diverted to this stream.
+  media::AudioOutputStream* diverting_to_stream_;
+
+  // The targets for audio stream to be copied to. |should_duplicate_| is set to
+  // 1 when the OnMoreData() call should proxy the data to
+  // BroadcastDataToDuplicationTargets().
+  base::flat_set<media::AudioPushSink*> duplication_targets_;
+  base::AtomicRefCount should_duplicate_;
+
+  // The current volume of the audio stream.
+  double volume_;
+
+  State state_;
+
+  // SyncReader is used only in low latency mode for synchronous reading.
+  SyncReader* const sync_reader_;
+
+  // Scans audio samples from OnMoreData() as input to compute power levels.
+  media::AudioPowerMonitor power_monitor_;
+
+  // Updated each time a power measurement is logged.
+  base::TimeTicks last_audio_level_log_time_;
+
+  // Used for keeping track of and logging stats. Created when a stream starts
+  // and destroyed when a stream stops. Also reset every time there is a stream
+  // being created due to device changes.
+  base::Optional<ErrorStatisticsTracker> stats_tracker_;
+
+  // Instantiated in Create(), and destroyed in Close().
+  base::Optional<ThreadHoppingDiverter> diverter_;
+
+  // WeakPtrFactory+WeakPtr that is used to post tasks that are canceled when a
+  // stream is closed.
+  base::WeakPtr<OutputController> weak_this_for_stream_;
+  base::WeakPtrFactory<OutputController> weak_factory_for_stream_;
+
+  DISALLOW_COPY_AND_ASSIGN(OutputController);
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_OUTPUT_CONTROLLER_H_
diff --git a/services/audio/output_controller_unittest.cc b/services/audio/output_controller_unittest.cc
new file mode 100644
index 0000000..0b30ff5
--- /dev/null
+++ b/services/audio/output_controller_unittest.cc
@@ -0,0 +1,637 @@
+// 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 "services/audio/output_controller.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/barrier_closure.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/environment.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_piece.h"
+#include "base/test/test_message_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "media/audio/audio_device_description.h"
+#include "media/audio/audio_source_diverter.h"
+#include "media/audio/test_audio_thread.h"
+#include "media/base/audio_bus.h"
+#include "media/base/audio_parameters.h"
+#include "media/base/gmock_callback_support.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::StrictMock;
+using ::testing::Mock;
+
+using media::AudioBus;
+using media::AudioManager;
+using media::AudioOutputStream;
+using media::AudioParameters;
+using media::AudioPushSink;
+using media::RunClosure;
+using media::RunOnceClosure;
+
+namespace audio {
+
+namespace {
+
+constexpr int kSampleRate = AudioParameters::kAudioCDSampleRate;
+constexpr int kBitsPerSample = 16;
+constexpr media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO;
+constexpr int kSamplesPerPacket = kSampleRate / 1000;
+constexpr double kTestVolume = 0.25;
+constexpr float kBufferNonZeroData = 1.0f;
+
+}  // namespace
+
+AudioParameters GetTestParams() {
+  return AudioParameters(AudioParameters::AUDIO_FAKE, kChannelLayout,
+                         kSampleRate, kBitsPerSample, kSamplesPerPacket);
+}
+
+class MockOutputControllerEventHandler : public OutputController::EventHandler {
+ public:
+  MockOutputControllerEventHandler() = default;
+
+  MOCK_METHOD0(OnControllerPlaying, void());
+  MOCK_METHOD0(OnControllerPaused, void());
+  MOCK_METHOD0(OnControllerError, void());
+  void OnLog(base::StringPiece) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockOutputControllerEventHandler);
+};
+
+class MockOutputControllerSyncReader : public OutputController::SyncReader {
+ public:
+  MockOutputControllerSyncReader() = default;
+
+  MOCK_METHOD3(RequestMoreData,
+               void(base::TimeDelta delay,
+                    base::TimeTicks delay_timestamp,
+                    int prior_frames_skipped));
+  MOCK_METHOD1(Read, void(AudioBus* dest));
+  MOCK_METHOD0(Close, void());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockOutputControllerSyncReader);
+};
+
+class MockAudioOutputStream : public AudioOutputStream,
+                              public AudioOutputStream::AudioSourceCallback {
+ public:
+  explicit MockAudioOutputStream(AudioManager* audio_manager)
+      : audio_manager_(audio_manager) {}
+
+  // We forward to a fake stream to get automatic OnMoreData callbacks,
+  // required by some tests.
+  MOCK_METHOD0(DidOpen, void());
+  MOCK_METHOD0(DidStart, void());
+  MOCK_METHOD0(DidStop, void());
+  MOCK_METHOD0(DidClose, void());
+  MOCK_METHOD1(SetVolume, void(double));
+  MOCK_METHOD1(GetVolume, void(double* volume));
+
+  bool Open() override {
+    EXPECT_EQ(nullptr, impl_);
+    impl_ =
+        audio_manager_->MakeAudioOutputStreamProxy(GetTestParams(), "default");
+    impl_->Open();
+    DidOpen();
+    return true;
+  }
+
+  void Start(AudioOutputStream::AudioSourceCallback* cb) override {
+    EXPECT_EQ(nullptr, callback_);
+    callback_ = cb;
+    impl_->Start(this);
+    DidStart();
+  }
+
+  void Stop() override {
+    impl_->Stop();
+    callback_ = nullptr;
+    DidStop();
+  }
+
+  void Close() override {
+    if (impl_) {
+      impl_->Close();
+      impl_ = nullptr;
+    }
+    DidClose();
+  }
+
+ private:
+  int OnMoreData(base::TimeDelta delay,
+                 base::TimeTicks delay_timestamp,
+                 int prior_frames_skipped,
+                 AudioBus* dest) override {
+    int res = callback_->OnMoreData(delay, delay_timestamp,
+                                    prior_frames_skipped, dest);
+    EXPECT_EQ(dest->channel(0)[0], kBufferNonZeroData);
+    return res;
+  }
+
+  void OnError() override {
+    // Fake stream doesn't send errors.
+    NOTREACHED();
+  }
+
+  AudioManager* audio_manager_;
+  AudioOutputStream* impl_ = nullptr;
+  AudioOutputStream::AudioSourceCallback* callback_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(MockAudioOutputStream);
+};
+
+class MockAudioPushSink : public AudioPushSink {
+ public:
+  MockAudioPushSink() = default;
+
+  MOCK_METHOD0(Close, void());
+  MOCK_METHOD1(OnDataCheck, void(float));
+
+  void OnData(std::unique_ptr<AudioBus> source,
+              base::TimeTicks reference_time) override {
+    OnDataCheck(source->channel(0)[0]);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockAudioPushSink);
+};
+
+ACTION(PopulateBuffer) {
+  arg0->Zero();
+  // Note: To confirm the buffer will be populated in these tests, it's
+  // sufficient that only the first float in channel 0 is set to the value.
+  arg0->channel(0)[0] = kBufferNonZeroData;
+}
+
+class OutputControllerTest : public ::testing::Test {
+ public:
+  OutputControllerTest()
+      : audio_manager_(AudioManager::CreateForTesting(
+            std::make_unique<media::TestAudioThread>(false))),
+        group_id_(base::UnguessableToken::Create()),
+        mock_stream_(audio_manager_.get()) {
+    audio_manager_->SetDiverterCallbacks(
+        base::BindRepeating(&OutputControllerTest::AddDiverter,
+                            base::Unretained(this)),
+        base::BindRepeating(&OutputControllerTest::RemoveDiverter,
+                            base::Unretained(this)));
+  }
+
+  ~OutputControllerTest() override { audio_manager_->Shutdown(); }
+
+ protected:
+  void Create() {
+    controller_.emplace(audio_manager_.get(), &mock_event_handler_,
+                        GetTestParams(), std::string(), group_id_,
+                        &mock_sync_reader_);
+    controller_->Create(false);
+    ASSERT_TRUE(diverter_);
+    controller_->SetVolume(kTestVolume);
+  }
+
+  void Play() {
+    base::RunLoop loop;
+    // The barrier is used to wait for all of the expectations to be fulfilled.
+    base::RepeatingClosure barrier =
+        base::BarrierClosure(3, loop.QuitClosure());
+    EXPECT_CALL(mock_event_handler_, OnControllerPlaying())
+        .WillOnce(RunClosure(barrier));
+    EXPECT_CALL(mock_sync_reader_, RequestMoreData(_, _, _))
+        .WillOnce(RunClosure(barrier))
+        .WillRepeatedly(Return());
+    EXPECT_CALL(mock_sync_reader_, Read(_))
+        .WillOnce(Invoke([barrier](AudioBus* data) {
+          data->channel(0)[0] = kBufferNonZeroData;
+          barrier.Run();
+        }))
+        .WillRepeatedly(PopulateBuffer());
+    controller_->Play();
+
+    // Waits for all gmock expectations to be satisfied.
+    loop.Run();
+  }
+
+  void PlayWhileDiverting() {
+    base::RunLoop loop;
+    // The barrier is used to wait for all of the expectations to be fulfilled.
+    base::RepeatingClosure barrier =
+        base::BarrierClosure(4, loop.QuitClosure());
+    EXPECT_CALL(mock_stream_, DidStart()).WillOnce(RunClosure(barrier));
+    EXPECT_CALL(mock_event_handler_, OnControllerPlaying())
+        .WillOnce(RunClosure(barrier));
+    // The mock stream will start pulling data. We verify that the calls are
+    // forwarded to SyncReader, and write some data to the buffer that we can
+    // verify later.
+    EXPECT_CALL(mock_sync_reader_, RequestMoreData(_, _, _))
+        .WillOnce(RunClosure(barrier))
+        .WillRepeatedly(Return());
+    EXPECT_CALL(mock_sync_reader_, Read(_))
+        .WillOnce(Invoke([barrier](AudioBus* data) {
+          data->channel(0)[0] = kBufferNonZeroData;
+          barrier.Run();
+        }))
+        .WillRepeatedly(PopulateBuffer());
+    controller_->Play();
+
+    // Waits for all gmock expectations to be satisfied.
+    loop.Run();
+    // At some point in the future, the stream must be stopped.
+    EXPECT_CALL(mock_stream_, DidStop());
+  }
+
+  void Pause() {
+    base::RunLoop loop;
+    EXPECT_CALL(mock_event_handler_, OnControllerPaused())
+        .WillOnce(RunOnceClosure(loop.QuitClosure()));
+    controller_->Pause();
+    loop.Run();
+    Mock::VerifyAndClearExpectations(&mock_event_handler_);
+  }
+
+  void ChangeDevice() {
+    // Expect the event handler to receive one OnControllerPaying() call and no
+    // OnControllerPaused() call.
+    EXPECT_CALL(mock_event_handler_, OnControllerPlaying());
+    EXPECT_CALL(mock_event_handler_, OnControllerPaused()).Times(0);
+
+    // Simulate a device change event to OutputController from the AudioManager.
+    audio_manager_->GetTaskRunner()->PostTask(
+        FROM_HERE, base::BindOnce(&OutputController::OnDeviceChange,
+                                  base::Unretained(&(*controller_))));
+
+    // Wait for device change to take effect.
+    base::RunLoop loop;
+    audio_manager_->GetTaskRunner()->PostTask(FROM_HERE, loop.QuitClosure());
+    loop.Run();
+  }
+
+  void DivertBeforePlaying() {
+    EXPECT_CALL(mock_stream_, DidOpen());
+    EXPECT_CALL(mock_stream_, SetVolume(kTestVolume));
+
+    ASSERT_TRUE(diverter_);
+    diverter_->StartDiverting(&mock_stream_);
+
+    base::RunLoop loop;
+    // Wait for controller to start diverting.
+    audio_manager_->GetTaskRunner()->PostTask(FROM_HERE, loop.QuitClosure());
+    loop.Run();
+  }
+
+  void DivertAfterClose() {
+    EXPECT_CALL(mock_stream_, DidClose());
+
+    ASSERT_TRUE(diverter_);
+    diverter_->StartDiverting(&mock_stream_);
+
+    // Note: Not running the TaskRunner yet. Close() will do that later.
+  }
+
+  void DivertWhilePlaying() {
+    base::RunLoop loop;
+    // The barrier is used to wait for all of the expectations to be fulfilled.
+    base::RepeatingClosure barrier =
+        base::BarrierClosure(4, loop.QuitClosure());
+    // Expect mock streams to be initialized and started.
+    EXPECT_CALL(mock_stream_, DidOpen()).WillOnce(RunClosure(barrier));
+    EXPECT_CALL(mock_stream_, SetVolume(kTestVolume))
+        .WillOnce(RunClosure(barrier));
+    EXPECT_CALL(mock_stream_, DidStart()).WillOnce(RunClosure(barrier));
+    // Expect event handler to be informed.
+    EXPECT_CALL(mock_event_handler_, OnControllerPlaying())
+        .WillOnce(RunClosure(barrier));
+
+    ASSERT_TRUE(diverter_);
+    diverter_->StartDiverting(&mock_stream_);
+    // Wait until callbacks has started.
+    loop.Run();
+
+    // At some point in the future, the stream must be stopped.
+    EXPECT_CALL(mock_stream_, DidStop());
+  }
+
+  void StartDuplicating(MockAudioPushSink* sink) {
+    base::RunLoop loop;
+    EXPECT_CALL(*sink, OnDataCheck(kBufferNonZeroData))
+        .WillOnce(RunOnceClosure(loop.QuitClosure()))
+        .WillRepeatedly(Return());
+    ASSERT_TRUE(diverter_);
+    diverter_->StartDuplicating(sink);
+    loop.Run();
+  }
+
+  void StartDuplicatingAfterClose(MockAudioPushSink* sink) {
+    EXPECT_CALL(*sink, Close());
+
+    ASSERT_TRUE(diverter_);
+    diverter_->StartDuplicating(sink);
+
+    // Note: Not running the TaskRunner yet. Close() will do that later.
+  }
+
+  void Revert(bool was_playing) {
+    if (was_playing) {
+      // Expect the handler to receive one OnControllerPlaying() call as a
+      // result of the stream switching back.
+      EXPECT_CALL(mock_event_handler_, OnControllerPlaying());
+    }
+
+    EXPECT_CALL(mock_stream_, DidClose());
+
+    ASSERT_TRUE(diverter_);
+    diverter_->StopDiverting();
+    base::RunLoop loop;
+    audio_manager_->GetTaskRunner()->PostTask(FROM_HERE, loop.QuitClosure());
+    loop.Run();
+  }
+
+  void RevertAfterClose(bool already_expecting_close_call) {
+    if (!already_expecting_close_call)
+      EXPECT_CALL(mock_stream_, DidClose());
+
+    ASSERT_TRUE(diverter_);
+    diverter_->StopDiverting();
+
+    // Note: Not running the TaskRunner yet. Close() will do that later.
+  }
+
+  void StopDuplicating(MockAudioPushSink* sink) {
+    {
+      // First, verify we're still getting callbacks. Must be done on the AM
+      // task runner, since it may be a separate thread, and EXPECTing from the
+      // main thread would be racy.
+      base::RunLoop loop;
+      audio_manager_->GetTaskRunner()->PostTask(
+          FROM_HERE,
+          base::BindOnce(
+              [](MockAudioPushSink* sink, base::RepeatingClosure done_closure) {
+                Mock::VerifyAndClear(sink);
+                EXPECT_CALL(*sink, OnDataCheck(kBufferNonZeroData))
+                    .WillOnce(RunClosure(done_closure))
+                    .WillRepeatedly(Return());
+              },
+              sink, loop.QuitClosure()));
+      loop.Run();
+    }
+
+    {
+      EXPECT_CALL(*sink, Close());
+      ASSERT_TRUE(diverter_);
+      diverter_->StopDuplicating(sink);
+      base::RunLoop loop;
+      audio_manager_->GetTaskRunner()->PostTask(FROM_HERE, loop.QuitClosure());
+      loop.Run();
+    }
+  }
+
+  void StopDuplicatingAfterClose(MockAudioPushSink* sink,
+                                 bool already_expecting_close_call) {
+    if (!already_expecting_close_call)
+      EXPECT_CALL(*sink, Close());
+
+    ASSERT_TRUE(diverter_);
+    diverter_->StopDuplicating(sink);
+
+    // Note: Not running the TaskRunner yet. Close() will do that later.
+  }
+
+  void Close() {
+    EXPECT_CALL(mock_sync_reader_, Close());
+    controller_->Close();
+
+    // Flush any pending tasks (that should have been canceled!).
+    base::RunLoop loop;
+    audio_manager_->GetTaskRunner()->PostTask(FROM_HERE, loop.QuitClosure());
+    loop.Run();
+  }
+
+  void CloseWithAutoRevert() {
+    EXPECT_CALL(mock_stream_, DidClose());
+    Close();
+  }
+
+  void SimulateErrorThenDeviceChange() {
+    audio_manager_->GetTaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&OutputControllerTest::TriggerErrorThenDeviceChange,
+                       base::Unretained(this)));
+
+    base::RunLoop loop;
+    audio_manager_->GetTaskRunner()->PostTask(FROM_HERE, loop.QuitClosure());
+    loop.Run();
+  }
+
+  // These help make test sequences more readable.
+  void RevertWasNotPlaying() { Revert(false); }
+  void RevertWhilePlaying() { Revert(true); }
+
+  void TriggerErrorThenDeviceChange() {
+    DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+
+    // Errors should be deferred; the device change should ensure it's dropped.
+    EXPECT_CALL(mock_event_handler_, OnControllerError()).Times(0);
+    controller_->OnError();
+
+    EXPECT_CALL(mock_event_handler_, OnControllerPlaying());
+    EXPECT_CALL(mock_event_handler_, OnControllerPaused()).Times(0);
+    controller_->OnDeviceChange();
+  }
+
+ private:
+  void AddDiverter(const base::UnguessableToken& group_id,
+                   media::AudioSourceDiverter* diverter) {
+    EXPECT_EQ(group_id_, group_id);
+    ASSERT_FALSE(diverter_);
+    diverter_ = diverter;
+    ASSERT_TRUE(diverter_);
+  }
+
+  void RemoveDiverter(media::AudioSourceDiverter* diverter) {
+    ASSERT_EQ(diverter_, diverter);
+    diverter_ = nullptr;
+  }
+
+  base::TestMessageLoop message_loop_;
+  std::unique_ptr<AudioManager> audio_manager_;
+  base::UnguessableToken group_id_;
+  StrictMock<MockOutputControllerEventHandler> mock_event_handler_;
+  StrictMock<MockOutputControllerSyncReader> mock_sync_reader_;
+  StrictMock<MockAudioOutputStream> mock_stream_;
+  base::Optional<OutputController> controller_;
+
+  media::AudioSourceDiverter* diverter_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(OutputControllerTest);
+};
+
+TEST_F(OutputControllerTest, CreateAndClose) {
+  Create();
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayAndClose) {
+  Create();
+  Play();
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayPauseClose) {
+  Create();
+  Play();
+  Pause();
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayPausePlayClose) {
+  Create();
+  Play();
+  Pause();
+  Play();
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayDeviceChangeClose) {
+  Create();
+  Play();
+  ChangeDevice();
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayDeviceChangeError) {
+  Create();
+  Play();
+  SimulateErrorThenDeviceChange();
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayDivertRevertClose) {
+  Create();
+  Play();
+  DivertWhilePlaying();
+  RevertWhilePlaying();
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayDivertRevertDivertRevertClose) {
+  Create();
+  Play();
+  DivertWhilePlaying();
+  RevertWhilePlaying();
+  DivertWhilePlaying();
+  RevertWhilePlaying();
+  Close();
+}
+
+TEST_F(OutputControllerTest, DivertPlayPausePlayRevertClose) {
+  Create();
+  DivertBeforePlaying();
+  PlayWhileDiverting();
+  Pause();
+  PlayWhileDiverting();
+  RevertWhilePlaying();
+  Close();
+}
+
+TEST_F(OutputControllerTest, DivertRevertClose) {
+  Create();
+  DivertBeforePlaying();
+  RevertWasNotPlaying();
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayDivertCloseRevert) {
+  Create();
+  Play();
+  DivertWhilePlaying();
+  RevertAfterClose(false);
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayDivertClose) {
+  Create();
+  Play();
+  DivertWhilePlaying();
+  CloseWithAutoRevert();
+}
+
+TEST_F(OutputControllerTest, PlayCloseDivertRevert) {
+  Create();
+  Play();
+  DivertAfterClose();
+  RevertAfterClose(true);
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayDuplicateStopClose) {
+  Create();
+  MockAudioPushSink mock_sink;
+  Play();
+  StartDuplicating(&mock_sink);
+  StopDuplicating(&mock_sink);
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayDuplicateCloseStop) {
+  Create();
+  MockAudioPushSink mock_sink;
+  Play();
+  StartDuplicating(&mock_sink);
+  StopDuplicatingAfterClose(&mock_sink, false);
+  Close();
+}
+
+TEST_F(OutputControllerTest, PlayCloseDuplicateStop) {
+  Create();
+  MockAudioPushSink mock_sink;
+  Play();
+  StartDuplicatingAfterClose(&mock_sink);
+  StopDuplicatingAfterClose(&mock_sink, true);
+  Close();
+}
+
+TEST_F(OutputControllerTest, TwoDuplicates) {
+  Create();
+  MockAudioPushSink mock_sink_1;
+  MockAudioPushSink mock_sink_2;
+  Play();
+  StartDuplicating(&mock_sink_1);
+  StartDuplicating(&mock_sink_2);
+  StopDuplicating(&mock_sink_1);
+  StopDuplicating(&mock_sink_2);
+  Close();
+}
+
+TEST_F(OutputControllerTest, DuplicateDivertInteract) {
+  Create();
+  MockAudioPushSink mock_sink;
+  Play();
+  StartDuplicating(&mock_sink);
+  DivertWhilePlaying();
+  StopDuplicating(&mock_sink);
+  RevertWhilePlaying();
+  Close();
+}
+
+}  // namespace audio
diff --git a/services/audio/output_stream.cc b/services/audio/output_stream.cc
index 8f54ff6a..20a338d 100644
--- a/services/audio/output_stream.cc
+++ b/services/audio/output_stream.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "media/audio/audio_sync_reader.h"
 
 namespace audio {
 
@@ -30,24 +29,27 @@
     const media::AudioParameters& params,
     const base::UnguessableToken& group_id)
     : foreign_socket_(),
-      created_callback_(std::move(created_callback)),
       delete_callback_(std::move(delete_callback)),
       binding_(this, std::move(stream_request)),
       client_(std::move(client)),
       observer_(std::move(observer)),
       log_(media::mojom::ThreadSafeAudioLogPtr::Create(std::move(log))),
       // Unretained is safe since we own |reader_|
-      reader_(media::AudioSyncReader::Create(
-          base::BindRepeating(&media::mojom::AudioLog::OnLogMessage,
-                              base::Unretained(log_->get())),
-          params,
-          &foreign_socket_)),
+      reader_(base::BindRepeating(&media::mojom::AudioLog::OnLogMessage,
+                                  base::Unretained(log_->get())),
+              params,
+              &foreign_socket_),
+      controller_(audio_manager,
+                  this,
+                  params,
+                  output_device_id,
+                  group_id,
+                  &reader_),
       weak_factory_(this) {
-  DCHECK(audio_manager);
   DCHECK(binding_.is_bound());
   DCHECK(client_.is_bound());
   DCHECK(observer_.is_bound());
-  DCHECK(created_callback_);
+  DCHECK(created_callback);
   DCHECK(delete_callback_);
 
   // |this| owns these objects, so unretained is safe.
@@ -61,15 +63,15 @@
 
   log_->get()->OnCreated(params, output_device_id);
 
-  if (!reader_) {
-    // Failed to create reader. Since we failed to initialize, don't bind the
-    // request.
-    OnError();
+  if (!reader_.IsValid() || !controller_.Create(false)) {
+    // Either SyncReader initialization failed or the controller failed to
+    // create the stream. In the latter case, the controller will have called
+    // OnControllerError().
+    std::move(created_callback).Run(nullptr);
     return;
   }
 
-  controller_ = media::AudioOutputController::Create(
-      audio_manager, this, params, output_device_id, group_id, reader_.get());
+  CreateAudioPipe(std::move(created_callback));
 }
 
 OutputStream::~OutputStream() {
@@ -77,33 +79,20 @@
 
   log_->get()->OnClosed();
 
-  if (created_callback_) {
-    // Didn't manage to create the stream. Call the callback anyways as mandated
-    // by mojo.
-    std::move(created_callback_).Run(nullptr);
-  }
-
-  if (!controller_) {
-    // Didn't initialize properly, nothing to clean up.
-    return;
-  }
-
-  // TODO(803102): remove AudioOutputController::Close() after content/ streams
-  // are removed, destructor should suffice.
-  controller_->Close(base::OnceClosure());
+  controller_.Close();
 }
 
 void OutputStream::Play() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
 
-  controller_->Play();
+  controller_.Play();
   log_->get()->OnStarted();
 }
 
 void OutputStream::Pause() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
 
-  controller_->Pause();
+  controller_.Pause();
   log_->get()->OnStopped();
 }
 
@@ -116,35 +105,32 @@
     return;
   }
 
-  controller_->SetVolume(volume);
+  controller_.SetVolume(volume);
   log_->get()->OnSetVolume(volume);
 }
 
-void OutputStream::OnControllerCreated() {
+void OutputStream::CreateAudioPipe(CreatedCallback created_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+  DCHECK(reader_.IsValid());
 
-  // TODO(803102): Get rid of the OnControllerCreated event after removing
-  // content/ streams.
-  const base::SharedMemory* memory = reader_->shared_memory();
-
+  const base::SharedMemory* memory = reader_.shared_memory();
   base::SharedMemoryHandle foreign_memory_handle =
       base::SharedMemory::DuplicateHandle(memory->handle());
-  if (!base::SharedMemory::IsHandleValid(foreign_memory_handle)) {
+  mojo::ScopedSharedBufferHandle buffer_handle;
+  mojo::ScopedHandle socket_handle;
+  if (base::SharedMemory::IsHandleValid(foreign_memory_handle)) {
+    buffer_handle = mojo::WrapSharedMemoryHandle(
+        foreign_memory_handle, memory->requested_size(),
+        mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
+    socket_handle = mojo::WrapPlatformFile(foreign_socket_.Release());
+  }
+  if (!buffer_handle.is_valid() || !socket_handle.is_valid()) {
+    std::move(created_callback).Run(nullptr);
     OnError();
     return;
   }
 
-  mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
-      foreign_memory_handle, memory->requested_size(),
-      mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
-
-  mojo::ScopedHandle socket_handle =
-      mojo::WrapPlatformFile(foreign_socket_.Release());
-
-  DCHECK(buffer_handle.is_valid());
-  DCHECK(socket_handle.is_valid());
-
-  std::move(created_callback_)
+  std::move(created_callback)
       .Run(
           {base::in_place, std::move(buffer_handle), std::move(socket_handle)});
 }
@@ -157,7 +143,7 @@
 
   playing_ = true;
   observer_->DidStartPlaying();
-  if (media::AudioOutputController::will_monitor_audio_levels()) {
+  if (OutputController::will_monitor_audio_levels()) {
     DCHECK(!poll_timer_.IsRunning());
     // base::Unretained is safe because |this| owns |poll_timer_|.
     poll_timer_.Start(
@@ -180,7 +166,7 @@
     return;
 
   playing_ = false;
-  if (media::AudioOutputController::will_monitor_audio_levels()) {
+  if (OutputController::will_monitor_audio_levels()) {
     DCHECK(poll_timer_.IsRunning());
     poll_timer_.Stop();
   }
@@ -229,10 +215,10 @@
     observer_->DidChangeAudibleState(is_audible_);
 }
 
-bool OutputStream::IsAudible() const {
+bool OutputStream::IsAudible() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
 
-  float power_dbfs = controller_->ReadCurrentPowerAndClip().first;
+  float power_dbfs = controller_.ReadCurrentPowerAndClip().first;
   return power_dbfs >= kSilenceThresholdDBFS;
 }
 
diff --git a/services/audio/output_stream.h b/services/audio/output_stream.h
index 4068786..a61ddc7 100644
--- a/services/audio/output_stream.h
+++ b/services/audio/output_stream.h
@@ -15,7 +15,6 @@
 #include "base/strings/string_piece.h"
 #include "base/sync_socket.h"
 #include "base/timer/timer.h"
-#include "media/audio/audio_output_controller.h"
 #include "media/mojo/interfaces/audio_data_pipe.mojom.h"
 #include "media/mojo/interfaces/audio_logging.mojom.h"
 #include "media/mojo/interfaces/audio_output_stream.mojom.h"
@@ -23,6 +22,8 @@
 #include "mojo/public/cpp/system/buffer.h"
 #include "mojo/public/cpp/system/handle.h"
 #include "mojo/public/cpp/system/platform_handle.h"
+#include "services/audio/output_controller.h"
+#include "services/audio/sync_reader.h"
 
 namespace base {
 class UnguessableToken;
@@ -31,13 +32,12 @@
 namespace media {
 class AudioManager;
 class AudioParameters;
-class AudioSyncReader;
 }  // namespace media
 
 namespace audio {
 
 class OutputStream final : public media::mojom::AudioOutputStream,
-                           public media::AudioOutputController::EventHandler {
+                           public OutputController::EventHandler {
  public:
   using DeleteCallback = base::OnceCallback<void(OutputStream*)>;
   using CreatedCallback =
@@ -61,31 +61,30 @@
   void Pause() final;
   void SetVolume(double volume) final;
 
-  // AudioOutputController::EventHandler implementation.
-  void OnControllerCreated() final;
+  // OutputController::EventHandler implementation.
   void OnControllerPlaying() final;
   void OnControllerPaused() final;
   void OnControllerError() final;
   void OnLog(base::StringPiece message) final;
 
  private:
+  void CreateAudioPipe(CreatedCallback created_callback);
   void OnError();
   void CallDeleter();
   void PollAudioLevel();
-  bool IsAudible() const;
+  bool IsAudible();
 
   SEQUENCE_CHECKER(owning_sequence_);
 
   base::CancelableSyncSocket foreign_socket_;
-  CreatedCallback created_callback_;
   DeleteCallback delete_callback_;
   mojo::Binding<AudioOutputStream> binding_;
   media::mojom::AudioOutputStreamClientPtr client_;
   media::mojom::AudioOutputStreamObserverAssociatedPtr observer_;
   scoped_refptr<media::mojom::ThreadSafeAudioLogPtr> log_;
 
-  const std::unique_ptr<media::AudioSyncReader> reader_;
-  scoped_refptr<media::AudioOutputController> controller_;
+  SyncReader reader_;
+  OutputController controller_;
 
   // This flag ensures that we only send OnStreamStateChanged notifications
   // and (de)register with the stream monitor when the state actually changes.
diff --git a/services/audio/sync_reader.cc b/services/audio/sync_reader.cc
new file mode 100644
index 0000000..fa1ef2a
--- /dev/null
+++ b/services/audio/sync_reader.cc
@@ -0,0 +1,274 @@
+// 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 "services/audio/sync_reader.h"
+
+#include <algorithm>
+#include <limits>
+#include <string>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/format_macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
+#include "media/audio/audio_device_thread.h"
+#include "media/base/audio_parameters.h"
+#include "media/base/media_switches.h"
+
+namespace {
+
+// Used to log if any audio glitches have been detected during an audio session.
+// Elements in this enum should not be added, deleted or rearranged.
+enum AudioGlitchResult {
+  AUDIO_RENDERER_NO_AUDIO_GLITCHES = 0,
+  AUDIO_RENDERER_AUDIO_GLITCHES = 1,
+  AUDIO_RENDERER_AUDIO_GLITCHES_MAX = AUDIO_RENDERER_AUDIO_GLITCHES
+};
+
+void LogAudioGlitchResult(AudioGlitchResult result) {
+  UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererAudioGlitches", result,
+                            AUDIO_RENDERER_AUDIO_GLITCHES_MAX + 1);
+}
+
+}  // namespace
+
+namespace audio {
+
+SyncReader::SyncReader(
+    base::RepeatingCallback<void(const std::string&)> log_callback,
+    const media::AudioParameters& params,
+    base::CancelableSyncSocket* foreign_socket)
+    : log_callback_(std::move(log_callback)),
+      mute_audio_for_testing_(base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kMuteAudio)),
+      had_socket_error_(false),
+      output_bus_buffer_size_(
+          media::AudioBus::CalculateMemorySize(params.channels(),
+                                               params.frames_per_buffer())),
+      renderer_callback_count_(0),
+      renderer_missed_callback_count_(0),
+      trailing_renderer_missed_callback_count_(0),
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+      maximum_wait_time_(params.GetBufferDuration() / 2),
+#else
+      // TODO(dalecurtis): Investigate if we can reduce this on all platforms.
+      maximum_wait_time_(base::TimeDelta::FromMilliseconds(20)),
+#endif
+      buffer_index_(0) {
+  base::CheckedNumeric<size_t> memory_size =
+      media::ComputeAudioOutputBufferSizeChecked(params);
+  if (memory_size.IsValid() &&
+      shared_memory_.CreateAndMapAnonymous(memory_size.ValueOrDie()) &&
+      base::CancelableSyncSocket::CreatePair(&socket_, foreign_socket)) {
+    auto* const buffer =
+        reinterpret_cast<media::AudioOutputBuffer*>(shared_memory_.memory());
+    output_bus_ = media::AudioBus::WrapMemory(params, buffer->audio);
+    output_bus_->Zero();
+    output_bus_->set_is_bitstream_format(params.IsBitstreamFormat());
+  }
+}
+
+SyncReader::~SyncReader() {
+  if (!renderer_callback_count_)
+    return;
+
+  DVLOG(1) << "Trailing glitch count on destruction: "
+           << trailing_renderer_missed_callback_count_;
+
+  // Subtract 'trailing' count of callbacks missed just before the destructor
+  // call. This happens if the renderer process was killed or e.g. the page
+  // refreshed while the output device was open etc.
+  // This trims off the end of both the missed and total counts so that we
+  // preserve the proportion of counts before the teardown period.
+  DCHECK_LE(trailing_renderer_missed_callback_count_,
+            renderer_missed_callback_count_);
+  DCHECK_LE(trailing_renderer_missed_callback_count_, renderer_callback_count_);
+
+  renderer_missed_callback_count_ -= trailing_renderer_missed_callback_count_;
+  renderer_callback_count_ -= trailing_renderer_missed_callback_count_;
+
+  if (!renderer_callback_count_)
+    return;
+
+  // Recording the percentage of deadline misses gives us a rough overview of
+  // how many users might be running into audio glitches.
+  int percentage_missed =
+      100.0 * renderer_missed_callback_count_ / renderer_callback_count_;
+  UMA_HISTOGRAM_PERCENTAGE("Media.AudioRendererMissedDeadline",
+                           percentage_missed);
+
+  // Add more detailed information regarding detected audio glitches where
+  // a non-zero value of |renderer_missed_callback_count_| is added to the
+  // AUDIO_RENDERER_AUDIO_GLITCHES bin.
+  renderer_missed_callback_count_ > 0
+      ? LogAudioGlitchResult(AUDIO_RENDERER_AUDIO_GLITCHES)
+      : LogAudioGlitchResult(AUDIO_RENDERER_NO_AUDIO_GLITCHES);
+  log_callback_.Run(base::StringPrintf(
+      "ASR: number of detected audio glitches: %" PRIuS " out of %" PRIuS,
+      renderer_missed_callback_count_, renderer_callback_count_));
+}
+
+bool SyncReader::IsValid() const {
+  if (output_bus_) {
+    DCHECK(shared_memory_.memory());
+    DCHECK_NE(socket_.handle(), base::SyncSocket::kInvalidHandle);
+    return true;
+  }
+  return false;
+}
+
+// AudioOutputController::SyncReader implementations.
+void SyncReader::RequestMoreData(base::TimeDelta delay,
+                                 base::TimeTicks delay_timestamp,
+                                 int prior_frames_skipped) {
+  // We don't send arguments over the socket since sending more than 4
+  // bytes might lead to being descheduled. The reading side will zero
+  // them when consumed.
+  auto* const buffer =
+      reinterpret_cast<media::AudioOutputBuffer*>(shared_memory_.memory());
+  // Increase the number of skipped frames stored in shared memory.
+  buffer->params.frames_skipped += prior_frames_skipped;
+  buffer->params.delay_us = delay.InMicroseconds();
+  buffer->params.delay_timestamp_us =
+      (delay_timestamp - base::TimeTicks()).InMicroseconds();
+
+  // Zero out the entire output buffer to avoid stuttering/repeating-buffers
+  // in the anomalous case if the renderer is unable to keep up with real-time.
+  output_bus_->Zero();
+
+  uint32_t control_signal = 0;
+  if (delay.is_max()) {
+    // std::numeric_limits<uint32_t>::max() is a special signal which is
+    // returned after the browser stops the output device in response to a
+    // renderer side request.
+    control_signal = std::numeric_limits<uint32_t>::max();
+  }
+
+  size_t sent_bytes = socket_.Send(&control_signal, sizeof(control_signal));
+  if (sent_bytes != sizeof(control_signal)) {
+    // Ensure we don't log consecutive errors as this can lead to a large
+    // amount of logs.
+    if (!had_socket_error_) {
+      had_socket_error_ = true;
+      static const char* socket_send_failure_message =
+          "ASR: No room in socket buffer.";
+      PLOG(WARNING) << socket_send_failure_message;
+      log_callback_.Run(socket_send_failure_message);
+      TRACE_EVENT_INSTANT0("audio", socket_send_failure_message,
+                           TRACE_EVENT_SCOPE_THREAD);
+    }
+  } else {
+    had_socket_error_ = false;
+  }
+  ++buffer_index_;
+}
+
+void SyncReader::Read(media::AudioBus* dest) {
+  ++renderer_callback_count_;
+  if (!WaitUntilDataIsReady()) {
+    ++trailing_renderer_missed_callback_count_;
+    ++renderer_missed_callback_count_;
+    if (renderer_missed_callback_count_ <= 100 &&
+        renderer_missed_callback_count_ % 10 == 0) {
+      LOG(WARNING) << "SyncReader::Read timed out, audio glitch count="
+                   << renderer_missed_callback_count_;
+      if (renderer_missed_callback_count_ == 100)
+        LOG(WARNING) << "(log cap reached, suppressing further logs)";
+    }
+    dest->Zero();
+    return;
+  }
+
+  trailing_renderer_missed_callback_count_ = 0;
+
+  // Zeroed buffers may be discarded immediately when outputing compressed
+  // bitstream.
+  if (mute_audio_for_testing_ && !output_bus_->is_bitstream_format()) {
+    dest->Zero();
+    return;
+  }
+
+  if (output_bus_->is_bitstream_format()) {
+    // For bitstream formats, we need the real data size and PCM frame count.
+    auto* const buffer =
+        reinterpret_cast<media::AudioOutputBuffer*>(shared_memory_.memory());
+    uint32_t data_size = buffer->params.bitstream_data_size;
+    uint32_t bitstream_frames = buffer->params.bitstream_frames;
+    // |bitstream_frames| is cast to int below, so it must fit.
+    if (data_size > output_bus_buffer_size_ ||
+        !base::IsValueInRangeForNumericType<int>(bitstream_frames)) {
+      // Received data doesn't fit in the buffer, shouldn't happen.
+      dest->Zero();
+      return;
+    }
+    output_bus_->SetBitstreamDataSize(data_size);
+    output_bus_->SetBitstreamFrames(bitstream_frames);
+  }
+  output_bus_->CopyTo(dest);
+}
+
+void SyncReader::Close() {
+  socket_.Close();
+  output_bus_.reset();
+}
+
+bool SyncReader::WaitUntilDataIsReady() {
+  TRACE_EVENT0("audio", "SyncReader::WaitUntilDataIsReady");
+  base::TimeDelta timeout = maximum_wait_time_;
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+  const base::TimeTicks finish_time = start_time + timeout;
+
+  // Check if data is ready and if not, wait a reasonable amount of time for it.
+  //
+  // Data readiness is achieved via parallel counters, one on the renderer side
+  // and one here.  Every time a buffer is requested via UpdatePendingBytes(),
+  // |buffer_index_| is incremented.  Subsequently every time the renderer has a
+  // buffer ready it increments its counter and sends the counter value over the
+  // SyncSocket.  Data is ready when |buffer_index_| matches the counter value
+  // received from the renderer.
+  //
+  // The counter values may temporarily become out of sync if the renderer is
+  // unable to deliver audio fast enough.  It's assumed that the renderer will
+  // catch up at some point, which means discarding counter values read from the
+  // SyncSocket which don't match our current buffer index.
+  size_t bytes_received = 0;
+  uint32_t renderer_buffer_index = 0;
+  while (timeout.InMicroseconds() > 0) {
+    bytes_received = socket_.ReceiveWithTimeout(
+        &renderer_buffer_index, sizeof(renderer_buffer_index), timeout);
+    if (bytes_received != sizeof(renderer_buffer_index)) {
+      bytes_received = 0;
+      break;
+    }
+
+    if (renderer_buffer_index == buffer_index_)
+      break;
+
+    // Reduce the timeout value as receives succeed, but aren't the right index.
+    timeout = finish_time - base::TimeTicks::Now();
+  }
+
+  // Receive timed out or another error occurred.  Receive can timeout if the
+  // renderer is unable to deliver audio data within the allotted time.
+  if (!bytes_received || renderer_buffer_index != buffer_index_) {
+    TRACE_EVENT_INSTANT0("audio", "SyncReader::Read timed out",
+                         TRACE_EVENT_SCOPE_THREAD);
+
+    base::TimeDelta time_since_start = base::TimeTicks::Now() - start_time;
+    UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
+                               time_since_start,
+                               base::TimeDelta::FromMilliseconds(1),
+                               base::TimeDelta::FromMilliseconds(1000), 50);
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace audio
diff --git a/services/audio/sync_reader.h b/services/audio/sync_reader.h
new file mode 100644
index 0000000..38397f70
--- /dev/null
+++ b/services/audio/sync_reader.h
@@ -0,0 +1,102 @@
+// 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 SERVICES_AUDIO_SYNC_READER_H_
+#define SERVICES_AUDIO_SYNC_READER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/process.h"
+#include "base/sync_socket.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "media/base/audio_bus.h"
+#include "services/audio/output_controller.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+namespace audio {
+
+// An OutputController::SyncReader implementation using SyncSocket. This is used
+// by OutputController to provide a low latency data source for transmitting
+// audio packets between the Audio Service process and the process where the
+// mojo client runs.
+class SyncReader : public OutputController::SyncReader {
+ public:
+  // Constructor: Creates and maps shared memory; and initializes a SyncSocket
+  // pipe, assigning the client handle to |foreign_socket|. The caller must
+  // confirm IsValid() returns true before any other methods are called.
+  SyncReader(base::RepeatingCallback<void(const std::string&)> log_callback,
+             const media::AudioParameters& params,
+             base::CancelableSyncSocket* foreign_socket);
+
+  ~SyncReader() override;
+
+  // Returns true if the SyncReader initialized successfully, and
+  // shared_memory() will return a valid pointer.
+  bool IsValid() const;
+
+  const base::SharedMemory* shared_memory() const { return &shared_memory_; }
+
+  // OutputController::SyncReader implementation.
+  void RequestMoreData(base::TimeDelta delay,
+                       base::TimeTicks delay_timestamp,
+                       int prior_frames_skipped) override;
+  void Read(media::AudioBus* dest) override;
+  void Close() override;
+
+ private:
+  // Blocks until data is ready for reading or a timeout expires.  Returns false
+  // if an error or timeout occurs.
+  bool WaitUntilDataIsReady();
+
+  const base::RepeatingCallback<void(const std::string&)> log_callback_;
+
+  base::SharedMemory shared_memory_;
+
+  // Mutes all incoming samples. This is used to prevent audible sound
+  // during automated testing.
+  const bool mute_audio_for_testing_;
+
+  // Denotes that the most recent socket error has been logged. Used to avoid
+  // log spam.
+  bool had_socket_error_;
+
+  // Socket for transmitting audio data.
+  base::CancelableSyncSocket socket_;
+
+  const uint32_t output_bus_buffer_size_;
+
+  // Shared memory wrapper used for transferring audio data to Read() callers.
+  std::unique_ptr<media::AudioBus> output_bus_;
+
+  // Track the number of times the renderer missed its real-time deadline and
+  // report a UMA stat during destruction.
+  size_t renderer_callback_count_;
+  size_t renderer_missed_callback_count_;
+  size_t trailing_renderer_missed_callback_count_;
+
+  // The maximum amount of time to wait for data from the renderer.  Calculated
+  // from the parameters given at construction.
+  const base::TimeDelta maximum_wait_time_;
+
+  // The index of the audio buffer we're expecting to be sent from the renderer;
+  // used to block with timeout for audio data.
+  uint32_t buffer_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(SyncReader);
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_SYNC_READER_H_
diff --git a/services/audio/sync_reader_unittest.cc b/services/audio/sync_reader_unittest.cc
new file mode 100644
index 0000000..a313deba
--- /dev/null
+++ b/services/audio/sync_reader_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/audio/sync_reader.h"
+
+#include <limits>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "base/memory/shared_memory.h"
+#include "base/sync_socket.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/time/time.h"
+#include "media/base/audio_bus.h"
+#include "media/base/audio_parameters.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::TestWithParam;
+
+using media::AudioBus;
+using media::AudioOutputBuffer;
+using media::AudioOutputBufferParameters;
+using media::AudioParameters;
+
+namespace audio {
+
+void NoLog(const std::string&) {}
+
+static_assert(
+    std::is_unsigned<
+        decltype(AudioOutputBufferParameters::bitstream_data_size)>::value,
+    "If |bitstream_data_size| is ever made signed, add tests for negative "
+    "buffer sizes.");
+
+enum OverflowTestCase {
+  kZero,
+  kNoOverflow,
+  kOverflowByOne,
+  kOverflowByOneThousand,
+  kOverflowByMax
+};
+
+static const OverflowTestCase overflow_test_case_values[]{
+    kZero, kNoOverflow, kOverflowByOne, kOverflowByOneThousand, kOverflowByMax};
+
+class SyncReaderBitstreamTest : public TestWithParam<OverflowTestCase> {
+ public:
+  SyncReaderBitstreamTest() {}
+  ~SyncReaderBitstreamTest() override {}
+
+ private:
+  base::test::ScopedTaskEnvironment env_;
+};
+
+TEST_P(SyncReaderBitstreamTest, BitstreamBufferOverflow_DoesNotWriteOOB) {
+  const int kSampleRate = 44100;
+  const int kBitsPerSample = 32;
+  const int kFramesPerBuffer = 1;
+  AudioParameters params(AudioParameters::AUDIO_BITSTREAM_AC3,
+                         media::CHANNEL_LAYOUT_STEREO, kSampleRate,
+                         kBitsPerSample, kFramesPerBuffer);
+
+  auto socket = std::make_unique<base::CancelableSyncSocket>();
+  SyncReader reader(base::BindRepeating(&NoLog), params, socket.get());
+  ASSERT_TRUE(reader.IsValid());
+  auto* const shmem = reader.shared_memory();
+  ASSERT_TRUE(shmem);
+  auto* const buffer =
+      reinterpret_cast<media::AudioOutputBuffer*>(shmem->memory());
+  ASSERT_TRUE(buffer);
+  reader.RequestMoreData(base::TimeDelta(), base::TimeTicks(), 0);
+
+  uint32_t signal;
+  EXPECT_EQ(socket->Receive(&signal, sizeof(signal)), sizeof(signal));
+
+  // So far, this is an ordinary stream.
+  // Now |reader| expects data to be written to the shared memory. The renderer
+  // says how much data was written.
+  switch (GetParam()) {
+    case kZero:
+      buffer->params.bitstream_data_size = 0;
+      break;
+    case kNoOverflow:
+      buffer->params.bitstream_data_size =
+          shmem->mapped_size() - sizeof(AudioOutputBufferParameters);
+      break;
+    case kOverflowByOne:
+      buffer->params.bitstream_data_size =
+          shmem->mapped_size() - sizeof(AudioOutputBufferParameters) + 1;
+      break;
+    case kOverflowByOneThousand:
+      buffer->params.bitstream_data_size =
+          shmem->mapped_size() - sizeof(AudioOutputBufferParameters) + 1000;
+      break;
+    case kOverflowByMax:
+      buffer->params.bitstream_data_size = std::numeric_limits<decltype(
+          buffer->params.bitstream_data_size)>::max();
+      break;
+  }
+
+  ++signal;
+  EXPECT_EQ(socket->Send(&signal, sizeof(signal)), sizeof(signal));
+
+  // The purpose of the test is to ensure this call doesn't result in undefined
+  // behavior, which should be verified by sanitizers.
+  std::unique_ptr<AudioBus> output_bus = AudioBus::Create(params);
+  reader.Read(output_bus.get());
+}
+
+INSTANTIATE_TEST_CASE_P(,
+                        SyncReaderBitstreamTest,
+                        ::testing::ValuesIn(overflow_test_case_values));
+
+}  // namespace audio
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 32194b9d..cecd0d2 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -97,6 +97,7 @@
 
   deps = [
     "//base",
+    "//components/certificate_transparency",
     "//components/cookie_config",
     "//components/network_session_configurator/browser",
     "//components/network_session_configurator/common",
diff --git a/services/network/DEPS b/services/network/DEPS
index 361831b..c953271 100644
--- a/services/network/DEPS
+++ b/services/network/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/certificate_transparency",
   "+components/cookie_config",
   "+components/network_session_configurator",
   # Prefs are used to create an independent file with a persisted key:value
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 68f9801b..b1ecb66 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/task_scheduler/task_traits.h"
+#include "components/certificate_transparency/ct_policy_manager.h"
 #include "components/cookie_config/cookie_store_util.h"
 #include "components/network_session_configurator/browser/network_session_configurator.h"
 #include "components/network_session_configurator/common/network_switches.h"
@@ -157,6 +158,12 @@
   // May be nullptr in tests.
   if (network_service_)
     network_service_->DeregisterNetworkContext(this);
+
+  if (GetURLRequestContext() &&
+      GetURLRequestContext()->transport_security_state()) {
+    GetURLRequestContext()->transport_security_state()->SetRequireCTDelegate(
+        nullptr);
+  }
 }
 
 std::unique_ptr<NetworkContext> NetworkContext::CreateForTesting() {
@@ -525,6 +532,20 @@
   user_agent_settings_->set_accept_language(new_accept_language);
 }
 
+void NetworkContext::SetCTPolicy(
+    const std::vector<std::string>& required_hosts,
+    const std::vector<std::string>& excluded_hosts,
+    const std::vector<std::string>& excluded_spkis,
+    const std::vector<std::string>& excluded_legacy_spkis) {
+  if (!ct_policy_manager_) {
+    ct_policy_manager_.reset(new certificate_transparency::CTPolicyManager());
+    GetURLRequestContext()->transport_security_state()->SetRequireCTDelegate(
+        ct_policy_manager_->GetDelegate());
+  }
+  ct_policy_manager_->UpdateCTPolicies(required_hosts, excluded_hosts,
+                                       excluded_spkis, excluded_legacy_spkis);
+}
+
 void NetworkContext::CreateUDPSocket(mojom::UDPSocketRequest request,
                                      mojom::UDPSocketReceiverPtr receiver) {
   socket_factory_.CreateUDPSocket(std::move(request), std::move(receiver));
diff --git a/services/network/network_context.h b/services/network/network_context.h
index f9b1ee9..292f42d 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -37,6 +37,10 @@
 class URLRequestContext;
 }  // namespace net
 
+namespace certificate_transparency {
+class CTPolicyManager;
+}
+
 namespace network {
 class NetworkService;
 class ResourceScheduler;
@@ -120,6 +124,11 @@
   void SetNetworkConditions(const std::string& profile_id,
                             mojom::NetworkConditionsPtr conditions) override;
   void SetAcceptLanguage(const std::string& new_accept_language) override;
+  void SetCTPolicy(
+      const std::vector<std::string>& required_hosts,
+      const std::vector<std::string>& excluded_hosts,
+      const std::vector<std::string>& excluded_spkis,
+      const std::vector<std::string>& excluded_legacy_spkis) override;
   void CreateUDPSocket(mojom::UDPSocketRequest request,
                        mojom::UDPSocketReceiverPtr receiver) override;
   void CreateTCPServerSocket(
@@ -221,6 +230,8 @@
   // TODO(yhirano): Consult with switches::kDisableResourceScheduler.
   constexpr static bool enable_resource_scheduler_ = true;
 
+  std::unique_ptr<certificate_transparency::CTPolicyManager> ct_policy_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(NetworkContext);
 };
 
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index 9441f68..ebef812 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -188,6 +188,12 @@
   // Updates the Accept-Language header to be used for requests.
   SetAcceptLanguage(string new_accept_language);
 
+  // Updates the CT policy to be used for requests.
+  SetCTPolicy(array<string> required_hosts,
+              array<string> excluded_hosts,
+              array<string> excluded_spkis,
+              array<string> excluded_legacy_spkis);
+
   // Creates a UDP socket. Caller can supply a |receiver| interface pointer
   // to listen for incoming datagrams. A null |receiver| is acceptable if caller
   // is not interested in incoming data.
diff --git a/services/network/public/mojom/network_service_test.mojom b/services/network/public/mojom/network_service_test.mojom
index 0050c00..d6ee979 100644
--- a/services/network/public/mojom/network_service_test.mojom
+++ b/services/network/public/mojom/network_service_test.mojom
@@ -39,4 +39,14 @@
       string host_pattern,
       CertVerifyResult verify_result,
       int32 rv) => ();
+
+  // Toggles requiring CT for testing
+  enum ShouldRequireCT {
+    RESET = 0,
+    REQUIRE = 1,
+    DONT_REQUIRE = 2,
+  };
+
+  [Sync]
+  SetShouldRequireCT(ShouldRequireCT required) => ();
 };
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 9921e60..649ee9ef 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -43,6 +43,12 @@
 -WebViewTests/WebViewTest.DownloadPermission/0
 -WebViewTests/WebViewTest.DownloadPermission/1
 
+# Need a test interface API that allows us to check on the CT status.
+# Then in ssl_browsertest.cc we can use that instead of the direct
+# call to the transport_security_state()
+-SSLUITest.CertificateTransparencyEnforcementDisabledForUrls/0
+-SSLUITest.CertificateTransparencyEnforcementDisabledForUrls/1
+
 # Redirects to chrome-extension:// should be blocked unless the resource is
 # webaccessible.  https://crbug.com/821586
 -ProcessManagerBrowserTest.ServerRedirectToNonWebAccessibleResource
@@ -102,7 +108,6 @@
 -DownloadExtensionTest.DownloadExtensionTest_Download_FileSystemURL
 -LoadImageBrowserTest.LoadImage
 -MimeHandlerViewTests/MimeHandlerViewTest.SingleRequest/0
--PolicyTest.CertificateTransparencyEnforcementDisabledForUrls
 -PolicyTest.ExtensionInstallSources
 -PolicyTest.ForceGoogleSafeSearch
 -ProfileBrowserTest.SendHPKPReport
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index 80b8db0..843adb96 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -330,8 +330,6 @@
 Bug(none) compositing/reflections/nested-reflection-on-overflow.html [ Failure Crash ]
 Bug(none) compositing/reflections/nested-reflection-opacity.html [ Failure Crash ]
 Bug(none) compositing/reflections/nested-reflection-size-change.html [ Failure Crash ]
-Bug(none) compositing/reflections/nested-reflection-transformed.html [ Failure Crash ]
-Bug(none) compositing/reflections/nested-reflection-transformed2.html [ Failure Crash ]
 Bug(none) compositing/reflections/nested-reflection-transition.html [ Failure Crash ]
 Bug(none) compositing/reflections/nested-reflection.html [ Failure Crash ]
 Bug(none) compositing/reflections/reflection-in-composited.html [ Failure Crash ]
@@ -503,7 +501,6 @@
 Bug(none) fast/forms/textarea/basic-textareas.html [ Failure ]
 Bug(none) fast/forms/textarea/textAreaLineHeight.html [ Failure ]
 Bug(none) fast/frames/iframe-scrolling-attribute.html [ Failure ]
-Bug(none) fast/frames/transparent-scrollbar.html [ Failure ]
 Bug(none) fast/gradients/css3-color-stop-units.html [ Failure ]
 Bug(none) fast/webgl/pixelated.html [ Failure ]
 Bug(none) images/color-profile-layer.html [ Failure ]
@@ -781,9 +778,7 @@
 crbug.com/707444 paint/invalidation/svg/resource-invalidate-on-target-update.svg [ Failure ]
 crbug.com/707444 svg/W3C-SVG-1.1/masking-intro-01-f.svg [ Failure ]
 crbug.com/707444 svg/batik/masking/maskRegions.svg [ Failure ]
-crbug.com/707444 svg/custom/clamped-masking-clipping.svg [ Failure ]
 crbug.com/707444 svg/custom/clip-mask-negative-scale.svg [ Failure ]
-crbug.com/707444 svg/custom/mask-inside-defs.svg [ Failure ]
 
 # No border radius applied to iframe documents
 Bug(none) compositing/overflow/border-radius-composited-subframe.html [ Failure ]
@@ -803,28 +798,14 @@
 Bug(none) compositing/overflow/siblings-with-border-radius-ancestor.html [ Failure ]
 Bug(none) fast/canvas/canvas-composite-video-shadow.html [ Failure ]
 Bug(none) fast/scrolling/fractional-scroll-offset-fixed-position-non-composited.html [ Failure ]
-Bug(none) fast/text/international/vertical-text-glyph-test.html [ Failure ]
 Bug(none) images/color-profile-mask-image-svg.html [ Failure ]
 Bug(none) svg/W3C-SVG-1.1/masking-mask-01-b.svg [ Failure ]
 Bug(none) svg/custom/absolute-root-position-masking.xhtml [ Failure ]
 Bug(none) svg/custom/grayscale-gradient-mask-2.svg [ Failure ]
 Bug(none) svg/custom/grayscale-gradient-mask.svg [ Failure ]
 Bug(none) svg/custom/recursive-mask.svg [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-dom-height-attr.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-dom-width-attr.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-dom-x-attr.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-dom-y-attr.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-svgdom-height-prop.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-svgdom-width-prop.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-svgdom-x-prop.html [ Failure ]
-Bug(none) svg/dynamic-updates/SVGMaskElement-svgdom-y-prop.html [ Failure ]
 Bug(none) svg/foreignObject/mask.html [ Failure ]
 Bug(none) svg/batik/text/textEffect2.svg [ Failure ]
-Bug(none) svg/batik/text/textLayout.svg [ Failure ]
 Bug(none) svg/batik/text/textProperties.svg [ Failure ]
 Bug(none) svg/custom/getscreenctm-in-scrollable-svg-area.xhtml [ Failure ]
 Bug(none) svg/custom/junk-data.svg [ Failure ]
@@ -958,8 +939,6 @@
 crbug.com/654554 fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar.html [ Crash Timeout Failure ]
 crbug.com/654554 fast/forms/suggestion-picker/week-suggestion-picker-appearance.html [ Crash Timeout Failure ]
 
-crbug.com/667071 svg/foreignObject/vertical-foreignObject.html [ Failure ]
-
 Bug(none) css3/blending/background-blend-mode-overlapping-accelerated-elements.html [ Failure ]
 Bug(none) css3/blending/effect-background-blend-mode-stacking.html [ Failure Crash ]
 
@@ -978,29 +957,17 @@
 # Failures due to rounding differences
 crbug.com/589265 compositing/culling/filter-occlusion-blur-large.html [ Failure ]
 crbug.com/589265 compositing/culling/filter-occlusion-blur.html [ Failure ]
-crbug.com/589265 css3/blending/effect-background-blend-mode-tiled.html [ Failure ]
-crbug.com/589265 css3/blending/effect-background-blend-mode.html [ Failure ]
 crbug.com/589265 css3/blending/mix-blend-mode-isolated-group-1.html [ Failure Timeout ]
 crbug.com/589265 css3/blending/mix-blend-mode-isolated-group-2.html [ Failure Timeout ]
 crbug.com/589265 css3/blending/mix-blend-mode-isolated-group-3.html [ Failure Timeout ]
 crbug.com/589265 css3/blending/svg-blend-exclusion.html [ Failure ]
 crbug.com/589265 css3/blending/svg-blend-screen.html [ Failure ]
-crbug.com/589265 fast/backgrounds/size/contain-and-cover-zoomed.html [ Failure ]
-crbug.com/589265 fast/forms/datalist/input-appearance-range-with-transform.html [ Failure ]
 crbug.com/589265 fast/forms/text/input-appearance-autocomplete-very-long-value.html [ Failure ]
-crbug.com/589265 images/color-profile-filter.html [ Failure ]
 crbug.com/589265 paint/invalidation/svg/deep-dynamic-updates.svg [ Failure ]
 crbug.com/589265 paint/invalidation/svg/foreign-object-repaint.svg [ Failure ]
 crbug.com/589265 paint/invalidation/svg/repaint-paintorder.svg [ Failure ]
 crbug.com/589265 paint/invalidation/svg/tabgroup.svg [ Failure ]
 crbug.com/589265 paint/masks/fieldset-mask.html [ Failure ]
-crbug.com/589265 svg/W3C-SVG-1.1/animate-elem-33-t.svg [ Failure ]
-crbug.com/589265 svg/as-background-image/background-image-preserveaspectRatio-support.html [ Failure ]
-crbug.com/589265 svg/as-background-image/svg-as-background-6.html [ Failure ]
-crbug.com/589265 svg/custom/marker-opacity.svg [ Failure ]
-crbug.com/589265 svg/text/text-selection-align-01-b.svg [ Failure ]
-crbug.com/589265 svg/text/text-selection-align-05-b.svg [ Failure ]
-crbug.com/589265 svg/zoom/page/zoom-svg-as-background-with-relative-size.html [ Failure ]
 
 # Failures due to effect compositing decision
 crbug.com/765003 compositing/reflections/reflection-opacity.html [ Failure ]
@@ -1018,11 +985,8 @@
 crbug.com/589265 compositing/overflow/border-radius-on-parent-composited-grandchild.html [ Failure ]
 crbug.com/589265 compositing/overflow/nested-border-radius-clipping.html [ Failure ]
 crbug.com/589265 fast/borders/border-radius-with-composited-child.html [ Failure ]
-crbug.com/589265 fast/clip/overflow-border-radius-combinations.html [ Failure ]
 crbug.com/589265 fast/clip/overflow-border-radius-composited-parent.html [ Failure ]
 crbug.com/589265 fast/clip/overflow-border-radius-composited.html [ Failure ]
-crbug.com/589265 fast/clip/overflow-border-radius-transformed.html [ Failure ]
-crbug.com/589265 fast/css/nested-rounded-corners.html [ Failure ]
 crbug.com/589265 paint/overflow/composited-rounded-clip-floating-element.html [ Failure ]
 crbug.com/589265 svg/custom/mask-changes.svg [ Failure ]
 crbug.com/589265 svg/custom/mask-colorspace.svg [ Failure ]
@@ -1081,16 +1045,11 @@
 # Tests that fail after changes to border dash painting, due to antialiasing differences
 # and minor border radius clipping differences. Some SPv2 change is being ticked by the border
 # painting code.
-Bug(700530) svg/text/small-fonts-in-html5.html [ Failure ]
 Bug(700530) compositing/overflow/paint-neg-z-order-descendants-into-scrolling-contents-layer.html [ Failure ]
 
 # The following debug crashes / failures have not been triaged.
 crbug.com/702805 fast/forms/select-popup/popup-menu-appearance-coarse.html [ Crash Timeout Failure ]
-crbug.com/702805 compositing/visibility/overlays-persist-on-navigation.html [ Crash Failure ]
 
-crbug.com/730284 images/color-profile-border-radius.html [ Failure ]
-crbug.com/730284 images/color-profile-image-shape.html [ Failure ]
-crbug.com/730284 images/color-profile-border-fade.html [ Failure ]
 crbug.com/730284 fast/borders/border-radius-mask-canvas-all.html [ Failure ]
 crbug.com/730284 fast/borders/border-radius-mask-canvas-border.html [ Failure ]
 crbug.com/730284 fast/borders/border-radius-mask-canvas-padding.html [ Failure ]
@@ -1100,7 +1059,6 @@
 crbug.com/730284 fast/borders/border-radius-mask-video-ratio.html [ Failure ]
 crbug.com/730284 fast/borders/border-radius-mask-video-shadow.html [ Failure ]
 crbug.com/730284 fast/borders/border-radius-mask-video.html [ Failure ]
-crbug.com/730284 fast/replaced/border-radius-clip-content-edge.html [ Failure ]
 crbug.com/730284 fast/replaced/border-radius-clip.html [ Failure ]
 
 # Check failed: layer_list_.empty() || *page_scale_factor == 1
@@ -1139,8 +1097,6 @@
 Bug(none) fast/forms/validation-bubble-appearance-iframe.html [ Failure ]
 Bug(none) fast/forms/validation-bubble-appearance-rtl-ui.html [ Failure ]
 Bug(none) fast/overflow/overflow-with-local-background-attachment.html [ Failure ]
-Bug(none) svg/text/text-selection-text-06-t.svg [ Failure ]
-Bug(none) svg/transforms/transformed-text-fill-pattern.html [ Failure ]
 
 Bug(none) fast/block/float/float-change-composited-scrolling.html [ Failure ]
 
@@ -1227,14 +1183,10 @@
 Bug(none) fast/body-propagation/overflow/007-declarative.xhtml [ Failure ]
 Bug(none) fast/body-propagation/overflow/007-xhtml.xhtml [ Failure ]
 Bug(none) fast/css/text-overflow-input.html [ Failure ]
-Bug(none) fast/forms/basic-inputs.html [ Failure ]
-Bug(none) fast/forms/minWidthPercent.html [ Failure ]
 Bug(none) fast/forms/select/select-item-background-clip.html [ Failure ]
 Bug(none) fast/forms/select/select-overflow-scroll-inherited.html [ Failure ]
 Bug(none) fast/forms/select/select-overflow-scroll.html [ Failure ]
 Bug(none) fast/forms/text/input-disabled-color.html [ Failure ]
-Bug(none) fast/forms/text/input-readonly-autoscroll.html [ Failure ]
-Bug(none) fast/forms/text/input-readonly-dimmed.html [ Failure ]
 Bug(none) fast/forms/textarea/textarea-scrollbar.html [ Failure ]
 Bug(none) fast/frames/frame-scrolling-attribute.html [ Failure ]
 Bug(none) fast/hidpi/scrollbar-appearance-decrease-device-scale-factor.html [ Failure ]
@@ -1266,11 +1218,6 @@
 Bug(none) fast/css/sticky/sticky-vertically-overconstrained.html [ Failure ]
 Bug(none) fast/css/sticky/sticky-overflowing.html [ Failure ]
 
-# Failures due to pixel snapping because the overflow clip rect is not snapped
-# in PaintPropertyTreeBuilder::UpdateOverflowClip but needs to be snapped to
-# prevent composited scrolling overdraw.
-crbug.com/755274 compositing/overflow/fractional-sized-scrolling-layer.html [ Failure ]
-
 # Different layer tree about scrolling layer. Some may also have wrong invalidations.
 crbug.com/738613 compositing/iframes/connect-compositing-iframe-delayed.html [ Failure ]
 crbug.com/738613 compositing/iframes/connect-compositing-iframe.html [ Failure ]
@@ -1320,7 +1267,6 @@
 Bug(none) paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-rl.html [ Failure ]
 Bug(none) paint/invalidation/selection/invalidation-rect-includes-newline.html [ Failure ]
 Bug(none) paint/invalidation/selection/invalidation-rect-with-br-includes-newline.html [ Failure ]
-Bug(none) svg/W3C-SVG-1.1/masking-opacity-01-b.svg [ Failure ]
 Bug(none) svg/transforms/text-with-pattern-with-svg-transform.svg [ Failure ]
 
 Bug(none) compositing/rendering-contexts.html [ Failure ]
@@ -1370,7 +1316,6 @@
 Bug(none) css3/blending/mix-blend-mode-simple-text.html [ Pass Timeout ]
 
 crbug.com/529963 paint/invalidation/background/background-attachment-fixed-scrolled.html [ Failure Crash ]
-Bug(none) fast/multicol/hit-test-translate-z.html [ Failure ]
 
 # Invalidation is incorrect.
 crbug.com/693741 paint/invalidation/reflection/scroll-absolute-layer-with-reflection.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 96557c5..4b46ed0 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2285,7 +2285,12 @@
 
 crbug.com/805463 external/wpt/acid/acid3/numbered-tests.html [ Skip ]
 
+crbug.com/829567 [ Linux Win ] fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Pass Failure ]
+crbug.com/829567 [ Linux Win ] virtual/mouseevent_fractional/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Pass Failure ]
+crbug.com/829567 [ Linux Win ] virtual/scroll_customization/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Pass Failure ]
+
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux Mac10.10 Mac10.11 Mac10.12 Retina Win ] external/wpt/html/editing/focus/focus-02.html [ Timeout ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-flex-basis-content-001a.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-abspos-child-002.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-flex-basis-content-002a.html [ Failure ]
@@ -3799,7 +3804,6 @@
 crbug.com/783154 [ Mac ] virtual/modern-media-controls/media/controls/modern/doubletap-to-toggle-fullscreen.html [ Skip ]
 
 # Test failing on WebKit Trusty
-crbug.com/829228 [ Linux Debug ] virtual/modern-media-controls/media/controls/modern/doubletap-to-jump-backwards.html [ Failure ]
 crbug.com/829228 [ Win7 Linux ] virtual/modern-media-controls/media/controls/modern/doubletap-to-jump-forwards-too-short.html [ Failure ]
 
 crbug.com/802915 css3/blending/isolation-should-include-non-local-background.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/css3/background/background-auto-no-intrinsic-expected.html b/third_party/WebKit/LayoutTests/css3/background/background-auto-no-intrinsic-expected.html
new file mode 100644
index 0000000..88164fb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/background/background-auto-no-intrinsic-expected.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<style>
+  div {
+    background-image: radial-gradient(red, yellow, green);
+    background-repeat: no-repeat;
+    border: solid 1px black;
+    margin: 10px;
+  }
+  .horizontal {
+    background-size: 100% 50%;
+    width: 200px;
+    height: 100px;
+  }
+  .vertical {
+    background-size: 50% 100%;
+    width: 100px;
+    height: 200px;
+  }
+</style>
+<div class="horizontal">
+</div>
+<div class="vertical">
+</div>
diff --git a/third_party/WebKit/LayoutTests/css3/background/background-auto-no-intrinsic.html b/third_party/WebKit/LayoutTests/css3/background/background-auto-no-intrinsic.html
new file mode 100644
index 0000000..b6ed7ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/background/background-auto-no-intrinsic.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<style>
+  div {
+    background-image: radial-gradient(red, yellow, green);
+    background-repeat: no-repeat;
+    border: solid 1px black;
+    margin: 10px;
+  }
+  .horizontal {
+    background-size: auto 50%;
+    width: 200px;
+    height: 100px;
+  }
+  .vertical {
+    background-size: 50% auto;
+    width: 100px;
+    height: 200px;
+  }
+</style>
+<div class="horizontal">
+</div>
+<div class="vertical">
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index bf8e4e04..94ed045 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -4075,45 +4075,45 @@
      {}
     ]
    ],
-   "html/browsers/offline/browser-state/navigator_online_event-manual.html": [
+   "html/browsers/offline/browser-state/navigator_online_event-manual.https.html": [
     [
-     "/html/browsers/offline/browser-state/navigator_online_event-manual.html",
+     "/html/browsers/offline/browser-state/navigator_online_event-manual.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/manifest_main_empty-manual.html": [
+   "html/browsers/offline/manifest_main_empty-manual.https.html": [
     [
-     "/html/browsers/offline/manifest_main_empty-manual.html",
+     "/html/browsers/offline/manifest_main_empty-manual.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/manifest_notchanged_online-manual.html": [
+   "html/browsers/offline/manifest_notchanged_online-manual.https.html": [
     [
-     "/html/browsers/offline/manifest_notchanged_online-manual.html",
+     "/html/browsers/offline/manifest_notchanged_online-manual.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/manifest_section_empty-manual.html": [
+   "html/browsers/offline/manifest_section_empty-manual.https.html": [
     [
-     "/html/browsers/offline/manifest_section_empty-manual.html",
+     "/html/browsers/offline/manifest_section_empty-manual.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/manifest_section_many-manual.html": [
+   "html/browsers/offline/manifest_section_many-manual.https.html": [
     [
-     "/html/browsers/offline/manifest_section_many-manual.html",
+     "/html/browsers/offline/manifest_section_many-manual.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/section_network_offline-manual.html": [
+   "html/browsers/offline/section_network_offline-manual.https.html": [
     [
-     "/html/browsers/offline/section_network_offline-manual.html",
+     "/html/browsers/offline/section_network_offline-manual.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/section_network_online-manual.html": [
+   "html/browsers/offline/section_network_online-manual.https.html": [
     [
-     "/html/browsers/offline/section_network_online-manual.html",
+     "/html/browsers/offline/section_network_online-manual.https.html",
      {}
     ]
    ],
@@ -32524,7 +32524,7 @@
      "/css/css-backgrounds/css3-background-origin-padding-box.html",
      [
       [
-       "/css/css-backgrounds/reference/css3-background-origin-content-box-ref.html",
+       "/css/css-backgrounds/reference/css3-background-origin-padding-box-ref.html",
        "=="
       ]
      ],
@@ -32536,7 +32536,7 @@
      "/css/css-backgrounds/css3-background-size-001.html",
      [
       [
-       "/css/css-backgrounds/reference/css3-background-size-ref.html",
+       "/css/css-backgrounds/reference/css3-background-size-001-ref.html",
        "=="
       ]
      ],
@@ -99289,11 +99289,6 @@
      {}
     ]
    ],
-   "clipboard-apis/async-interfaces.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "common/PrefixedLocalStorage.js": [
     [
      {}
@@ -138214,11 +138209,6 @@
      {}
     ]
    ],
-   "hr-time/idlharness-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "hr-time/resources/now_frame.html": [
     [
      {}
@@ -139504,7 +139494,7 @@
      {}
     ]
    ],
-   "html/browsers/offline/application-cache-api/api_update-expected.txt": [
+   "html/browsers/offline/application-cache-api/api_update.https-expected.txt": [
     [
      {}
     ]
@@ -139919,7 +139909,7 @@
      {}
     ]
    ],
-   "html/browsers/the-window-object/security-window/window-security-expected.txt": [
+   "html/browsers/the-window-object/security-window/window-security.https-expected.txt": [
     [
      {}
     ]
@@ -139949,7 +139939,7 @@
      {}
     ]
    ],
-   "html/browsers/the-window-object/window-properties-expected.txt": [
+   "html/browsers/the-window-object/window-properties.https-expected.txt": [
     [
      {}
     ]
@@ -140439,7 +140429,7 @@
      {}
     ]
    ],
-   "html/dom/dynamic-markup-insertion/opening-the-input-stream/009-expected.txt": [
+   "html/dom/dynamic-markup-insertion/opening-the-input-stream/009.https-expected.txt": [
     [
      {}
     ]
@@ -141004,7 +140994,7 @@
      {}
     ]
    ],
-   "html/dom/interfaces-expected.txt": [
+   "html/dom/interfaces.https-expected.txt": [
     [
      {}
     ]
@@ -150214,11 +150204,6 @@
      {}
     ]
    ],
-   "html/semantics/text-level-semantics/the-a-element/a-download-click-404-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/semantics/text-level-semantics/the-a-element/resources/a-download-404.html": [
     [
      {}
@@ -153244,11 +153229,6 @@
      {}
     ]
    ],
-   "navigation-timing/nav2_idlharness-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "navigation-timing/resources/blank_page_green.html": [
     [
      {}
@@ -153739,11 +153719,6 @@
      {}
     ]
    ],
-   "payment-request/payment-request-insecure.http-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "payment-request/payment-response/helpers.js": [
     [
      {}
@@ -158349,11 +158324,6 @@
      {}
     ]
    ],
-   "service-workers/service-worker/interfaces-window.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "service-workers/service-worker/local-url-inherit-controller.https-expected.txt": [
     [
      {}
@@ -161704,16 +161674,6 @@
      {}
     ]
    ],
-   "web-animations/interfaces/Animatable/getAnimations-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "web-animations/interfaces/Animation/cancel-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "web-animations/interfaces/Animation/constructor-expected.txt": [
     [
      {}
@@ -161739,11 +161699,6 @@
      {}
     ]
    ],
-   "web-animations/interfaces/AnimationEffect/updateTiming-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "web-animations/interfaces/AnimationEffectTiming/getComputedTiming-expected.txt": [
     [
      {}
@@ -161754,11 +161709,6 @@
      {}
     ]
    ],
-   "web-animations/interfaces/KeyframeEffect/copy-constructor-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "web-animations/interfaces/KeyframeEffect/idlharness-expected.txt": [
     [
      {}
@@ -162329,11 +162279,6 @@
      {}
     ]
    ],
-   "webauthn/interfaces.https.any-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "webmessaging/MessageEvent-trusted-worker.js": [
     [
      {}
@@ -175264,9 +175209,9 @@
      }
     ]
    ],
-   "bluetooth/idl/idl-Bluetooth.html": [
+   "bluetooth/idl/idl-Bluetooth.https.html": [
     [
-     "/bluetooth/idl/idl-Bluetooth.html",
+     "/bluetooth/idl/idl-Bluetooth.https.html",
      {}
     ]
    ],
@@ -195412,81 +195357,87 @@
      {}
     ]
    ],
-   "html/browsers/offline/appcache/workers/appcache-worker.html": [
+   "html/browsers/offline/appcache/workers/appcache-worker.https.html": [
     [
-     "/html/browsers/offline/appcache/workers/appcache-worker.html",
+     "/html/browsers/offline/appcache/workers/appcache-worker.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/application-cache-api/api_status_idle.html": [
+   "html/browsers/offline/application-cache-api/api_status_idle.https.html": [
     [
-     "/html/browsers/offline/application-cache-api/api_status_idle.html",
+     "/html/browsers/offline/application-cache-api/api_status_idle.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/application-cache-api/api_status_uncached.html": [
+   "html/browsers/offline/application-cache-api/api_status_uncached.https.html": [
     [
-     "/html/browsers/offline/application-cache-api/api_status_uncached.html",
+     "/html/browsers/offline/application-cache-api/api_status_uncached.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/application-cache-api/api_swapcache_error.html": [
+   "html/browsers/offline/application-cache-api/api_swapcache_error.https.html": [
     [
-     "/html/browsers/offline/application-cache-api/api_swapcache_error.html",
+     "/html/browsers/offline/application-cache-api/api_swapcache_error.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/application-cache-api/api_update.html": [
+   "html/browsers/offline/application-cache-api/api_update.https.html": [
     [
-     "/html/browsers/offline/application-cache-api/api_update.html",
+     "/html/browsers/offline/application-cache-api/api_update.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/application-cache-api/api_update_error.html": [
+   "html/browsers/offline/application-cache-api/api_update_error.https.html": [
     [
-     "/html/browsers/offline/application-cache-api/api_update_error.html",
+     "/html/browsers/offline/application-cache-api/api_update_error.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/browser-state/navigator_online_online.html": [
+   "html/browsers/offline/application-cache-api/secure_context.html": [
     [
-     "/html/browsers/offline/browser-state/navigator_online_online.html",
+     "/html/browsers/offline/application-cache-api/secure_context.html",
      {}
     ]
    ],
-   "html/browsers/offline/introduction-4/event_cached.html": [
+   "html/browsers/offline/browser-state/navigator_online_online.https.html": [
     [
-     "/html/browsers/offline/introduction-4/event_cached.html",
+     "/html/browsers/offline/browser-state/navigator_online_online.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/introduction-4/event_checking.html": [
+   "html/browsers/offline/introduction-4/event_cached.https.html": [
     [
-     "/html/browsers/offline/introduction-4/event_checking.html",
+     "/html/browsers/offline/introduction-4/event_cached.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/introduction-4/event_noupdate.html": [
+   "html/browsers/offline/introduction-4/event_checking.https.html": [
     [
-     "/html/browsers/offline/introduction-4/event_noupdate.html",
+     "/html/browsers/offline/introduction-4/event_checking.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/introduction-4/event_progress.html": [
+   "html/browsers/offline/introduction-4/event_noupdate.https.html": [
     [
-     "/html/browsers/offline/introduction-4/event_progress.html",
+     "/html/browsers/offline/introduction-4/event_noupdate.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/manifest_url_check.html": [
+   "html/browsers/offline/introduction-4/event_progress.https.html": [
     [
-     "/html/browsers/offline/manifest_url_check.html",
+     "/html/browsers/offline/introduction-4/event_progress.https.html",
      {}
     ]
    ],
-   "html/browsers/offline/no-appcache-in-shared-workers-historical.html": [
+   "html/browsers/offline/manifest_url_check.https.https.html": [
     [
-     "/html/browsers/offline/no-appcache-in-shared-workers-historical.html",
+     "/html/browsers/offline/manifest_url_check.https.https.html",
+     {}
+    ]
+   ],
+   "html/browsers/offline/no-appcache-in-shared-workers-historical.https.html": [
+    [
+     "/html/browsers/offline/no-appcache-in-shared-workers-historical.https.html",
      {}
     ]
    ],
@@ -195806,9 +195757,9 @@
      {}
     ]
    ],
-   "html/browsers/the-window-object/security-window/window-security.html": [
+   "html/browsers/the-window-object/security-window/window-security.https.html": [
     [
-     "/html/browsers/the-window-object/security-window/window-security.html",
+     "/html/browsers/the-window-object/security-window/window-security.https.html",
      {}
     ]
    ],
@@ -195842,9 +195793,9 @@
      {}
     ]
    ],
-   "html/browsers/the-window-object/window-properties.html": [
+   "html/browsers/the-window-object/window-properties.https.html": [
     [
-     "/html/browsers/the-window-object/window-properties.html",
+     "/html/browsers/the-window-object/window-properties.https.html",
      {}
     ]
    ],
@@ -196904,9 +196855,9 @@
      {}
     ]
    ],
-   "html/dom/dynamic-markup-insertion/opening-the-input-stream/009.html": [
+   "html/dom/dynamic-markup-insertion/opening-the-input-stream/009.https.html": [
     [
-     "/html/dom/dynamic-markup-insertion/opening-the-input-stream/009.html",
+     "/html/dom/dynamic-markup-insertion/opening-the-input-stream/009.https.html",
      {}
     ]
    ],
@@ -197174,9 +197125,9 @@
      {}
     ]
    ],
-   "html/dom/interfaces.html": [
+   "html/dom/interfaces.https.html": [
     [
-     "/html/dom/interfaces.html",
+     "/html/dom/interfaces.https.html",
      {
       "timeout": "long"
      }
@@ -197398,6 +197349,14 @@
      }
     ]
    ],
+   "html/editing/focus/focus-02.html": [
+    [
+     "/html/editing/focus/focus-02.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "html/editing/focus/focus-management/focus-event-targets-simple.html": [
     [
      "/html/editing/focus/focus-management/focus-event-targets-simple.html",
@@ -251918,7 +251877,7 @@
    "support"
   ],
   "accelerometer/idlharness.https.html": [
-   "f6da2046a4bc1c31a7ad2169c51e22c74105b989",
+   "93a78732bf63dcdd30ca1004f7ab850d5e7faaae",
    "testharness"
   ],
   "accname/description_from_content_of_describedby_element-manual-expected.txt": [
@@ -252642,11 +252601,11 @@
    "testharness"
   ],
   "background-fetch/interfaces-expected.txt": [
-   "b6cf948689a9c2aab5d953b2976febda0e8b3344",
+   "74aa2d04a6e984b6bad2d68d55dcdbcd44643c56",
    "support"
   ],
   "background-fetch/interfaces-worker.https-expected.txt": [
-   "472a8ea0508cf94040e3a123395a463cf5538353",
+   "158cb7ebe2c6aca027f11d631c5b719f51a3f739",
    "support"
   ],
   "background-fetch/interfaces-worker.https.html": [
@@ -252654,7 +252613,7 @@
    "testharness"
   ],
   "background-fetch/interfaces.html": [
-   "d95f416256134d8c4e50946c39668849c7f66298",
+   "dc48b3e0bff00fed4a0e846e35f2499d6579dcd8",
    "testharness"
   ],
   "background-fetch/interfaces.worker-expected.txt": [
@@ -252662,7 +252621,7 @@
    "support"
   ],
   "background-fetch/interfaces.worker.js": [
-   "b1c9c41179028dc432b3a1bb988df4b23b3105af",
+   "c1f72ff423ec67b8400ce233a6ede945b8d262eb",
    "testharness"
   ],
   "background-fetch/mixed-content-and-allowed-schemes.https.window.js": [
@@ -253013,7 +252972,7 @@
    "b8749e25c58da9a903feb5edc84c2d6ed8ebda67",
    "support"
   ],
-  "bluetooth/idl/idl-Bluetooth.html": [
+  "bluetooth/idl/idl-Bluetooth.https.html": [
    "9ef91a8214b3a46278d8b9b442b34d9052342342",
    "testharness"
   ],
@@ -253697,12 +253656,8 @@
    "29571a481e6d9fbbef55c7e0731280f08af5ac93",
    "support"
   ],
-  "clipboard-apis/async-interfaces.https-expected.txt": [
-   "cc28a931a8cf5e62b2f83f4f3ace508677499749",
-   "support"
-  ],
   "clipboard-apis/async-interfaces.https.html": [
-   "f0b8b999ac1a99d956fcfdd3ee52b4875d453974",
+   "ffc8726b7afa6dc3e58745bd0dac525a570970ef",
    "testharness"
   ],
   "clipboard-apis/async-navigator-clipboard-basics.https.html": [
@@ -255950,7 +255905,7 @@
    "testharness"
   ],
   "content-security-policy/securitypolicyviolation/idl.html": [
-   "fb8f2938d76a29cc68c46fb49a12feebc0031e54",
+   "29c68c73b221ec65466645dfa5e9ecc1f2a0f007",
    "testharness"
   ],
   "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html": [
@@ -256654,7 +256609,7 @@
    "testharness"
   ],
   "cookie-store/idlharness.tentative.html": [
-   "8654087597cc0c11b880b0144897dab26691d12a",
+   "2a588a0b80a3cee80af52b9109770fe8ec17becd",
    "testharness"
   ],
   "cookie-store/idlharness_serviceworker.js": [
@@ -274390,11 +274345,11 @@
    "reftest"
   ],
   "css/css-backgrounds/css3-background-origin-padding-box.html": [
-   "ac859dfb47379cca21e83b196db3224cef3cde9f",
+   "96e3a35dff509a2409b7b802c770d38a338c7a39",
    "reftest"
   ],
   "css/css-backgrounds/css3-background-size-001.html": [
-   "a11a88981efe0379dc0158adff4e0cc98909a17c",
+   "0b5430700b89540f9ca5d6989ea82d5e286c1d74",
    "reftest"
   ],
   "css/css-backgrounds/css3-background-size-contain.html": [
@@ -300450,7 +300405,7 @@
    "support"
   ],
   "css/css-timing/cubic-bezier-timing-functions-output.html": [
-   "77a45437209844f7e5128bd6aa2efeeacf876187",
+   "2d60e1bcdad1f454373ecde2367bb9a9a223cd12",
    "testharness"
   ],
   "css/css-timing/frames-timing-functions-output.html": [
@@ -316798,7 +316753,7 @@
    "support"
   ],
   "css/cssom-view/interfaces.html": [
-   "d74bbaf34040d130444915b4432c529a73d9604c",
+   "0cecd644b3363618acd1496865578a15306e18fe",
    "testharness"
   ],
   "css/cssom-view/matchMedia.xht": [
@@ -317302,7 +317257,7 @@
    "support"
   ],
   "css/cssom/interfaces.html": [
-   "c1dfd96239986c9c57d7b07caebbd1fc9654e0b9",
+   "de0fd22930a606a17da15291ca14321463316f11",
    "testharness"
   ],
   "css/cssom/medialist-dynamic-001-ref.html": [
@@ -327006,7 +326961,7 @@
    "testharness"
   ],
   "encrypted-media/idlharness.https.html": [
-   "49b0c8508501b73ba979f7c86ebcc40de0073caf",
+   "29f3c9774b623413c4127ea0e5a915e67f24cd24",
    "testharness"
   ],
   "encrypted-media/polyfill/cast-polyfill.js": [
@@ -329950,7 +329905,7 @@
    "support"
   ],
   "gamepad/idlharness.html": [
-   "302f0796746f252a1a851d306d7e96cf86d7d402",
+   "acf9bec9b03479458c4b8b17a1d4ef9f87d15d7b",
    "testharness"
   ],
   "generic-sensor/OWNERS": [
@@ -330126,7 +330081,7 @@
    "support"
   ],
   "geolocation-sensor/idlharness.https.html": [
-   "8e22460ccb5e31bdcf9c9d3fc135abc55345e7ab",
+   "38c75b8946de5be961435045007b8af9a4627cd2",
    "testharness"
   ],
   "graphics-aam/graphics-document_on_html_element-manual-expected.txt": [
@@ -330230,7 +330185,7 @@
    "support"
   ],
   "gyroscope/idlharness.https.html": [
-   "c6c627cc2e250664e174edf90aa9b402ea5c0500",
+   "8b9b8fcdc6d33fb20c174b67306a182bdbb707fd",
    "testharness"
   ],
   "hr-time/OWNERS": [
@@ -330241,12 +330196,8 @@
    "5c727eed4efd84b4b280b2584b7338217971a9e7",
    "testharness"
   ],
-  "hr-time/idlharness-expected.txt": [
-   "e064a696afab015c130966f2d5a389572f978543",
-   "support"
-  ],
   "hr-time/idlharness.html": [
-   "579176cad14656ca5cdc616dd1323dc38a5b62ba",
+   "17353579d4224ac08fd90453fd065acee56d7621",
    "testharness"
   ],
   "hr-time/monotonic-clock.any.js": [
@@ -332077,7 +332028,7 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
-  "html/browsers/offline/appcache/workers/appcache-worker.html": [
+  "html/browsers/offline/appcache/workers/appcache-worker.https.html": [
    "d4dc559a600b1d197e7b31f960b396da3faa4e42",
    "testharness"
   ],
@@ -332109,39 +332060,43 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
-  "html/browsers/offline/application-cache-api/api_status_idle.html": [
+  "html/browsers/offline/application-cache-api/api_status_idle.https.html": [
    "b93f97a03166e627a13acf64a3a540501f375c2e",
    "testharness"
   ],
-  "html/browsers/offline/application-cache-api/api_status_uncached.html": [
+  "html/browsers/offline/application-cache-api/api_status_uncached.https.html": [
    "52685e57f8b19694baae135c5adc9f5385d23ead",
    "testharness"
   ],
-  "html/browsers/offline/application-cache-api/api_swapcache_error.html": [
+  "html/browsers/offline/application-cache-api/api_swapcache_error.https.html": [
    "43bd16e925b002e4bc562326b4d2fc00aeb3b933",
    "testharness"
   ],
-  "html/browsers/offline/application-cache-api/api_update-expected.txt": [
+  "html/browsers/offline/application-cache-api/api_update.https-expected.txt": [
    "d3ef10552fd83d25fb151b71fe6a2ca9c817f133",
    "support"
   ],
-  "html/browsers/offline/application-cache-api/api_update.html": [
+  "html/browsers/offline/application-cache-api/api_update.https.html": [
    "99e4b5d9ebec73a932fe522aceece7fb3b94ef26",
    "testharness"
   ],
-  "html/browsers/offline/application-cache-api/api_update_error.html": [
+  "html/browsers/offline/application-cache-api/api_update_error.https.html": [
    "a08540b1a71a7512a8b9cc2b0af28fd5c64bfe25",
    "testharness"
   ],
+  "html/browsers/offline/application-cache-api/secure_context.html": [
+   "fd1eea1cc64dcc5d816545ac3420351d5e8cb317",
+   "testharness"
+  ],
   "html/browsers/offline/browser-state/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
-  "html/browsers/offline/browser-state/navigator_online_event-manual.html": [
+  "html/browsers/offline/browser-state/navigator_online_event-manual.https.html": [
    "6ad5311783547501b80d05eea9b7a414348b151a",
    "manual"
   ],
-  "html/browsers/offline/browser-state/navigator_online_online.html": [
+  "html/browsers/offline/browser-state/navigator_online_online.https.html": [
    "a06d993d34908fb332aca34a3a2002a917db9ee5",
    "testharness"
   ],
@@ -332173,39 +332128,39 @@
    "c63851b0649b98d8aa06fd82934ca8356ffa13f0",
    "support"
   ],
-  "html/browsers/offline/introduction-4/event_cached.html": [
+  "html/browsers/offline/introduction-4/event_cached.https.html": [
    "5bb7aeb2bdc2223966fc507feb1abbee6d3b8aa9",
    "testharness"
   ],
-  "html/browsers/offline/introduction-4/event_checking.html": [
+  "html/browsers/offline/introduction-4/event_checking.https.html": [
    "c54edd9e042e00ee5d9929c54748e2eb55cdfabf",
    "testharness"
   ],
-  "html/browsers/offline/introduction-4/event_noupdate.html": [
+  "html/browsers/offline/introduction-4/event_noupdate.https.html": [
    "2f93ca32a46957612008705bdea4a63c04e73c17",
    "testharness"
   ],
-  "html/browsers/offline/introduction-4/event_progress.html": [
+  "html/browsers/offline/introduction-4/event_progress.https.html": [
    "1558fa802305fe5238fac58f47203f901805ea53",
    "testharness"
   ],
-  "html/browsers/offline/manifest_main_empty-manual.html": [
+  "html/browsers/offline/manifest_main_empty-manual.https.html": [
    "92ec1cd83c5a9509d19763f33720aa256e199ce2",
    "manual"
   ],
-  "html/browsers/offline/manifest_notchanged_online-manual.html": [
+  "html/browsers/offline/manifest_notchanged_online-manual.https.html": [
    "f3228a9349a536ece39789a6625eb2d53444181a",
    "manual"
   ],
-  "html/browsers/offline/manifest_section_empty-manual.html": [
+  "html/browsers/offline/manifest_section_empty-manual.https.html": [
    "da1aff7c25acc12be27193a52b5c173e2ddcf87b",
    "manual"
   ],
-  "html/browsers/offline/manifest_section_many-manual.html": [
+  "html/browsers/offline/manifest_section_many-manual.https.html": [
    "54c51d8c86cc5378ebde985570dca89c20a24fa0",
    "manual"
   ],
-  "html/browsers/offline/manifest_url_check.html": [
+  "html/browsers/offline/manifest_url_check.https.https.html": [
    "0959d9811748aa674d4863bd31a5cca2d2db0d15",
    "testharness"
   ],
@@ -332217,7 +332172,7 @@
    "f844a4d122bf6a46e2ccd4725483a72f8ebb9f42",
    "support"
   ],
-  "html/browsers/offline/no-appcache-in-shared-workers-historical.html": [
+  "html/browsers/offline/no-appcache-in-shared-workers-historical.https.html": [
    "2c48e76225b084b3a13b7d9f52c95a98463e4bee",
    "testharness"
   ],
@@ -332265,11 +332220,11 @@
    "302b651285dd9e4367a90ce48070a3854ad3d0a2",
    "support"
   ],
-  "html/browsers/offline/section_network_offline-manual.html": [
+  "html/browsers/offline/section_network_offline-manual.https.html": [
    "e63dc04a5b870d923689cc892168f0cd22b72405",
    "manual"
   ],
-  "html/browsers/offline/section_network_online-manual.html": [
+  "html/browsers/offline/section_network_online-manual.https.html": [
    "6a403d69ed90abeea5a4c61f6f09778224a5c184",
    "manual"
   ],
@@ -332705,12 +332660,12 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
-  "html/browsers/the-window-object/security-window/window-security-expected.txt": [
-   "55446512a7bb2d7e0b2492aee6d93ed2d8f08324",
+  "html/browsers/the-window-object/security-window/window-security.https-expected.txt": [
+   "a033d653f2d9b0ddb3474f660fb7c83e37d73f16",
    "support"
   ],
-  "html/browsers/the-window-object/security-window/window-security.html": [
-   "a590848d52c2ed7d66e9889957d58828566717c1",
+  "html/browsers/the-window-object/security-window/window-security.https.html": [
+   "16f41760b88216c36fbdfba95d249cf99f33b8a3",
    "testharness"
   ],
   "html/browsers/the-window-object/support/noopener-target.html": [
@@ -332777,11 +332732,11 @@
    "2e20bfcd1dfe9bee00a9747b87cdaf42004d6415",
    "testharness"
   ],
-  "html/browsers/the-window-object/window-properties-expected.txt": [
-   "e8d73098d8e5147005babef8456df51cbb686977",
+  "html/browsers/the-window-object/window-properties.https-expected.txt": [
+   "f3ce1d8416df1174e77ecd1c78e08f082dab3581",
    "support"
   ],
-  "html/browsers/the-window-object/window-properties.html": [
+  "html/browsers/the-window-object/window-properties.https.html": [
    "ee0ade0a8de422597c362d15cf4a9dd446e4af00",
    "testharness"
   ],
@@ -333897,11 +333852,11 @@
    "1c813722dd68b1a13348aa8071d99cf358ab9eca",
    "testharness"
   ],
-  "html/dom/dynamic-markup-insertion/opening-the-input-stream/009-expected.txt": [
+  "html/dom/dynamic-markup-insertion/opening-the-input-stream/009.https-expected.txt": [
    "37c7df8f30a22219c493917e16ddea0405088e27",
    "support"
   ],
-  "html/dom/dynamic-markup-insertion/opening-the-input-stream/009.html": [
+  "html/dom/dynamic-markup-insertion/opening-the-input-stream/009.https.html": [
    "02278f0ed00b2392afcbcacd56ddd750b7204241",
    "testharness"
   ],
@@ -334865,12 +334820,12 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
-  "html/dom/interfaces-expected.txt": [
-   "5199c193d81b05bcccb06b31f023389650484b1f",
+  "html/dom/interfaces.https-expected.txt": [
+   "b10103421e93b085dd29e364926a481b9f8e5972",
    "support"
   ],
-  "html/dom/interfaces.html": [
-   "c937f2d908ecfae269b95ade6c830414acf0a005",
+  "html/dom/interfaces.https.html": [
+   "80050746d7869d52bfe7926fa259300ce05db79e",
    "testharness"
   ],
   "html/dom/interfaces.worker-expected.txt": [
@@ -338561,6 +338516,10 @@
    "e41cfdeaf3e9ddeed0450298212443bfcad8298d",
    "testharness"
   ],
+  "html/editing/focus/focus-02.html": [
+   "1280112041cf00a7d10c9414dca8c855f72f2c2b",
+   "testharness"
+  ],
   "html/editing/focus/focus-management/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
@@ -347881,10 +347840,6 @@
    "c28a2e25288ef685cbcba11493a5eab7d5ede9a5",
    "support"
   ],
-  "html/semantics/text-level-semantics/the-a-element/a-download-click-404-expected.txt": [
-   "621908ef7e399b8129bc3db3491cfc522b6a4141",
-   "support"
-  ],
   "html/semantics/text-level-semantics/the-a-element/a-download-click-404.html": [
    "a5368cce11f6fcaf4d220fabe17685ca1cc4953d",
    "testharness"
@@ -350618,7 +350573,7 @@
    "support"
   ],
   "magnetometer/idlharness.https.html": [
-   "2a08a46bc2fa6e5b75c3c05c0396b48280075892",
+   "d5ba7fe95ed2740eec56757dfe3b0a900f3ea4c4",
    "testharness"
   ],
   "media-capabilities/OWNERS": [
@@ -351278,11 +351233,11 @@
    "support"
   ],
   "mediacapture-record/idlharness-expected.txt": [
-   "4047129823877b8386e21cf3c290c4abf8596597",
+   "d4763e580815724eb26e9d5a27aacd2065f280fd",
    "support"
   ],
   "mediacapture-record/idlharness.html": [
-   "d96f50512a47fed449151b716d838ac10d23f47f",
+   "99adc299359aad8cdd4f08ba920dde780bd06063",
    "testharness"
   ],
   "mediacapture-streams/GUM-api.https.html": [
@@ -351318,11 +351273,11 @@
    "testharness"
   ],
   "mediacapture-streams/MediaDevices-IDL-all-expected.txt": [
-   "1e4453398efb9372ae072f3a5b87758133e47292",
+   "63000ec3c8cfd3c0f0c2195e2a702e25188295dd",
    "support"
   ],
   "mediacapture-streams/MediaDevices-IDL-all.html": [
-   "2d9b604f3039fd5bebbe0491f0bb31d5b0b47722",
+   "42f245551c0d64377f949efda4cfad4934323b48",
    "testharness"
   ],
   "mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt": [
@@ -351330,7 +351285,7 @@
    "support"
   ],
   "mediacapture-streams/MediaDevices-IDL-enumerateDevices.html": [
-   "8382c7e6be38bad808be950b14d80fe59513ff0d",
+   "cea6395d985eadd8340a4f3d64df2bb266a7f793",
    "testharness"
   ],
   "mediacapture-streams/MediaDevices-enumerateDevices.https.html": [
@@ -353029,12 +352984,8 @@
    "b5f72095f600b8a840c0b3d8048e863ab5fbf215",
    "support"
   ],
-  "navigation-timing/nav2_idlharness-expected.txt": [
-   "5ae0a0da40fe33e7b09d2b4d4143b733287b8c1d",
-   "support"
-  ],
   "navigation-timing/nav2_idlharness.html": [
-   "ffc5d6f4a11a4bf2ad72404fc62d88be1c45a5f5",
+   "935c963cbec9f000ea0564a0e0c4ce872da40ea8",
    "testharness"
   ],
   "navigation-timing/nav2_test_attributes_exist.html": [
@@ -359502,7 +359453,7 @@
    "support"
   ],
   "orientation-sensor/idlharness.https.html": [
-   "05a95e835ce72800601fcd18007eaec0c05dc79a",
+   "1f94329cb330a1a904d409a6e158a5fe9f8dd709",
    "testharness"
   ],
   "page-visibility/OWNERS": [
@@ -359686,11 +359637,11 @@
    "support"
   ],
   "payment-handler/interfaces.https.any.js": [
-   "66f067e3988546afc0796dcbc276b04b5a5615fc",
+   "4d1e2360e69d2c2f1664e73a79c1d893c6ee10fb",
    "testharness"
   ],
   "payment-handler/interfaces.https.any.worker-expected.txt": [
-   "b9567acc565acb84bb9ef84eb13b1f7f9671fcc8",
+   "3b98367c319505acf40aa79361394c0585d11a02",
    "support"
   ],
   "payment-handler/manifest.json": [
@@ -359913,10 +359864,6 @@
    "34dd889e8bc906eb9a99c192e547fab831099f7c",
    "testharness"
   ],
-  "payment-request/payment-request-insecure.http-expected.txt": [
-   "b97d187511f905c5a7573693c53e13f3475534ed",
-   "support"
-  ],
   "payment-request/payment-request-insecure.http.html": [
    "34452230c20571ef161fa237130faea57240f532",
    "testharness"
@@ -360166,7 +360113,7 @@
    "manual"
   ],
   "pointerevents/extension/idlharness.html": [
-   "83ee5397ece0126d71c235cecb554b024e3515d1",
+   "c1ee780b59d596535e697db237a3af3aa019b2f7",
    "testharness"
   ],
   "pointerevents/extension/pointerevent_coalesced_events_attributes-manual-expected.txt": [
@@ -360206,7 +360153,7 @@
    "manual"
   ],
   "pointerevents/idlharness.html": [
-   "7db1757e519a8ebb9123dd150f17bf5c6f23e311",
+   "ee6982f1735711a9ac3c8c3a1447eb96f8e8d61c",
    "testharness"
   ],
   "pointerevents/pointerevent_attributes_hoverable_pointers-manual.html": [
@@ -368494,7 +368441,7 @@
    "testharness"
   ],
   "remote-playback/idlharness.html": [
-   "70cfb1603b69e1daff48682cf41e746221158a55",
+   "5a780e9fcdc2215b4f5fb9d81347ef804ed88f71",
    "testharness"
   ],
   "remote-playback/watch-availability-initial-callback.html": [
@@ -370702,19 +370649,15 @@
    "testharness"
   ],
   "service-workers/service-worker/interfaces-sw.https-expected.txt": [
-   "3b7144f638df25c1c7b0bd36635faf86b88d8d64",
+   "5dc8613c6e57e7b782383eb841b72cfac3bd1ad8",
    "support"
   ],
   "service-workers/service-worker/interfaces-sw.https.html": [
    "c6ea8c330c7886581ba57314cc65a707b25b44f3",
    "testharness"
   ],
-  "service-workers/service-worker/interfaces-window.https-expected.txt": [
-   "ef73ed497362ccd78a82cd47ce7000eb18182f58",
-   "support"
-  ],
   "service-workers/service-worker/interfaces-window.https.html": [
-   "5c604b248656dae755f0b4107c6ab4f19f3e5c08",
+   "10b0dbc64783f88e5d990a1fdab35d06416d6f86",
    "testharness"
   ],
   "service-workers/service-worker/invalid-blobtype.https.html": [
@@ -371574,7 +371517,7 @@
    "support"
   ],
   "service-workers/service-worker/resources/interfaces-worker.sub.js": [
-   "1e30c1df9970486b5dea379f2430a871d5f270ed",
+   "1b783078b34532a0f8236a964e77eb1f5836af6a",
    "support"
   ],
   "service-workers/service-worker/resources/invalid-blobtype-iframe.https.html": [
@@ -376222,7 +376165,7 @@
    "testharness"
   ],
   "web-animations/interfaces/Animatable/animate-expected.txt": [
-   "9e83cf9fad363d76e829ad098b333e37247572f2",
+   "fc25345ab338b9eb3076f607e76a53f2e7ffef98",
    "support"
   ],
   "web-animations/interfaces/Animatable/animate-no-browsing-context-expected.txt": [
@@ -376237,18 +376180,10 @@
    "4cd816ad368f1dae077f601022f9b57d9cb931ae",
    "testharness"
   ],
-  "web-animations/interfaces/Animatable/getAnimations-expected.txt": [
-   "65cd4e69b57d415eeebf2dac2a4d4de76d1f8dcf",
-   "support"
-  ],
   "web-animations/interfaces/Animatable/getAnimations.html": [
    "a11049c78d2ca16a9df9d0f21b3a3d0fd35e29f3",
    "testharness"
   ],
-  "web-animations/interfaces/Animation/cancel-expected.txt": [
-   "f3b8e000f0f6b383c3742c4f8ea6aaf63a9a31c6",
-   "support"
-  ],
   "web-animations/interfaces/Animation/cancel.html": [
    "105313dffbe7953ca6b413e860ba8b47e316e0b7",
    "testharness"
@@ -376266,7 +376201,7 @@
    "testharness"
   ],
   "web-animations/interfaces/Animation/finished-expected.txt": [
-   "3f9f416b1976aae8b2cccde1778139234f5c5c85",
+   "bbf5319f8bf5d347fa37c9ca885133bdef7380e8",
    "support"
   ],
   "web-animations/interfaces/Animation/finished.html": [
@@ -376325,10 +376260,6 @@
    "e0d4ba4c0f1a5da4d126c501eca733e00adbef1a",
    "testharness"
   ],
-  "web-animations/interfaces/AnimationEffect/updateTiming-expected.txt": [
-   "a7182805f6450e1efd7e99c4c1cf8294d264a51d",
-   "support"
-  ],
   "web-animations/interfaces/AnimationEffect/updateTiming.html": [
    "5daa5580c2d34e992f3560bf5b85419498b6c5ee",
    "testharness"
@@ -376366,17 +376297,13 @@
    "testharness"
   ],
   "web-animations/interfaces/KeyframeEffect/constructor-expected.txt": [
-   "5733d115900aa50624e04ac84051348ef8ade012",
+   "669fd5a80e13cf55598381b7a95999c6b3ba9ea1",
    "support"
   ],
   "web-animations/interfaces/KeyframeEffect/constructor.html": [
    "38ff2a4b64e7318fa96eb867aae7f25bed53e67b",
    "testharness"
   ],
-  "web-animations/interfaces/KeyframeEffect/copy-constructor-expected.txt": [
-   "74353cf40fdb42a530fbf516148268b4d61f1747",
-   "support"
-  ],
   "web-animations/interfaces/KeyframeEffect/copy-constructor.html": [
    "0e3d893d7b8e438b279f087846df596256ccbe84",
    "testharness"
@@ -376474,7 +376401,7 @@
    "testharness"
   ],
   "web-animations/timing-model/animation-effects/phases-and-states-expected.txt": [
-   "a99653f0b75182cc5406ff502f134e7522de7d24",
+   "dfd52899f36d48cd23e8323b04d359be59c8b1f3",
    "support"
   ],
   "web-animations/timing-model/animation-effects/phases-and-states.html": [
@@ -376810,7 +376737,7 @@
    "support"
   ],
   "webaudio/idlharness.https.html": [
-   "2951a126a8b168e6fe4699890d5a3c4772c7f960",
+   "9863249e71e4855b50c1712c3155d2d4a05fa1fe",
    "testharness"
   ],
   "webaudio/js/buffer-loader.js": [
@@ -377170,7 +377097,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-delaynode-interface/idl-test.html": [
-   "8507a293b696d2d3fc51b429864373606a75eeb6",
+   "4f75f58d7286231e48236d1736e5739b8007502e",
    "testharness"
   ],
   "webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html": [
@@ -377202,7 +377129,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-gainnode-interface/idl-test.html": [
-   "30843d3b74e8ec33bedd849f3f2b1bbd4bcc9f5e",
+   "a2abc80981a4f6ec810850150cdcd149854daf4b",
    "testharness"
   ],
   "webaudio/the-audio-api/the-gainnode-interface/no-dezippering.html": [
@@ -377477,12 +377404,8 @@
    "472ce38374096ae334fe7a6b0a58457654ce3a77",
    "support"
   ],
-  "webauthn/interfaces.https.any-expected.txt": [
-   "339f20c89e47d9fc75fef8aeb319b45c3a95aa40",
-   "support"
-  ],
   "webauthn/interfaces.https.any.js": [
-   "bc3e3c5a85f068efa88c4ed256cc2d270c8eca0f",
+   "3ca7a0855f38bf8d0250d0a352dd60c2ee6515fa",
    "testharness"
   ],
   "webauthn/securecontext.http.html": [
@@ -379742,7 +379665,7 @@
    "support"
   ],
   "webstorage/idlharness.html": [
-   "e57413a1868e8d84ba7c500ff13b7e68675cbe66",
+   "cb4ee5af9381129c483e97925eab309cc41a2fa0",
    "testharness"
   ],
   "webstorage/missing_arguments.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/accelerometer/idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/accelerometer/idlharness.https.html
index 3c3c96e..1f32be9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/accelerometer/idlharness.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/accelerometer/idlharness.https.html
@@ -15,7 +15,7 @@
   const idl_array = new IdlArray();
   idl_array.add_untested_idls(dom);
   idl_array.add_untested_idls('interface EventHandler {};');
-  idl_array.add_idls(generic_sensor, { only: ['Sensor'] });
+  idl_array.add_idls(generic_sensor, { only: ['Sensor', 'SensorOptions'] });
   idl_array.add_idls(accelerometer);
   idl_array.add_objects({
     Accelerometer: ['new Accelerometer();'],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces-expected.txt
index dbd51c5..ca96873 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 70 tests; 52 PASS, 18 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 70 tests; 54 PASS, 16 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Exposed interfaces in a Document.
 PASS ServiceWorkerRegistration interface: attribute backgroundFetch
 PASS Unscopable handled correctly for backgroundFetch property on ServiceWorkerRegistration
@@ -16,10 +16,10 @@
 PASS Unscopable handled correctly for get(DOMString) on BackgroundFetchManager
 PASS BackgroundFetchManager interface: operation getIds()
 PASS Unscopable handled correctly for getIds() on BackgroundFetchManager
-FAIL BackgroundFetchRegistration interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS BackgroundFetchRegistration interface: existence and properties of interface object
 PASS BackgroundFetchRegistration interface object length
 PASS BackgroundFetchRegistration interface object name
-FAIL BackgroundFetchRegistration interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object
 PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's "constructor" property
 PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's @@unscopables property
 PASS BackgroundFetchRegistration interface: attribute id
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces-worker.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces-worker.https-expected.txt
index 9831c3d5..62fda83 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces-worker.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces-worker.https-expected.txt
@@ -10,6 +10,7 @@
 PASS Unscopable handled correctly for onbackgroundfetchabort property on ServiceWorkerGlobalScope
 FAIL ServiceWorkerGlobalScope interface: attribute onbackgroundfetchclick assert_true: The prototype object must have a property "onbackgroundfetchclick" expected true got false
 PASS Unscopable handled correctly for onbackgroundfetchclick property on ServiceWorkerGlobalScope
+FAIL ExtendableEvent interface: existence and properties of interface object assert_false: expected false got true
 PASS BackgroundFetchManager interface: existence and properties of interface object
 PASS BackgroundFetchManager interface object length
 PASS BackgroundFetchManager interface object name
@@ -22,10 +23,10 @@
 PASS Unscopable handled correctly for get(DOMString) on BackgroundFetchManager
 PASS BackgroundFetchManager interface: operation getIds()
 PASS Unscopable handled correctly for getIds() on BackgroundFetchManager
-FAIL BackgroundFetchRegistration interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS BackgroundFetchRegistration interface: existence and properties of interface object
 PASS BackgroundFetchRegistration interface object length
 PASS BackgroundFetchRegistration interface object name
-FAIL BackgroundFetchRegistration interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object
 PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's "constructor" property
 PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's @@unscopables property
 PASS BackgroundFetchRegistration interface: attribute id
@@ -70,10 +71,10 @@
 FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
 FAIL BackgroundFetchActiveFetch interface: attribute responseReady assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
 PASS Unscopable handled correctly for responseReady property on BackgroundFetchActiveFetch
-FAIL BackgroundFetchEvent interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS BackgroundFetchEvent interface: existence and properties of interface object
 PASS BackgroundFetchEvent interface object length
 PASS BackgroundFetchEvent interface object name
-FAIL BackgroundFetchEvent interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS BackgroundFetchEvent interface: existence and properties of interface prototype object
 PASS BackgroundFetchEvent interface: existence and properties of interface prototype object's "constructor" property
 PASS BackgroundFetchEvent interface: existence and properties of interface prototype object's @@unscopables property
 PASS BackgroundFetchEvent interface: attribute id
@@ -115,7 +116,7 @@
 PASS BackgroundFetchClickEvent interface: existence and properties of interface object
 PASS BackgroundFetchClickEvent interface object length
 PASS BackgroundFetchClickEvent interface object name
-FAIL BackgroundFetchClickEvent interface: existence and properties of interface prototype object Cannot read property 'has_stringifier' of undefined
+PASS BackgroundFetchClickEvent interface: existence and properties of interface prototype object
 PASS BackgroundFetchClickEvent interface: existence and properties of interface prototype object's "constructor" property
 PASS BackgroundFetchClickEvent interface: existence and properties of interface prototype object's @@unscopables property
 PASS BackgroundFetchClickEvent interface: attribute state
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces.html b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces.html
index f512e45..51e320e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces.html
@@ -12,15 +12,17 @@
 <script>
 'use strict';
 
-promise_test(function() {
-  return fetch('/interfaces/background-fetch.idl')
-    .then(response => response.text())
-    .then(idls => {
-      var idlArray = new IdlArray();
-      idlArray.add_untested_idls('interface ServiceWorkerRegistration {};');
-      idlArray.add_untested_idls('[Exposed=ServiceWorker] interface ServiceWorkerGlobalScope {};');
-      idlArray.add_idls(idls);
-      idlArray.test();
-    });
+promise_test(async function () {
+  const idls = await fetch('/interfaces/background-fetch.idl').then(r => r.text());
+  const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
+
+  var idlArray = new IdlArray();
+  idlArray.add_untested_idls('interface ServiceWorkerRegistration {};');
+  idlArray.add_untested_idls('[Exposed=ServiceWorker] interface ServiceWorkerGlobalScope {};');
+  idlArray.add_untested_idls('interface ExtendableEvent{};');
+  idlArray.add_untested_idls('dictionary ExtendableEventInit{};');
+  idlArray.add_untested_idls(dom, { only: ['EventTarget'] });
+  idlArray.add_idls(idls);
+  idlArray.test();
 }, 'Exposed interfaces in a Document.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces.worker.js b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces.worker.js
index 89a7cb3d..9b8d0264 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces.worker.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/interfaces.worker.js
@@ -3,16 +3,18 @@
 importScripts('/resources/testharness.js');
 importScripts('/resources/WebIDLParser.js', '/resources/idlharness.js');
 
-promise_test(function() {
-  return fetch('/interfaces/background-fetch.idl')
-    .then(response => response.text())
-    .then(idls => {
-      var idlArray = new IdlArray();
-      idlArray.add_untested_idls('interface ServiceWorkerRegistration {};');
-      idlArray.add_untested_idls('[Exposed=ServiceWorker] interface ServiceWorkerGlobalScope {};');
-      idlArray.add_idls(idls);
-      idlArray.test();
-    });
+promise_test(async function() {
+  const idls = await fetch('/interfaces/background-fetch.idl').then(r => r.text());
+  const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
+
+  var idlArray = new IdlArray();
+  idlArray.add_untested_idls('interface ServiceWorkerRegistration {};');
+  idlArray.add_untested_idls('[Exposed=ServiceWorker] interface ServiceWorkerGlobalScope {};');
+  idlArray.add_untested_idls('interface ExtendableEvent{};');
+  idlArray.add_untested_idls('dictionary ExtendableEventInit{};');
+  idlArray.add_untested_idls(dom, { only: ['EventTarget'] });
+  idlArray.add_idls(idls);
+  idlArray.test();
 }, 'Exposed interfaces in a Service Worker.');
 
 done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/clipboard-apis/async-interfaces.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/clipboard-apis/async-interfaces.https-expected.txt
deleted file mode 100644
index b31ecfc3..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/clipboard-apis/async-interfaces.https-expected.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-This is a testharness.js-based test.
-PASS Test driver
-PASS Navigator interface: attribute clipboard
-PASS Unscopable handled correctly for clipboard property on Navigator
-PASS Navigator interface: navigator must inherit property "clipboard" with the proper type
-FAIL ClipboardEvent interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
-PASS ClipboardEvent interface object length
-PASS ClipboardEvent interface object name
-FAIL ClipboardEvent interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
-PASS ClipboardEvent interface: existence and properties of interface prototype object's "constructor" property
-PASS ClipboardEvent interface: existence and properties of interface prototype object's @@unscopables property
-PASS ClipboardEvent interface: attribute clipboardData
-PASS Unscopable handled correctly for clipboardData property on ClipboardEvent
-PASS ClipboardEvent must be primary interface of new ClipboardEvent("x")
-FAIL Stringification of new ClipboardEvent("x") Cannot read property 'has_stringifier' of undefined
-PASS ClipboardEvent interface: new ClipboardEvent("x") must inherit property "clipboardData" with the proper type
-PASS Clipboard interface: existence and properties of interface object
-PASS Clipboard interface object length
-PASS Clipboard interface object name
-PASS Clipboard interface: existence and properties of interface prototype object
-PASS Clipboard interface: existence and properties of interface prototype object's "constructor" property
-PASS Clipboard interface: existence and properties of interface prototype object's @@unscopables property
-PASS Clipboard interface: operation read()
-PASS Unscopable handled correctly for read() on Clipboard
-PASS Clipboard interface: operation readText()
-PASS Unscopable handled correctly for readText() on Clipboard
-PASS Clipboard interface: operation write(DataTransfer)
-PASS Unscopable handled correctly for write(DataTransfer) on Clipboard
-PASS Clipboard interface: operation writeText(DOMString)
-PASS Unscopable handled correctly for writeText(DOMString) on Clipboard
-PASS Clipboard must be primary interface of navigator.clipboard
-PASS Stringification of navigator.clipboard
-PASS Clipboard interface: navigator.clipboard must inherit property "read()" with the proper type
-PASS Clipboard interface: navigator.clipboard must inherit property "readText()" with the proper type
-PASS Clipboard interface: navigator.clipboard must inherit property "write(DataTransfer)" with the proper type
-PASS Clipboard interface: calling write(DataTransfer) on navigator.clipboard with too few arguments must throw TypeError
-PASS Clipboard interface: navigator.clipboard must inherit property "writeText(DOMString)" with the proper type
-PASS Clipboard interface: calling writeText(DOMString) on navigator.clipboard with too few arguments must throw TypeError
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/clipboard-apis/async-interfaces.https.html b/third_party/WebKit/LayoutTests/external/wpt/clipboard-apis/async-interfaces.https.html
index d69fb70..1f523e5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/clipboard-apis/async-interfaces.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/clipboard-apis/async-interfaces.https.html
@@ -9,13 +9,13 @@
 <script>
 'use strict';
 
-function doTest(idls) {
+function doTest(idl, dom) {
   var idl_array = new IdlArray();
   idl_array.add_untested_idls('interface Navigator {};');
   idl_array.add_untested_idls('interface EventTarget {};');
-  for (let idl of idls) {
-    idl_array.add_idls(idl);
-  }
+  idl_array.add_untested_idls('dictionary PermissionDescriptor {};');
+  idl_array.add_untested_idls(dom, { only: ['Event', 'EventInit'] });
+  idl_array.add_idls(idl);
   idl_array.add_objects({
     Navigator: ['navigator'],
     Clipboard: ['navigator.clipboard'],
@@ -29,7 +29,11 @@
 }
 
 promise_test(() => {
-  return Promise.all(["/interfaces/clipboard-apis.idl"].map(fetchText))
-    .then(doTest);
+  return Promise.all(
+    [
+      "/interfaces/clipboard-apis.idl",
+      "/interfaces/dom.idl",
+    ].map(fetchText))
+    .then(([idl, dom]) => doTest(idl, dom));
 }, "Test driver");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/idl.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/idl.html
index a4f9e68..2853b868e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/idl.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/idl.html
@@ -21,9 +21,6 @@
       long           lineNumber;
       long           columnNumber;
   };
-
-  interface Event {
-  };
 </script>
 <script type="text/plain" id="tested">
   [Constructor(DOMString type, optional SecurityPolicyViolationEventInit eventInitDict)]
@@ -42,11 +39,16 @@
   };
 </script>
 <script>
+  promise_test(async function() {
+    let dom = await fetch('/interfaces/dom.idl').then(r => r.text());
+
     var idl_array = new IdlArray();
     idl_array.add_untested_idls(document.querySelector('#untested').textContent);
+    idl_array.add_untested_idls(dom, { only: ['Event', 'EventInit'] });
     idl_array.add_idls(document.querySelector('#tested').textContent);
     idl_array.add_objects({
-      SecurityPolicyViolationEvent: ['new SecurityPolicyViolationEvent({})']      
+      SecurityPolicyViolationEvent: ['new SecurityPolicyViolationEvent({})']
     });
     idl_array.test();
+  })
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/cookieStore_special_names.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/cookieStore_special_names.tentative.html
index 3a80f83..81b03d6c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/cookieStore_special_names.tentative.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/cookieStore_special_names.tentative.html
@@ -1,6 +1,6 @@
 <!doctype html>
 <meta charset="utf-8">
-<title>Async Cookies: cookieStore handles special cookie names correctly</title>
+<title>Cookie Store: cookieStore handles special cookie names correctly</title>
 <link rel="help" href="https://github.com/WICG/cookie-store">
 <link rel="author" href="pwnall@chromium.org" title="Victor Costan">
 <script src="/resources/testharness.js"></script>
@@ -8,28 +8,64 @@
 <script>
 'use strict';
 
-promise_test(async testCase => {
-  await promise_rejects(testCase, new TypeError(), cookieStore.set(
-      '__Secure-cookie-name', 'secure-cookie-value'));
+['__Secure-', '__Host-'].forEach(prefix => {
+  promise_test(async testCase => {
+    await promise_rejects(
+      testCase, new TypeError(),
+      cookieStore.set(`${prefix}cookie-name`, `secure-cookie-value`),
+      `Setting ${prefix} cookies should fail in non-secure contexts`);
 
-  try { await cookieStore.delete('__Secure-cookie-name'); } catch (e) {}
-}, 'cookieStore.set with __Secure- name on insecure origin');
+    try { await cookieStore.delete(`${prefix}cookie-name`); } catch (e) {}
+  }, `cookieStore.set with ${prefix} name on non-secure origin`);
 
-promise_test(async testCase => {
-  await promise_rejects(testCase, new TypeError(), cookieStore.set(
-      '__Host-cookie-name', 'host-cookie-value'));
+  promise_test(async testCase => {
+    await promise_rejects(
+      testCase, new TypeError(),
+      cookieStore.set(
+        `${prefix}cookie-name`, `secure-cookie-value`, {
+          expires: Date.now()
+        }),
+      `Setting expired ${prefix} cookies should fail in non-secure contexts`);
 
-  try { await cookieStore.delete('__Host-cookie-name'); } catch (e) {}
-}, 'cookieStore.set with __Host- name on insecure origin');
+    try { await cookieStore.delete(`${prefix}cookie-name`); } catch (e) {}
+  }, `cookieStore.set of expired ${prefix} cookie on non-secure origin`);
 
-promise_test(async testCase => {
-  await promise_rejects(testCase, new TypeError(), cookieStore.delete(
-      '__Secure-cookie-name', 'secure-cookie-value'));
-}, 'cookieStore.delete with __Secure- name on insecure origin');
+  promise_test(async testCase => {
+    assert_equals(
+      await cookieStore.get(`${prefix}cookie-name`),
+      null,
+      'get with ${prefix} prefix should not reject');
+    assert_equals(
+      await cookieStore.get({name: `${prefix}cookie-name`}),
+      null,
+      'get with ${prefix} prefix name option should not reject');
+    assert_equals(
+      await cookieStore.get({name: prefix, matchType: 'startsWith'}),
+      null,
+      'get with ${prefix} name and startsWith options should not reject');
+  }, `cookieStore.get with ${prefix} name on non-secure origin`);
 
-promise_test(async testCase => {
-  await promise_rejects(testCase, new TypeError(), cookieStore.delete(
-      '__Host-cookie-name', 'host-cookie-value'));
-}, 'cookieStore.delete with __Host- name on insecure origin');
+  promise_test(async testCase => {
+    assert_array_equals(
+      await cookieStore.getAll(`${prefix}cookie-name`),
+      [],
+      'getAll with ${prefix} prefix should not reject');
+    assert_array_equals(
+      await cookieStore.getAll({name: `${prefix}cookie-name`}),
+      [],
+      'getAll with ${prefix} prefix name option should not reject');
+    assert_array_equals(
+      await cookieStore.getAll({name: prefix, matchType: 'startsWith'}),
+      [],
+      'getAll with ${prefix} name and startsWith options should not reject');
+  }, `cookieStore.getAll with ${prefix} name on non-secure origin`);
+
+  promise_test(async testCase => {
+    await promise_rejects(
+      testCase, new TypeError(),
+      cookieStore.delete(`${prefix}cookie-name`, `host-cookie-value`),
+      `Deleting ${prefix} cookies should fail in non-secure contexts`);
+  }, `cookieStore.delete with ${prefix} name on non-secure origin`);
+});
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/cookieStore_special_names.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/cookieStore_special_names.tentative.https.html
new file mode 100644
index 0000000..2af701e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/cookieStore_special_names.tentative.https.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Cookie Store: cookieStore handles special cookie names correctly (secure context)</title>
+<link rel="help" href="https://github.com/WICG/cookie-store">
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+['__Secure-', '__Host-'].forEach(prefix => {
+  promise_test(async testCase => {
+    await cookieStore.set(`${prefix}cookie-name`, `secure-cookie-value`);
+    assert_equals(
+      (await cookieStore.get(`${prefix}cookie-name`)).value,
+      'secure-cookie-value',
+      `Setting ${prefix} cookies should not fail in secure context`);
+
+    try { await cookieStore.delete(`${prefix}cookie-name`); } catch (e) {}
+  }, `cookieStore.set with ${prefix} name on secure origin`);
+
+  promise_test(async testCase => {
+    await cookieStore.set(
+      `${prefix}cookie-name`, `secure-cookie-value`, {
+        expires: Date.now()
+      });
+    assert_equals(await cookieStore.get(`${prefix}cookie-name`), null);
+    try { await cookieStore.delete(`${prefix}cookie-name`); } catch (e) {}
+  }, `cookieStore.set of expired ${prefix} cookie name on secure origin`);
+
+  promise_test(async testCase => {
+    assert_equals(
+      await cookieStore.delete(`${prefix}cookie-name`), undefined,
+      `Deleting ${prefix} cookies should not fail in secure context`);
+  }, `cookieStore.delete with ${prefix} name on secure origin`);
+});
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness.tentative.html
index e9ffab37..e313b04 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness.tentative.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/idlharness.tentative.html
@@ -10,21 +10,38 @@
 'use strict';
 
 promise_test(async t => {
-  const urls = ['/interfaces/html.idl', '/interfaces/cookie-store.idl'];
-  const [html, cookie_store] = await Promise.all(
-    urls.map(url => fetch(url).then(response => response.text())));
+  const urls = [
+    '/interfaces/uievents.idl',
+    '/interfaces/dom.idl',
+    '/interfaces/html.idl',
+    '/interfaces/cookie-store.idl'
+  ];
+  const [uievents, dom, html, cookie_store] = await Promise.all(
+    urls.map(url => fetch(url).then(r => r.text())));
 
   const idl_array = new IdlArray();
 
   // Dependencies of HTML
+  idl_array.add_untested_idls(dom, { only: [
+    'Event',
+    'EventInit',
+    'EventTarget',
+    'HTMLCollection',
+    'NodeList',
+  ] });
   idl_array.add_untested_idls('interface Document {};');
+  idl_array.add_untested_idls('interface Element {};');
   idl_array.add_untested_idls('interface LinkStyle {};');
   idl_array.add_untested_idls('interface SVGElement {};');
   idl_array.add_untested_idls(html);
+  idl_array.add_untested_idls(uievents, { only: [
+    'UIEvent',
+    'UIEventInit',
+    'MouseEvent',
+    'MouseEventInit',
+    'EventModifierInit',
+  ] });
 
-  idl_array.add_untested_idls('interface Event {};');
-  idl_array.add_untested_idls('dictionary EventInit {};');
-  idl_array.add_untested_idls('interface EventTarget {};');
   idl_array.add_untested_idls(
     `[Global=ServiceWorker, Exposed=ServiceWorker]
      interface ServiceWorkerGlobalScope {};`);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/no_name_equals_in_value.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/no_name_equals_in_value.tentative-expected.txt
deleted file mode 100644
index 14c06d9d..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/no_name_equals_in_value.tentative-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Verify that attempting to set a cookie with no name and with '=' in the value does not work. assert_unreached: Should have rejected: Expected promise rejection when setting a cookie with no name and "=" in value Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/no_name_equals_in_value.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/no_name_equals_in_value.tentative.https-expected.txt
deleted file mode 100644
index 14c06d9d..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/no_name_equals_in_value.tentative.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Verify that attempting to set a cookie with no name and with '=' in the value does not work. assert_unreached: Should have rejected: Expected promise rejection when setting a cookie with no name and "=" in value Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/one_simple_origin_cookie.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/one_simple_origin_cookie.tentative.html
deleted file mode 100644
index b1d264cd..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/one_simple_origin_cookie.tentative.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Async Cookies: One simple origin cookie</title>
-<meta name="help" href="https://github.com/WICG/cookie-store/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/cookie-test-helpers.js"></script>
-<script src="resources/one_simple_origin_cookie.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/one_simple_origin_cookie.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/one_simple_origin_cookie.tentative.https.html
deleted file mode 100644
index 132d8ccb..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/one_simple_origin_cookie.tentative.https.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Async Cookies: One simple origin cookie (HTTPS)</title>
-<meta name="help" href="https://github.com/WICG/cookie-store/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/cookie-test-helpers.js"></script>
-<script src="resources/one_simple_origin_cookie.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/no_name_equals_in_value.js b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/no_name_equals_in_value.js
index 3dc73e8..b6cfab5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/no_name_equals_in_value.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/no_name_equals_in_value.js
@@ -3,10 +3,10 @@
 cookie_test(async t => {
   let eventPromise = observeNextCookieChangeEvent();
   await cookieStore.set('', 'first-value');
-  const actual1 =
-      (await cookieStore.getAll('')).map(({ value }) => value).join(';');
-  const expected1 = 'first-value';
-  assert_equals(actual1, expected1);
+  assert_equals(
+    (await cookieStore.getAll('')).map(({ value }) => value).join(';'),
+    'first-value',
+    'Cookie with no name and normal value should have been set');
   await verifyCookieChangeEvent(
     eventPromise, {changed: [{name: '', value: 'first-value'}]},
     'Observed no-name change');
@@ -16,31 +16,26 @@
     new TypeError(),
     cookieStore.set('', 'suspicious-value=resembles-name-and-value'),
     'Expected promise rejection when setting a cookie with' +
-      ' no name and "=" in value');
+      ' no name and "=" in value (via arguments)');
 
-  const actual2 =
-        (await cookieStore.getAll('')).map(({ value }) => value).join(';');
-  const expected2 = 'first-value';
-  assert_equals(actual2, expected2);
+  await promise_rejects(
+    t,
+    new TypeError(),
+    cookieStore.set(
+      {name: '', value: 'suspicious-value=resembles-name-and-value'}),
+    'Expected promise rejection when setting a cookie with' +
+      ' no name and "=" in value (via options)');
+
   assert_equals(
-    await getCookieString(),
+    (await cookieStore.getAll('')).map(({ value }) => value).join(';'),
     'first-value',
-    'Earlier cookie jar after rejected');
+    'Cookie with no name should still have previous value');
 
   eventPromise = observeNextCookieChangeEvent();
   await cookieStore.delete('');
   await verifyCookieChangeEvent(
-    eventPromise, {deleted: [{name: '', value: ''}]},
+    eventPromise, {deleted: [{name: ''}]},
     'Observed no-name deletion');
 
-  assert_equals(
-    await getCookieString(),
-    undefined,
-    'Empty cookie jar after cleanup');
-  assert_equals(
-    await getCookieStringHttp(),
-    undefined,
-    'Empty HTTP cookie jar after cleanup');
-
 }, "Verify that attempting to set a cookie with no name and with '=' in" +
              " the value does not work.");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/one_simple_origin_cookie.js b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/one_simple_origin_cookie.js
deleted file mode 100644
index cbaf73d..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/one_simple_origin_cookie.js
+++ /dev/null
@@ -1,57 +0,0 @@
-'use strict';
-
-// Helper to verify first-of-name get using async/await.
-//
-// Returns the first script-visible value of the __Host-COOKIENAME cookie or
-// undefined if no matching cookies are script-visible.
-async function getOneSimpleOriginCookie() {
-  let cookie = await cookieStore.get('__Host-COOKIENAME');
-  if (!cookie) return undefined;
-  return cookie.value;
-}
-
-// Returns the number of script-visible cookies whose names start with
-// __Host-COOKIEN
-async function countMatchingSimpleOriginCookies() {
-  let cookieList = await cookieStore.getAll({
-    name: '__Host-COOKIEN',
-    matchType: 'startsWith'
-  });
-  return cookieList.length;
-}
-
-// Set the secure implicit-domain cookie __Host-COOKIENAME with value
-// cookie-value on path / and session duration.
-async function setOneSimpleOriginSessionCookie() {
-  await cookieStore.set('__Host-COOKIENAME', 'cookie-value');
-};
-
-cookie_test(async testCase => {
-  await promise_rejects_when_unsecured(
-    testCase,
-    new TypeError(),
-    setOneSimpleOriginSessionCookie(),
-    '__Host- prefix only writable from secure contexts');
-  if (!kIsUnsecured) {
-    assert_equals(
-      await getOneSimpleOriginCookie(),
-      'cookie-value',
-      '__Host-COOKIENAME cookie should be found in a secure context');
-  } else {
-    assert_equals(
-      await getOneSimpleOriginCookie(),
-      undefined,
-      '__Host-COOKIENAME cookie should not be found in an unsecured context');
-  }
-  if (kIsUnsecured) {
-    assert_equals(
-      await countMatchingSimpleOriginCookies(),
-      0,
-      'No __Host-COOKIEN* cookies should be found in an unsecured context');
-  } else {
-    assert_equals(
-      await countMatchingSimpleOriginCookies(),
-      1,
-      'One __Host-COOKIEN* cookie should be found in a secure context');
-  }
-}, 'One simple origin cookie');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/secure_cookies.js b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/secure_cookies.js
deleted file mode 100644
index 9f600ecd..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/resources/secure_cookies.js
+++ /dev/null
@@ -1,46 +0,0 @@
-
-cookie_test(async t => {
-  const theVeryRecentPast = Date.now();
-  const expiredCookieSentinelValue = 'EXPIRED';
-  await promise_rejects_when_unsecured(
-    t,
-    new TypeError(),
-    cookieStore.set('__Secure-COOKIENAME', expiredCookieSentinelValue, {
-      path: kPath,
-      expires: theVeryRecentPast,
-      secure: true,
-      domain: location.hostname
-    }),
-    'Secure cookies only writable from secure contexts');
-
-}, 'Set an already-expired secure cookie');
-
-['__Host-', '__Secure-'].forEach(prefix => {
-  cookie_test(async t => {
-    const name = prefix + 'COOKIENAME';
-    const value = 'cookie-value';
-
-    await promise_rejects_when_unsecured(
-      t,
-      new TypeError(),
-      cookieStore.set(name, value),
-      `Setting ${prefix} cookies should fail in non-secure contexts`);
-
-    // Getting does not produce an exception, even in non-secure contexts.
-    const pair = await cookieStore.get(name);
-
-    if (kIsUnsecured) {
-      assert_equals(pair, null);
-    } else {
-      assert_equals(pair.value, value);
-    }
-
-    await promise_rejects_when_unsecured(
-      t,
-      new TypeError(),
-      cookieStore.delete(name),
-      `Deleting ${prefix} cookies should fail in non-secure contexts`);
-
-    assert_equals(await cookieStore.get(name), null);
-  }, `${prefix} cookies only writable from secure context`);
-});
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/secure_cookies.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/secure_cookies.tentative.html
deleted file mode 100644
index 4bbf718..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/secure_cookies.tentative.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Async Cookies: __Secure- and __Host- cookies</title>
-<meta name="help" href="https://github.com/WICG/cookie-store/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/cookie-test-helpers.js"></script>
-<script src="resources/secure_cookies.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/secure_cookies.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/cookie-store/secure_cookies.tentative.https.html
deleted file mode 100644
index 2fa9a412..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/cookie-store/secure_cookies.tentative.https.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Async Cookies: __Secure- and __Host- cookies (HTTPS)</title>
-<meta name="help" href="https://github.com/WICG/cookie-store/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/cookie-test-helpers.js"></script>
-<script src="resources/secure_cookies.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/css3-background-origin-padding-box.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/css3-background-origin-padding-box.html
index 1b2fe5e..c1dc3f0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/css3-background-origin-padding-box.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/css3-background-origin-padding-box.html
@@ -2,11 +2,11 @@
 <html lang="en">
   <head>
     <meta charset="utf-8" />
-    <title>CSS Backgrounds Test:background origin property with value content-box</title>
+    <title>CSS Backgrounds Test:background origin property with value padding-box</title>
     <link rel="author" title="yanshasha" href="mailto:yanshasha133@gmail.com" />
     <link rel="reviewer" title="Dayang Shen" href="mailto:shendayang@baidu.com" /> <!-- 2013-08-26 -->
     <link rel="help" href="http://www.w3.org/TR/css3-background/#the-background-origin" />
-    <link rel="match" href="reference/css3-background-origin-content-box-ref.html" />
+    <link rel="match" href="reference/css3-background-origin-padding-box-ref.html" />
     <style type="text/css">
             div {
                 width: 100px;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/css3-background-size-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/css3-background-size-001.html
index f049ac3b..6da2c9d3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/css3-background-size-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/css3-background-size-001.html
@@ -6,7 +6,7 @@
     <link rel="author" title="yanshasha" href="mailto:yanshasha133@gmail.com" />
     <link rel="reviewer" title="Dayang Shen" href="mailto:shendayang@baidu.com" /><!-- 2013-08-26 -->
     <link rel="help" href="http://www.w3.org/TR/css3-background/#the-background-size" />
-    <link rel="match" href="reference/css3-background-size-ref.html" />
+    <link rel="match" href="reference/css3-background-size-001-ref.html" />
     <style type="text/css">
             div {
                 width: 150px;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces.html
index c6e3662..308c1b4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces.html
@@ -17,11 +17,12 @@
 <script>
 "use strict";
 
-function doTest([html, dom, cssom, geometry, cssom_view]) {
+function doTest([html, dom, uievents, cssom, geometry, cssom_view]) {
 
   var idlArray = new IdlArray();
   var svg = "interface SVGElement : Element {};";
   idlArray.add_untested_idls(html + dom + svg + cssom + geometry);
+  idlArray.add_untested_idls(uievents, { only: ['UIEvent', 'UIEventInit', 'MouseEvent', 'MouseEventInit', 'EventModifierInit'] });
   idlArray.add_idls(cssom_view);
 
   idlArray.add_objects({
@@ -57,6 +58,7 @@
   // Have to wait for onload
   return Promise.all([fetchData("/interfaces/html.idl"),
                       fetchData("/interfaces/dom.idl"),
+                      fetchData("/interfaces/uievents.idl"),
                       fetchData("/interfaces/cssom.idl"),
                       fetchData("/interfaces/geometry.idl"),
                       fetchData("/interfaces/cssom-view.idl"),
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces.html
index e289c5a3..b92da9f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/interfaces.html
@@ -31,7 +31,7 @@
 "use strict";
 var style_element, svg_element, xmlss_pi;
 
-function doTest([html, dom, cssom]) {
+function doTest([html, dom, uievents, cssom]) {
   style_element = document.getElementById('styleElement');
   svg_element = document.getElementById('svgElement');
   xmlss_pi = document.getElementById('xmlssPiIframe').contentDocument.firstChild;
@@ -39,6 +39,7 @@
   var idlArray = new IdlArray();
   var svg = "interface SVGElement : Element {};";
   idlArray.add_untested_idls(html + dom + svg);
+  idlArray.add_untested_idls(uievents, { only: ['UIEvent', 'UIEventInit', 'MouseEvent', 'MouseEventInit', 'EventModifierInit']});
   idlArray.add_idls(cssom);
 
   idlArray.add_objects({
@@ -81,6 +82,7 @@
   // Have to wait for onload
   return Promise.all([fetchData("/interfaces/html.idl"),
                       fetchData("/interfaces/dom.idl"),
+                      fetchData("/interfaces/uievents.idl"),
                       fetchData("/interfaces/cssom.idl"),
                       waitForLoad()])
                 .then(doTest);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/idlharness.https.html
index cd87ecdc..a609f94 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/idlharness.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/idlharness.https.html
@@ -33,6 +33,7 @@
                 idl_array.add_untested_idls("interface Navigator {};");
                 idl_array.add_untested_idls("interface HTMLMediaElement {};");
                 idl_array.add_untested_idls("interface Event {};");
+                idl_array.add_untested_idls("dictionary EventInit {};");
                 idl_array.add_untested_idls("interface EventTarget {};");
 
                 idl_array.add_idls(idls);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/gamepad/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/gamepad/idlharness.html
index 833449d7..9719d02 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/gamepad/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/gamepad/idlharness.html
@@ -14,8 +14,9 @@
 promise_test(async () => {
   const idl_array = new IdlArray();
   const gamepad_idl = await fetch("/interfaces/gamepad.idl").then(r => r.text());
+  const dom = await fetch("/interfaces/dom.idl").then(r => r.text());
 
-  idl_array.add_untested_idls('interface Event {};');
+  idl_array.add_untested_idls(dom, {only: ['Event', 'EventInit']});
   idl_array.add_untested_idls('interface Navigator {};');
   idl_array.add_idls(gamepad_idl);
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/geolocation-sensor/idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/geolocation-sensor/idlharness.https.html
index d674a79f..75d29eb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/geolocation-sensor/idlharness.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/geolocation-sensor/idlharness.https.html
@@ -14,7 +14,7 @@
   const idl_array = new IdlArray();
   idl_array.add_untested_idls('interface EventTarget {};');
   idl_array.add_untested_idls('interface EventHandler {};');
-  idl_array.add_idls(generic_sensor, { only: ['Sensor'] });
+  idl_array.add_idls(generic_sensor, { only: ['Sensor', 'SensorOptions'] });
   idl_array.add_idls(geolocation_sensor);
   idl_array.add_objects({
     GeolocationSensor: ['new GeolocationSensor'],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/gyroscope/idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/gyroscope/idlharness.https.html
index ca552a9..4b3ed48 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/gyroscope/idlharness.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/gyroscope/idlharness.https.html
@@ -15,7 +15,7 @@
   const idl_array = new IdlArray();
   idl_array.add_untested_idls(dom);
   idl_array.add_untested_idls('interface EventHandler {};');
-  idl_array.add_idls(generic_sensor, { only: ['Sensor'] });
+  idl_array.add_idls(generic_sensor, { only: ['Sensor', 'SensorOptions'] });
   idl_array.add_idls(gyroscope);
   idl_array.add_objects({
     Gyroscope: ['new Gyroscope();']
diff --git a/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness-expected.txt
deleted file mode 100644
index 169a07f..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test driver promise_test: Unhandled rejection with value: object "Error: undefined EventTarget not found (inherited by Performance)"
-FAIL Performance interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
-PASS Performance interface object length
-PASS Performance interface object name
-FAIL Performance interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
-PASS Performance interface: existence and properties of interface prototype object's "constructor" property
-PASS Performance interface: existence and properties of interface prototype object's @@unscopables property
-PASS Performance interface: operation now()
-PASS Unscopable handled correctly for now() on Performance
-PASS Performance interface: attribute timeOrigin
-PASS Unscopable handled correctly for timeOrigin property on Performance
-PASS Performance interface: operation toJSON()
-PASS Unscopable handled correctly for toJSON() on Performance
-PASS Performance must be primary interface of window.performance
-FAIL Stringification of window.performance Cannot read property 'has_stringifier' of undefined
-PASS Performance interface: window.performance must inherit property "now()" with the proper type
-PASS Performance interface: window.performance must inherit property "timeOrigin" with the proper type
-PASS Performance interface: window.performance must inherit property "toJSON()" with the proper type
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.html
index 4abaf60..d28cee3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/hr-time/idlharness.html
@@ -16,8 +16,9 @@
 <script>
 'use strict';
 
-function doTest([html, hr_time]) {
+function doTest([dom, html, hr_time]) {
   var idl_array = new IdlArray();
+  idl_array.add_untested_idls(dom, { only: ['EventTarget'] });
   idl_array.add_untested_idls(html, { only: ['WindowOrWorkerGlobalScope'] });
   idl_array.add_idls(hr_time);
   idl_array.add_objects({
@@ -32,7 +33,8 @@
 }
 
 promise_test(() => {
-  return Promise.all(['/interfaces/html.idl',
+  return Promise.all(['/interfaces/dom.idl',
+                      '/interfaces/html.idl',
                       '/interfaces/hr-time.idl'].map(fetchText))
                 .then(doTest);
 }, 'Test driver');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/focus-02.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/focus-02.html
new file mode 100644
index 0000000..2592880
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/focus-02.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: focus - key events</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#focus">
+<meta assert="flag" content="interact">
+<meta assert="assert" content="Check if the key events received by document are targeted at the element when no element is focused">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<div id="log"></div>
+<script>
+
+//These tests can be automated once we have an uniform way to use webdriver.
+var t1 = async_test("The keydown event must be targeted at the body element"),
+    t2 = async_test("The keypress event must be targeted at the body element"),
+    t3 = async_test("The keyup event must be targeted at the body element");
+
+setup({timeout: 10000});
+
+document.onkeydown = t1.step_func_done(function(evt){
+  assert_equals(evt.target, document.body, "The keydown events must be targeted at the document's body.");
+});
+
+document.onkeypress = t2.step_func_done(function(evt){
+  assert_equals(evt.target, document.body, "The keypress events must be targeted at the document's body.");
+});
+
+document.onkeyup = t3.step_func_done(function(evt){
+  assert_equals(evt.target, document.body, "The keyup events must be targeted at the document's body.");
+});
+
+t1.step(function() {
+  test_driver.send_keys(document.body, "a");
+});
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/magnetometer/idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/magnetometer/idlharness.https.html
index 3ab2bc2..904869eb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/magnetometer/idlharness.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/magnetometer/idlharness.https.html
@@ -15,7 +15,7 @@
   const idl_array = new IdlArray();
   idl_array.add_untested_idls(dom);
   idl_array.add_untested_idls('interface EventHandler {};');
-  idl_array.add_idls(generic_sensor, { only: ['Sensor'] });
+  idl_array.add_idls(generic_sensor, { only: ['Sensor', 'SensorOptions'] });
   idl_array.add_idls(magnetometer);
   idl_array.add_objects({
     Magnetometer: ['new Magnetometer();'],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness-expected.txt
index cfb7068..ff171cd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness-expected.txt
@@ -1,5 +1,6 @@
 This is a testharness.js-based test.
-Found 79 tests; 72 PASS, 7 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 80 tests; 73 PASS, 7 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS mediacapture-record interfaces
 PASS MediaRecorder interface: existence and properties of interface object
 PASS MediaRecorder interface object length
 PASS MediaRecorder interface object name
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness.html
index 95f60d737..2da20a1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness.html
@@ -80,19 +80,24 @@
 
   </pre>
   <script>
-    var canvas = document.getElementById('canvas');
-    var context = canvas.getContext("2d");
-    context.fillStyle = "red";
-    context.fillRect(0, 0, 10, 10);
-    var stream = canvas.captureStream();
+    promise_test(async function() {
+      const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
 
-    var idl_array = new IdlArray();
-    idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
-    idl_array.add_idls(document.getElementById("idl").textContent);
-    idl_array.add_objects({
-        MediaRecorder: [new MediaRecorder(stream)],
-      });
-    idl_array.test();
+      var canvas = document.getElementById('canvas');
+      var context = canvas.getContext("2d");
+      context.fillStyle = "red";
+      context.fillRect(0, 0, 10, 10);
+      var stream = canvas.captureStream();
+
+      var idl_array = new IdlArray();
+      idl_array.add_untested_idls(dom, { only: ['EventInit'] });
+      idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
+      idl_array.add_idls(document.getElementById("idl").textContent);
+      idl_array.add_objects({
+          MediaRecorder: [new MediaRecorder(stream)],
+        });
+      idl_array.test();
+    }, 'mediacapture-record interfaces');
   </script>
   <div id="log"></div>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-all-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-all-expected.txt
index 8ec1f47..7efe128 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-all-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-all-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 135 tests; 125 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 135 tests; 127 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver
 PASS Navigator interface: attribute mediaDevices
 PASS Unscopable handled correctly for mediaDevices property on Navigator
@@ -74,10 +74,10 @@
 PASS Unscopable handled correctly for applyConstraints(MediaTrackConstraints) on MediaStreamTrack
 FAIL MediaStreamTrack interface: attribute onoverconstrained assert_true: The prototype object must have a property "onoverconstrained" expected true got false
 PASS Unscopable handled correctly for onoverconstrained property on MediaStreamTrack
-FAIL MediaStreamTrackEvent interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaStreamTrackEvent interface: existence and properties of interface object
 PASS MediaStreamTrackEvent interface object length
 PASS MediaStreamTrackEvent interface object name
-FAIL MediaStreamTrackEvent interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object
 PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object's "constructor" property
 PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object's @@unscopables property
 PASS MediaStreamTrackEvent interface: attribute track
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-all.html b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-all.html
index f6dfb36..a793bed 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-all.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-all.html
@@ -19,10 +19,11 @@
     <script>
       'use strict';
 
-      function doIdlTest(idlText) {
+      function doIdlTest([dom, idlText]) {
         var idl_array = new IdlArray();
 
         // dummies
+        idl_array.add_untested_idls(dom, { only: ['Event', 'EventInit']});
         idl_array.add_untested_idls("interface Navigator {};");
         idl_array.add_untested_idls("interface EventTarget {};");
         idl_array.add_untested_idls("interface EventHandler {};");
@@ -35,10 +36,12 @@
       }
 
       promise_test(() => {
-        return fetch('/interfaces/mediacapture-main.idl')
-          .then(response => response.text())
-          .then(doIdlTest);
-
+        return Promise.all(
+          [
+            '/interfaces/dom.idl',
+            '/interfaces/mediacapture-main.idl',
+          ].map(url => fetch(url).then(r => r.text())))
+            .then(doIdlTest);
       }, 'Test driver')
     </script>
   </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html
index c2449ae..0d6c6c0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html
@@ -20,10 +20,10 @@
 <script>
   "use strict";
 
-  function doIdlTest(idlText) {
+  function doIdlTest([dom, idlText]) {
     const MDI_idl = new IdlArray();
 
-    MDI_idl.add_untested_idls("interface Event {};");
+    MDI_idl.add_untested_idls(dom, { only: ['Event', 'EventInit'] });
     MDI_idl.add_untested_idls("interface EventTarget {};");
     MDI_idl.add_untested_idls("interface Navigator {};");
     MDI_idl.add_idls(idlText);
@@ -59,8 +59,11 @@
   }
 
   promise_test(() => {
-    return fetch('/interfaces/mediacapture-main.idl')
-      .then(response => response.text())
+      return Promise.all(
+        [
+          '/interfaces/dom.idl',
+          '/interfaces/mediacapture-main.idl',
+        ].map(url => fetch(url).then(r => r.text())))
       .then(doIdlTest);
 
   }, "Test MediaDevices.enumerateDevices call and result. Types only.");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_idlharness-expected.txt
deleted file mode 100644
index 2851111..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_idlharness-expected.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-This is a testharness.js-based test.
-PASS PerformanceNavigationTiming interface: existence and properties of interface object
-PASS PerformanceNavigationTiming interface object length
-PASS PerformanceNavigationTiming interface object name
-FAIL PerformanceNavigationTiming interface: existence and properties of interface prototype object Cannot read property 'has_stringifier' of undefined
-PASS PerformanceNavigationTiming interface: existence and properties of interface prototype object's "constructor" property
-PASS PerformanceNavigationTiming interface: existence and properties of interface prototype object's @@unscopables property
-PASS PerformanceNavigationTiming interface: attribute unloadEventStart
-PASS Unscopable handled correctly for unloadEventStart property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: attribute unloadEventEnd
-PASS Unscopable handled correctly for unloadEventEnd property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: attribute domInteractive
-PASS Unscopable handled correctly for domInteractive property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: attribute domContentLoadedEventStart
-PASS Unscopable handled correctly for domContentLoadedEventStart property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: attribute domContentLoadedEventEnd
-PASS Unscopable handled correctly for domContentLoadedEventEnd property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: attribute domComplete
-PASS Unscopable handled correctly for domComplete property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: attribute loadEventStart
-PASS Unscopable handled correctly for loadEventStart property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: attribute loadEventEnd
-PASS Unscopable handled correctly for loadEventEnd property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: attribute type
-PASS Unscopable handled correctly for type property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: attribute redirectCount
-PASS Unscopable handled correctly for redirectCount property on PerformanceNavigationTiming
-PASS PerformanceNavigationTiming interface: operation toJSON()
-PASS Unscopable handled correctly for toJSON() on PerformanceNavigationTiming
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_idlharness.html
index eb7d94b..6d1a1249 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_idlharness.html
@@ -32,6 +32,7 @@
     [MeasureAs=PerformanceResourceTimingSizes] readonly attribute unsigned long long encodedBodySize;
     [MeasureAs=PerformanceResourceTimingSizes] readonly attribute unsigned long long decodedBodySize;
 };
+interface PerformanceEntry {};
 </pre>
 
 <pre id='idl'>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/orientation-sensor/idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/orientation-sensor/idlharness.https.html
index d1099b57..c87d99f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/orientation-sensor/idlharness.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/orientation-sensor/idlharness.https.html
@@ -15,7 +15,7 @@
   const idl_array = new IdlArray();
   idl_array.add_untested_idls(dom);
   idl_array.add_untested_idls('interface EventHandler {};');
-  idl_array.add_idls(generic_sensor, { only: ['Sensor'] });
+  idl_array.add_idls(generic_sensor, { only: ['Sensor', 'SensorOptions'] });
   idl_array.add_idls(orientation_sensor);
   idl_array.add_objects({
     AbsoluteOrientationSensor: ['new AbsoluteOrientationSensor();'],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-handler/interfaces.https.any.js b/third_party/WebKit/LayoutTests/external/wpt/payment-handler/interfaces.https.any.js
index ccddf46..7367930 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-handler/interfaces.https.any.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-handler/interfaces.https.any.js
@@ -6,11 +6,11 @@
 // https://w3c.github.io/payment-handler/
 
 promise_test(async () => {
-  const text = await fetch('/interfaces/payment-handler.idl').then(response =>
-    response.text(),
-  );
+  const idl = await fetch('/interfaces/payment-handler.idl').then(r => r.text());
   const idlArray = new IdlArray();
-  idlArray.add_idls(text);
+  idlArray.add_idls(idl);
+  idlArray.add_untested_idls('interface ExtendableEvent {};');
+  idlArray.add_untested_idls('dictionary ExtendableEventInit {};');
   idlArray.test();
   done();
 }, 'Payment handler interfaces.');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-handler/interfaces.https.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-handler/interfaces.https.any.worker-expected.txt
index 572c566..49c3855 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-handler/interfaces.https.any.worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-handler/interfaces.https.any.worker-expected.txt
@@ -29,5 +29,6 @@
 PASS Unscopable handled correctly for clear() on PaymentInstruments
 PASS CanMakePaymentEvent interface: existence and properties of interface object
 PASS PaymentRequestEvent interface: existence and properties of interface object
+PASS ExtendableEvent interface: existence and properties of interface object
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-insecure.http-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-insecure.http-expected.txt
deleted file mode 100644
index 3b796d72..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-insecure.http-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL PaymentRequest constructor must not be exposed in insecure context assert_false: expected false got true
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-insecure.http.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-insecure.http.html
index c097bf1..0212220 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-insecure.http.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-insecure.http.html
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<!-- Copyright © 2017 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
 <meta charset="utf-8">
 <title>Test for PaymentRequest Constructor (insecure)</title>
 <link rel="help" href="https://w3c.github.io/payment-request/#paymentrequest-interface">
@@ -7,8 +8,6 @@
 <script>
 test(() => {
   assert_false(isSecureContext);
-  assert_false('PaymentRequest' in window);
-  assert_false('PaymentResponse' in window);
-  assert_false('PaymentRequestUpdateEvent' in window);
+  assert_false("PaymentRequest" in window);
 }, "PaymentRequest constructor must not be exposed in insecure context");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/extension/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/extension/idlharness.html
index d1bbdebd..7da7fed 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/extension/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/extension/idlharness.html
@@ -48,8 +48,15 @@
 
 </pre>
 <script>
+promise_test(async function () {
+  const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
+  const uievents = await fetch('/interfaces/uievents.idl').then(r => r.text());
+
   var idl_array = new IdlArray();
+  idl_array.add_untested_idls(dom, { only: ['EventInit'] });
+  idl_array.add_untested_idls(uievents, { only: ['UIEventInit', 'MouseEventInit', 'EventModifierInit'] });
   idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
   idl_array.add_idls(document.getElementById("idl").textContent);
   idl_array.test();
+}, 'pointerevents extension interfaces');
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness.html
index 729d357..bdc7ad7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness.html
@@ -91,14 +91,21 @@
 };
 </pre>
 <script>
-  var idl_array = new IdlArray();
-  idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
-  idl_array.add_idls(document.getElementById("idl").textContent);
+  promise_test(async function() {
+    const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
+    const uievents = await fetch('/interfaces/uievents.idl').then(r => r.text());
 
-  // Note that I don't bother including Document here because there are still
-  // a bunch of differences between browsers around Document vs HTMLDocument.
-  idl_array.add_objects({
+    var idl_array = new IdlArray();
+    idl_array.add_untested_idls(dom, { only: ['EventInit'] });
+    idl_array.add_untested_idls(uievents, { only: ['UIEventInit', 'MouseEventInit', 'EventModifierInit'] });
+    idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
+    idl_array.add_idls(document.getElementById("idl").textContent);
+
+    // Note that I don't bother including Document here because there are still
+    // a bunch of differences between browsers around Document vs HTMLDocument.
+    idl_array.add_objects({
     Window: ["window"],
     Navigator: ["navigator"]});
-  idl_array.test();
+    idl_array.test();
+  }, 'pointerevents interfaces');
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/remote-playback/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/idlharness.html
index bd9cbf6..274771a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/remote-playback/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/idlharness.html
@@ -19,20 +19,32 @@
 </pre>
 <script>
 "use strict"
-var idl_array = new IdlArray();
-function doTest(idl) {
-  idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
-  idl_array.add_idls(idl);
-  idl_array.add_objects({
-    HTMLVideoElement: [document.getElementById("media")],
-    RemotePlayback: [document.getElementById("media").remote]
-  });
-  idl_array.test();
-}
 
-promise_test(function() {
-  return fetch("/interfaces/remoteplayback.idl")
-      .then(response => response.text())
+promise_test(async function() {
+  var idl_array = new IdlArray();
+  function doTest([html, idl]) {
+    idl_array.add_untested_idls('interface Element {};');
+    idl_array.add_untested_idls(html, { only: [
+      'HTMLElement',
+      'HTMLOrSVGElement',
+      'GlobalEventHandlers',
+      'DocumentAndElementEventHandlers',
+      'ElementContentEditable',
+    ] });
+    idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
+    idl_array.add_idls(idl);
+    idl_array.add_objects({
+      HTMLVideoElement: [document.getElementById("media")],
+      RemotePlayback: [document.getElementById("media").remote]
+    });
+    idl_array.test();
+  }
+
+  return Promise.all(
+    [
+      "/interfaces/html.idl",
+      "/interfaces/remoteplayback.idl",
+    ].map(url => fetch(url).then(r => r.text())))
       .then(doTest);
 }, "Test driver");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/idlharness.js b/third_party/WebKit/LayoutTests/external/wpt/resources/idlharness.js
index c3045c4..bfa8c2a2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/resources/idlharness.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/idlharness.js
@@ -683,6 +683,19 @@
     }
     this["includes"] = {};
 
+    // Assert B defined for A : B
+    for (const member of Object.values(this.members).filter(m => m.base)) {
+        const lhs = member.name;
+        const rhs = member.base;
+        if (!(rhs in this.members)) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${rhs} is undefined.`);
+        const lhs_is_interface = this.members[lhs] instanceof IdlInterface;
+        const rhs_is_interface = this.members[rhs] instanceof IdlInterface;
+        if (rhs_is_interface != lhs_is_interface) {
+            if (!lhs_is_interface) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${lhs} is not an interface.`);
+            if (!rhs_is_interface) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${rhs} is not an interface.`);
+        }
+    }
+
     Object.getOwnPropertyNames(this.members).forEach(function(memberName) {
         var member = this.members[memberName];
         if (!(member instanceof IdlInterface)) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-sw.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-sw.https-expected.txt
index e526d229..04c40c72 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-sw.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-sw.https-expected.txt
@@ -17,10 +17,10 @@
 PASS Unscopable handled correctly for postMessage(any, [object Object]) on ServiceWorker
 FAIL ServiceWorker interface: attribute onstatechange assert_own_property: self does not have own property "ServiceWorker" expected property "ServiceWorker" missing
 PASS Unscopable handled correctly for onstatechange property on ServiceWorker
-FAIL ServiceWorkerRegistration interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS ServiceWorkerRegistration interface: existence and properties of interface object
 PASS ServiceWorkerRegistration interface object length
 PASS ServiceWorkerRegistration interface object name
-FAIL ServiceWorkerRegistration interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS ServiceWorkerRegistration interface: existence and properties of interface prototype object
 PASS ServiceWorkerRegistration interface: existence and properties of interface prototype object's "constructor" property
 PASS ServiceWorkerRegistration interface: existence and properties of interface prototype object's @@unscopables property
 PASS ServiceWorkerRegistration interface: attribute installing
@@ -42,7 +42,7 @@
 PASS ServiceWorkerRegistration interface: attribute onupdatefound
 PASS Unscopable handled correctly for onupdatefound property on ServiceWorkerRegistration
 PASS ServiceWorkerRegistration must be primary interface of self.registration
-FAIL Stringification of self.registration Cannot read property 'has_stringifier' of undefined
+PASS Stringification of self.registration
 PASS ServiceWorkerRegistration interface: self.registration must inherit property "installing" with the proper type
 PASS ServiceWorkerRegistration interface: self.registration must inherit property "waiting" with the proper type
 PASS ServiceWorkerRegistration interface: self.registration must inherit property "active" with the proper type
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-window.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-window.https-expected.txt
deleted file mode 100644
index bbd9eba7a..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-window.https-expected.txt
+++ /dev/null
@@ -1,115 +0,0 @@
-This is a testharness.js-based test.
-PASS test setup (worker registration)
-PASS WorkerGlobalScope interface: existence and properties of interface object
-FAIL ServiceWorker interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
-PASS ServiceWorker interface object length
-PASS ServiceWorker interface object name
-FAIL ServiceWorker interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
-PASS ServiceWorker interface: existence and properties of interface prototype object's "constructor" property
-PASS ServiceWorker interface: existence and properties of interface prototype object's @@unscopables property
-PASS ServiceWorker interface: attribute scriptURL
-PASS Unscopable handled correctly for scriptURL property on ServiceWorker
-PASS ServiceWorker interface: attribute state
-PASS Unscopable handled correctly for state property on ServiceWorker
-PASS ServiceWorker interface: operation postMessage(any, [object Object])
-PASS Unscopable handled correctly for postMessage(any, [object Object]) on ServiceWorker
-PASS ServiceWorker interface: attribute onstatechange
-PASS Unscopable handled correctly for onstatechange property on ServiceWorker
-PASS ServiceWorker must be primary interface of window.registrationInstance.installing
-FAIL Stringification of window.registrationInstance.installing Cannot read property 'has_stringifier' of undefined
-PASS ServiceWorker interface: window.registrationInstance.installing must inherit property "scriptURL" with the proper type
-PASS ServiceWorker interface: window.registrationInstance.installing must inherit property "state" with the proper type
-PASS ServiceWorker interface: window.registrationInstance.installing must inherit property "postMessage(any, [object Object])" with the proper type
-PASS ServiceWorker interface: calling postMessage(any, [object Object]) on window.registrationInstance.installing with too few arguments must throw TypeError
-PASS ServiceWorker interface: window.registrationInstance.installing must inherit property "onstatechange" with the proper type
-FAIL ServiceWorkerRegistration interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
-PASS ServiceWorkerRegistration interface object length
-PASS ServiceWorkerRegistration interface object name
-FAIL ServiceWorkerRegistration interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
-PASS ServiceWorkerRegistration interface: existence and properties of interface prototype object's "constructor" property
-PASS ServiceWorkerRegistration interface: existence and properties of interface prototype object's @@unscopables property
-PASS ServiceWorkerRegistration interface: attribute installing
-PASS Unscopable handled correctly for installing property on ServiceWorkerRegistration
-PASS ServiceWorkerRegistration interface: attribute waiting
-PASS Unscopable handled correctly for waiting property on ServiceWorkerRegistration
-PASS ServiceWorkerRegistration interface: attribute active
-PASS Unscopable handled correctly for active property on ServiceWorkerRegistration
-PASS ServiceWorkerRegistration interface: attribute navigationPreload
-PASS Unscopable handled correctly for navigationPreload property on ServiceWorkerRegistration
-PASS ServiceWorkerRegistration interface: attribute scope
-PASS Unscopable handled correctly for scope property on ServiceWorkerRegistration
-PASS ServiceWorkerRegistration interface: attribute updateViaCache
-PASS Unscopable handled correctly for updateViaCache property on ServiceWorkerRegistration
-PASS ServiceWorkerRegistration interface: operation update()
-PASS Unscopable handled correctly for update() on ServiceWorkerRegistration
-PASS ServiceWorkerRegistration interface: operation unregister()
-PASS Unscopable handled correctly for unregister() on ServiceWorkerRegistration
-PASS ServiceWorkerRegistration interface: attribute onupdatefound
-PASS Unscopable handled correctly for onupdatefound property on ServiceWorkerRegistration
-PASS ServiceWorkerRegistration must be primary interface of window.registrationInstance
-FAIL Stringification of window.registrationInstance Cannot read property 'has_stringifier' of undefined
-PASS ServiceWorkerRegistration interface: window.registrationInstance must inherit property "installing" with the proper type
-PASS ServiceWorkerRegistration interface: window.registrationInstance must inherit property "waiting" with the proper type
-PASS ServiceWorkerRegistration interface: window.registrationInstance must inherit property "active" with the proper type
-PASS ServiceWorkerRegistration interface: window.registrationInstance must inherit property "navigationPreload" with the proper type
-PASS ServiceWorkerRegistration interface: window.registrationInstance must inherit property "scope" with the proper type
-PASS ServiceWorkerRegistration interface: window.registrationInstance must inherit property "updateViaCache" with the proper type
-PASS ServiceWorkerRegistration interface: window.registrationInstance must inherit property "update()" with the proper type
-PASS ServiceWorkerRegistration interface: window.registrationInstance must inherit property "unregister()" with the proper type
-PASS ServiceWorkerRegistration interface: window.registrationInstance must inherit property "onupdatefound" with the proper type
-PASS NavigationPreloadManager interface: existence and properties of interface object
-PASS NavigationPreloadManager interface object length
-PASS NavigationPreloadManager interface object name
-PASS NavigationPreloadManager interface: existence and properties of interface prototype object
-PASS NavigationPreloadManager interface: existence and properties of interface prototype object's "constructor" property
-PASS NavigationPreloadManager interface: existence and properties of interface prototype object's @@unscopables property
-PASS NavigationPreloadManager interface: operation enable()
-PASS Unscopable handled correctly for enable() on NavigationPreloadManager
-PASS NavigationPreloadManager interface: operation disable()
-PASS Unscopable handled correctly for disable() on NavigationPreloadManager
-PASS NavigationPreloadManager interface: operation setHeaderValue(ByteString)
-PASS Unscopable handled correctly for setHeaderValue(ByteString) on NavigationPreloadManager
-PASS NavigationPreloadManager interface: operation getState()
-PASS Unscopable handled correctly for getState() on NavigationPreloadManager
-PASS ServiceWorkerGlobalScope interface: existence and properties of interface object
-PASS Client interface: existence and properties of interface object
-PASS WindowClient interface: existence and properties of interface object
-PASS Clients interface: existence and properties of interface object
-PASS Cache interface: existence and properties of interface object
-PASS Cache interface object length
-PASS Cache interface object name
-PASS Cache interface: existence and properties of interface prototype object
-PASS Cache interface: existence and properties of interface prototype object's "constructor" property
-PASS Cache interface: existence and properties of interface prototype object's @@unscopables property
-PASS Cache interface: operation match(RequestInfo, CacheQueryOptions)
-PASS Unscopable handled correctly for match(RequestInfo, CacheQueryOptions) on Cache
-PASS Cache interface: operation matchAll(RequestInfo, CacheQueryOptions)
-PASS Unscopable handled correctly for matchAll(RequestInfo, CacheQueryOptions) on Cache
-PASS Cache interface: operation add(RequestInfo)
-PASS Unscopable handled correctly for add(RequestInfo) on Cache
-PASS Cache interface: operation addAll([object Object])
-PASS Unscopable handled correctly for addAll([object Object]) on Cache
-PASS Cache interface: operation put(RequestInfo, Response)
-PASS Unscopable handled correctly for put(RequestInfo, Response) on Cache
-PASS Cache interface: operation delete(RequestInfo, CacheQueryOptions)
-PASS Unscopable handled correctly for delete(RequestInfo, CacheQueryOptions) on Cache
-PASS Cache interface: operation keys(RequestInfo, CacheQueryOptions)
-PASS Unscopable handled correctly for keys(RequestInfo, CacheQueryOptions) on Cache
-PASS CacheStorage interface: existence and properties of interface object
-PASS CacheStorage interface object length
-PASS CacheStorage interface object name
-PASS CacheStorage interface: existence and properties of interface prototype object
-PASS CacheStorage interface: existence and properties of interface prototype object's "constructor" property
-PASS CacheStorage interface: existence and properties of interface prototype object's @@unscopables property
-PASS CacheStorage interface: operation match(RequestInfo, CacheQueryOptions)
-PASS Unscopable handled correctly for match(RequestInfo, CacheQueryOptions) on CacheStorage
-PASS CacheStorage interface: operation has(DOMString)
-PASS Unscopable handled correctly for has(DOMString) on CacheStorage
-PASS CacheStorage interface: operation open(DOMString)
-PASS Unscopable handled correctly for open(DOMString) on CacheStorage
-PASS CacheStorage interface: operation delete(DOMString)
-PASS Unscopable handled correctly for delete(DOMString) on CacheStorage
-PASS CacheStorage interface: operation keys()
-PASS Unscopable handled correctly for keys() on CacheStorage
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-window.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-window.https.html
index 3074724..54f83f20 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-window.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/interfaces-window.https.html
@@ -11,9 +11,11 @@
 
 promise_test(async (t) => {
   var idlArray = new IdlArray();
-  let serviceWorkerIdl = await fetch('/interfaces/ServiceWorker.idl').then(r => r.text());
+  const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
+  const serviceWorkerIdl = await fetch('/interfaces/ServiceWorker.idl').then(r => r.text());
 
   idlArray.add_untested_idls(idls.untested);
+  idlArray.add_untested_idls(dom, { only: ['EventTarget'] });
   idlArray.add_idls(serviceWorkerIdl, { only: [
     'ServiceWorkerGlobalScope',
     'Client',
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/interfaces-worker.sub.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/interfaces-worker.sub.js
index e8147f7..29c859b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/interfaces-worker.sub.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/interfaces-worker.sub.js
@@ -7,9 +7,11 @@
 
 promise_test(async (t) => {
   var idlArray = new IdlArray();
-  let serviceWorkerIdl = await fetch('/interfaces/ServiceWorker.idl').then(r => r.text());
+  const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
+  const serviceWorkerIdl = await fetch('/interfaces/ServiceWorker.idl').then(r => r.text());
 
   idlArray.add_untested_idls(idls.untested);
+  idlArray.add_untested_idls(dom, { only: ['EventTarget'] });
   idlArray.add_idls(serviceWorkerIdl, { only: [
     'ServiceWorkerGlobalScope',
     'Client',
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/idlharness.https.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/idlharness.https.html
index aed9170..09ec2c43 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/idlharness.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/idlharness.https.html
@@ -10,13 +10,16 @@
 'use strict';
 
 promise_test(async t => {
-  const [html, dom, mediacapture, webaudio] = await Promise.all([
+  const [html, dom, uievents, mediacapture, webaudio] = await Promise.all([
     // Needed for EventTarget, HTMLMediaElement
     '/interfaces/html.idl',
 
     // Needed for Event, EventListener
     '/interfaces/dom.idl',
 
+    // Needed for MouseEvent
+    '/interfaces/uievents.idl',
+
     // Needed for MediaStream, MediaStreamTrack
     '/interfaces/mediacapture-main.idl',
 
@@ -28,7 +31,15 @@
   // Dependencies of HTML
   idl_array.add_untested_idls('interface LinkStyle {};');
   idl_array.add_untested_idls('interface SVGElement {};');
+  idl_array.add_untested_idls('interface WorkletGlobalScope {};');
   idl_array.add_untested_idls(html);
+  idl_array.add_untested_idls(uievents, { only: [
+    'MouseEvent',
+    'MouseEventInit',
+    'EventModifierInit',
+    'UIEvent',
+    'UIEventInit',
+  ]});
 
   idl_array.add_untested_idls(dom);
   idl_array.add_untested_idls(mediacapture);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-delaynode-interface/idl-test.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-delaynode-interface/idl-test.html
index 5922b96..eb42a4a0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-delaynode-interface/idl-test.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-delaynode-interface/idl-test.html
@@ -138,8 +138,11 @@
   <div id="log"></div>
 
   <script>
-(function() {
+promise_test(async function() {
+  const webAudioApi = await fetch('/interfaces/web-audio-api.idl').then(r => r.text());
+
   var idl_array = new IdlArray();
+  idl_array.add_untested_idls(webAudioApi, { only: ['AudioNodeOptions']});
   idl_array.add_untested_idls(document.getElementById("event-target-idl").textContent);
   idl_array.add_untested_idls(document.getElementById("base-audio-context-idl").textContent);
   idl_array.add_untested_idls(document.getElementById("audio-node-idl").textContent);
@@ -150,7 +153,7 @@
 
   idl_array.add_objects({DelayNode: ["delay_node"]});
   idl_array.test();
-})();
+}, 'webaudio Delay interfaces');
   </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-gainnode-interface/idl-test.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-gainnode-interface/idl-test.html
index 7ad8bc9..69606c9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-gainnode-interface/idl-test.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-gainnode-interface/idl-test.html
@@ -136,8 +136,11 @@
   <div id="log"></div>
 
   <script>
-(function() {
+promise_test(async function () {
+  const webAudioApi = await fetch('/interfaces/web-audio-api.idl').then(r => r.text());
+
   var idl_array = new IdlArray();
+  idl_array.add_untested_idls(webAudioApi, { only: ['AudioNodeOptions'] });
   idl_array.add_untested_idls(document.getElementById("event-target-idl").textContent);
   idl_array.add_untested_idls(document.getElementById("base-audio-context-idl").textContent);
   idl_array.add_untested_idls(document.getElementById("audio-node-idl").textContent);
@@ -148,7 +151,7 @@
 
   idl_array.add_objects({GainNode: ["gain_node"]});
   idl_array.test();
-})();
+}, 'webaudio Gain interfaces');
   </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https.any-expected.txt
deleted file mode 100644
index da88d868..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https.any-expected.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-This is a testharness.js-based test.
-PASS WebAuthn interfaces.
-FAIL PublicKeyCredential interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
-PASS PublicKeyCredential interface object length
-PASS PublicKeyCredential interface object name
-FAIL PublicKeyCredential interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
-PASS PublicKeyCredential interface: existence and properties of interface prototype object's "constructor" property
-PASS PublicKeyCredential interface: existence and properties of interface prototype object's @@unscopables property
-PASS PublicKeyCredential interface: attribute rawId
-PASS Unscopable handled correctly for rawId property on PublicKeyCredential
-PASS PublicKeyCredential interface: attribute response
-PASS Unscopable handled correctly for response property on PublicKeyCredential
-PASS PublicKeyCredential interface: operation getClientExtensionResults()
-PASS Unscopable handled correctly for getClientExtensionResults() on PublicKeyCredential
-PASS PublicKeyCredential interface: operation isUserVerifyingPlatformAuthenticatorAvailable()
-PASS Unscopable handled correctly for isUserVerifyingPlatformAuthenticatorAvailable() on PublicKeyCredential
-PASS AuthenticatorResponse interface: existence and properties of interface object
-PASS AuthenticatorResponse interface object length
-PASS AuthenticatorResponse interface object name
-PASS AuthenticatorResponse interface: existence and properties of interface prototype object
-PASS AuthenticatorResponse interface: existence and properties of interface prototype object's "constructor" property
-PASS AuthenticatorResponse interface: existence and properties of interface prototype object's @@unscopables property
-PASS AuthenticatorResponse interface: attribute clientDataJSON
-PASS Unscopable handled correctly for clientDataJSON property on AuthenticatorResponse
-PASS AuthenticatorAttestationResponse interface: existence and properties of interface object
-PASS AuthenticatorAttestationResponse interface object length
-PASS AuthenticatorAttestationResponse interface object name
-PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object
-PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object's "constructor" property
-PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object's @@unscopables property
-PASS AuthenticatorAttestationResponse interface: attribute attestationObject
-PASS Unscopable handled correctly for attestationObject property on AuthenticatorAttestationResponse
-PASS AuthenticatorAssertionResponse interface: existence and properties of interface object
-PASS AuthenticatorAssertionResponse interface object length
-PASS AuthenticatorAssertionResponse interface object name
-PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object
-PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object's "constructor" property
-PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object's @@unscopables property
-PASS AuthenticatorAssertionResponse interface: attribute authenticatorData
-PASS Unscopable handled correctly for authenticatorData property on AuthenticatorAssertionResponse
-PASS AuthenticatorAssertionResponse interface: attribute signature
-PASS Unscopable handled correctly for signature property on AuthenticatorAssertionResponse
-PASS AuthenticatorAssertionResponse interface: attribute userHandle
-PASS Unscopable handled correctly for userHandle property on AuthenticatorAssertionResponse
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https.any.js b/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https.any.js
index bd5f9dc4..22766e6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https.any.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/webauthn/interfaces.https.any.js
@@ -20,6 +20,7 @@
   idlArray.add_untested_idls('interface CredentialCreationOptions {};');
   idlArray.add_untested_idls('interface CredentialRequestOptions {};');
   idlArray.add_untested_idls("interface Navigator { };");
+  idlArray.add_untested_idls("interface Credential { };");
   // TODO: change to "tested" for real browsers?
   idlArray.add_untested_idls("partial interface Navigator { readonly attribute WebAuthentication authentication; };");
   idlArray.add_objects({
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webstorage/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/webstorage/idlharness.html
index cd880a3..4204344 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webstorage/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webstorage/idlharness.html
@@ -18,12 +18,6 @@
 [Global=Window, Exposed=Window]
 interface Window {
 };
-
-interface Event {
-};
-
-interface EventInit {
-};
 </pre>
 
 <pre id='idl'>
@@ -65,16 +59,21 @@
 
 <script>
 
-(function() {
+promise_test(async function() {
+  const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
+  const html = await fetch('/interfaces/html.idl').then(r => r.text());
+
   var idl_array = new IdlArray();
 
+  idl_array.add_untested_idls(dom, { only: ['Event', 'EventInit'] });
+  idl_array.add_untested_idls(html, { only: ['EventStorageInit'] });
   idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
   idl_array.add_idls(document.getElementById("idl").textContent);
 
   idl_array.add_objects({Storage: ["window.localStorage"]});
 
   idl_array.test();
-})();
+}, 'webstorage interfaces');
 
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/animation/scroll-animations/animation-created-with-scroll-timeline.html b/third_party/WebKit/LayoutTests/fast/animation/scroll-animations/animation-created-with-scroll-timeline.html
new file mode 100644
index 0000000..9429f62
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/animation/scroll-animations/animation-created-with-scroll-timeline.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test an Animation created with a ScrollTimeline doesn't crash</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<script>
+test(t => {
+  // We don't yet support ScrollTimeline, but creating an Animation object with
+  // one should not crash.
+  var timeline = new ScrollTimeline({ timeRange: 100, orientation: 'block' });
+  assert_throws("NotSupportedError", function() { new Animation(null, timeline) });
+}, 'An Animation created with a ScrollTimeline should not crash');
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-clone.html b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-clone.html
index 16ed9c0c..373f0fd 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-clone.html
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-clone.html
@@ -1,7 +1,6 @@
 <!DOCTYPE HTML>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
-<canvas id="canvas"/>
 <script>
 
 createTrack = function() {
@@ -33,6 +32,42 @@
                     "Tracks enabled status should not be linked.");
 }, "Clones of disabled MediaStreamTracks are still disabled.");
 
+promise_test(function() {
+  return navigator.mediaDevices.getUserMedia({audio: { echoCancellation: true }})
+    .then(function(s) {
+      track = s.getAudioTracks()[0];
+      constraints = track.getConstraints();
+      assert_equals(Object.keys(constraints).length, 1);
+      assert_true(constraints.hasOwnProperty('echoCancellation'));
+      assert_true(constraints.echoCancellation);
+      cloned_track = track.clone();
+      cloned_track_constraints = cloned_track.getConstraints();
+      assert_equals(Object.keys(cloned_track_constraints).length, Object.keys(constraints).length);
+      assert_true(constraints.hasOwnProperty('echoCancellation'));
+      assert_equals(cloned_track_constraints.echoCancellation, constraints.echoCancellation);
+    });
+}, 'Cloned audio MediaStreamTrack has same constraints');
+
+promise_test(function() {
+  return navigator.mediaDevices.getUserMedia({video: { width: 800, height: 600 }})
+    .then(function(s) {
+      track = s.getVideoTracks()[0];
+      constraints = track.getConstraints();
+      assert_equals(Object.keys(constraints).length, 2);
+      assert_true(constraints.hasOwnProperty('width'));
+      assert_equals(constraints.width, 800);
+      assert_true(constraints.hasOwnProperty('height'));
+      assert_equals(constraints.height, 600);
+      cloned_track = track.clone();
+      cloned_track_constraints = cloned_track.getConstraints();
+      assert_equals(Object.keys(cloned_track_constraints).length, Object.keys(constraints).length);
+      assert_true(constraints.hasOwnProperty('width'));
+      assert_equals(cloned_track_constraints.width, constraints.width);
+      assert_true(constraints.hasOwnProperty('height'));
+      assert_equals(cloned_track_constraints.height, constraints.height);
+    });
+}, 'Cloned video MediaStreamTrack has same constraints');
+
 // TODO(pbos): Add tests that make sure muted and stopped properties are
 // carried over. Part of crbug:669212.
 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/overflow/border-radius-above-composited-subframe-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/overflow/border-radius-above-composited-subframe-expected.png
index 55024e3..1a941fc1 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/overflow/border-radius-above-composited-subframe-expected.png
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/overflow/border-radius-above-composited-subframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/backgrounds/repeat/negative-offset-repeat-transformed-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/backgrounds/repeat/negative-offset-repeat-transformed-expected.png
index 5485703..6a8c8e0 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/backgrounds/repeat/negative-offset-repeat-transformed-expected.png
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/backgrounds/repeat/negative-offset-repeat-transformed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/font-format-support-cbdt-sbix-cff2-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/font-format-support-cbdt-sbix-cff2-expected.png
new file mode 100644
index 0000000..487be33
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/font-format-support-cbdt-sbix-cff2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/clip/control-clip-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/clip/control-clip-expected.txt
index b5bb31d0..c6f5e10 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/clip/control-clip-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/clip/control-clip-expected.txt
@@ -18,12 +18,12 @@
         },
         {
           "object": "InlineTextBox 'FAILURE'",
-          "rect": [80, 117, 56, 16],
+          "rect": [81, 117, 54, 16],
           "reason": "disappeared"
         },
         {
           "object": "InlineTextBox 'FAILURE'",
-          "rect": [9, 87, 55, 16],
+          "rect": [9, 87, 54, 16],
           "reason": "disappeared"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/details-open-repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/details-open-repaint-expected.txt
index 11ead38..fdf7f7e 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/details-open-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/details-open-repaint-expected.txt
@@ -8,7 +8,7 @@
       "paintInvalidations": [
         {
           "object": "LayoutTextControl INPUT",
-          "rect": [8, 72, 154, 22],
+          "rect": [8, 72, 181, 22],
           "reason": "appeared"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/make-children-non-inline-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/make-children-non-inline-expected.txt
index 3b981b42..b0a419b4 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/make-children-non-inline-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/make-children-non-inline-expected.txt
@@ -78,12 +78,12 @@
         },
         {
           "object": "InlineTextBox 'Word,'",
-          "rect": [8, 64, 39, 19],
+          "rect": [8, 64, 38, 19],
           "reason": "appeared"
         },
         {
           "object": "InlineTextBox 'Word,'",
-          "rect": [8, 64, 39, 19],
+          "rect": [8, 64, 38, 19],
           "reason": "disappeared"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multi-layout-one-frame-expected.txt
index a7074c1..b548210 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multi-layout-one-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multi-layout-one-frame-expected.txt
@@ -8,7 +8,7 @@
       "paintInvalidations": [
         {
           "object": "InlineTextBox 'PASSED'",
-          "rect": [168, 11, 53, 16],
+          "rect": [195, 11, 53, 16],
           "reason": "appeared"
         },
         {
@@ -18,12 +18,12 @@
         },
         {
           "object": "InlineTextBox 'FAILED'",
-          "rect": [168, 11, 46, 16],
+          "rect": [195, 11, 45, 16],
           "reason": "disappeared"
         },
         {
           "object": "InlineTextBox 'FAILED'",
-          "rect": [10, 11, 46, 16],
+          "rect": [10, 11, 45, 16],
           "reason": "disappeared"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/reflection/reflection-with-rotation-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/reflection/reflection-with-rotation-expected.png
deleted file mode 100644
index c2ffd7a..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/reflection/reflection-with-rotation-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/reflection/reflection-with-rotation-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/reflection/reflection-with-rotation-expected.txt
index c7374bb..6db86bb 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/reflection/reflection-with-rotation-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/reflection/reflection-with-rotation-expected.txt
@@ -13,12 +13,12 @@
         },
         {
           "object": "InlineTextBox 'PASS'",
-          "rect": [23, 51, 72, 110],
+          "rect": [23, 51, 71, 109],
           "reason": "appeared"
         },
         {
           "object": "InlineTextBox 'FAIL'",
-          "rect": [23, 51, 69, 109],
+          "rect": [23, 51, 68, 108],
           "reason": "disappeared"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/remove-inline-after-layout-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/remove-inline-after-layout-expected.txt
index 6afe45f..836628954 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/remove-inline-after-layout-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/remove-inline-after-layout-expected.txt
@@ -13,7 +13,7 @@
         },
         {
           "object": "LayoutBlockFlow DIV",
-          "rect": [290, 108, 101, 100],
+          "rect": [291, 108, 100, 100],
           "reason": "geometry"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/remove-inline-layer-after-layout-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/remove-inline-layer-after-layout-expected.txt
index 9902754..666afc71 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/remove-inline-layer-after-layout-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/remove-inline-layer-after-layout-expected.txt
@@ -13,7 +13,7 @@
         },
         {
           "object": "LayoutBlockFlow DIV",
-          "rect": [290, 108, 101, 100],
+          "rect": [291, 108, 100, 100],
           "reason": "geometry"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/subtree-root-skipped-expected.txt
index 4412e1b..d1645681 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/subtree-root-skipped-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/subtree-root-skipped-expected.txt
@@ -13,7 +13,7 @@
         },
         {
           "object": "InlineTextBox 'FAIL'",
-          "rect": [10, 11, 28, 16],
+          "rect": [10, 11, 27, 16],
           "reason": "disappeared"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/text-rescale-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/text-rescale-expected.txt
index fa7410b..f16e5f4f 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/text-rescale-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/text-rescale-expected.txt
@@ -8,27 +8,37 @@
       "paintInvalidations": [
         {
           "object": "InlineTextBox 'PASS '",
-          "rect": [0, 114, 302, 46],
+          "rect": [0, 114, 192, 46],
           "reason": "appeared"
         },
         {
           "object": "LayoutSVGRoot (positioned) svg",
-          "rect": [0, 14, 302, 46],
+          "rect": [0, 14, 192, 46],
           "reason": "appeared"
         },
         {
           "object": "LayoutSVGViewportContainer svg",
-          "rect": [310, 114, 92, 46],
+          "rect": [310, 114, 91, 46],
           "reason": "paint property change"
         },
         {
           "object": "LayoutSVGViewportContainer svg",
-          "rect": [310, 14, 92, 46],
+          "rect": [310, 14, 91, 46],
           "reason": "appeared"
         },
         {
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [210, 114, 91, 46],
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [210, 14, 91, 46],
+          "reason": "paint property change"
+        },
+        {
           "object": "LayoutSVGContainer g id='text3g'",
-          "rect": [0, 3, 10, 3],
+          "rect": [0, 3, 8, 3],
           "reason": "disappeared"
         },
         {
@@ -37,9 +47,14 @@
           "reason": "paint property change"
         },
         {
-          "object": "LayoutSVGContainer g id='text1g'",
+          "object": "LayoutSVGForeignObject foreignObject",
+          "rect": [6, 3, 4, 2],
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGForeignObject foreignObject",
           "rect": [0, 0, 1, 1],
-          "reason": "disappeared"
+          "reason": "paint property change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-set-bypass-csp-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-set-bypass-csp-expected.txt
new file mode 100644
index 0000000..783620a2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-set-bypass-csp-expected.txt
@@ -0,0 +1,15 @@
+Tests that Page.setBypassCSP works for main frame.
+Verify CSP works when set with <meta>
+  CSP bypassed: false
+Verify CSP works when set with header
+  CSP bypassed: false
+
+>> ENABLING CSP BYPASS <<
+
+Verify CSP is bypassed when set with <meta>
+  CSP bypassed: true
+Verify CSP is bypassed when set with header
+  CSP bypassed: true
+Check bypass after cross-origin navigation
+  CSP bypassed: true
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-set-bypass-csp.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-set-bypass-csp.js
new file mode 100644
index 0000000..0feb3cb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-set-bypass-csp.js
@@ -0,0 +1,38 @@
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startBlank(
+      `Tests that Page.setBypassCSP works for main frame.`);
+
+  await dp.Page.enable();
+  await dp.Runtime.enable();
+
+  testRunner.log('Verify CSP works when set with <meta>');
+  await page.navigate('./resources/csp.html');
+  await dumpCSPEnabled();
+
+  testRunner.log('Verify CSP works when set with header');
+  await page.navigate('./resources/csp.php');
+  await dumpCSPEnabled();
+
+  testRunner.log('\n>> ENABLING CSP BYPASS <<\n');
+  await dp.Page.setBypassCSP({ enabled: true });
+
+  testRunner.log('Verify CSP is bypassed when set with <meta>');
+  await page.navigate('./resources/csp.html');
+  await dumpCSPEnabled();
+
+  testRunner.log('Verify CSP is bypassed when set with header');
+  await page.navigate('./resources/csp.php');
+  await dumpCSPEnabled();
+
+  testRunner.log('Check bypass after cross-origin navigation');
+  await page.navigate('http://127.0.0.1:8000/inspector-protocol/page/resources/csp.php');
+  await page.navigate('https://127.0.0.1:8443/inspector-protocol/page/resources/csp.php');
+  await dumpCSPEnabled();
+
+  testRunner.completeTest();
+
+  async function dumpCSPEnabled() {
+    const message = await dp.Runtime.evaluate({ expression: 'window.__injected' });
+    testRunner.log('  CSP bypassed: ' + (message.result.result.value === 42));
+  }
+})
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/resources/csp.html b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/resources/csp.html
new file mode 100644
index 0000000..3e4ce9a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/resources/csp.html
@@ -0,0 +1,2 @@
+<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
+<script type="text/javascript">window.__injected = 42;</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/resources/csp.php b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/resources/csp.php
new file mode 100644
index 0000000..58f6db9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/resources/csp.php
@@ -0,0 +1,4 @@
+<?php
+ob_start();
+header("Content-Security-Policy: default-src 'self'");
+echo "<script type='text/javascript'>window.__injected = 42;</script>";
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
index 63f9a08..8dd407f5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
@@ -77,6 +77,8 @@
   }
 
   url(relative) {
+    if (relative.startsWith('http://') || relative.startsWith('https://'))
+      return relative;
     return this._baseURL + relative;
   }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-suspend-after-have-enough-data.html b/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-suspend-after-have-enough-data.html
new file mode 100644
index 0000000..7537c15
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-suspend-after-have-enough-data.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src="/w3c/resources/testharness.js"></script>
+<script src="/w3c/resources/testharnessreport.js"></script>
+<script src="/media-resources/suspend-util.js"></script>
+<script src="mediasource-util.js"></script>
+<link rel="stylesheet" href="/w3c/resources/testharness.css">
+<div id="log"></div>
+<script>
+mediasource_testafterdataloaded(function(
+    test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) {
+  suspendMediaElement(mediaElement, HTMLMediaElement.HAVE_ENOUGH_DATA, function() {
+    completeTestUponPlayback(test, mediaElement);
+  });
+
+  test.expectEvent(sourceBuffer, 'updateend', 'init append ended.');
+  var init = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+  sourceBuffer.appendBuffer(init);
+
+  test.waitForExpectedEvents(function() {
+    var mediaSegment =
+      MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+    sourceBuffer.appendBuffer(mediaSegment);
+  });
+}, 'Test that a media element using MSE can be resumed after an idle suspend initiated during the HAVE_ENOUGH_DATA ready state.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-suspend-after-have-metadata.html b/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-suspend-after-have-metadata.html
new file mode 100644
index 0000000..31946bb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-suspend-after-have-metadata.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<script src="/w3c/resources/testharness.js"></script>
+<script src="/w3c/resources/testharnessreport.js"></script>
+<script src="/media-resources/suspend-util.js"></script>
+<script src="mediasource-util.js"></script>
+<link rel="stylesheet" href="/w3c/resources/testharness.css">
+<div id="log"></div>
+<script>
+mediasource_testafterdataloaded(function(
+    test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) {
+  suspendMediaElement(mediaElement, HTMLMediaElement.HAVE_METADATA, function() {
+    // Upgrade the stale flag to a higher state now to wakeup the element. In
+    // a normal flow the stale flag can not be set prior to have future data.
+    completeTestUponPlayback(test, mediaElement);
+    window.internals.forceStaleStateForMediaElement(
+        mediaElement, HTMLMediaElement.HAVE_ENOUGH_DATA);
+  });
+
+  test.expectEvent(sourceBuffer, 'updateend', 'init append ended.');
+  var init = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+  sourceBuffer.appendBuffer(init);
+
+  test.waitForExpectedEvents(function() {
+    var mediaSegment =
+      MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+    sourceBuffer.appendBuffer(mediaSegment);
+  });
+}, 'Test that a media element using MSE can be resumed after an idle suspend initiated during the HAVE_METADATA ready state.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-suspend-before-have-metadata.html b/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-suspend-before-have-metadata.html
new file mode 100644
index 0000000..8521045
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-suspend-before-have-metadata.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<script src="/w3c/resources/testharness.js"></script>
+<script src="/w3c/resources/testharnessreport.js"></script>
+<script src="/media-resources/suspend-util.js"></script>
+<script src="mediasource-util.js"></script>
+<link rel="stylesheet" href="/w3c/resources/testharness.css">
+<div id="log"></div>
+<script>
+mediasource_testafterdataloaded(function(
+    test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData) {
+  suspendMediaElement(mediaElement, HTMLMediaElement.HAVE_NOTHING, function() {
+    // Upgrade the stale flag to a higher state now to wakeup the element. In
+    // a normal flow the stale flag can not be set prior to have future data.
+    completeTestUponPlayback(test, mediaElement);
+    window.internals.forceStaleStateForMediaElement(
+        mediaElement, HTMLMediaElement.HAVE_ENOUGH_DATA);
+  });
+
+  test.expectEvent(sourceBuffer, 'updateend', 'init append ended.');
+  var init = MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.init);
+  sourceBuffer.appendBuffer(init);
+
+  test.waitForExpectedEvents(function() {
+    var mediaSegment =
+      MediaSourceUtil.extractSegmentData(mediaData, segmentInfo.media[0]);
+    sourceBuffer.appendBuffer(mediaSegment);
+  });
+}, 'Test that a media element using MSE can be resumed after an idle suspend initiated before the HAVE_METADATA ready state.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/media/suspend-util.js b/third_party/WebKit/LayoutTests/media/suspend-util.js
index 763e719..9e1dca5 100644
--- a/third_party/WebKit/LayoutTests/media/suspend-util.js
+++ b/third_party/WebKit/LayoutTests/media/suspend-util.js
@@ -1,3 +1,5 @@
+// Requests that |video| suspends upon reaching or exceeding |expectedState|;
+// |callback| will be called once the suspend is detected.
 function suspendMediaElement(video, expectedState, callback) {
   var pollSuspendState = function() {
     if (!window.internals.isMediaElementSuspended(video)) {
@@ -12,10 +14,8 @@
   window.internals.forceStaleStateForMediaElement(video, expectedState);
 }
 
-function preloadMetadataSuspendTest(t, video, src, expectSuspend) {
-  assert_true(!!window.internals, 'This test requires windows.internals.');
-  video.onerror = t.unreached_func();
-
+// Calls play() on |video| and executes t.done() when currentTime > 0.
+function completeTestUponPlayback(t, video) {
   var timeWatcher = t.step_func(function() {
     if (video.currentTime > 0) {
       assert_false(window.internals.isMediaElementSuspended(video));
@@ -25,6 +25,14 @@
     }
   });
 
+  window.requestAnimationFrame(timeWatcher);
+  video.play();
+}
+
+function preloadMetadataSuspendTest(t, video, src, expectSuspend) {
+  assert_true(!!window.internals, 'This test requires windows.internals.');
+  video.onerror = t.unreached_func();
+
   var eventListener = t.step_func(function() {
     assert_equals(expectSuspend,
                   window.internals.isMediaElementSuspended(video));
@@ -33,8 +41,7 @@
       return;
     }
 
-    window.requestAnimationFrame(timeWatcher);
-    video.play();
+    completeTestUponPlayback(t, video);
   });
 
   video.addEventListener('loadedmetadata', eventListener, false);
@@ -45,21 +52,11 @@
   assert_true(!!window.internals, 'This test requires windows.internals.');
   video.onerror = t.unreached_func();
 
-  var timeWatcher = t.step_func(function() {
-    if (video.currentTime > 0) {
-      assert_false(window.internals.isMediaElementSuspended(video));
-      t.done();
-    } else {
-      window.requestAnimationFrame(timeWatcher);
-    }
-  });
-
   // We can't force a suspend state until loading has started.
   video.addEventListener('loadstart', t.step_func(function() {
     suspendMediaElement(video, expectedState, t.step_func(function() {
       assert_true(window.internals.isMediaElementSuspended(video));
-      window.requestAnimationFrame(timeWatcher);
-      video.play();
+      completeTestUponPlayback(t, video);
     }));
   }), false);
 
diff --git a/third_party/WebKit/LayoutTests/paint/roundedrects/composited-overflow-and-border-radius-clip-expected.html b/third_party/WebKit/LayoutTests/paint/roundedrects/composited-overflow-and-border-radius-clip-expected.html
new file mode 100644
index 0000000..ae787b3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/roundedrects/composited-overflow-and-border-radius-clip-expected.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<div style="will-change: transform; width: 100px; height: 100px; border-radius: 10px; overflow: scroll">
+  <div style="width: 190px; height: 200px; background: blue"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/paint/roundedrects/composited-overflow-and-border-radius-clip.html b/third_party/WebKit/LayoutTests/paint/roundedrects/composited-overflow-and-border-radius-clip.html
new file mode 100644
index 0000000..7ca1ac9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/roundedrects/composited-overflow-and-border-radius-clip.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<div style="will-change: transform; width: 100px; height: 100px; border-radius: 10px; overflow: scroll">
+  <div style="transform: translateX(-10px); width: 200px; height: 200px; background: blue"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/external/wpt/background-fetch/interfaces.worker-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/external/wpt/background-fetch/interfaces.worker-expected.txt
new file mode 100644
index 0000000..2faa453
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/external/wpt/background-fetch/interfaces.worker-expected.txt
@@ -0,0 +1,74 @@
+This is a testharness.js-based test.
+Found 70 tests; 53 PASS, 17 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS Exposed interfaces in a Service Worker.
+FAIL ServiceWorkerRegistration interface: existence and properties of interface object assert_false: expected false got true
+PASS ServiceWorkerGlobalScope interface: existence and properties of interface object
+PASS ExtendableEvent interface: existence and properties of interface object
+PASS BackgroundFetchManager interface: existence and properties of interface object
+PASS BackgroundFetchManager interface object length
+PASS BackgroundFetchManager interface object name
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchManager interface: operation fetch(DOMString, [object Object],[object Object], BackgroundFetchOptions)
+PASS Unscopable handled correctly for fetch(DOMString, [object Object],[object Object], BackgroundFetchOptions) on BackgroundFetchManager
+PASS BackgroundFetchManager interface: operation get(DOMString)
+PASS Unscopable handled correctly for get(DOMString) on BackgroundFetchManager
+PASS BackgroundFetchManager interface: operation getIds()
+PASS Unscopable handled correctly for getIds() on BackgroundFetchManager
+PASS BackgroundFetchRegistration interface: existence and properties of interface object
+PASS BackgroundFetchRegistration interface object length
+PASS BackgroundFetchRegistration interface object name
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchRegistration interface: attribute id
+PASS Unscopable handled correctly for id property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute uploadTotal
+PASS Unscopable handled correctly for uploadTotal property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute uploaded
+PASS Unscopable handled correctly for uploaded property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute downloadTotal
+PASS Unscopable handled correctly for downloadTotal property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute downloaded
+PASS Unscopable handled correctly for downloaded property on BackgroundFetchRegistration
+FAIL BackgroundFetchRegistration interface: attribute activeFetches assert_true: The prototype object must have a property "activeFetches" expected true got false
+PASS Unscopable handled correctly for activeFetches property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute onprogress
+PASS Unscopable handled correctly for onprogress property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: operation abort()
+PASS Unscopable handled correctly for abort() on BackgroundFetchRegistration
+PASS BackgroundFetchFetch interface: existence and properties of interface object
+PASS BackgroundFetchFetch interface object length
+PASS BackgroundFetchFetch interface object name
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchFetch interface: attribute request
+PASS Unscopable handled correctly for request property on BackgroundFetchFetch
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation match(RequestInfo) assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+PASS Unscopable handled correctly for match(RequestInfo) on BackgroundFetchActiveFetches
+FAIL BackgroundFetchActiveFetches interface: operation values() assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+PASS Unscopable handled correctly for values() on BackgroundFetchActiveFetches
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: attribute responseReady assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+PASS Unscopable handled correctly for responseReady property on BackgroundFetchActiveFetch
+PASS BackgroundFetchEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetches interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetch interface: existence and properties of interface object
+PASS BackgroundFetchUpdateEvent interface: existence and properties of interface object
+PASS BackgroundFetchClickEvent interface: existence and properties of interface object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/masking/mask-luminance-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/masking/mask-luminance-gradient-expected.png
index 82ea862..d2e31e32 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/masking/mask-luminance-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/masking/mask-luminance-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/masking/mask-luminance-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/masking/mask-luminance-gradient-expected.png
index 9b13536..80ef5b7f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/masking/mask-luminance-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/masking/mask-luminance-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/background-fetch/interfaces.worker-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/background-fetch/interfaces.worker-expected.txt
new file mode 100644
index 0000000..2faa453
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/background-fetch/interfaces.worker-expected.txt
@@ -0,0 +1,74 @@
+This is a testharness.js-based test.
+Found 70 tests; 53 PASS, 17 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS Exposed interfaces in a Service Worker.
+FAIL ServiceWorkerRegistration interface: existence and properties of interface object assert_false: expected false got true
+PASS ServiceWorkerGlobalScope interface: existence and properties of interface object
+PASS ExtendableEvent interface: existence and properties of interface object
+PASS BackgroundFetchManager interface: existence and properties of interface object
+PASS BackgroundFetchManager interface object length
+PASS BackgroundFetchManager interface object name
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchManager interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchManager interface: operation fetch(DOMString, [object Object],[object Object], BackgroundFetchOptions)
+PASS Unscopable handled correctly for fetch(DOMString, [object Object],[object Object], BackgroundFetchOptions) on BackgroundFetchManager
+PASS BackgroundFetchManager interface: operation get(DOMString)
+PASS Unscopable handled correctly for get(DOMString) on BackgroundFetchManager
+PASS BackgroundFetchManager interface: operation getIds()
+PASS Unscopable handled correctly for getIds() on BackgroundFetchManager
+PASS BackgroundFetchRegistration interface: existence and properties of interface object
+PASS BackgroundFetchRegistration interface object length
+PASS BackgroundFetchRegistration interface object name
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchRegistration interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchRegistration interface: attribute id
+PASS Unscopable handled correctly for id property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute uploadTotal
+PASS Unscopable handled correctly for uploadTotal property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute uploaded
+PASS Unscopable handled correctly for uploaded property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute downloadTotal
+PASS Unscopable handled correctly for downloadTotal property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute downloaded
+PASS Unscopable handled correctly for downloaded property on BackgroundFetchRegistration
+FAIL BackgroundFetchRegistration interface: attribute activeFetches assert_true: The prototype object must have a property "activeFetches" expected true got false
+PASS Unscopable handled correctly for activeFetches property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: attribute onprogress
+PASS Unscopable handled correctly for onprogress property on BackgroundFetchRegistration
+PASS BackgroundFetchRegistration interface: operation abort()
+PASS Unscopable handled correctly for abort() on BackgroundFetchRegistration
+PASS BackgroundFetchFetch interface: existence and properties of interface object
+PASS BackgroundFetchFetch interface object length
+PASS BackgroundFetchFetch interface object name
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's "constructor" property
+PASS BackgroundFetchFetch interface: existence and properties of interface prototype object's @@unscopables property
+PASS BackgroundFetchFetch interface: attribute request
+PASS Unscopable handled correctly for request property on BackgroundFetchFetch
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+FAIL BackgroundFetchActiveFetches interface: operation match(RequestInfo) assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+PASS Unscopable handled correctly for match(RequestInfo) on BackgroundFetchActiveFetches
+FAIL BackgroundFetchActiveFetches interface: operation values() assert_own_property: self does not have own property "BackgroundFetchActiveFetches" expected property "BackgroundFetchActiveFetches" missing
+PASS Unscopable handled correctly for values() on BackgroundFetchActiveFetches
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object length assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface object name assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+FAIL BackgroundFetchActiveFetch interface: attribute responseReady assert_own_property: self does not have own property "BackgroundFetchActiveFetch" expected property "BackgroundFetchActiveFetch" missing
+PASS Unscopable handled correctly for responseReady property on BackgroundFetchActiveFetch
+PASS BackgroundFetchEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledEvent interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetches interface: existence and properties of interface object
+PASS BackgroundFetchSettledFetch interface: existence and properties of interface object
+PASS BackgroundFetchUpdateEvent interface: existence and properties of interface object
+PASS BackgroundFetchClickEvent interface: existence and properties of interface object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/webaudio/constructor/analyser.html b/third_party/WebKit/LayoutTests/webaudio/constructor/analyser.html
index d9500bf..a78e504 100644
--- a/third_party/WebKit/LayoutTests/webaudio/constructor/analyser.html
+++ b/third_party/WebKit/LayoutTests/webaudio/constructor/analyser.html
@@ -41,12 +41,7 @@
           {name: 'fftSize', value: 2048},
           {name: 'frequencyBinCount', value: 1024},
           {name: 'minDecibels', value: -100}, {name: 'maxDecibels', value: -30},
-          {
-            // Compare against the single-precision float value since 0.8 isn't
-            // exactly representable as a float.
-            name: 'smoothingTimeConstant',
-            value: Math.fround(0.8)
-          }
+          {name: 'smoothingTimeConstant', value: 0.8}
         ]);
 
         task.done();
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableMarkingVisitorTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableMarkingVisitorTest.cpp
index 2f2d2a4..c08f5bb2 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableMarkingVisitorTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableMarkingVisitorTest.cpp
@@ -9,6 +9,7 @@
 #include "bindings/core/v8/V8GCController.h"
 #include "core/testing/DeathAwareScriptWrappable.h"
 #include "platform/bindings/TraceWrapperV8Reference.h"
+#include "platform/bindings/V8DOMWrapper.h"
 #include "platform/bindings/V8PerIsolateData.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -379,16 +380,16 @@
   HeapObjectHeader::FromPayload(target)->MarkWrapperHeader();
 
   // Create a 'wrapper' object.
-  v8::Local<v8::ObjectTemplate> t = v8::ObjectTemplate::New(scope.GetIsolate());
-  t->SetInternalFieldCount(2);
-  v8::Local<v8::Object> obj =
-      t->NewInstance(scope.GetContext()).ToLocalChecked();
+  v8::Local<v8::Object> wrapper = V8DOMWrapper::CreateWrapper(
+      scope.GetIsolate(), scope.GetContext()->Global(),
+      target->GetWrapperTypeInfo());
 
   // Upon setting the wrapper we should have executed the write barrier.
   CHECK_EQ(0u, raw_visitor->NumberOfMarkedWrappers());
-  bool success =
-      target->SetWrapper(scope.GetIsolate(), target->GetWrapperTypeInfo(), obj);
-  CHECK(success);
+  v8::Local<v8::Object> final_wrapper =
+      V8DOMWrapper::AssociateObjectWithWrapper(
+          scope.GetIsolate(), target, target->GetWrapperTypeInfo(), wrapper);
+  CHECK(!final_wrapper.IsEmpty());
   CHECK_EQ(1u, raw_visitor->NumberOfMarkedWrappers());
 }
 
diff --git a/third_party/WebKit/Source/core/animation/Animation.cpp b/third_party/WebKit/Source/core/animation/Animation.cpp
index 5b588bd5..3954912 100644
--- a/third_party/WebKit/Source/core/animation/Animation.cpp
+++ b/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -69,10 +69,14 @@
 }
 
 Animation* Animation::Create(AnimationEffect* effect,
-                             AnimationTimeline* timeline) {
+                             AnimationTimeline* timeline,
+                             ExceptionState& exception_state) {
   if (!timeline || !timeline->IsDocumentTimeline()) {
     // FIXME: Support creating animations without a timeline.
-    NOTREACHED();
+    exception_state.ThrowDOMException(kNotSupportedError,
+                                      "Animations can currently only be "
+                                      "created with a non-null "
+                                      "DocumentTimeline");
     return nullptr;
   }
 
@@ -95,7 +99,7 @@
   DCHECK(RuntimeEnabledFeatures::WebAnimationsAPIEnabled());
 
   Document* document = ToDocument(execution_context);
-  return Create(effect, &document->Timeline());
+  return Create(effect, &document->Timeline(), exception_state);
 }
 
 Animation* Animation::Create(ExecutionContext* execution_context,
@@ -108,7 +112,7 @@
     return Create(execution_context, effect, exception_state);
   }
 
-  return Create(effect, timeline);
+  return Create(effect, timeline, exception_state);
 }
 
 Animation::Animation(ExecutionContext* execution_context,
diff --git a/third_party/WebKit/Source/core/animation/Animation.h b/third_party/WebKit/Source/core/animation/Animation.h
index bb74d55..e815f6f 100644
--- a/third_party/WebKit/Source/core/animation/Animation.h
+++ b/third_party/WebKit/Source/core/animation/Animation.h
@@ -80,7 +80,9 @@
     kFinished
   };
 
-  static Animation* Create(AnimationEffect*, AnimationTimeline*);
+  static Animation* Create(AnimationEffect*,
+                           AnimationTimeline*,
+                           ExceptionState& = ASSERT_NO_EXCEPTION);
 
   // Web Animations API IDL constructors.
   static Animation* Create(ExecutionContext*,
diff --git a/third_party/WebKit/Source/core/editing/PlainTextRange.cpp b/third_party/WebKit/Source/core/editing/PlainTextRange.cpp
index eb3089de..1ab1eb7 100644
--- a/third_party/WebKit/Source/core/editing/PlainTextRange.cpp
+++ b/third_party/WebKit/Source/core/editing/PlainTextRange.cpp
@@ -81,6 +81,21 @@
   return CreateRangeFor(scope, behavior);
 }
 
+static Position CreatePositionInTextRun(size_t offset_in_run,
+                                        const Position& text_run_start_position,
+                                        const Position& text_run_end_position) {
+  if (text_run_start_position.ComputeContainerNode()->IsTextNode()) {
+    // TODO(editing-dev): DCHECK |offset_in_run| falls in int value range.
+    const int offset = offset_in_run;
+    return Position(text_run_start_position.ComputeContainerNode(),
+                    offset + text_run_start_position.OffsetInContainerNode());
+  }
+
+  if (!offset_in_run)
+    return text_run_start_position;
+  return text_run_end_position;
+}
+
 EphemeralRange PlainTextRange::CreateRangeFor(
     const ContainerNode& scope,
     const TextIteratorBehavior& behavior) const {
@@ -92,9 +107,7 @@
   Position text_run_start_position;
   Position text_run_end_position;
 
-  auto range = EphemeralRange::RangeOfContents(scope);
-
-  TextIterator it(range.StartPosition(), range.EndPosition(), behavior);
+  TextIterator it(EphemeralRange::RangeOfContents(scope), behavior);
 
   // FIXME: the atEnd() check shouldn't be necessary, workaround for
   // <http://bugs.webkit.org/show_bug.cgi?id=6289>.
@@ -105,14 +118,14 @@
   Position result_end = result_start;
 
   for (; !it.AtEnd(); it.Advance()) {
-    int len = it.length();
+    const int len = it.length();
 
     text_run_start_position = it.StartPositionInCurrentContainer();
     text_run_end_position = it.EndPositionInCurrentContainer();
 
-    bool found_start =
+    const bool found_start =
         Start() >= doc_text_position && Start() <= doc_text_position + len;
-    bool found_end =
+    const bool found_end =
         End() >= doc_text_position && End() <= doc_text_position + len;
 
     // Fix textRunRange->endPosition(), but only if foundStart || foundEnd,
@@ -138,34 +151,19 @@
 
     if (found_start) {
       start_range_found = true;
-      if (text_run_start_position.ComputeContainerNode()->IsTextNode()) {
-        int offset = Start() - doc_text_position;
-        result_start =
-            Position(text_run_start_position.ComputeContainerNode(),
-                     offset + text_run_start_position.OffsetInContainerNode());
-      } else {
-        if (Start() == doc_text_position)
-          result_start = text_run_start_position;
-        else
-          result_start = text_run_end_position;
-      }
+      result_start = CreatePositionInTextRun(Start() - doc_text_position,
+                                             text_run_start_position,
+                                             text_run_end_position);
     }
 
     if (found_end) {
-      if (text_run_start_position.ComputeContainerNode()->IsTextNode()) {
-        int offset = End() - doc_text_position;
-        result_end =
-            Position(text_run_start_position.ComputeContainerNode(),
-                     offset + text_run_start_position.OffsetInContainerNode());
-      } else {
-        if (End() == doc_text_position)
-          result_end = text_run_start_position;
-        else
-          result_end = text_run_end_position;
-      }
+      result_end = CreatePositionInTextRun(End() - doc_text_position,
+                                           text_run_start_position,
+                                           text_run_end_position);
       doc_text_position += len;
       break;
     }
+
     doc_text_position += len;
   }
 
diff --git a/third_party/WebKit/Source/core/exported/WebDocumentSubresourceFilterTest.cpp b/third_party/WebKit/Source/core/exported/WebDocumentSubresourceFilterTest.cpp
index ebd3a7a4..fda8434 100644
--- a/third_party/WebKit/Source/core/exported/WebDocumentSubresourceFilterTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebDocumentSubresourceFilterTest.cpp
@@ -28,17 +28,23 @@
 
 class TestDocumentSubresourceFilter : public WebDocumentSubresourceFilter {
  public:
-  explicit TestDocumentSubresourceFilter(bool allow_loads)
-      : allow_loads_(allow_loads) {}
+  explicit TestDocumentSubresourceFilter(LoadPolicy policy)
+      : load_policy_(policy) {}
 
   LoadPolicy GetLoadPolicy(const WebURL& resource_url,
                            WebURLRequest::RequestContext) override {
     std::string resource_path = WebString(KURL(resource_url).GetPath()).Utf8();
     if (std::find(queried_subresource_paths_.begin(),
                   queried_subresource_paths_.end(),
-                  resource_path) == queried_subresource_paths_.end())
+                  resource_path) == queried_subresource_paths_.end()) {
       queried_subresource_paths_.push_back(resource_path);
-    return allow_loads_ ? kAllow : kDisallow;
+    }
+    String resource_string = resource_url.GetString();
+    for (const String& suffix : blacklisted_suffixes_) {
+      if (resource_string.EndsWith(suffix))
+        return load_policy_;
+    }
+    return LoadPolicy::kAllow;
   }
 
   LoadPolicy GetLoadPolicyForWebSocketConnect(const WebURL& url) override {
@@ -49,6 +55,10 @@
 
   bool ShouldLogToConsole() override { return false; }
 
+  void AddToBlacklist(const String& suffix) {
+    blacklisted_suffixes_.push_back(suffix);
+  }
+
   const std::vector<std::string>& QueriedSubresourcePaths() const {
     return queried_subresource_paths_;
   }
@@ -56,8 +66,10 @@
   bool GetIsAssociatedWithAdSubframe() const override { return false; }
 
  private:
+  // Using STL types for compatibility with gtest/gmock.
   std::vector<std::string> queried_subresource_paths_;
-  bool allow_loads_;
+  Vector<String> blacklisted_suffixes_;
+  LoadPolicy load_policy_;
 };
 
 class SubresourceFilteringWebFrameClient
@@ -69,12 +81,14 @@
     // the sake of this test, however, inject it earlier to verify that it
     // is not consulted for the main resource load.
     subresource_filter_ =
-        new TestDocumentSubresourceFilter(allow_subresources_from_next_load_);
+        new TestDocumentSubresourceFilter(load_policy_for_next_load_);
+    subresource_filter_->AddToBlacklist("1x1.png");
     data_source->SetSubresourceFilter(subresource_filter_);
   }
 
-  void SetAllowSubresourcesFromNextLoad(bool allow) {
-    allow_subresources_from_next_load_ = allow;
+  void SetLoadPolicyFromNextLoad(
+      TestDocumentSubresourceFilter::LoadPolicy policy) {
+    load_policy_for_next_load_ = policy;
   }
   const TestDocumentSubresourceFilter* SubresourceFilter() const {
     return subresource_filter_;
@@ -83,7 +97,7 @@
  private:
   // Weak, owned by WebDocumentLoader.
   TestDocumentSubresourceFilter* subresource_filter_ = nullptr;
-  bool allow_subresources_from_next_load_ = false;
+  TestDocumentSubresourceFilter::LoadPolicy load_policy_for_next_load_;
 };
 
 }  // namespace
@@ -96,8 +110,8 @@
     web_view_helper_.Initialize(&client_);
   }
 
-  void LoadDocument(bool allow_subresources) {
-    client_.SetAllowSubresourcesFromNextLoad(allow_subresources);
+  void LoadDocument(TestDocumentSubresourceFilter::LoadPolicy policy) {
+    client_.SetLoadPolicyFromNextLoad(policy);
     FrameTestHelpers::LoadFrame(MainFrame(), BaseURL() + "foo_with_image.html");
   }
 
@@ -133,7 +147,7 @@
 };
 
 TEST_F(WebDocumentSubresourceFilterTest, AllowedSubresource) {
-  LoadDocument(true /* allowSubresources */);
+  LoadDocument(TestDocumentSubresourceFilter::kAllow);
   ExpectSubresourceWasLoaded(true);
   // The filter should not be consulted for the main document resource.
   EXPECT_THAT(QueriedSubresourcePaths(),
@@ -141,20 +155,20 @@
 }
 
 TEST_F(WebDocumentSubresourceFilterTest, DisallowedSubresource) {
-  LoadDocument(false /* allowSubresources */);
+  LoadDocument(TestDocumentSubresourceFilter::kDisallow);
   ExpectSubresourceWasLoaded(false);
 }
 
 TEST_F(WebDocumentSubresourceFilterTest, FilteringDecisionIsMadeLoadByLoad) {
-  for (const bool allow_subresources : {false, true}) {
-    SCOPED_TRACE(testing::Message()
-                 << "First load allows subresources = " << allow_subresources);
+  for (const TestDocumentSubresourceFilter::LoadPolicy policy :
+       {TestDocumentSubresourceFilter::kDisallow,
+        TestDocumentSubresourceFilter::kAllow,
+        TestDocumentSubresourceFilter::kWouldDisallow}) {
+    SCOPED_TRACE(testing::Message() << "First load policy= " << policy);
 
-    LoadDocument(allow_subresources);
-    ExpectSubresourceWasLoaded(allow_subresources);
-
-    LoadDocument(!allow_subresources);
-    ExpectSubresourceWasLoaded(!allow_subresources);
+    LoadDocument(policy);
+    ExpectSubresourceWasLoaded(policy !=
+                               TestDocumentSubresourceFilter::kDisallow);
     EXPECT_THAT(QueriedSubresourcePaths(),
                 testing::ElementsAre("/white-1x1.png"));
 
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 5458d196..4e6dae8 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -3507,13 +3507,13 @@
 
   frame_->GetDocument()->UpdateStyleAndLayoutTree();
 
-  // Update style for all embedded replaced content under this frame, so
+  // Update style for all embedded SVG documents underneath this frame, so
   // that intrinsic size computation for any embedded objects has up-to-date
-  // information.
-  // TODO(chrishtr): generalize this to fully separate style from layout.
+  // information before layout.
   ForAllChildLocalFrameViews([](LocalFrameView& view) {
-    if (view.EmbeddedReplacedContent())
-      view.GetLayoutView()->GetDocument().UpdateStyleAndLayoutTree();
+    Document& document = *view.GetFrame().GetDocument();
+    if (document.IsSVGDocument())
+      document.UpdateStyleAndLayoutTree();
   });
 
   CHECK(!ShouldThrottleRendering());
diff --git a/third_party/WebKit/Source/core/frame/Settings.h b/third_party/WebKit/Source/core/frame/Settings.h
index eccd4c8..0f8519a 100644
--- a/third_party/WebKit/Source/core/frame/Settings.h
+++ b/third_party/WebKit/Source/core/frame/Settings.h
@@ -70,6 +70,9 @@
   void SetTextAutosizingEnabled(bool);
   bool TextAutosizingEnabled() const { return text_autosizing_enabled_; }
 
+  void SetBypassCSP(bool enabled) { bypass_csp_ = enabled; }
+  bool BypassCSP() const { return bypass_csp_; }
+
   // Only set by Layout Tests, and only used if textAutosizingEnabled() returns
   // true.
   void SetTextAutosizingWindowSizeOverride(const IntSize&);
@@ -105,6 +108,7 @@
   // use counter via the shadow page. Once blink side use counter is removed,
   // this flag is no longer needed (crbug.com/811948).
   bool is_shadow_page_;
+  bool bypass_csp_ = false;
 
   SETTINGS_MEMBER_VARIABLES
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
index 337816c0..8d0d795 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -87,6 +87,7 @@
     "pageAgentScriptsToEvaluateOnLoad";
 static const char kScreencastEnabled[] = "screencastEnabled";
 static const char kLifecycleEventsEnabled[] = "lifecycleEventsEnabled";
+static const char kBypassCSPEnabled[] = "bypassCSPEnabled";
 }
 
 namespace {
@@ -458,6 +459,8 @@
 void InspectorPageAgent::Restore() {
   if (state_->booleanProperty(PageAgentState::kPageAgentEnabled, false))
     enable();
+  if (state_->booleanProperty(PageAgentState::kBypassCSPEnabled, false))
+    setBypassCSP(true);
 }
 
 Response InspectorPageAgent::enable() {
@@ -751,6 +754,13 @@
                 WTF::Passed(std::move(callback))));
 }
 
+Response InspectorPageAgent::setBypassCSP(bool enabled) {
+  LocalFrame* frame = inspected_frames_->Root();
+  frame->GetSettings()->SetBypassCSP(enabled);
+  state_->setBoolean(PageAgentState::kBypassCSPEnabled, enabled);
+  return Response::OK();
+}
+
 Response InspectorPageAgent::setDocumentContent(const String& frame_id,
                                                 const String& html) {
   LocalFrame* frame =
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
index 1bd0c87..4de8468 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
@@ -135,6 +135,8 @@
                         std::unique_ptr<SearchInResourceCallback>) override;
   protocol::Response setDocumentContent(const String& frame_id,
                                         const String& html) override;
+  protocol::Response setBypassCSP(bool enabled) override;
+
   protocol::Response startScreencast(Maybe<String> format,
                                      Maybe<int> quality,
                                      Maybe<int> max_width,
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index b384a59..abcc7e6 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -10381,6 +10381,18 @@
                     ]
                 },
                 {
+                    "name": "setBypassCSP",
+                    "description": "Enable page Content Security Policy by-passing.",
+                    "experimental": true,
+                    "parameters": [
+                        {
+                            "name": "enabled",
+                            "description": "Whether to bypass page CSP.",
+                            "type": "boolean"
+                        }
+                    ]
+                },
+                {
                     "name": "setDeviceMetricsOverride",
                     "description": "Overrides the values of device screen dimensions (window.screen.width, window.screen.height,\nwindow.innerWidth, window.innerHeight, and \"device-width\"/\"device-height\"-related CSS media\nquery results).",
                     "experimental": true,
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.pdl b/third_party/WebKit/Source/core/inspector/browser_protocol.pdl
index fc11ac4..5eb117b 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.pdl
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.pdl
@@ -4751,6 +4751,12 @@
       # Whether to block ads.
       boolean enabled
 
+  # Enable page Content Security Policy by-passing.
+  experimental command setBypassCSP
+    parameters
+      # Whether to bypass page CSP.
+      boolean enabled
+
   # Overrides the values of device screen dimensions (window.screen.width, window.screen.height,
   # window.innerWidth, window.innerHeight, and "device-width"/"device-height"-related CSS media
   # query results).
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index af6b909..52719a7 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -601,14 +601,17 @@
 
   content_security_policy_ = ContentSecurityPolicy::Create();
   content_security_policy_->SetOverrideURLForSelf(response.Url());
-  content_security_policy_->DidReceiveHeaders(
-      ContentSecurityPolicyResponseHeaders(response));
+  if (!frame_->GetSettings()->BypassCSP()) {
+    content_security_policy_->DidReceiveHeaders(
+        ContentSecurityPolicyResponseHeaders(response));
+  }
   if (!content_security_policy_->AllowAncestors(frame_, response.Url())) {
     CancelLoadAfterCSPDenied(response);
     return;
   }
 
-  if (RuntimeEnabledFeatures::EmbedderCSPEnforcementEnabled() &&
+  if (!frame_->GetSettings()->BypassCSP() &&
+      RuntimeEnabledFeatures::EmbedderCSPEnforcementEnabled() &&
       !GetFrameLoader().RequiredCSP().IsEmpty()) {
     const SecurityOrigin* parent_security_origin =
         frame_->Tree().Parent()->GetSecurityContext()->GetSecurityOrigin();
diff --git a/third_party/WebKit/Source/core/loader/HttpEquiv.cpp b/third_party/WebKit/Source/core/loader/HttpEquiv.cpp
index 9b2a417..86d438cc 100644
--- a/third_party/WebKit/Source/core/loader/HttpEquiv.cpp
+++ b/third_party/WebKit/Source/core/loader/HttpEquiv.cpp
@@ -9,6 +9,7 @@
 #include "core/dom/ScriptableDocumentParser.h"
 #include "core/frame/Deprecation.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/Settings.h"
 #include "core/frame/UseCounter.h"
 #include "core/frame/csp/ContentSecurityPolicy.h"
 #include "core/inspector/ConsoleMessage.h"
@@ -67,6 +68,8 @@
     const AtomicString& content) {
   if (document.ImportLoader())
     return;
+  if (document.GetSettings() && document.GetSettings()->BypassCSP())
+    return;
   if (EqualIgnoringASCIICase(equiv, "content-security-policy")) {
     document.GetContentSecurityPolicy()->DidReceiveHeader(
         content, kContentSecurityPolicyHeaderTypeEnforce,
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp
index d30c272..23ac92e 100644
--- a/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp
@@ -30,11 +30,9 @@
 
 #include "core/loader/ThreadableLoader.h"
 
-#include "core/dom/Document.h"
 #include "core/execution_context/ExecutionContext.h"
 #include "core/loader/DocumentThreadableLoader.h"
 #include "core/loader/ThreadableLoadingContext.h"
-#include "core/loader/WorkerThreadableLoader.h"
 #include "core/workers/WorkerGlobalScope.h"
 
 namespace blink {
@@ -45,18 +43,10 @@
     const ThreadableLoaderOptions& options,
     const ResourceLoaderOptions& resource_loader_options) {
   DCHECK(client);
-
-  if (context.IsWorkerGlobalScope()) {
+  if (context.IsWorkerGlobalScope())
     ToWorkerGlobalScope(&context)->EnsureFetcher();
-    // TODO(horo): Rename DocumentThreadableLoader. We are using it on the
-    // worker thread also.
-    return DocumentThreadableLoader::Create(
-        *ThreadableLoadingContext::Create(*ToWorkerGlobalScope(&context)),
-        client, options, resource_loader_options);
-  }
-
   return DocumentThreadableLoader::Create(
-      *ThreadableLoadingContext::Create(*ToDocument(&context)), client, options,
+      *ThreadableLoadingContext::Create(context), client, options,
       resource_loader_options);
 }
 
@@ -66,16 +56,9 @@
     ThreadableLoaderClient& client,
     const ThreadableLoaderOptions& options,
     const ResourceLoaderOptions& resource_loader_options) {
-  if (context.IsWorkerGlobalScope()) {
-    DocumentThreadableLoader::LoadResourceSynchronously(
-        *ThreadableLoadingContext::Create(*ToWorkerGlobalScope(&context)),
-        request, client, options, resource_loader_options);
-    return;
-  }
-
   DocumentThreadableLoader::LoadResourceSynchronously(
-      *ThreadableLoadingContext::Create(*ToDocument(&context)), request, client,
-      options, resource_loader_options);
+      *ThreadableLoadingContext::Create(context), request, client, options,
+      resource_loader_options);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index 6a101f8..b759107 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -87,7 +87,11 @@
       // If one of the values is auto we have to use the appropriate
       // scale to maintain our aspect ratio.
       if (layer_width.IsAuto() && !layer_height.IsAuto()) {
-        if (image_intrinsic_size.Height()) {
+        if (image->ImageHasRelativeSize()) {
+          // Spec says that auto should be 100% in the absence of
+          // an intrinsic ratio or size.
+          tile_size.SetWidth(positioning_area_size.Width());
+        } else if (image_intrinsic_size.Height()) {
           LayoutUnit adjusted_width = image_intrinsic_size.Width() *
                                       tile_size.Height() /
                                       image_intrinsic_size.Height();
@@ -96,7 +100,11 @@
           tile_size.SetWidth(adjusted_width);
         }
       } else if (!layer_width.IsAuto() && layer_height.IsAuto()) {
-        if (image_intrinsic_size.Width()) {
+        if (image->ImageHasRelativeSize()) {
+          // Spec says that auto should be 100% in the absence of
+          // an intrinsic ratio or size.
+          tile_size.SetHeight(positioning_area_size.Height());
+        } else if (image_intrinsic_size.Width()) {
           LayoutUnit adjusted_height = image_intrinsic_size.Height() *
                                        tile_size.Width() /
                                        image_intrinsic_size.Width();
diff --git a/third_party/WebKit/Source/core/paint/FragmentData.cpp b/third_party/WebKit/Source/core/paint/FragmentData.cpp
index ca19c609..040186e 100644
--- a/third_party/WebKit/Source/core/paint/FragmentData.cpp
+++ b/third_party/WebKit/Source/core/paint/FragmentData.cpp
@@ -52,7 +52,7 @@
   return LocalBorderBoxProperties().Transform();
 }
 
-const ClipPaintPropertyNode* FragmentData::ClipPathClip() const {
+const ClipPaintPropertyNode* FragmentData::PreClip() const {
   if (const auto* properties = PaintProperties()) {
     if (properties->ClipPathClip()) {
       // SPv1 composited clip-path has an alternative clip tree structure.
diff --git a/third_party/WebKit/Source/core/paint/FragmentData.h b/third_party/WebKit/Source/core/paint/FragmentData.h
index e845084..324f5c1 100644
--- a/third_party/WebKit/Source/core/paint/FragmentData.h
+++ b/third_party/WebKit/Source/core/paint/FragmentData.h
@@ -172,7 +172,7 @@
   // from the ancestor before applying any local CSS properties,
   // but includes paint offset transform.
   PropertyTreeState PreEffectProperties() const {
-    return PropertyTreeState(PreTransform(), ClipPathClip(), PreEffect());
+    return PropertyTreeState(PreTransform(), PreClip(), PreEffect());
   }
 
   // This is the complete set of property nodes that can be used to
@@ -198,7 +198,7 @@
 
   const TransformPaintPropertyNode* PreTransform() const;
   const TransformPaintPropertyNode* PostScrollTranslation() const;
-  const ClipPaintPropertyNode* ClipPathClip() const;
+  const ClipPaintPropertyNode* PreClip() const;
   const ClipPaintPropertyNode* PostOverflowClip() const;
   const EffectPaintPropertyNode* PreEffect() const;
   const EffectPaintPropertyNode* PreFilter() const;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
index 02163d3..9eeefb5 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
@@ -555,22 +555,13 @@
                                         .FirstFragment()
                                         .LocalBorderBoxProperties();
 
-  auto* ancestor_properties =
-      context.root_layer->GetLayoutObject().FirstFragment().PaintProperties();
-  if (!ancestor_properties)
-    return;
-
+  const auto& ancestor_fragment_data =
+      context.root_layer->GetLayoutObject().FirstFragment();
   if (context.ShouldRespectRootLayerClip()) {
-    const auto* ancestor_css_clip = ancestor_properties->CssClip();
-    if (ancestor_css_clip) {
-      DCHECK_EQ(destination_property_tree_state.Clip(),
-                ancestor_css_clip);
-      destination_property_tree_state.SetClip(ancestor_css_clip->Parent());
-    }
-  } else if (const auto* clip =
-                 ancestor_properties->OverflowOrInnerBorderRadiusClip()) {
-    DCHECK_EQ(destination_property_tree_state.Clip(), clip->Parent());
-    destination_property_tree_state.SetClip(clip);
+    destination_property_tree_state.SetClip(ancestor_fragment_data.PreClip());
+  } else {
+    destination_property_tree_state.SetClip(
+        ancestor_fragment_data.PostOverflowClip());
   }
 }
 
diff --git a/third_party/WebKit/Source/modules/BUILD.gn b/third_party/WebKit/Source/modules/BUILD.gn
index ed879aeb..4a859a4b 100644
--- a/third_party/WebKit/Source/modules/BUILD.gn
+++ b/third_party/WebKit/Source/modules/BUILD.gn
@@ -271,6 +271,7 @@
     "media_controls/elements/MediaControlInputElementTest.cpp",
     "media_controls/elements/MediaControlLoadingPanelElementTest.cpp",
     "media_controls/elements/MediaControlOverlayPlayButtonElementTest.cpp",
+    "media_controls/elements/MediaControlScrubbingMessageElementTest.cpp",
     "media_controls/elements/MediaControlTimelineElementTest.cpp",
     "media_controls/elements/MediaControlToggleClosedCaptionsButtonElementTest.cpp",
     "mediastream/MediaConstraintsTest.cpp",
diff --git a/third_party/WebKit/Source/modules/cookie_store/CookieStore.cpp b/third_party/WebKit/Source/modules/cookie_store/CookieStore.cpp
index 97e35816..ce21e04 100644
--- a/third_party/WebKit/Source/modules/cookie_store/CookieStore.cpp
+++ b/third_party/WebKit/Source/modules/cookie_store/CookieStore.cpp
@@ -127,6 +127,13 @@
       canonical_cookie->value = value;
     }
 
+    if (canonical_cookie->name.IsEmpty() &&
+        canonical_cookie->value.Contains('=')) {
+      exception_state.ThrowTypeError(
+          "Cookie value cannot contain '=' if the name is empty.");
+      return nullptr;
+    }
+
     if (options.hasExpires())
       canonical_cookie->expiry = WTF::Time::FromJavaTime(options.expires());
     // The expires option is not set in CookieStoreSetOptions for session
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlElementBase.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlElementBase.h
index 637957c8..840aa95a 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlElementBase.h
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlElementBase.h
@@ -27,7 +27,7 @@
  public:
   // These hold the state about whether this control should be shown if
   // space permits.  These will also show / hide as needed.
-  void SetIsWanted(bool);
+  virtual void SetIsWanted(bool);
   bool IsWanted() const;
 
   // Tell us whether we fit or not.  This will hide / show the control as
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp
index 1e01d36c..f7b6e61f 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp
@@ -47,10 +47,25 @@
 
 MediaControlOverlayPlayButtonElement::AnimatedArrow::AnimatedArrow(
     const AtomicString& id,
-    ContainerNode& parent)
-    : HTMLDivElement(parent.GetDocument()) {
+    Document& document)
+    : HTMLDivElement(document) {
   setAttribute("id", id);
-  parent.AppendChild(this);
+}
+
+void MediaControlOverlayPlayButtonElement::AnimatedArrow::HideInternal() {
+  DCHECK(!hidden_);
+  svg_container_->SetInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
+  hidden_ = true;
+}
+
+void MediaControlOverlayPlayButtonElement::AnimatedArrow::ShowInternal() {
+  DCHECK(hidden_);
+  hidden_ = false;
+
+  if (svg_container_) {
+    svg_container_->RemoveInlineStyleProperty(CSSPropertyDisplay);
+    return;
+  }
 
   SetInnerHTMLFromString(MediaControlsResourceLoader::GetJumpSVGImage());
 
@@ -58,24 +73,19 @@
   svg_container_ = getElementById("jump");
 
   event_listener_ = new MediaControlAnimationEventListener(this);
-  svg_container_->SetInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
 }
 
 void MediaControlOverlayPlayButtonElement::AnimatedArrow::
     OnAnimationIteration() {
   counter_--;
 
-  if (counter_ == 0) {
-    svg_container_->SetInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
-    hidden_ = true;
-  }
+  if (counter_ == 0)
+    HideInternal();
 }
 
 void MediaControlOverlayPlayButtonElement::AnimatedArrow::Show() {
-  if (hidden_) {
-    svg_container_->RemoveInlineStyleProperty(CSSPropertyDisplay);
-    hidden_ = false;
-  }
+  if (hidden_)
+    ShowInternal();
 
   counter_++;
 }
@@ -116,24 +126,9 @@
   SetShadowPseudoId(AtomicString("-webkit-media-controls-overlay-play-button"));
 
   if (MediaControlsImpl::IsModern()) {
-    ShadowRoot* shadow_root = GetShadowRoot();
-
-    // This stylesheet element and will contain rules that are specific to the
-    // loading panel. The shadow DOM protects these rules from the parent DOM
-    // from bleeding across the shadow DOM boundary.
-    auto* style = HTMLStyleElement::Create(GetDocument(), CreateElementFlags());
-    style->setTextContent(
-        MediaControlsResourceLoader::GetOverlayPlayStyleSheet());
-    shadow_root->AppendChild(style);
-
-    left_jump_arrow_ = new MediaControlOverlayPlayButtonElement::AnimatedArrow(
-        "left-arrow", *shadow_root);
-
     internal_button_ = MediaControlElementsHelper::CreateDiv(
-        "-internal-media-controls-overlay-play-button-internal", shadow_root);
-
-    right_jump_arrow_ = new MediaControlOverlayPlayButtonElement::AnimatedArrow(
-        "right-arrow", *shadow_root);
+        "-internal-media-controls-overlay-play-button-internal",
+        GetShadowRoot());
   }
 }
 
@@ -172,6 +167,31 @@
 }
 
 void MediaControlOverlayPlayButtonElement::MaybeJump(int seconds) {
+  // Load the arrow icons and associate CSS the first time we jump.
+  if (!left_jump_arrow_) {
+    DCHECK(!right_jump_arrow_);
+    ShadowRoot* shadow_root = GetShadowRoot();
+
+    // This stylesheet element and will contain rules that are specific to the
+    // jump arrows. The shadow DOM protects these rules from the parent DOM
+    // from bleeding across the shadow DOM boundary.
+    auto* style = HTMLStyleElement::Create(GetDocument(), CreateElementFlags());
+    style->setTextContent(
+        MediaControlsResourceLoader::GetOverlayPlayStyleSheet());
+    shadow_root->AppendChild(style);
+
+    // Insert the left jump arrow to the left of the play button.
+    left_jump_arrow_ = new MediaControlOverlayPlayButtonElement::AnimatedArrow(
+        "left-arrow", GetDocument());
+    shadow_root->InsertBefore(left_jump_arrow_, shadow_root->firstChild());
+
+    // Insert the right jump arrow to the right of the play button.
+    right_jump_arrow_ = new MediaControlOverlayPlayButtonElement::AnimatedArrow(
+        "right-arrow", GetDocument());
+    shadow_root->AppendChild(right_jump_arrow_);
+  }
+
+  DCHECK(left_jump_arrow_ && right_jump_arrow_);
   double new_time = std::max(0.0, MediaElement().currentTime() + seconds);
   new_time = std::min(new_time, MediaElement().duration());
   MediaElement().setCurrentTime(new_time);
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.h
index 09c825c9..866fb65 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.h
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.h
@@ -17,7 +17,6 @@
 
 namespace blink {
 
-class ContainerNode;
 class Event;
 class MediaControlsImpl;
 
@@ -49,7 +48,7 @@
     USING_GARBAGE_COLLECTED_MIXIN(AnimatedArrow);
 
    public:
-    AnimatedArrow(const AtomicString& id, ContainerNode& parent);
+    AnimatedArrow(const AtomicString& id, Document& document);
 
     // MediaControlAnimationEventListener::Observer overrides
     void OnAnimationIteration() override;
@@ -64,6 +63,9 @@
     void Trace(Visitor*);
 
    private:
+    void HideInternal();
+    void ShowInternal();
+
     int counter_ = 0;
     bool hidden_ = true;
 
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElementTest.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElementTest.cpp
index 50e8feba..e77a6237b 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElementTest.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElementTest.cpp
@@ -18,29 +18,40 @@
     // Create page and instance of AnimatedArrow to run tests on.
     PageTestBase::SetUp();
     arrow_element_ = new MediaControlOverlayPlayButtonElement::AnimatedArrow(
-        "test", *GetDocument().body());
+        "test", GetDocument());
+    GetDocument().body()->AppendChild(arrow_element_);
   }
 
  protected:
-  void ExpectIsHidden() { EXPECT_TRUE(SVGElementHasDisplayValue()); }
+  void ExpectNotPresent() { EXPECT_FALSE(SVGElementIsPresent()); }
 
-  void ExpectIsShown() { EXPECT_FALSE(SVGElementHasDisplayValue()); }
+  void ExpectPresentAndShown() {
+    EXPECT_TRUE(SVGElementIsPresent());
+    EXPECT_FALSE(SVGElementHasDisplayValue());
+  }
+
+  void ExpectPresentAndHidden() {
+    EXPECT_TRUE(SVGElementIsPresent());
+    EXPECT_TRUE(SVGElementHasDisplayValue());
+  }
 
   void SimulateShow() { arrow_element_->Show(); }
 
   void SimulateAnimationIteration() {
     Event* event = Event::Create(EventTypeNames::animationiteration);
-    GetElementById("arrow-3").DispatchEvent(event);
+    GetElementById("arrow-3")->DispatchEvent(event);
   }
 
  private:
   bool SVGElementHasDisplayValue() {
-    return GetElementById("jump").InlineStyle()->HasProperty(
+    return GetElementById("jump")->InlineStyle()->HasProperty(
         CSSPropertyDisplay);
   }
 
-  Element& GetElementById(const AtomicString& id) {
-    return *GetDocument().body()->getElementById(id);
+  bool SVGElementIsPresent() { return GetElementById("jump"); }
+
+  Element* GetElementById(const AtomicString& id) {
+    return GetDocument().body()->getElementById(id);
   }
 
   Persistent<MediaControlOverlayPlayButtonElement::AnimatedArrow>
@@ -48,24 +59,24 @@
 };
 
 TEST_F(MediaControlOverlayPlayButtonElementTest, ShowIncrementsCounter) {
-  ExpectIsHidden();
+  ExpectNotPresent();
 
   // Start a new show.
   SimulateShow();
-  ExpectIsShown();
+  ExpectPresentAndShown();
 
   // Increment the counter and finish the first show.
   SimulateShow();
   SimulateAnimationIteration();
-  ExpectIsShown();
+  ExpectPresentAndShown();
 
   // Finish the second show.
   SimulateAnimationIteration();
-  ExpectIsHidden();
+  ExpectPresentAndHidden();
 
   // Start a new show.
   SimulateShow();
-  ExpectIsShown();
+  ExpectPresentAndShown();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElement.cpp
index 5961030..74e9ee6e 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElement.cpp
@@ -19,7 +19,10 @@
     : MediaControlDivElement(media_controls, kMediaScrubbingMessage) {
   SetShadowPseudoId(AtomicString("-internal-media-controls-scrubbing-message"));
   CreateShadowRootInternal();
+  SetIsWanted(false);
+}
 
+void MediaControlScrubbingMessageElement::PopulateChildren() {
   ShadowRoot* shadow_root = GetShadowRoot();
 
   // This stylesheet element will contain rules that are specific to the
@@ -53,8 +56,14 @@
       MediaControlsResourceLoader::GetArrowRightSVGImage());
   arrow_right_div2->SetInnerHTMLFromString(
       MediaControlsResourceLoader::GetArrowRightSVGImage());
+}
 
-  SetIsWanted(false);
+void MediaControlScrubbingMessageElement::SetIsWanted(bool wanted) {
+  // Populate the DOM on demand.
+  if (wanted && !GetShadowRoot()->firstChild())
+    PopulateChildren();
+
+  MediaControlDivElement::SetIsWanted(wanted);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElement.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElement.h
index a6fdccc5..a95d040 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElement.h
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElement.h
@@ -5,16 +5,22 @@
 #ifndef MediaControlScrubbingMessageElement_h
 #define MediaControlScrubbingMessageElement_h
 
+#include "modules/ModulesExport.h"
 #include "modules/media_controls/elements/MediaControlDivElement.h"
 
 namespace blink {
 
 class MediaControlsImpl;
 
-class MediaControlScrubbingMessageElement final
+class MODULES_EXPORT MediaControlScrubbingMessageElement final
     : public MediaControlDivElement {
  public:
   explicit MediaControlScrubbingMessageElement(MediaControlsImpl&);
+
+  void SetIsWanted(bool) final;
+
+ private:
+  void PopulateChildren();
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElementTest.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElementTest.cpp
new file mode 100644
index 0000000..6c20770
--- /dev/null
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlScrubbingMessageElementTest.cpp
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "modules/media_controls/elements/MediaControlScrubbingMessageElement.h"
+
+#include "core/dom/ShadowRoot.h"
+#include "core/html/media/HTMLMediaElement.h"
+#include "core/html/media/HTMLVideoElement.h"
+#include "core/testing/PageTestBase.h"
+#include "modules/media_controls/MediaControlsImpl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+namespace {
+
+// The number of child elements the shadow DOM should have.
+const unsigned kExpectedElementCount = 6;
+
+}  // namespace
+
+class MediaControlScrubbingMessageElementTest : public PageTestBase {
+ public:
+  void SetUp() final {
+    // Create page and add a video element with controls.
+    PageTestBase::SetUp();
+    media_element_ = HTMLVideoElement::Create(GetDocument());
+    media_element_->SetBooleanAttribute(HTMLNames::controlsAttr, true);
+    GetDocument().body()->AppendChild(media_element_);
+
+    // Create instance of MediaControlScrubbingMessageElement to run tests on.
+    media_controls_ =
+        static_cast<MediaControlsImpl*>(media_element_->GetMediaControls());
+    ASSERT_NE(nullptr, media_controls_);
+    message_element_ =
+        new MediaControlScrubbingMessageElement(*media_controls_);
+  }
+
+ protected:
+  void SetIsWanted(bool wanted) { message_element_->SetIsWanted(wanted); }
+
+  unsigned CountChildren() const {
+    return message_element_->GetShadowRoot()->CountChildren();
+  }
+
+ private:
+  Persistent<HTMLMediaElement> media_element_;
+  Persistent<MediaControlsImpl> media_controls_;
+  Persistent<MediaControlScrubbingMessageElement> message_element_;
+};
+
+TEST_F(MediaControlScrubbingMessageElementTest, PopulateShadowDOM) {
+  EXPECT_EQ(0u, CountChildren());
+
+  // Show the element and the shadow DOM should now have children.
+  SetIsWanted(true);
+  EXPECT_EQ(kExpectedElementCount, CountChildren());
+
+  // Show the element again and we should have no more children.
+  SetIsWanted(true);
+  EXPECT_EQ(kExpectedElementCount, CountChildren());
+
+  // Hide the element and expect the children to remain.
+  SetIsWanted(false);
+  EXPECT_EQ(kExpectedElementCount, CountChildren());
+
+  // Hide the element again and still expect the children to remain.
+  SetIsWanted(false);
+  EXPECT_EQ(kExpectedElementCount, CountChildren());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/AnalyserOptions.idl b/third_party/WebKit/Source/modules/webaudio/AnalyserOptions.idl
index 8825426..7ad55d3 100644
--- a/third_party/WebKit/Source/modules/webaudio/AnalyserOptions.idl
+++ b/third_party/WebKit/Source/modules/webaudio/AnalyserOptions.idl
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// See https://webaudio.github.io/web-audio-api/#analyseroptions
+// See https://webaudio.github.io/web-audio-api/#dictdef-analyseroptions
 dictionary AnalyserOptions : AudioNodeOptions {
     unsigned long fftSize = 2048;
-    float maxDecibels = -30;
-    float minDecibels = -100;
-    float smoothingTimeConstant = 0.8;
+    double maxDecibels = -30;
+    double minDecibels = -100;
+    double smoothingTimeConstant = 0.8;
 };
\ No newline at end of file
diff --git a/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h b/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h
index 3fa24b5..a6e6ad0 100644
--- a/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h
+++ b/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h
@@ -51,7 +51,7 @@
   STATIC_ONLY(V8DOMWrapper);
 
  public:
-  static v8::Local<v8::Object> CreateWrapper(
+  PLATFORM_EXPORT static v8::Local<v8::Object> CreateWrapper(
       v8::Isolate*,
       v8::Local<v8::Object> creation_context,
       const WrapperTypeInfo*);
@@ -61,11 +61,11 @@
   // ScriptWrappable is not yet associated with any wrapper.  Returns the
   // wrapper already associated or |wrapper| if not yet associated.
   // The caller should always use the returned value rather than |wrapper|.
-  WARN_UNUSED_RESULT static v8::Local<v8::Object> AssociateObjectWithWrapper(
-      v8::Isolate*,
-      ScriptWrappable*,
-      const WrapperTypeInfo*,
-      v8::Local<v8::Object> wrapper);
+  PLATFORM_EXPORT WARN_UNUSED_RESULT static v8::Local<v8::Object>
+  AssociateObjectWithWrapper(v8::Isolate*,
+                             ScriptWrappable*,
+                             const WrapperTypeInfo*,
+                             v8::Local<v8::Object> wrapper);
   static void SetNativeInfo(v8::Isolate*,
                             v8::Local<v8::Object>,
                             const WrapperTypeInfo*,
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
index 28853613..b4af440e 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
@@ -345,6 +345,8 @@
   const EffectPaintPropertyNode* lca_effect =
       &LowestCommonAncestor(*target_effect, *current_effect_);
   while (current_effect_ != lca_effect) {
+    // This EndClips() and the later EndEffect() pop to the parent effect.
+    EndClips();
 #if DCHECK_IS_ON()
     DCHECK(state_stack_.size())
         << "Error: Chunk has an effect that escapes layer's effect.\n"
@@ -354,8 +356,6 @@
 #endif
     if (!state_stack_.size())
       break;
-    // Pop to the parent effect.
-    EndClips();
     EndEffect();
   }
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp
index d034b7a..0b7bc644 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp
@@ -165,6 +165,8 @@
   request->SetCheckForBrowserSideNavigation(CheckForBrowserSideNavigation());
   request->SetWasDiscarded(WasDiscarded());
   request->SetCORSPreflightPolicy(CORSPreflightPolicy());
+  if (IsAdResource())
+    request->SetIsAdResource();
 
   return request;
 }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequestTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequestTest.cpp
index 165898d..4b30898e0 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequestTest.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequestTest.cpp
@@ -148,6 +148,14 @@
   EXPECT_FALSE(original.IsAdResource());
   original.SetIsAdResource();
   EXPECT_TRUE(original.IsAdResource());
+
+  // Should persist across redirects.
+  std::unique_ptr<ResourceRequest> redirect_request =
+      original.CreateRedirectRequest(
+          KURL("https://example.test/redirect"), original.HttpMethod(),
+          original.SiteForCookies(), original.HttpReferrer(),
+          original.GetReferrerPolicy(), original.GetSkipServiceWorker());
+  EXPECT_TRUE(redirect_request->IsAdResource());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.cpp b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.cpp
index 8f6fc3d..5db46791 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.cpp
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.cpp
@@ -62,35 +62,17 @@
 
 MediaStreamComponent::MediaStreamComponent(const String& id,
                                            MediaStreamSource* source)
-    : MediaStreamComponent(id,
-                           source,
-                           true,
-                           false,
-                           WebMediaStreamTrack::ContentHintType::kNone) {}
-
-MediaStreamComponent::MediaStreamComponent(
-    const String& id,
-    MediaStreamSource* source,
-    bool enabled,
-    bool muted,
-    WebMediaStreamTrack::ContentHintType content_hint)
-    : source_(source),
-      id_(id),
-      unique_id_(GenerateUniqueId()),
-      enabled_(enabled),
-      muted_(muted),
-      content_hint_(content_hint),
-      constraints_() {
+    : source_(source), id_(id), unique_id_(GenerateUniqueId()) {
   DCHECK(id_.length());
 }
 
 MediaStreamComponent* MediaStreamComponent::Clone() const {
-  MediaStreamComponent* cloned_component = new MediaStreamComponent(
-      CreateCanonicalUUIDString(), Source(), enabled_, muted_, content_hint_);
-  // TODO(pbos): Clone |m_trackData| as well.
-  // TODO(pbos): Move properties from MediaStreamTrack here so that they are
-  // also cloned. Part of crbug:669212 since stopped is currently not carried
-  // over, nor is ended().
+  MediaStreamComponent* cloned_component =
+      new MediaStreamComponent(CreateCanonicalUUIDString(), Source());
+  cloned_component->SetEnabled(enabled_);
+  cloned_component->SetMuted(muted_);
+  cloned_component->SetContentHint(content_hint_);
+  cloned_component->SetConstraints(constraints_);
   return cloned_component;
 }
 
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h
index ac5a5df..554259e8 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h
@@ -111,11 +111,6 @@
 
  private:
   MediaStreamComponent(const String& id, MediaStreamSource*);
-  MediaStreamComponent(const String& id,
-                       MediaStreamSource*,
-                       bool enabled,
-                       bool muted,
-                       WebMediaStreamTrack::ContentHintType);
 
   // AudioSourceProviderImpl wraps a WebAudioSourceProvider::provideInput()
   // calls into chromium to get a rendered audio stream.
@@ -143,9 +138,10 @@
   Member<MediaStreamSource> source_;
   String id_;
   int unique_id_;
-  bool enabled_;
-  bool muted_;
-  WebMediaStreamTrack::ContentHintType content_hint_;
+  bool enabled_ = true;
+  bool muted_ = false;
+  WebMediaStreamTrack::ContentHintType content_hint_ =
+      WebMediaStreamTrack::ContentHintType::kNone;
   WebMediaConstraints constraints_;
   std::unique_ptr<TrackData> track_data_;
 };
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py
index 08631801..5aca7a1 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py
@@ -114,14 +114,14 @@
     def run_command(self,
                     args,
                     cwd=None,
+                    env=None,
                     input=None,  # pylint: disable=redefined-builtin
-                    timeout_seconds=False,
+                    timeout_seconds=None,
                     error_handler=None,
                     return_exit_code=False,
                     return_stderr=True,
-                    decode_output=False,
-                    env=None,
-                    debug_logging=False):
+                    decode_output=True,
+                    debug_logging=True):
         self._append_call(args, cwd=cwd, input=input, env=env)
 
         assert isinstance(args, list) or isinstance(args, tuple)
@@ -150,10 +150,13 @@
             script_error = ScriptError(script_args=args, exit_code=self._exit_code, output=self._output)
             error_handler(script_error)
 
+        output = self._output
         if return_stderr:
-            return self._output + self._stderr
+            output += self._stderr
+        if decode_output and type(output) is not unicode:
+            output = output.decode('utf-8')
 
-        return self._output
+        return output
 
     def cpu_count(self):
         return 2
@@ -176,7 +179,7 @@
                 env_string = ', env=%s' % env
             _log.info('MOCK popen: %s%s%s', args, cwd_string, env_string)
         if not self._proc:
-            self._proc = MockProcess(self._output)
+            self._proc = MockProcess(stdout=self._output, stderr=self._stderr, returncode=self._exit_code)
         return self._proc
 
     def call(self, args, **_):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py
index 500dd9b..d3dd34e 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py
@@ -31,8 +31,9 @@
 import optparse
 import traceback
 
-from webkitpy.common.host import Host
 from webkitpy.common import exit_codes
+from webkitpy.common.host import Host
+from webkitpy.common.system.log_utils import configure_logging
 from webkitpy.layout_tests.models import test_expectations
 from webkitpy.layout_tests.port.factory import platform_options
 from webkitpy.w3c.wpt_manifest import WPTManifest
@@ -126,43 +127,29 @@
     return failures
 
 
-def set_up_logging(logging_stream):
-    logger = logging.getLogger()
-    logger.setLevel(logging.INFO)
-    handler = logging.StreamHandler(logging_stream)
-    logger.addHandler(handler)
-    return (logger, handler)
+def run_checks(host, options):
+    failures = []
+    failures.extend(lint(host, options))
+    failures.extend(check_virtual_test_suites(host, options))
+    failures.extend(check_smoke_tests(host, options))
 
+    if options.json:
+        with open(options.json, 'w') as f:
+            json.dump(failures, f)
 
-def tear_down_logging(logger, handler):
-    logger.removeHandler(handler)
-
-
-def run_checks(host, options, logging_stream):
-    logger, handler = set_up_logging(logging_stream)
-    try:
-        failures = []
-        failures.extend(lint(host, options))
-        failures.extend(check_virtual_test_suites(host, options))
-        failures.extend(check_smoke_tests(host, options))
-
-        if options.json:
-            with open(options.json, 'w') as f:
-                json.dump(failures, f)
-
-        if failures:
-            _log.error('Lint failed.')
-            return 1
-        else:
-            _log.info('Lint succeeded.')
-            return 0
-    finally:
-        logger.removeHandler(handler)
+    if failures:
+        _log.error('Lint failed.')
+        return 1
+    else:
+        _log.info('Lint succeeded.')
+        return 0
 
 
 def main(argv, stderr, host=None):
     parser = optparse.OptionParser(option_list=platform_options(use_globs=True))
     parser.add_option('--json', help='Path to JSON output file')
+    parser.add_option('--verbose', action='store_true', default=False,
+                      help='log extra details that may be helpful when debugging')
     options, _ = parser.parse_args(argv)
 
     if not host:
@@ -175,13 +162,20 @@
         else:
             host = Host()
 
-    # Need to generate MANIFEST.json since some expectations correspond to WPT
-    # tests that aren't files and only exist in the manifest.
-    _log.info('Generating MANIFEST.json for web-platform-tests ...')
-    WPTManifest.ensure_manifest(host)
+    if options.verbose:
+        configure_logging(logging_level=logging.DEBUG, stream=stderr)
+        # Print full stdout/stderr when a command fails.
+        host.executive.error_output_limit = None
+    else:
+        # PRESUBMIT.py relies on our output, so don't include timestamps.
+        configure_logging(logging_level=logging.INFO, stream=stderr, include_time=False)
 
     try:
-        exit_status = run_checks(host, options, stderr)
+        # Need to generate MANIFEST.json since some expectations correspond to WPT
+        # tests that aren't files and only exist in the manifest.
+        _log.debug('Generating MANIFEST.json for web-platform-tests ...')
+        WPTManifest.ensure_manifest(host)
+        exit_status = run_checks(host, options)
     except KeyboardInterrupt:
         exit_status = exit_codes.INTERRUPTED_EXIT_STATUS
     except Exception as error:  # pylint: disable=broad-except
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py
index 0d95954..a17e067a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py
@@ -32,6 +32,7 @@
 
 from webkitpy.common import exit_codes
 from webkitpy.common.host_mock import MockHost
+from webkitpy.common.system.log_testing import LoggingTestCase
 from webkitpy.layout_tests import lint_test_expectations
 
 
@@ -89,7 +90,7 @@
         return sorted(self.ports.keys())
 
 
-class LintTest(unittest.TestCase):
+class LintTest(LoggingTestCase):
 
     def test_all_configurations(self):
         host = MockHost()
@@ -98,29 +99,19 @@
                                                FakePort(host, 'b', 'path-to-b'),
                                                FakePort(host, 'b-win', 'path-to-b')))
 
-        logging_stream = StringIO.StringIO()
         options = optparse.Values({'platform': None})
-        logger, handler = lint_test_expectations.set_up_logging(logging_stream)
-        try:
-            res = lint_test_expectations.lint(host, options)
-        finally:
-            lint_test_expectations.tear_down_logging(logger, handler)
+        res = lint_test_expectations.lint(host, options)
         self.assertEqual(res, [])
         self.assertEqual(host.ports_parsed, ['a', 'b', 'b-win'])
 
     def test_lint_test_files(self):
-        logging_stream = StringIO.StringIO()
         options = optparse.Values({'platform': 'test-mac-mac10.10'})
         host = MockHost()
 
         host.port_factory.all_port_names = lambda platform=None: [platform]
 
-        logger, handler = lint_test_expectations.set_up_logging(logging_stream)
-        try:
-            res = lint_test_expectations.lint(host, options)
-            self.assertEqual(res, [])
-        finally:
-            lint_test_expectations.tear_down_logging(logger, handler)
+        res = lint_test_expectations.lint(host, options)
+        self.assertEqual(res, [])
 
     def test_lint_test_files_errors(self):
         options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False})
@@ -132,16 +123,12 @@
         host.port_factory.get = lambda platform, options=None: port
         host.port_factory.all_port_names = lambda platform=None: [port.name()]
 
-        logging_stream = StringIO.StringIO()
-        logger, handler = lint_test_expectations.set_up_logging(logging_stream)
-        try:
-            res = lint_test_expectations.lint(host, options)
-        finally:
-            lint_test_expectations.tear_down_logging(logger, handler)
+        res = lint_test_expectations.lint(host, options)
 
         self.assertTrue(res)
-        self.assertIn('foo:1', logging_stream.getvalue())
-        self.assertIn('bar:1', logging_stream.getvalue())
+        all_logs = ''.join(self.logMessages())
+        self.assertIn('foo:1', all_logs)
+        self.assertIn('bar:1', all_logs)
 
     def test_extra_files_errors(self):
         options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False})
@@ -154,15 +141,11 @@
         host.port_factory.all_port_names = lambda platform=None: [port.name()]
         host.filesystem.write_text_file('/test.checkout/LayoutTests/LeakExpectations', '-- syntax error')
 
-        logging_stream = StringIO.StringIO()
-        logger, handler = lint_test_expectations.set_up_logging(logging_stream)
-        try:
-            res = lint_test_expectations.lint(host, options)
-        finally:
-            lint_test_expectations.tear_down_logging(logger, handler)
+        res = lint_test_expectations.lint(host, options)
 
         self.assertTrue(res)
-        self.assertIn('LeakExpectations:1', logging_stream.getvalue())
+        all_logs = ''.join(self.logMessages())
+        self.assertIn('LeakExpectations:1', all_logs)
 
     def test_lint_flag_specific_expectation_errors(self):
         options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False})
@@ -174,16 +157,12 @@
         host.port_factory.get = lambda platform, options=None: port
         host.port_factory.all_port_names = lambda platform=None: [port.name()]
 
-        logging_stream = StringIO.StringIO()
-        logger, handler = lint_test_expectations.set_up_logging(logging_stream)
-        try:
-            res = lint_test_expectations.lint(host, options)
-        finally:
-            lint_test_expectations.tear_down_logging(logger, handler)
+        res = lint_test_expectations.lint(host, options)
 
         self.assertTrue(res)
-        self.assertIn('flag-specific:1 Path does not exist. does/not/exist', logging_stream.getvalue())
-        self.assertNotIn('noproblem', logging_stream.getvalue())
+        all_logs = ''.join(self.logMessages())
+        self.assertIn('flag-specific:1 Path does not exist. does/not/exist', all_logs)
+        self.assertNotIn('noproblem', all_logs)
 
 
 class CheckVirtualSuiteTest(unittest.TestCase):
@@ -194,18 +173,13 @@
         orig_get = host.port_factory.get
         host.port_factory.get = lambda options: orig_get('test', options=options)
 
-        logging_stream = StringIO.StringIO()
-        logger, handler = lint_test_expectations.set_up_logging(logging_stream)
-        try:
-            res = lint_test_expectations.check_virtual_test_suites(host, options)
-            self.assertTrue(res)
+        res = lint_test_expectations.check_virtual_test_suites(host, options)
+        self.assertTrue(res)
 
-            options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False})
-            host.filesystem.exists = lambda path: True
-            res = lint_test_expectations.check_virtual_test_suites(host, options)
-            self.assertFalse(res)
-        finally:
-            lint_test_expectations.tear_down_logging(logger, handler)
+        options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False})
+        host.filesystem.exists = lambda path: True
+        res = lint_test_expectations.check_virtual_test_suites(host, options)
+        self.assertFalse(res)
 
 
 class MainTest(unittest.TestCase):
@@ -223,13 +197,13 @@
     def test_success(self):
         lint_test_expectations.lint = lambda host, options: []
         res = lint_test_expectations.main(['--platform', 'test'], self.stderr)
-        self.assertTrue('Lint succeeded' in self.stderr.getvalue())
+        self.assertEqual('Lint succeeded.', self.stderr.getvalue().strip())
         self.assertEqual(res, 0)
 
     def test_failure(self):
         lint_test_expectations.lint = lambda host, options: ['test failure']
         res = lint_test_expectations.main(['--platform', 'test'], self.stderr)
-        self.assertTrue('Lint failed' in self.stderr.getvalue())
+        self.assertEqual('Lint failed.', self.stderr.getvalue().strip())
         self.assertEqual(res, 1)
 
     def test_interrupt(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/README.chromium b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/README.chromium
index bc76730..ea6832d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/README.chromium
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/README.chromium
@@ -51,7 +51,7 @@
 Name: web-platform-tests - Test Suites for Web Platform specifications
 Short Name: wpt
 URL: https://github.com/w3c/web-platform-tests/
-Version: 5122353fba91c9d97599cb94a02fb8ec7ec1384e
+Version: d00f7bab7aecadbc2fc9a47172d090b4ba7e2ef2
 License: LICENSES FOR W3C TEST SUITES (http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html)
 License File: wpt/wpt/LICENSE.md
 Security Critical: no
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/checkout.sh b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/checkout.sh
index 08031d86..d8f77bd6 100755
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/checkout.sh
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/checkout.sh
@@ -9,7 +9,7 @@
 
 TARGET_DIR=$DIR/wpt
 REMOTE_REPO="https://chromium.googlesource.com/external/w3c/web-platform-tests.git"
-WPT_HEAD=5122353fba91c9d97599cb94a02fb8ec7ec1384e
+WPT_HEAD=d00f7bab7aecadbc2fc9a47172d090b4ba7e2ef2
 
 function clone {
   # Remove existing repo if already exists.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt.config.json b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt.config.json
index 146cdd1..be1b3e2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt.config.json
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt.config.json
@@ -1,9 +1,8 @@
 {
-  "bind_hostname": false,
   "doc_root": null,
   "ws_doc_root": null,
-  "external_host": null,
   "check_subdomains": false,
+  "server_host": "127.0.0.1",
   "ports": {
     "http": [8001, 8081],
     "https": [8444],
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/.gitignore b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/.gitignore
index ad1e88e..fd6a495 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/.gitignore
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/.gitignore
@@ -1,18 +1,31 @@
-*#
+# Python
 *.py[co]
+.virtualenv/
+_venv/
+.cache/
+.pytest_cache/
+.tox/
+
+# Node
+node_modules/
+
+# WPT repo stuff
+/MANIFEST.json
+
+testharness_runner.html
+!/testharness_runner.html
+!/tools/wptrunner/wptrunner/testharness_runner.html
+
+_certs
+config.json
+
+# Various OS/editor specific files
+*#
 *.sw[po]
 *~
-MANIFEST.json
 \#*
-_certs
-.virtualenv
-config.json
-node_modules
 scratch
-testharness_runner.html
-webdriver/.idea
+.idea/
 .vscode/
 .DS_Store
 *.rej
-_venv
-webdriver/.cache
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/config.default.json b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/config.default.json
index a55b17c..d08d7c4a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/config.default.json
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/config.default.json
@@ -1,14 +1,14 @@
-{"host": "web-platform.test",
+{"browser_host": "web-platform.test",
  "doc_root": null,
  "ws_doc_root": null,
- "external_host": null,
+ "server_host": null,
  "ports":{"http":[8000, "auto"],
           "https":[8443],
           "ws":["auto"],
           "wss":["auto"]},
  "check_subdomains": true,
  "log_level":"debug",
- "bind_hostname": true,
+ "bind_address": true,
  "ssl": {"type": "pregenerated",
          "encrypt_after_connect": false,
          "openssl": {
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/gitignore/gitignore.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/gitignore/gitignore.py
index 629ed6b..0be6f8f 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/gitignore/gitignore.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/gitignore/gitignore.py
@@ -17,6 +17,12 @@
     else:
         any_char = "."
         parts.append("^(?:.*/)?")
+    if pat[-1] == "/":
+        # If the last character is / match this directory or any subdirectory
+        pat = pat[:-1]
+        suffix = "(?:/|$)"
+    else:
+        suffix = "$"
     while i < len(pat):
         c = pat[i]
         if c == "\\":
@@ -63,7 +69,7 @@
 
     if seq:
         raise ValueError
-    parts.append("$")
+    parts.append(suffix)
     try:
         return re.compile("".join(parts))
     except Exception:
@@ -84,7 +90,7 @@
     if dir_only:
         line = line[:-1]
 
-    return invert, dir_only, fnmatch_translate(line, "/" in line)
+    return invert, dir_only, fnmatch_translate(line, dir_only)
 
 
 class PathFilter(object):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/lint/lint.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/lint/lint.py
index 03cd4c2..39c44cf 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/lint/lint.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/lint/lint.py
@@ -9,6 +9,7 @@
 import re
 import subprocess
 import sys
+import tempfile
 
 from collections import defaultdict
 
@@ -58,17 +59,20 @@
 
 %s: %s"""
 
-def all_filesystem_paths(repo_root):
-    path_filter = PathFilter(repo_root, extras=[".git/*"])
-    for dirpath, dirnames, filenames in os.walk(repo_root):
+def all_filesystem_paths(repo_root, subdir=None):
+    path_filter = PathFilter(repo_root, extras=[".git/"])
+    if subdir:
+        expanded_path = subdir
+    else:
+        expanded_path = repo_root
+    for dirpath, dirnames, filenames in os.walk(expanded_path):
         for filename in filenames:
             path = os.path.relpath(os.path.join(dirpath, filename), repo_root)
             if path_filter(path):
                 yield path
         dirnames[:] = [item for item in dirnames if
                        path_filter(os.path.relpath(os.path.join(dirpath, item) + "/",
-                                                   repo_root))]
-
+                                                   repo_root)+"/")]
 
 def _all_files_equal(paths):
     """
@@ -134,6 +138,28 @@
     return []
 
 
+def check_git_ignore(repo_root, paths):
+    errors = []
+    with tempfile.TemporaryFile('w+') as f:
+        f.write('\n'.join(paths))
+        f.seek(0)
+        try:
+            matches = subprocess.check_output(
+                ["git", "check-ignore", "--verbose", "--no-index", "--stdin"], stdin=f)
+            for match in matches.strip().split('\n'):
+                match_filter, path = match.split()
+                _, _, filter_string = match_filter.split(':')
+                # If the matching filter reported by check-ignore is a special-case exception,
+                # that's fine. Otherwise, it requires a new special-case exception.
+                if filter_string[0] != '!':
+                    errors += [("IGNORED PATH", "%s matches an ignore filter in .gitignore - "
+                                "please add a .gitignore exception" % path, path, None)]
+        except subprocess.CalledProcessError as e:
+            # Nonzero return code means that no match exists.
+            pass
+    return errors
+
+
 drafts_csswg_re = re.compile(r"https?\:\/\/drafts\.csswg\.org\/([^/?#]+)")
 w3c_tr_re = re.compile(r"https?\:\/\/www\.w3c?\.org\/TR\/([^/?#]+)")
 w3c_dev_re = re.compile(r"https?\:\/\/dev\.w3c?\.org\/[^/?#]+\/([^/?#]+)")
@@ -278,7 +304,9 @@
 
     for i, (error_type, msg, path, line) in enumerate(errors):
         normpath = os.path.normcase(path)
-        if error_type in data:
+        # Allow whitelisting all lint errors except the IGNORED PATH lint,
+        # which explains how to fix it correctly and shouldn't be ignored.
+        if error_type in data and error_type != "IGNORED PATH":
             wl_files = data[error_type]
             for file_match, allowed_lines in iteritems(wl_files):
                 if None in allowed_lines or line in allowed_lines:
@@ -722,14 +750,20 @@
 
 def lint_paths(kwargs, wpt_root):
     if kwargs.get("paths"):
-        r = os.path.realpath(wpt_root)
-        paths = [os.path.relpath(os.path.realpath(x), r) for x in kwargs["paths"]]
+        paths = []
+        for path in kwargs.get("paths"):
+            if os.path.isdir(path):
+                path_dir = list(all_filesystem_paths(wpt_root, path))
+                paths.extend(path_dir)
+            elif os.path.isfile(path):
+                paths.append(os.path.relpath(os.path.abspath(path), wpt_root))
+
+
     elif kwargs["all"]:
         paths = list(all_filesystem_paths(wpt_root))
     else:
         changed_paths = changed_files(wpt_root)
         force_all = False
-        # If we changed the lint itself ensure that we retest everything
         for path in changed_paths:
             path = path.replace(os.path.sep, "/")
             if path == "lint.whitelist" or path.startswith("tools/lint/"):
@@ -846,6 +880,13 @@
 all_paths_lints = [check_css_globally_unique]
 file_lints = [check_regexp_line, check_parsed, check_python_ast, check_script_metadata]
 
+# Don't break users of the lint that don't have git installed.
+try:
+    subprocess.check_output(["git", "--version"])
+    all_paths_lints += [check_git_ignore]
+except subprocess.CalledProcessError:
+    print('No git present; skipping .gitignore lint.')
+
 if __name__ == "__main__":
     args = create_parser().parse_args()
     error_count = main(**vars(args))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/manifest/manifest.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/manifest/manifest.py
index 8ceeb38..4a8deb06 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/manifest/manifest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/manifest/manifest.py
@@ -225,6 +225,9 @@
                 rv = Manifest.from_json(tests_root, json.load(f))
         except IOError:
             return None
+        except ValueError:
+            logger.warning("%r may be corrupted", manifest)
+            return None
         return rv
 
     return Manifest.from_json(tests_root, json.load(manifest))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/serve/serve.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/serve/serve.py
index e73a175..e58f149f 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/serve/serve.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/serve/serve.py
@@ -17,7 +17,7 @@
 from collections import defaultdict, OrderedDict
 from multiprocessing import Process, Event
 
-from ..localpaths import repo_root
+from localpaths import repo_root
 
 import sslutils
 from manifest.sourcefile import read_script_metadata, js_meta_re
@@ -387,19 +387,19 @@
         self.daemon = None
         self.stop = Event()
 
-    def start(self, init_func, host, port, paths, routes, bind_hostname, config,
+    def start(self, init_func, host, port, paths, routes, bind_address, config,
               ssl_config, **kwargs):
         self.proc = Process(target=self.create_daemon,
-                            args=(init_func, host, port, paths, routes, bind_hostname,
+                            args=(init_func, host, port, paths, routes, bind_address,
                                   config, ssl_config),
                             kwargs=kwargs)
         self.proc.daemon = True
         self.proc.start()
 
-    def create_daemon(self, init_func, host, port, paths, routes, bind_hostname,
+    def create_daemon(self, init_func, host, port, paths, routes, bind_address,
                       config, ssl_config, **kwargs):
         try:
-            self.daemon = init_func(host, port, paths, routes, bind_hostname, config,
+            self.daemon = init_func(host, port, paths, routes, bind_address, config,
                                     ssl_config, **kwargs)
         except socket.error:
             print("Socket error on port %s" % port, file=sys.stderr)
@@ -432,12 +432,12 @@
         return self.proc.is_alive()
 
 
-def check_subdomains(host, paths, bind_hostname, ssl_config, aliases):
+def check_subdomains(host, paths, bind_address, ssl_config, aliases):
     port = get_port()
     subdomains = get_subdomains(host)
 
     wrapper = ServerProc()
-    wrapper.start(start_http_server, host, port, paths, build_routes(aliases), bind_hostname,
+    wrapper.start(start_http_server, host, port, paths, build_routes(aliases), bind_address,
                   None, ssl_config)
 
     connected = False
@@ -490,7 +490,7 @@
     return "".join(rv)
 
 
-def start_servers(host, ports, paths, routes, bind_hostname, config, ssl_config,
+def start_servers(host, ports, paths, routes, bind_address, config, ssl_config,
                   **kwargs):
     servers = defaultdict(list)
     for scheme, ports in ports.iteritems():
@@ -505,21 +505,21 @@
                          "wss":start_wss_server}[scheme]
 
             server_proc = ServerProc()
-            server_proc.start(init_func, host, port, paths, routes, bind_hostname,
+            server_proc.start(init_func, host, port, paths, routes, bind_address,
                               config, ssl_config, **kwargs)
             servers[scheme].append((port, server_proc))
 
     return servers
 
 
-def start_http_server(host, port, paths, routes, bind_hostname, config, ssl_config,
+def start_http_server(host, port, paths, routes, bind_address, config, ssl_config,
                       **kwargs):
     return wptserve.WebTestHttpd(host=host,
                                  port=port,
                                  doc_root=paths["doc_root"],
                                  routes=routes,
                                  rewrites=rewrites,
-                                 bind_hostname=bind_hostname,
+                                 bind_address=bind_address,
                                  config=config,
                                  use_ssl=False,
                                  key_file=None,
@@ -527,14 +527,14 @@
                                  latency=kwargs.get("latency"))
 
 
-def start_https_server(host, port, paths, routes, bind_hostname, config, ssl_config,
+def start_https_server(host, port, paths, routes, bind_address, config, ssl_config,
                        **kwargs):
     return wptserve.WebTestHttpd(host=host,
                                  port=port,
                                  doc_root=paths["doc_root"],
                                  routes=routes,
                                  rewrites=rewrites,
-                                 bind_hostname=bind_hostname,
+                                 bind_address=bind_address,
                                  config=config,
                                  use_ssl=True,
                                  key_file=ssl_config["key_path"],
@@ -544,7 +544,7 @@
 
 
 class WebSocketDaemon(object):
-    def __init__(self, host, port, doc_root, handlers_root, log_level, bind_hostname,
+    def __init__(self, host, port, doc_root, handlers_root, log_level, bind_address,
                  ssl_config):
         self.host = host
         cmd_args = ["-p", port,
@@ -569,7 +569,7 @@
                          "--certificate", ssl_config["cert_path"],
                          "--tls-module", tls_module]
 
-        if (bind_hostname):
+        if (bind_address):
             cmd_args = ["-H", host] + cmd_args
         opts, args = pywebsocket._parse_args_and_config(cmd_args)
         opts.cgi_directories = []
@@ -608,25 +608,25 @@
         self.server = None
 
 
-def start_ws_server(host, port, paths, routes, bind_hostname, config, ssl_config,
+def start_ws_server(host, port, paths, routes, bind_address, config, ssl_config,
                     **kwargs):
     return WebSocketDaemon(host,
                            str(port),
                            repo_root,
                            paths["ws_doc_root"],
                            "debug",
-                           bind_hostname,
+                           bind_address,
                            ssl_config = None)
 
 
-def start_wss_server(host, port, paths, routes, bind_hostname, config, ssl_config,
+def start_wss_server(host, port, paths, routes, bind_address, config, ssl_config,
                      **kwargs):
     return WebSocketDaemon(host,
                            str(port),
                            repo_root,
                            paths["ws_doc_root"],
                            "debug",
-                           bind_hostname,
+                           bind_address,
                            ssl_config)
 
 
@@ -646,9 +646,15 @@
 
 
 def normalise_config(config, ports):
-    host = config["external_host"] if config["external_host"] else config["host"]
+    if "host" in config:
+        logger.warning("host in config is deprecated; use browser_host instead")
+        host = config["host"]
+    else:
+        host = config["browser_host"]
+
     domains = get_subdomains(host)
     not_domains = get_not_subdomains(host)
+
     ports_ = {}
     for scheme, ports_used in ports.iteritems():
         ports_[scheme] = ports_used
@@ -661,17 +667,21 @@
 
     domains[""] = host
 
-    ports_ = {}
-    for scheme, ports_used in ports.iteritems():
-        ports_[scheme] = ports_used
+    if "bind_hostname" in config:
+        logger.warning("bind_hostname in config is deprecated; use bind_address instead")
+        bind_address = config["bind_hostname"]
+    else:
+        bind_address = config["bind_address"]
 
     # make a (shallow) copy of the config and update that, so that the
     # normalized config can be used in place of the original one.
     config_ = config.copy()
-    config_["host"] = host
     config_["domains"] = domains
     config_["not_domains"] = not_domains
     config_["ports"] = ports_
+    config_["bind_address"] = bind_address
+    if config.get("server_host", None) is None:
+        config_["server_host"] = host
     return config_
 
 
@@ -687,14 +697,15 @@
             "cert_path": cert_path,
             "encrypt_after_connect": config["ssl"]["encrypt_after_connect"]}
 
+
 def start(config, ssl_environment, routes, **kwargs):
-    host = config["host"]
+    host = config["server_host"]
     ports = get_ports(config, ssl_environment)
     paths = get_paths(config)
-    bind_hostname = config["bind_hostname"]
+    bind_address = config["bind_address"]
     ssl_config = get_ssl_config(config, ssl_environment)
 
-    servers = start_servers(host, ports, paths, routes, bind_hostname, config,
+    servers = start_servers(host, ports, paths, routes, bind_address, config,
                             ssl_config, **kwargs)
 
     return servers
@@ -811,17 +822,18 @@
     with get_ssl_environment(config) as ssl_env:
         ports = get_ports(config, ssl_env)
         config = normalise_config(config, ports)
-        host = config["host"]
-        bind_hostname = config["bind_hostname"]
+        browser_host = config["browser_host"]
+        server_host = config["server_host"]
+        bind_address = config["bind_address"]
 
         if config["check_subdomains"]:
             paths = get_paths(config)
             ssl_config = get_ssl_config(config, ssl_env)
-            check_subdomains(host, paths, bind_hostname, ssl_config, config["aliases"])
+            check_subdomains(browser_host, paths, bind_address, ssl_config, config["aliases"])
 
         stash_address = None
-        if bind_hostname:
-            stash_address = (host, get_port())
+        if bind_address:
+            stash_address = (server_host, get_port())
 
         with stash.StashServer(stash_address, authkey=str(uuid.uuid4())):
             servers = start(config, ssl_env, build_routes(config["aliases"]), **kwargs)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/browser.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/browser.py
index 3246052d..d52feb03 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/browser.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/browser.py
@@ -65,29 +65,10 @@
     """
 
     product = "firefox"
-    binary = "firefox/firefox"
-    platform_ini = "firefox/platform.ini"
+    binary = "browsers/firefox/firefox"
+    platform_ini = "browsers/firefox/platform.ini"
     requirements = "requirements_firefox.txt"
 
-    def platform_string(self):
-        platform = {
-            "Linux": "linux",
-            "Windows": "win",
-            "Darwin": "mac"
-        }.get(uname[0])
-
-        if platform is None:
-            raise ValueError("Unable to construct a valid Firefox package name for current platform")
-
-        if platform == "linux":
-            bits = "-%s" % uname[4]
-        elif platform == "win":
-            bits = "64" if uname[4] == "x86_64" else "32"
-        else:
-            bits = ""
-
-        return "%s%s" % (platform, bits)
-
     def platform_string_geckodriver(self):
         platform = {
             "Linux": "linux",
@@ -105,40 +86,87 @@
 
         return "%s%s" % (platform, bits)
 
-    def latest_nightly_listing(self):
-        resp = get("https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/")
-        resp.raise_for_status()
-        return resp.text
-
-    def get_nightly_link(self, index, platform):
-        pattern = re.compile("<a[^>]*>(firefox-(\d+)\.\d(?:\w\d)?.en-US.%s\.tar\.bz2)" % platform)
-        max_version = None
-        for match in pattern.finditer(index):
-            try:
-                version = int(match.group(2))
-            except ValueError:
-                continue
-            if max_version is None or version > max_version[0]:
-                max_version = (version, match.group(1))
-        if not max_version:
-            raise ValueError("Failed to find version to download")
-        return ("https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/%s" %
-                max_version[1])
-
     def install(self, dest=None):
         """Install Firefox."""
+
+        from mozdownload import FactoryScraper
+        import mozinstall
+
+        platform = {
+            "Linux": "linux",
+            "Windows": "win",
+            "Darwin": "mac"
+        }.get(uname[0])
+
+        if platform is None:
+            raise ValueError("Unable to construct a valid Firefox package name for current platform")
+
         if dest is None:
-            dest = os.getcwd()
+            # os.getcwd() doesn't include the venv path
+            dest = os.path.join(os.getcwd(), "_venv")
 
-        nightly_link = self.get_nightly_link(self.latest_nightly_listing(),
-                                             self.platform_string())
-        resp = get(nightly_link)
-        resp.raise_for_status()
-        untar(resp.raw, dest=dest)
-        return find_executable("firefox", os.path.join(dest, "firefox"))
+        dest = os.path.join(dest, "browsers")
 
-    def find_binary(self):
-        return find_executable("firefox")
+        filename = FactoryScraper("daily", branch="mozilla-central", destination=dest).download()
+
+        try:
+            mozinstall.install(filename, dest)
+        except mozinstall.mozinstall.InstallError as e:
+            if platform == "mac" and os.path.exists(os.path.join(dest, "Firefox Nightly.app")):
+                # mozinstall will fail if nightly is already installed in the venv because
+                # mac installation uses shutil.copy_tree
+                mozinstall.uninstall(os.path.join(dest, "Firefox Nightly.app"))
+                mozinstall.install(filename, dest)
+            else:
+                raise
+
+        os.remove(filename)
+        return self.find_binary_path(dest)
+
+    def find_binary_path(self, path=None):
+        """Looks for the firefox binary in the virtual environment"""
+
+        platform = {
+            "Linux": "linux",
+            "Windows": "win",
+            "Darwin": "mac"
+        }.get(uname[0])
+
+        if path is None:
+            #os.getcwd() doesn't include the venv path
+            path = os.path.join(os.getcwd(), "_venv", "browsers")
+
+        binary = None
+
+        if platform == "linux":
+            binary = find_executable("firefox", os.path.join(path, "firefox"))
+        elif platform == "win":
+            import mozinstall
+            binary = mozinstall.get_binary(path, "firefox")
+        elif platform == "mac":
+            binary = find_executable("firefox", os.path.join(path, "Firefox Nightly.app", "Contents", "MacOS"))
+
+        return binary
+
+    def find_binary(self, venv_path=None):
+        if venv_path is None:
+            venv_path = os.path.join(os.getcwd(), venv_path)
+
+        binary = self.find_binary_path(os.path.join(venv_path, "browsers"))
+
+        if not binary and uname[0] == "Darwin":
+            macpaths = ["/Applications/FirefoxNightly.app/Contents/MacOS",
+                        os.path.expanduser("~/Applications/FirefoxNightly.app/Contents/MacOS"),
+                        "/Applications/Firefox Developer Edition.app/Contents/MacOS",
+                        os.path.expanduser("~/Applications/Firefox Developer Edition.app/Contents/MacOS"),
+                        "/Applications/Firefox.app/Contents/MacOS",
+                        os.path.expanduser("~/Applications/Firefox.app/Contents/MacOS")]
+            return find_executable("firefox", os.pathsep.join(macpaths))
+
+        if binary is None:
+            return find_executable("firefox")
+
+        return binary
 
     def find_certutil(self):
         path = find_executable("certutil")
@@ -431,8 +459,37 @@
     product = "servo"
     requirements = "requirements_servo.txt"
 
+    def platform_components(self):
+        platform = {
+            "Linux": "linux",
+            "Windows": "win",
+            "Darwin": "mac"
+        }.get(uname[0])
+
+        if platform is None:
+            raise ValueError("Unable to construct a valid Servo package for current platform")
+
+        if platform == "linux":
+            extension = ".tar.gz"
+            decompress = untar
+        elif platform == "win" or platform == "mac":
+            raise ValueError("Unable to construct a valid Servo package for current platform")
+
+        return (platform, extension, decompress)
+
     def install(self, dest=None):
-        raise NotImplementedError
+        """Install latest Browser Engine."""
+        if dest is None:
+            dest = os.pwd
+
+        platform, extension, decompress = self.platform_components()
+        url = "https://download.servo.org/nightly/%s/servo-latest%s" % (platform, extension)
+
+        decompress(get(url).raw, dest=dest)
+        path = find_executable("servo", os.path.join(dest, "servo"))
+        st = os.stat(path)
+        os.chmod(path, st.st_mode | stat.S_IEXEC)
+        return path
 
     def find_binary(self):
         return find_executable("servo")
@@ -444,7 +501,9 @@
         raise NotImplementedError
 
     def version(self, root):
-        return None
+        """Retrieve the release version of the installed browser."""
+        output = call(self.binary, "--version")
+        return re.search(r"[0-9\.]+( [a-z]+)?$", output.strip()).group(0)
 
 
 class Sauce(Browser):
@@ -467,3 +526,24 @@
 
     def version(self, root):
         return None
+
+class WebKit(Browser):
+    """WebKit-specific interface."""
+
+    product = "webkit"
+    requirements = "requirements_webkit.txt"
+
+    def install(self, dest=None):
+        raise NotImplementedError
+
+    def find_binary(self, path=None):
+        return None
+
+    def find_webdriver(self):
+        return None
+
+    def install_webdriver(self):
+        raise NotImplementedError
+
+    def version(self, root):
+        return None
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/commands.json b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/commands.json
index 38cdd3a..0ea6b25 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/commands.json
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/commands.json
@@ -9,6 +9,7 @@
                       "help": "Get a list of files that have changed", "virtualenv": false},
     "tests-affected": {"path": "testfiles.py", "script": "run_tests_affected", "parser": "get_parser_affected",
                        "help": "Get a list of tests affected by changes", "virtualenv": false},
-    "install": {"path": "install.py", "script": "run", "parser": "get_parser", "help": "Install browser components"},
+    "install": {"path": "install.py", "script": "run", "parser": "get_parser", "help": "Install browser components",
+                "install": ["mozdownload", "mozinstall"]},
     "branch-point": {"path": "testfiles.py", "script": "display_branch_point", "parser": null, "help": "Print branch point from master", "virtualenv": false}
 }
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/run.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/run.py
index 1b9acec..dab11d9a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/run.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wpt/run.py
@@ -96,10 +96,11 @@
 
 def check_environ(product):
     if product not in ("firefox", "servo"):
-        expected_hosts = {".".join(x)
-                          for x in serve.get_subdomains("web-platform.test").values()}
-        expected_hosts |= {".".join(x)
-                           for x in serve.get_not_subdomains("web-platform.test").values()}
+        config = serve.load_config(os.path.join(wpt_root, "config.default.json"),
+                                   os.path.join(wpt_root, "config.json"))
+        config = serve.normalise_config(config, {})
+        expected_hosts = (set(config["domains"].itervalues()) ^
+                          set(config["not_domains"].itervalues()))
         missing_hosts = set(expected_hosts)
         if platform.uname()[0] != "Windows":
             hosts_path = "/etc/hosts"
@@ -116,13 +117,13 @@
                 if platform.uname()[0] != "Windows":
                     message = """Missing hosts file configuration. Run
 
-python wpt make-hosts-file >> %s
-
-from a shell with Administrator privileges.""" % hosts_path
+./wpt make-hosts-file | sudo tee -a %s""" % hosts_path
                 else:
                     message = """Missing hosts file configuration. Run
 
-./wpt make-hosts-file | sudo tee -a %s""" % hosts_path
+python wpt make-hosts-file >> %s
+
+from a shell with Administrator privileges.""" % hosts_path
                 raise WptrunError(message)
 
 
@@ -150,8 +151,10 @@
         if self.prompt_install(self.name):
             return self.browser.install(venv.path)
 
-    def setup(self, kwargs):
+    def install_requirements(self):
         self.venv.install_requirements(os.path.join(wpt_root, "tools", "wptrunner", self.browser.requirements))
+
+    def setup(self, kwargs):
         self.setup_kwargs(kwargs)
 
 
@@ -161,7 +164,7 @@
 
     def setup_kwargs(self, kwargs):
         if kwargs["binary"] is None:
-            binary = self.browser.find_binary()
+            binary = self.browser.find_binary(self.venv.path)
             if binary is None:
                 raise WptrunError("""Firefox binary not found on $PATH.
 
@@ -350,7 +353,8 @@
     browser_cls = browser.Servo
 
     def install(self, venv):
-        raise NotImplementedError
+        if self.prompt_install(self.name):
+            return self.browser.install(venv.path)
 
     def setup_kwargs(self, kwargs):
         if kwargs["binary"] is None:
@@ -361,6 +365,17 @@
             kwargs["binary"] = binary
 
 
+class WebKit(BrowserSetup):
+    name = "webkit"
+    browser_cls = browser.WebKit
+
+    def install(self, venv):
+        raise NotImplementedError
+
+    def setup_kwargs(self, kwargs):
+        pass
+
+
 product_setup = {
     "firefox": Firefox,
     "chrome": Chrome,
@@ -371,6 +386,7 @@
     "servo": Servo,
     "sauce": Sauce,
     "opera": Opera,
+    "webkit": WebKit,
 }
 
 
@@ -395,6 +411,7 @@
         raise WptrunError("Unsupported product %s" % kwargs["product"])
 
     setup_cls = product_setup[kwargs["product"]](venv, prompt, sub_product)
+    setup_cls.install_requirements()
 
     if install:
         logger.info("Installing browser")
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/pipes.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/pipes.py
index 534afed6..126a68e3 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/pipes.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/pipes.py
@@ -398,6 +398,8 @@
                 value = request.server.config['not_domains']
             else:
                 value = request.server.config['domains']
+        elif field == "host":
+            value = request.server.config["browser_host"]
         elif field in request.server.config:
             value = request.server.config[tokens[0][1]]
         elif field == "location":
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/server.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/server.py
index f9ed238..d1ef750 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/server.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/server.py
@@ -111,7 +111,7 @@
     daemon_threads = True
 
     def __init__(self, server_address, request_handler_cls,
-                 router, rewriter, bind_hostname,
+                 router, rewriter, bind_address,
                  config=None, use_ssl=False, key_file=None, certificate=None,
                  encrypt_after_connect=False, latency=None, **kwargs):
         """Server for HTTP(s) Requests
@@ -141,10 +141,10 @@
                                       This enables the server to act as a
                                       self-proxy.
 
-        :param bind_hostname True to bind the server to both the hostname and
-                             port specified in the server_address parameter.
-                             False to bind the server only to the port in the
-                             server_address parameter, but not to the hostname.
+        :param bind_address True to bind the server to both the IP address and
+                            port specified in the server_address parameter.
+                            False to bind the server only to the port in the
+                            server_address parameter, but not to the address.
         :param latency: Delay in ms to wait before seving each response, or
                         callable that returns a delay in ms
         """
@@ -156,7 +156,7 @@
 
         self.latency = latency
 
-        if bind_hostname:
+        if bind_address:
             hostname_port = server_address
         else:
             hostname_port = ("",server_address[1])
@@ -168,7 +168,8 @@
             Server.config = config
         else:
             self.logger.debug("Using default configuration")
-            Server.config = {"host": server_address[0],
+            Server.config = {"browser_host": server_address[0],
+                             "server_host": server_address[0],
                              "domains": {"": server_address[0]},
                              "ports": {"http": [self.server_address[1]]}}
 
@@ -343,7 +344,7 @@
     :param rewrites: List of rewrites with which to initialize the rewriter_cls
     :param config: Dictionary holding environment configuration settings for
                    handlers to read, or None to use the default values.
-    :param bind_hostname: Boolean indicating whether to bind server to hostname.
+    :param bind_address: Boolean indicating whether to bind server to IP address.
     :param latency: Delay in ms to wait before seving each response, or
                     callable that returns a delay in ms
 
@@ -381,7 +382,7 @@
                  server_cls=None, handler_cls=WebTestRequestHandler,
                  use_ssl=False, key_file=None, certificate=None, encrypt_after_connect=False,
                  router_cls=Router, doc_root=os.curdir, routes=None,
-                 rewriter_cls=RequestRewriter, bind_hostname=True, rewrites=None,
+                 rewriter_cls=RequestRewriter, bind_address=True, rewrites=None,
                  latency=None, config=None):
 
         if routes is None:
@@ -409,7 +410,7 @@
                                     self.router,
                                     self.rewriter,
                                     config=config,
-                                    bind_hostname=bind_hostname,
+                                    bind_address=bind_address,
                                     use_ssl=use_ssl,
                                     key_file=key_file,
                                     certificate=certificate,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier.py
index bd5c394c..17de2ba 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier.py
@@ -215,7 +215,8 @@
             directory, self.finder.path_from_layout_tests('external', 'wpt'))
         commit_list = ''
         for sha, subject in imported_commits:
-            line = '{}: {}'.format(subject, GITHUB_COMMIT_PREFIX + sha)
+            # subject is a Unicode string and can contain non-ASCII characters.
+            line = u'{}: {}'.format(subject, GITHUB_COMMIT_PREFIX + sha)
             if self.local_wpt.is_commit_affecting_directory(sha, path_from_wpt):
                 line += ' [affecting this directory]'
             commit_list += line + '\n'
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier_unittest.py
index 5c2c8da..73082cbc 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/import_notifier_unittest.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # Copyright 2017 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -130,7 +131,9 @@
         self.assertEqual(self.notifier.new_failures_by_directory, {})
 
     def test_format_commit_list(self):
-        imported_commits = [('SHA1', 'Subject 1'), ('SHA2', 'Subject 2')]
+        imported_commits = [('SHA1', 'Subject 1'),
+                            # Use non-ASCII chars to really test Unicode handling.
+                            ('SHA2', u'ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ')]
 
         def _is_commit_affecting_directory(commit, directory):
             self.assertIn(commit, ('SHA1', 'SHA2'))
@@ -140,8 +143,8 @@
         self.local_wpt.is_commit_affecting_directory = _is_commit_affecting_directory
         self.assertEqual(
             self.notifier.format_commit_list(imported_commits, '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo'),
-            'Subject 1: https://github.com/w3c/web-platform-tests/commit/SHA1 [affecting this directory]\n'
-            'Subject 2: https://github.com/w3c/web-platform-tests/commit/SHA2\n'
+            u'Subject 1: https://github.com/w3c/web-platform-tests/commit/SHA1 [affecting this directory]\n'
+            u'ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ: https://github.com/w3c/web-platform-tests/commit/SHA2\n'
         )
 
     def test_find_owned_directory_non_virtual(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
index 6e973784..ec123ea8 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
@@ -117,25 +117,17 @@
         wpt_path = manifest_path = finder.path_from_layout_tests('external', 'wpt')
         WPTManifest.generate_manifest(host, wpt_path)
 
-        # Adding this log line to diagnose https://crbug.com/714503
         _log.debug('Manifest generation completed.')
 
     @staticmethod
     def generate_manifest(host, dest_path):
         """Generates MANIFEST.json on the specified directory."""
-        executive = host.executive
         finder = PathFinder(host.filesystem)
         wpt_exec_path = finder.path_from_tools_scripts('webkitpy', 'thirdparty', 'wpt', 'wpt', 'wpt')
-
         cmd = ['python', wpt_exec_path, 'manifest', '--work', '--tests-root', dest_path]
-        _log.debug('Running command: %s', ' '.join(cmd))
-        proc = executive.popen(cmd, stdout=executive.PIPE, stderr=executive.PIPE, stdin=executive.PIPE)
-        out, err = proc.communicate('')
-        if proc.returncode:
-            _log.info('# ret> %d', proc.returncode)
-            if out:
-                _log.info(out)
-            if err:
-                _log.info(err)
-            host.exit(proc.returncode)
-        return proc.returncode, out
+
+        # ScriptError will be raised if the command fails.
+        host.executive.run_command(
+            cmd,
+            return_stderr=True  # This will also include stderr in the exception message.
+        )
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest_unittest.py
index fd72080..201f0cc0 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest_unittest.py
@@ -5,6 +5,8 @@
 import unittest
 
 from webkitpy.common.host_mock import MockHost
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.w3c.wpt_manifest import WPTManifest
 
 
@@ -37,7 +39,7 @@
         host = MockHost()
         manifest_path = '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json'
 
-        host.filesystem.write_binary_file(manifest_path, '{}')
+        host.filesystem.write_text_file(manifest_path, '{}')
         self.assertTrue(host.filesystem.exists(manifest_path))
 
         WPTManifest.ensure_manifest(host)
@@ -57,3 +59,10 @@
                 ]
             ]
         )
+
+    def test_ensure_manifest_raises_exception(self):
+        host = MockHost()
+        host.executive = MockExecutive(should_throw=True)
+
+        with self.assertRaises(ScriptError):
+            WPTManifest.ensure_manifest(host)
diff --git a/third_party/blink/tools/move_blink_source.py b/third_party/blink/tools/move_blink_source.py
index bffa5b2..3c0be5f1 100755
--- a/third_party/blink/tools/move_blink_source.py
+++ b/third_party/blink/tools/move_blink_source.py
@@ -12,6 +12,7 @@
 import argparse
 import logging
 import os
+import platform
 import re
 import sys
 from functools import partial
@@ -29,6 +30,7 @@
 from webkitpy.common.system.executive import Executive
 from webkitpy.common.system.executive import ScriptError
 from webkitpy.common.system.filesystem import FileSystem
+from webkitpy.common.system.platform_info import PlatformInfo
 
 _log = logging.getLogger('move_blink_source')
 
@@ -89,17 +91,18 @@
 
     def __init__(self, fs, options, repo_root):
         self._fs = fs
+        self._platform = PlatformInfo(sys, platform, fs, Executive())
         self._options = options
         _log.debug(options)
         self._repo_root = repo_root
 
         # The following fields are initialized in _create_basename_maps.
         self._basename_map = None
-        self._basename_re = None
+        self._basename_re_list = None
         self._idl_generated_impl_headers = None
-        # _checked_in_header_re is used to distinguish checked-in header files
-        # and generated header files.
-        self._checked_in_header_re = None
+        # _checked_in_header_re_list is used to distinguish checked-in
+        # header files and generated header files.
+        self._checked_in_header_re_list = None
 
         self._updated_files = []
 
@@ -216,7 +219,7 @@
 
         if self._options.run:
             _log.info('Formatting updated %d files ...', len(self._updated_files))
-            git = Git(cwd=self._repo_root)
+            git = self._create_git()
             # |git cl format| can't handle too many files at once.
             while len(self._updated_files) > 0:
                 end_index = 100
@@ -253,7 +256,7 @@
                           if 'third_party/WebKit/' + src.replace('\\', '/') in apply_only]
         _log.info('Will move %d files', len(file_pairs))
 
-        git = Git(cwd=self._repo_root)
+        git = self._create_git()
         files_set = self._get_checked_in_files(git)
         for i, (src, dest) in enumerate(file_pairs):
             src_from_repo = self._fs.join('third_party', 'WebKit', src)
@@ -295,7 +298,7 @@
 """)
 
     def fix_branch(self):
-        git = Git(cwd=self._repo_root)
+        git = self._create_git()
         status = self._get_local_change_status(git)
         if len(status) == 0:
             _log.info('No local changes.')
@@ -342,12 +345,9 @@
 
     def _create_basename_maps(self, file_pairs):
         basename_map = {}
-        # Generated inspector/protocol/* contains a lot of names duplicated with
-        # checked-in core files. We don't want to rename them, and don't want to
-        # replace them in BUILD.gn and #include accidentally.
-        pattern = r'(?<!inspector/protocol/)\b('
+        basenames = []
         idl_headers = set()
-        header_pattern = r'(?<!inspector/protocol/)\b('
+        headers = []
         for source, dest in file_pairs:
             _, source_base = self._fs.split(source)
             _, dest_base = self._fs.split(dest)
@@ -356,27 +356,45 @@
             if 'bindings/tests' in source.replace('\\', '/'):
                 continue
             if source_base.endswith('.h'):
-                header_pattern += re.escape(source_base) + '|'
+                headers.append(re.escape(source_base))
             if source_base == dest_base:
                 continue
             basename_map[source_base] = dest_base
-            pattern += re.escape(source_base) + '|'
+            basenames.append(re.escape(source_base))
             # IDL sometimes generates implementation files as well as
             # binding files. We'd like to update #includes for such files.
             if source_base.endswith('.idl'):
                 source_header = source_base.replace('.idl', '.h')
                 basename_map[source_header] = dest_base.replace('.idl', '.h')
-                pattern += re.escape(source_header) + '|'
+                basenames.append(re.escape(source_header))
                 idl_headers.add(source_header)
             elif source_base.endswith('.proto'):
                 source_header = source_base.replace('.proto', '.pb.h')
                 basename_map[source_header] = dest_base.replace('.proto', '.pb.h')
-                pattern += re.escape(source_header) + '|'
+                basenames.append(re.escape(source_header))
         _log.debug('Rename %d files for snake_case', len(basename_map))
         self._basename_map = basename_map
-        self._basename_re = re.compile(pattern[0:len(pattern) - 1] + ')(?=["\']|$)')
         self._idl_generated_impl_headers = idl_headers
-        self._checked_in_header_re = re.compile(header_pattern[0:len(header_pattern) - 1] + ')$')
+
+        self._basename_re_list = []
+        self._checked_in_header_re_list = []
+        # Split file names into some chunks to avoid "Regular expression
+        # code size limit exceeded" on Windows
+        CHUNK_SIZE = 700
+        # Generated inspector/protocol/* contains a lot of names duplicated with
+        # checked-in core files. We don't want to rename them, and don't want to
+        # replace them in BUILD.gn and #include accidentally.
+        RE_PREFIX = r'(?<!inspector/protocol/)'
+
+        while len(basenames) > 0:
+            end_index = min(CHUNK_SIZE, len(basenames))
+            self._basename_re_list.append(re.compile(RE_PREFIX + r'\b(' + '|'.join(basenames[0:end_index]) + ')(?=["\']|$)'))
+            basenames = basenames[end_index:]
+
+        while len(headers) > 0:
+            end_index = min(CHUNK_SIZE, len(headers))
+            self._checked_in_header_re_list.append(re.compile(RE_PREFIX + r'\b(' + '|'.join(headers[0:end_index]) + ')$'))
+            headers = headers[end_index:]
 
     def _shorten_path(self, path):
         if path.startswith(self._repo_root):
@@ -466,7 +484,9 @@
                                'file:///gen/third_party/blink/public/')
 
     def _update_basename(self, content):
-        return self._basename_re.sub(lambda match: self._basename_map[match.group(1)], content)
+        for regex in self._basename_re_list:
+            content = regex.sub(lambda match: self._basename_map[match.group(1)], content)
+        return content
 
     @staticmethod
     def _append_unless_upper_dir_exists(dirs, new_dir):
@@ -575,7 +595,11 @@
             path = self._update_basename(path)
             return '#%s "%s"' % (include_or_import, path)
 
-        match = self._checked_in_header_re.search(path)
+        match = None
+        for regex in self._checked_in_header_re_list:
+            match = regex.search(path)
+            if match:
+                break
         if match:
             if match.group(1) in self._basename_map:
                 path = path[:match.start(1)] + self._basename_map[match.group(1)]
@@ -644,6 +668,9 @@
         else:
             _log.warning('%s does not contain specified source strings.', file_path)
 
+    def _create_git(self):
+        return Git(cwd=self._repo_root, filesystem=self._fs, platform=self._platform)
+
 
 def main():
     logging.basicConfig(level=logging.INFO,
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 9d35711..89ed495 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: 08ce02c3527674f331d4ebfd5ac0bdc4748c4661
+Revision: 1ebedb05dde4fccb9d9459062a3a9fa9cb28bd5a
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS
index 94847ae..e6719e2 100644
--- a/third_party/crashpad/crashpad/DEPS
+++ b/third_party/crashpad/crashpad/DEPS
@@ -29,7 +29,7 @@
       '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f',
   'crashpad/third_party/mini_chromium/mini_chromium':
       Var('chromium_git') + '/chromium/mini_chromium@' +
-      'd42eb410123667fe94427986d2616795897efa0c',
+      '6e0fdb2e4966ec44b1ce7b8464fd7c80d1b59203',
   'crashpad/third_party/zlib/zlib':
       Var('chromium_git') + '/chromium/src/third_party/zlib@' +
       '13dc246a58e4b72104d35f9b1809af95221ebda7',
@@ -120,6 +120,8 @@
     # Linux build host and vice-versa. https://crbug.com/789364. This package is
     # only updated when the solution in .gclient includes an entry like:
     #   "custom_vars": { "pull_linux_clang": True }
+    # The ref used is "goma". This is like "latest", but is considered a more
+    # stable latest by the Fuchsia toolchain team.
     'name': 'clang_linux',
     'pattern': '.',
     'condition': 'checkout_linux and pull_linux_clang',
@@ -129,7 +131,7 @@
       # sic, using Fuchsia team's generic build of clang for linux-amd64 to
       # build for linux-amd64 target too.
       'fuchsia/clang/linux-amd64',
-      'latest',
+      'goma',
       '-root', 'crashpad/third_party/linux/clang/linux-amd64',
       '-log-level', 'info',
     ],
@@ -137,7 +139,7 @@
   {
     # If using a local clang ("pull_linux_clang" above), also pull down a
     # sysroot.
-    'name': 'clang_linux',
+    'name': 'sysroot_linux',
     'pattern': '.',
     'condition': 'checkout_linux and pull_linux_clang',
     'action': [
@@ -147,6 +149,7 @@
   {
     # Same rationale for using "install" rather than "ensure" as for first clang
     # package. https://crbug.com/789364.
+    # Same rationale for using "goma" instead of "latest" as clang_linux above.
     'name': 'fuchsia_clang_mac',
     'pattern': '.',
     'condition': 'checkout_fuchsia and host_os == "mac"',
@@ -154,7 +157,7 @@
       'cipd',
       'install',
       'fuchsia/clang/mac-amd64',
-      'latest',
+      'goma',
       '-root', 'crashpad/third_party/fuchsia/clang/mac-amd64',
       '-log-level', 'info',
     ],
@@ -162,6 +165,7 @@
   {
     # Same rationale for using "install" rather than "ensure" as for first clang
     # package. https://crbug.com/789364.
+    # Same rationale for using "goma" instead of "latest" as clang_linux above.
     'name': 'fuchsia_clang_linux',
     'pattern': '.',
     'condition': 'checkout_fuchsia and host_os == "linux"',
@@ -169,7 +173,7 @@
       'cipd',
       'install',
       'fuchsia/clang/linux-amd64',
-      'latest',
+      'goma',
       '-root', 'crashpad/third_party/fuchsia/clang/linux-amd64',
       '-log-level', 'info',
     ],
diff --git a/third_party/crashpad/crashpad/handler/linux/exception_handler_server_test.cc b/third_party/crashpad/crashpad/handler/linux/exception_handler_server_test.cc
index b68e738..247ac8c 100644
--- a/third_party/crashpad/crashpad/handler/linux/exception_handler_server_test.cc
+++ b/third_party/crashpad/crashpad/handler/linux/exception_handler_server_test.cc
@@ -141,6 +141,25 @@
   ~MockPtraceStrategyDecider() {}
 
   Strategy ChooseStrategy(int sock, const ucred& client_credentials) override {
+    if (strategy_ == Strategy::kUseBroker) {
+      ServerToClientMessage message = {};
+      message.type = ServerToClientMessage::kTypeForkBroker;
+
+      Errno status;
+      bool result = LoggingWriteFile(sock, &message, sizeof(message)) &&
+                    LoggingReadFileExactly(sock, &status, sizeof(status));
+      EXPECT_TRUE(result);
+
+      if (!result) {
+        return Strategy::kError;
+      }
+
+      if (status != 0) {
+        errno = status;
+        ADD_FAILURE() << ErrnoMessage("Handler Client ForkBroker");
+        return Strategy::kNoPtrace;
+      }
+    }
     return strategy_;
   }
 
diff --git a/third_party/crashpad/crashpad/snapshot/BUILD.gn b/third_party/crashpad/crashpad/snapshot/BUILD.gn
index 9bb49ae..44bb53f 100644
--- a/third_party/crashpad/crashpad/snapshot/BUILD.gn
+++ b/third_party/crashpad/crashpad/snapshot/BUILD.gn
@@ -56,7 +56,7 @@
     "unloaded_module_snapshot.h",
   ]
 
-  if (crashpad_is_posix) {
+  if (crashpad_is_posix || crashpad_is_fuchsia) {
     sources += [
       "posix/timezone.cc",
       "posix/timezone.h",
diff --git a/third_party/crashpad/crashpad/test/BUILD.gn b/third_party/crashpad/crashpad/test/BUILD.gn
index dc2e2a7..a8d6595 100644
--- a/third_party/crashpad/crashpad/test/BUILD.gn
+++ b/third_party/crashpad/crashpad/test/BUILD.gn
@@ -44,7 +44,7 @@
     "test_paths.h",
   ]
 
-  if (crashpad_is_posix) {
+  if (crashpad_is_posix || crashpad_is_fuchsia) {
     sources += [ "scoped_temp_dir_posix.cc" ]
 
     if (!crashpad_is_fuchsia) {
@@ -140,6 +140,8 @@
     "test_paths_test.cc",
   ]
 
+  # TODO(crbug.com/812974): Remove !crashpad_is_fuchsia when Fuchsia is no
+  # longer treated as a posix platform.
   if (crashpad_is_posix && !crashpad_is_fuchsia) {
     sources += [ "multiprocess_posix_test.cc" ]
   }
@@ -155,9 +157,6 @@
     ]
   }
 
-  if (!crashpad_is_fuchsia) {
-  }
-
   deps = [
     ":test",
     "../compat",
diff --git a/third_party/crashpad/crashpad/util/BUILD.gn b/third_party/crashpad/crashpad/util/BUILD.gn
index 1e2c968..e8f2dc08 100644
--- a/third_party/crashpad/crashpad/util/BUILD.gn
+++ b/third_party/crashpad/crashpad/util/BUILD.gn
@@ -160,7 +160,7 @@
     "thread/worker_thread.h",
   ]
 
-  if (crashpad_is_posix) {
+  if (crashpad_is_posix || crashpad_is_fuchsia) {
     sources += [
       "file/directory_reader_posix.cc",
       "file/file_io_posix.cc",
@@ -512,7 +512,7 @@
     sources += [ "net/http_transport_test.cc" ]
   }
 
-  if (crashpad_is_posix) {
+  if (crashpad_is_posix || crashpad_is_fuchsia) {
     if (!crashpad_is_fuchsia) {
       sources += [
         "posix/process_info_test.cc",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d819fee8..d2d2a8c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -14968,6 +14968,10 @@
   <int value="1232" label="DECLARATIVENETREQUEST_REMOVEWHITELISTEDPAGES"/>
   <int value="1233" label="DECLARATIVENETREQUEST_GETWHITELISTEDPAGES"/>
   <int value="1234" label="DEVELOPERPRIVATE_INSTALLDROPPEDFILE"/>
+  <int value="1235" label="AUTOMATIONINTERNAL_ENABLEFRAME"/>
+  <int value="1236" label="AUTOMATIONINTERNAL_QUERYSELECTOR"/>
+  <int value="1237" label="DEBUGGER_GETTARGETS"/>
+  <int value="1238" label="NOTIFICATIONS_GETPERMISSIONLEVEL"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -26667,6 +26671,7 @@
   <int value="-174319545" label="BulkPrinters:enabled"/>
   <int value="-171173736" label="VrBrowsingExperimentalFeatures:disabled"/>
   <int value="-170986053" label="EnableManualFallbacksFilling:enabled"/>
+  <int value="-167744090" label="EnableHomeLauncher:enabled"/>
   <int value="-165756594" label="enable-touch-feedback"/>
   <int value="-159877930" label="MaterialDesignUserManager:disabled"/>
   <int value="-158549277" label="enable-embeddedsearch-api"/>
@@ -26808,6 +26813,7 @@
   <int value="191737931" label="enable-mark-http-as"/>
   <int value="194573877" label="MacViewsNativeDialogs:disabled"/>
   <int value="194895489" label="passive-listeners-default"/>
+  <int value="195570937" label="EnableHomeLauncher:disabled"/>
   <int value="200347243" label="WebVRExperimentalRendering:disabled"/>
   <int value="201343576" label="enable-password-change-support:enabled"/>
   <int value="203776499" label="enable-virtual-keyboard-overscroll"/>
@@ -39786,10 +39792,24 @@
 </enum>
 
 <enum name="SearchWidgetUseInfo">
-  <int value="0" label="Present in partnership device"/>
-  <int value="1" label="Not present in partnership device"/>
-  <int value="2" label="Present in non-partnership device"/>
-  <int value="3" label="Not present in non-partnership device"/>
+  <int value="0" label="defunct Present in partnership device"/>
+  <int value="1" label="defunct Not present in partnership device"/>
+  <int value="2" label="defunct Present in non-partnership device"/>
+  <int value="3" label="defunct Not present in non-partnership device"/>
+  <int value="4" label="Present in partnership device (Always available)"/>
+  <int value="5"
+      label="Present in partnership device (Added after first start)"/>
+  <int value="6" label="Not Present in partnership device (Never present)"/>
+  <int value="7"
+      label="Not Present in partnership device (Removed after first start)"/>
+  <int value="8" label="Present in non-partnership device (Always available)"/>
+  <int value="9"
+      label="Present in non-partnership device (Added after first start)"/>
+  <int value="10"
+      label="Not Present in non-partnership device (Never present)"/>
+  <int value="11"
+      label="Not Present in non-partnership device (Removed after first
+             start)"/>
 </enum>
 
 <enum name="SecurityInterstitialDecision">
diff --git a/ui/app_list/app_list_features.cc b/ui/app_list/app_list_features.cc
index 046ff63..0fb85a60 100644
--- a/ui/app_list/app_list_features.cc
+++ b/ui/app_list/app_list_features.cc
@@ -17,6 +17,8 @@
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kEnablePlayStoreAppSearch{"EnablePlayStoreAppSearch",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kEnableHomeLauncher{"EnableHomeLauncher",
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
 bool IsAnswerCardEnabled() {
   // Not using local static variable to allow tests to change this value.
@@ -34,6 +36,10 @@
   return base::FeatureList::IsEnabled(kEnablePlayStoreAppSearch);
 }
 
+bool IsHomeLauncherEnabled() {
+  return base::FeatureList::IsEnabled(kEnableHomeLauncher);
+}
+
 std::string AnswerServerUrl() {
   const std::string experiment_url =
       base::GetFieldTrialParamValueByFeature(kEnableAnswerCard, "ServerUrl");
diff --git a/ui/app_list/app_list_features.h b/ui/app_list/app_list_features.h
index 443d9526..7c32262 100644
--- a/ui/app_list/app_list_features.h
+++ b/ui/app_list/app_list_features.h
@@ -29,9 +29,13 @@
 // Enables the Play Store app search.
 APP_LIST_EXPORT extern const base::Feature kEnablePlayStoreAppSearch;
 
+// Enables the home launcher in tablet mode.
+APP_LIST_EXPORT extern const base::Feature kEnableHomeLauncher;
+
 bool APP_LIST_EXPORT IsAnswerCardEnabled();
 bool APP_LIST_EXPORT IsBackgroundBlurEnabled();
 bool APP_LIST_EXPORT IsPlayStoreAppSearchEnabled();
+bool APP_LIST_EXPORT IsHomeLauncherEnabled();
 std::string APP_LIST_EXPORT AnswerServerUrl();
 std::string APP_LIST_EXPORT AnswerServerQuerySuffix();
 
diff --git a/ui/app_list/app_list_util.cc b/ui/app_list/app_list_util.cc
index 9b77b76..29cf6229 100644
--- a/ui/app_list/app_list_util.cc
+++ b/ui/app_list/app_list_util.cc
@@ -77,10 +77,9 @@
   return true;
 }
 
-int GetPreferredIconDimension(SearchResult* search_result) {
-  switch (search_result->display_type()) {
-    case ash::SearchResultDisplayType::kRecommendation:  // Falls
-                                                         // through.
+int GetPreferredIconDimension(SearchResult::DisplayType display_type) {
+  switch (display_type) {
+    case ash::SearchResultDisplayType::kRecommendation:  // Falls through.
     case ash::SearchResultDisplayType::kTile:
       return kTileIconSize;
     case ash::SearchResultDisplayType::kList:
diff --git a/ui/app_list/app_list_util.h b/ui/app_list/app_list_util.h
index aa1099f..bfaf1e42 100644
--- a/ui/app_list/app_list_util.h
+++ b/ui/app_list/app_list_util.h
@@ -30,7 +30,8 @@
     const ui::KeyEvent& key_event);
 
 // Returns the dimension at which a result's icon should be displayed.
-APP_LIST_EXPORT int GetPreferredIconDimension(SearchResult* search_result);
+APP_LIST_EXPORT int GetPreferredIconDimension(
+    ash::SearchResultDisplayType display_type);
 
 }  // namespace app_list
 
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index 2daaad3b..b8cef8e 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -1099,7 +1099,8 @@
   if (is_side_shelf_)
     return;
 
-  const int display_height = GetDisplayNearestView().size().height();
+  const display::Display display = GetDisplayNearestView();
+  const int display_height = display.size().height();
   int target_state_y = 0;
 
   switch (target_state) {
@@ -1114,7 +1115,7 @@
       // The ChromeVox panel as well as the Docked Magnifier viewport affect the
       // workarea of the display. We need to account for that when applist is in
       // fullscreen to avoid being shown below them.
-      target_state_y = GetDisplayNearestView().work_area().y();
+      target_state_y = display.work_area().y() - display.bounds().y();
       break;
 
     case AppListViewState::CLOSED:
@@ -1142,7 +1143,7 @@
   }
 
   if (fullscreen_widget_->GetNativeView()->bounds().y() ==
-      GetDisplayNearestView().work_area().bottom()) {
+      display.work_area().bottom()) {
     // If the animation start position is the bottom of the screen activate the
     // fade in animation.
     app_list_main_view_->contents_view()->FadeInOnOpen(
diff --git a/ui/base/material_design/material_design_controller.cc b/ui/base/material_design/material_design_controller.cc
index 5abb641..d4dd4b1 100644
--- a/ui/base/material_design/material_design_controller.cc
+++ b/ui/base/material_design/material_design_controller.cc
@@ -120,8 +120,7 @@
 
 // static
 bool MaterialDesignController::IsSecondaryUiMaterial() {
-  return base::FeatureList::IsEnabled(features::kSecondaryUiMd) ||
-         GetMode() == MATERIAL_REFRESH;
+  return base::FeatureList::IsEnabled(features::kSecondaryUiMd);
 }
 
 // static
diff --git a/ui/gfx/color_palette.h b/ui/gfx/color_palette.h
index 9721b555..3171747 100644
--- a/ui/gfx/color_palette.h
+++ b/ui/gfx/color_palette.h
@@ -13,8 +13,6 @@
 // as a visual flag for misbehaving code.
 constexpr SkColor kPlaceholderColor = SK_ColorRED;
 
-constexpr SkColor kChromeIconGrey = SkColorSetRGB(0x5A, 0x5A, 0x5A);
-
 // The number refers to the shade of darkness. Each color in the MD
 // palette ranges from 100-900.
 constexpr SkColor kGoogleBlue300 = SkColorSetRGB(0x8A, 0xB4, 0xF8);
@@ -42,6 +40,12 @@
 constexpr SkColor kGoogleGrey800 = SkColorSetRGB(0x3C, 0x40, 0x43);
 constexpr SkColor kGoogleGrey900 = SkColorSetRGB(0x20, 0x21, 0x24);
 
+// kChromeIconGrey is subject to change in the future, kGoogleGrey700 is set in
+// stone. If you're semantically looking for "the icon color Chrome uses" then
+// use kChromeIconGrey, if you're looking for GG700 grey specifically, use the
+// Google-grey constant directly.
+constexpr SkColor kChromeIconGrey = kGoogleGrey700;
+
 // An alpha value for designating a control's disabled state. In specs this is
 // sometimes listed as 0.38a.
 constexpr SkAlpha kDisabledControlAlpha = 0x61;
diff --git a/ui/gfx/color_utils.cc b/ui/gfx/color_utils.cc
index e6f537e..c67023b 100644
--- a/ui/gfx/color_utils.cc
+++ b/ui/gfx/color_utils.cc
@@ -336,15 +336,9 @@
 #endif  // !defined(OS_WIN)
 
 SkColor DeriveDefaultIconColor(SkColor text_color) {
-  // Lighten a dark color but leave it fully opaque.
-  if (IsDark(text_color)) {
-    // For black text, this comes out to kChromeIconGrey.
-    return color_utils::AlphaBlend(SK_ColorWHITE, text_color,
-                                   SkColorGetR(gfx::kChromeIconGrey));
-  }
-  // For a light color, just reduce opacity.
-  return SkColorSetA(text_color,
-                     static_cast<int>(0.8f * SkColorGetA(text_color)));
+  // Lighten dark colors and brighten light colors. The alpha value here (0x4c)
+  // is chosen to generate a value close to GoogleGrey700 from GoogleGrey900.
+  return BlendTowardOppositeLuma(text_color, 0x4c);
 }
 
 std::string SkColorToRgbaString(SkColor color) {
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index c071807f..a79f2ef 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -216,7 +216,7 @@
       }
     }
 
-    if (is_posix) {
+    if (is_posix || is_fuchsia) {
       # Windows has USE_EGL but doesn't support base::FileDescriptor
       sources += [
         "gl_fence_android_native_fence_sync.cc",
diff --git a/ui/gl/gl_image_dxgi.cc b/ui/gl/gl_image_dxgi.cc
index 7dbd703..b649e1f 100644
--- a/ui/gl/gl_image_dxgi.cc
+++ b/ui/gl/gl_image_dxgi.cc
@@ -6,6 +6,7 @@
 
 #include <d3d11_1.h>
 
+#include "base/debug/alias.h"
 #include "third_party/khronos/EGL/egl.h"
 #include "third_party/khronos/EGL/eglext.h"
 #include "ui/gl/gl_angle_util_win.h"
@@ -236,6 +237,8 @@
 
   HRESULT hr = d3d11_device_->CreateTexture2D(
       &desc, nullptr, decoder_copy_texture_.GetAddressOf());
+  // TODO(sunnyps): Remove after fixing https://crbug.com/794735
+  base::debug::Alias(&hr);
   CHECK(SUCCEEDED(hr));
   EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
 
diff --git a/ui/latency/frame_metrics_test_common.cc b/ui/latency/frame_metrics_test_common.cc
index 835cc00c..15125fc 100644
--- a/ui/latency/frame_metrics_test_common.cc
+++ b/ui/latency/frame_metrics_test_common.cc
@@ -75,7 +75,7 @@
   added_samples_.push_back({value, weight});
 }
 
-PercentileResults TestHistogram::CalculatePercentiles() const {
+PercentileResults TestHistogram::ComputePercentiles() const {
   return results_;
 }
 
diff --git a/ui/latency/frame_metrics_test_common.h b/ui/latency/frame_metrics_test_common.h
index 170b0144..7dbe380f 100644
--- a/ui/latency/frame_metrics_test_common.h
+++ b/ui/latency/frame_metrics_test_common.h
@@ -156,7 +156,7 @@
 
   // Histogram interface.
   void AddSample(uint32_t value, uint32_t weight) override;
-  PercentileResults CalculatePercentiles() const override;
+  PercentileResults ComputePercentiles() const override;
   void Reset() override{};
 
   // Test interface.
diff --git a/ui/latency/histograms.cc b/ui/latency/histograms.cc
index 85b3c140..e7cd947 100644
--- a/ui/latency/histograms.cc
+++ b/ui/latency/histograms.cc
@@ -225,7 +225,7 @@
   total_samples_ += weight;
 }
 
-PercentileResults RatioHistogram::CalculatePercentiles() const {
+PercentileResults RatioHistogram::ComputePercentiles() const {
   RatioBoundaryIterator i;
   return PercentilesHelper(&i, buckets_.data(),
                            buckets_.data() + buckets_.size(), total_samples_);
@@ -370,7 +370,7 @@
   total_samples_ += weight;
 }
 
-PercentileResults VSyncHistogram::CalculatePercentiles() const {
+PercentileResults VSyncHistogram::ComputePercentiles() const {
   VSyncBoundaryIterator i;
   return PercentilesHelper(&i, buckets_.data(),
                            buckets_.data() + buckets_.size(), total_samples_);
diff --git a/ui/latency/histograms.h b/ui/latency/histograms.h
index b56bf92..bbe4ddb 100644
--- a/ui/latency/histograms.h
+++ b/ui/latency/histograms.h
@@ -32,9 +32,9 @@
   // Increases the bucket that contains |value| by |weight|.
   virtual void AddSample(uint32_t value, uint32_t weight) = 0;
 
-  // Calculates and returns the approximate percentiles based on the
+  // Computes and returns the approximate percentiles based on the
   // histogram distribution.
-  virtual PercentileResults CalculatePercentiles() const = 0;
+  virtual PercentileResults ComputePercentiles() const = 0;
 
   // Resets all buckets in the histogram to 0.
   // Higher level logic may periodically reset the the counts after it
@@ -52,7 +52,7 @@
   RatioHistogram();
   ~RatioHistogram() override;
   void AddSample(uint32_t ratio, uint32_t weight) override;
-  PercentileResults CalculatePercentiles() const override;
+  PercentileResults ComputePercentiles() const override;
   void Reset() override;
 
  private:
@@ -72,7 +72,7 @@
   VSyncHistogram();
   ~VSyncHistogram() override;
   void AddSample(uint32_t microseconds, uint32_t weight) override;
-  PercentileResults CalculatePercentiles() const override;
+  PercentileResults ComputePercentiles() const override;
   void Reset() override;
 
  private:
diff --git a/ui/latency/histograms_perftest.cc b/ui/latency/histograms_perftest.cc
index 6173cbb..ab7480f 100644
--- a/ui/latency/histograms_perftest.cc
+++ b/ui/latency/histograms_perftest.cc
@@ -39,7 +39,7 @@
     sample_vector_.Accumulate(microseconds, weight);
   }
 
-  PercentileResults CalculatePercentiles() const override {
+  PercentileResults ComputePercentiles() const override {
     return PercentileResults();
   }
   void Reset() override {}
@@ -157,7 +157,7 @@
     sample_vector_.Accumulate(microseconds, weight);
   }
 
-  PercentileResults CalculatePercentiles() const override {
+  PercentileResults ComputePercentiles() const override {
     return PercentileResults();
   }
   void Reset() override {}
diff --git a/ui/latency/histograms_unittest.cc b/ui/latency/histograms_unittest.cc
index 45f62a5..4278f86 100644
--- a/ui/latency/histograms_unittest.cc
+++ b/ui/latency/histograms_unittest.cc
@@ -55,7 +55,7 @@
     uint32_t stride = std::max<uint32_t>(1u, (bucket_end - bucket_start) / 8);
     for (uint64_t value = bucket_start; value < bucket_end; value += stride) {
       histogram->AddSample(value, 1);
-      percentiles = histogram->CalculatePercentiles();
+      percentiles = histogram->ComputePercentiles();
       histogram->Reset();
       EXPECT_LE(bucket_start, percentiles.values[0]);
       EXPECT_GT(bucket_end, percentiles.values[0]);
@@ -63,7 +63,7 @@
 
     // Verify the value just before the next bucket doesn't affect percentile.
     histogram->AddSample(bucket_end - 1, 1);
-    percentiles = histogram->CalculatePercentiles();
+    percentiles = histogram->ComputePercentiles();
     histogram->Reset();
     EXPECT_LE(bucket_start, percentiles.values[0]);
     EXPECT_GT(bucket_end, percentiles.values[0]);
@@ -112,7 +112,7 @@
                            samples_added_outside - samples_added_left);
     }
 
-    percentiles = histogram->CalculatePercentiles();
+    percentiles = histogram->ComputePercentiles();
     histogram->Reset();
 
     double index = (samples_added_inside + samples_added_outside) * percentile -
diff --git a/ui/latency/stream_analyzer.cc b/ui/latency/stream_analyzer.cc
index 93458abd..2ecd094 100644
--- a/ui/latency/stream_analyzer.cc
+++ b/ui/latency/stream_analyzer.cc
@@ -136,7 +136,7 @@
 
 PercentileResults StreamAnalyzer::ComputePercentiles() const {
   PercentileResults result;
-  result = histogram_->CalculatePercentiles();
+  result = histogram_->ComputePercentiles();
   for (size_t i = 0; i < PercentileResults::kCount; i++) {
     result.values[i] = client_->TransformResult(result.values[i]);
   }
diff --git a/ui/latency/stream_analyzer_unittest.cc b/ui/latency/stream_analyzer_unittest.cc
index 20af1ba..0841096 100644
--- a/ui/latency/stream_analyzer_unittest.cc
+++ b/ui/latency/stream_analyzer_unittest.cc
@@ -64,10 +64,10 @@
                                      expected_value, weight);
 
         // Verify values are forwarded to the WindowedAnalyzer.
-        EXPECT_EQ(expected_value, analyzer_->window().WorstMean().value);
-        EXPECT_EQ(expected_value, analyzer_->window().WorstRMS().value);
-        EXPECT_NEAR_SMR(expected_value, analyzer_->window().WorstSMR().value,
-                        weight);
+        EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstMean().value);
+        EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstRMS().value);
+        EXPECT_NEAR_SMR(expected_value,
+                        analyzer_->window().ComputeWorstSMR().value, weight);
       }
     }
   }
@@ -90,10 +90,10 @@
                                    expected_value, weight);
 
       // Verify values are forwarded to the WindowedAnalyzer.
-      EXPECT_EQ(expected_value, analyzer_->window().WorstMean().value);
-      EXPECT_EQ(expected_value, analyzer_->window().WorstRMS().value);
-      EXPECT_NEAR_SMR(expected_value, analyzer_->window().WorstSMR().value,
-                      weight);
+      EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstMean().value);
+      EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstRMS().value);
+      EXPECT_NEAR_SMR(expected_value,
+                      analyzer_->window().ComputeWorstSMR().value, weight);
     }
   }
 }
diff --git a/ui/latency/windowed_analyzer.cc b/ui/latency/windowed_analyzer.cc
index 50271cdd..01e61c9 100644
--- a/ui/latency/windowed_analyzer.cc
+++ b/ui/latency/windowed_analyzer.cc
@@ -88,7 +88,7 @@
   }
 }
 
-FrameRegionResult WindowedAnalyzer::WorstMean() const {
+FrameRegionResult WindowedAnalyzer::ComputeWorstMean() const {
   FrameRegionResult result;
   if (results_) {
     result = results_->mean;
@@ -99,7 +99,7 @@
   return result;
 }
 
-FrameRegionResult WindowedAnalyzer::WorstRMS() const {
+FrameRegionResult WindowedAnalyzer::ComputeWorstRMS() const {
   FrameRegionResult result;
   if (results_) {
     result = results_->square;
@@ -110,7 +110,7 @@
   return result;
 }
 
-FrameRegionResult WindowedAnalyzer::WorstSMR() const {
+FrameRegionResult WindowedAnalyzer::ComputeWorstSMR() const {
   FrameRegionResult result;
   if (results_) {
     result = results_->root;
@@ -126,17 +126,17 @@
     base::trace_event::TracedValue* state) const {
   FrameRegionResult region;
 
-  region = WorstMean();
+  region = ComputeWorstMean();
   state->BeginDictionary("worst_mean");
   region.AsValueInto(state);
   state->EndDictionary();
 
-  region = WorstSMR();
+  region = ComputeWorstSMR();
   state->BeginDictionary("worst_smr");
   region.AsValueInto(state);
   state->EndDictionary();
 
-  region = WorstRMS();
+  region = ComputeWorstRMS();
   state->BeginDictionary("worst_rms");
   region.AsValueInto(state);
   state->EndDictionary();
diff --git a/ui/latency/windowed_analyzer.h b/ui/latency/windowed_analyzer.h
index 004ffc9..248b6cc 100644
--- a/ui/latency/windowed_analyzer.h
+++ b/ui/latency/windowed_analyzer.h
@@ -99,9 +99,9 @@
                  const Accumulator96b& weighted_square);
 
   // Returns the worst regions encountered so far.
-  FrameRegionResult WorstMean() const;
-  FrameRegionResult WorstRMS() const;
-  FrameRegionResult WorstSMR() const;
+  FrameRegionResult ComputeWorstMean() const;
+  FrameRegionResult ComputeWorstRMS() const;
+  FrameRegionResult ComputeWorstSMR() const;
 
   void AsValueInto(base::trace_event::TracedValue* state) const;
 
diff --git a/ui/latency/windowed_analyzer_unittest.cc b/ui/latency/windowed_analyzer_unittest.cc
index 96fb6788..71b4248 100644
--- a/ui/latency/windowed_analyzer_unittest.cc
+++ b/ui/latency/windowed_analyzer_unittest.cc
@@ -33,11 +33,12 @@
         AddSamplesHelper(&analyzer, value, weight, samples);
         uint64_t expected_value =
             value * TestWindowedAnalyzerClient::result_scale;
-        EXPECT_EQ(analyzer.WorstMean().value, expected_value)
+        EXPECT_EQ(analyzer.ComputeWorstMean().value, expected_value)
             << value << " x " << weight;
-        EXPECT_EQ(analyzer.WorstRMS().value, expected_value)
+        EXPECT_EQ(analyzer.ComputeWorstRMS().value, expected_value)
             << value << " x " << weight;
-        EXPECT_NEAR_SMR(analyzer.WorstSMR().value, expected_value, weight)
+        EXPECT_NEAR_SMR(analyzer.ComputeWorstSMR().value, expected_value,
+                        weight)
             << value << " x " << weight;
       }
     }
@@ -54,11 +55,11 @@
       uint64_t expected_value =
           value * TestWindowedAnalyzerClient::result_scale;
       // Makes sure our precision is good enough.
-      EXPECT_EQ(analyzer.WorstMean().value, expected_value)
+      EXPECT_EQ(analyzer.ComputeWorstMean().value, expected_value)
           << value << " x " << weight;
-      EXPECT_EQ(analyzer.WorstRMS().value, expected_value)
+      EXPECT_EQ(analyzer.ComputeWorstRMS().value, expected_value)
           << value << " x " << weight;
-      EXPECT_NEAR_SMR(analyzer.WorstSMR().value, expected_value, weight)
+      EXPECT_NEAR_SMR(analyzer.ComputeWorstSMR().value, expected_value, weight)
           << value << " x " << weight;
     }
   }
@@ -118,17 +119,17 @@
   AddPatternHelper(&shared_client, &analyzer, pattern_max_rms, kSampleWeight);
   AddPatternHelper(&shared_client, &analyzer, pattern_clear, kSampleWeight);
 
-  FrameRegionResult worst_mean = analyzer.WorstMean();
+  FrameRegionResult worst_mean = analyzer.ComputeWorstMean();
   EXPECT_DOUBLE_EQ(expected_worst_mean, worst_mean.value);
   EXPECT_EQ(worst_mean_client.window_begin, worst_mean.window_begin);
   EXPECT_EQ(worst_mean_client.window_end, worst_mean.window_end);
 
-  FrameRegionResult worst_smr = analyzer.WorstSMR();
+  FrameRegionResult worst_smr = analyzer.ComputeWorstSMR();
   EXPECT_NEAR_SMR(expected_worst_smr, worst_smr.value, kSampleWeight);
   EXPECT_EQ(worst_smr_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(worst_smr_client.window_end, worst_smr.window_end);
 
-  FrameRegionResult worst_rms = analyzer.WorstRMS();
+  FrameRegionResult worst_rms = analyzer.ComputeWorstRMS();
   EXPECT_DOUBLE_EQ(expected_worst_rms, worst_rms.value);
   EXPECT_EQ(worst_rms_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(worst_rms_client.window_end, worst_rms.window_end);
@@ -152,17 +153,17 @@
   AddPatternHelper(&shared_client, &analyzer, pattern_short, kSampleWeight);
   SharedWindowedAnalyzerClient short_client(shared_client);
 
-  FrameRegionResult worst_mean = analyzer.WorstMean();
+  FrameRegionResult worst_mean = analyzer.ComputeWorstMean();
   EXPECT_DOUBLE_EQ(expected_initial_value, worst_mean.value);
   EXPECT_EQ(short_client.window_begin, worst_mean.window_begin);
   EXPECT_EQ(short_client.window_end, worst_mean.window_end);
 
-  FrameRegionResult worst_smr = analyzer.WorstSMR();
+  FrameRegionResult worst_smr = analyzer.ComputeWorstSMR();
   EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
   EXPECT_EQ(short_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(short_client.window_end, worst_smr.window_end);
 
-  FrameRegionResult worst_rms = analyzer.WorstRMS();
+  FrameRegionResult worst_rms = analyzer.ComputeWorstRMS();
   EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
   EXPECT_EQ(short_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(short_client.window_end, worst_rms.window_end);
@@ -189,17 +190,17 @@
   AddPatternHelper(&shared_client, &analyzer, pattern_short, kSampleWeight);
   SharedWindowedAnalyzerClient short_client(shared_client);
 
-  worst_mean = analyzer.WorstMean();
+  worst_mean = analyzer.ComputeWorstMean();
   EXPECT_DOUBLE_EQ(expected_initial_value, worst_mean.value);
   EXPECT_EQ(short_client.window_begin, worst_mean.window_begin);
   EXPECT_EQ(short_client.window_end, worst_mean.window_end);
 
-  worst_smr = analyzer.WorstSMR();
+  worst_smr = analyzer.ComputeWorstSMR();
   EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
   EXPECT_EQ(short_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(short_client.window_end, worst_smr.window_end);
 
-  worst_rms = analyzer.WorstRMS();
+  worst_rms = analyzer.ComputeWorstRMS();
   EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
   EXPECT_EQ(short_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(short_client.window_end, worst_rms.window_end);
@@ -215,17 +216,17 @@
   AddPatternHelper(&shared_client, &analyzer, pattern_long, kSampleWeight);
   SharedWindowedAnalyzerClient long_client(shared_client);
 
-  worst_mean = analyzer.WorstMean();
+  worst_mean = analyzer.ComputeWorstMean();
   EXPECT_DOUBLE_EQ(expected_final_value, worst_mean.value);
   EXPECT_EQ(long_client.window_begin, worst_mean.window_begin);
   EXPECT_EQ(long_client.window_end, worst_mean.window_end);
 
-  worst_smr = analyzer.WorstSMR();
+  worst_smr = analyzer.ComputeWorstSMR();
   EXPECT_NEAR_SMR(expected_final_value, worst_smr.value, kSampleWeight);
   EXPECT_EQ(long_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(long_client.window_end, worst_smr.window_end);
 
-  worst_rms = analyzer.WorstRMS();
+  worst_rms = analyzer.ComputeWorstRMS();
   EXPECT_DOUBLE_EQ(expected_final_value, worst_rms.value);
   EXPECT_EQ(long_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(long_client.window_end, worst_rms.window_end);
@@ -250,17 +251,17 @@
   AddPatternHelper(&shared_client, &analyzer, pattern1, kSampleWeight);
   SharedWindowedAnalyzerClient initial_client(shared_client);
 
-  worst_mean = analyzer.WorstMean();
+  worst_mean = analyzer.ComputeWorstMean();
   EXPECT_DOUBLE_EQ(expected_initial_value, worst_mean.value);
   EXPECT_EQ(initial_client.window_begin, worst_mean.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_mean.window_end);
 
-  worst_smr = analyzer.WorstSMR();
+  worst_smr = analyzer.ComputeWorstSMR();
   EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
   EXPECT_EQ(initial_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_smr.window_end);
 
-  worst_rms = analyzer.WorstRMS();
+  worst_rms = analyzer.ComputeWorstRMS();
   EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
   EXPECT_EQ(initial_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_rms.window_end);
@@ -270,17 +271,17 @@
   const std::vector<uint32_t> pattern2 = {4, 4, 4, 4, 4, 4};
   AddPatternHelper(&shared_client, &analyzer, pattern2, kSampleWeight);
 
-  worst_mean = analyzer.WorstMean();
+  worst_mean = analyzer.ComputeWorstMean();
   EXPECT_DOUBLE_EQ(expected_initial_value, worst_mean.value);
   EXPECT_EQ(initial_client.window_begin, worst_mean.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_mean.window_end);
 
-  worst_smr = analyzer.WorstSMR();
+  worst_smr = analyzer.ComputeWorstSMR();
   EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight);
   EXPECT_EQ(initial_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_smr.window_end);
 
-  worst_rms = analyzer.WorstRMS();
+  worst_rms = analyzer.ComputeWorstRMS();
   EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value);
   EXPECT_EQ(initial_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(initial_client.window_end, worst_rms.window_end);
@@ -301,17 +302,17 @@
   const std::vector<uint32_t> pattern4 = {1, 1, 1, 1, 1, 1};
   AddPatternHelper(&shared_client, &analyzer, pattern4, kSampleWeight);
 
-  worst_mean = analyzer.WorstMean();
+  worst_mean = analyzer.ComputeWorstMean();
   EXPECT_DOUBLE_EQ(expected_final_value, worst_mean.value);
   EXPECT_EQ(final_client.window_begin, worst_mean.window_begin);
   EXPECT_EQ(final_client.window_end, worst_mean.window_end);
 
-  worst_smr = analyzer.WorstSMR();
+  worst_smr = analyzer.ComputeWorstSMR();
   EXPECT_NEAR_SMR(expected_final_value, worst_smr.value, kSampleWeight);
   EXPECT_EQ(final_client.window_begin, worst_smr.window_begin);
   EXPECT_EQ(final_client.window_end, worst_smr.window_end);
 
-  worst_rms = analyzer.WorstRMS();
+  worst_rms = analyzer.ComputeWorstRMS();
   EXPECT_DOUBLE_EQ(expected_final_value, worst_rms.value);
   EXPECT_EQ(final_client.window_begin, worst_rms.window_begin);
   EXPECT_EQ(final_client.window_end, worst_rms.window_end);
diff --git a/ui/views/controls/button/image_button_factory.cc b/ui/views/controls/button/image_button_factory.cc
index 6e7ddda2..649002d85 100644
--- a/ui/views/controls/button/image_button_factory.cc
+++ b/ui/views/controls/button/image_button_factory.cc
@@ -1,7 +1,6 @@
 // Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-
 #include "ui/views/controls/button/image_button_factory.h"
 
 #include "ui/gfx/color_utils.h"
diff --git a/ui/views/controls/button/image_button_factory.h b/ui/views/controls/button/image_button_factory.h
index d965957..2bb9a229 100644
--- a/ui/views/controls/button/image_button_factory.h
+++ b/ui/views/controls/button/image_button_factory.h
@@ -6,6 +6,7 @@
 #define UI_VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_FACTORY_H_
 
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/views/views_export.h"
 
 namespace gfx {
@@ -28,7 +29,7 @@
 VIEWS_EXPORT void SetImageFromVectorIcon(
     ImageButton* button,
     const gfx::VectorIcon& icon,
-    SkColor related_text_color = SK_ColorBLACK);
+    SkColor related_text_color = gfx::kGoogleGrey900);
 
 }  // namespace views
 
diff --git a/ui/views/controls/button/image_button_factory_unittest.cc b/ui/views/controls/button/image_button_factory_unittest.cc
index c231499..52728ff3 100644
--- a/ui/views/controls/button/image_button_factory_unittest.cc
+++ b/ui/views/controls/button/image_button_factory_unittest.cc
@@ -5,6 +5,7 @@
 #include "ui/views/controls/button/image_button_factory.h"
 
 #include "components/vector_icons/vector_icons.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/views/animation/test/ink_drop_host_view_test_api.h"
 #include "ui/views/controls/button/button.h"
@@ -31,9 +32,9 @@
   EXPECT_EQ(color_utils::DeriveDefaultIconColor(SK_ColorRED),
             button->GetInkDropBaseColor());
 
-  // Default to black.
+  // Default to GoogleGrey900.
   SetImageFromVectorIcon(button, vector_icons::kClose16Icon);
-  EXPECT_EQ(color_utils::DeriveDefaultIconColor(SK_ColorBLACK),
+  EXPECT_EQ(color_utils::DeriveDefaultIconColor(gfx::kGoogleGrey900),
             button->GetInkDropBaseColor());
   delete button;
 }
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc
index 16ec528c8..d57fbb05 100644
--- a/ui/views/controls/scroll_view_unittest.cc
+++ b/ui/views/controls/scroll_view_unittest.cc
@@ -134,12 +134,12 @@
   DISALLOW_COPY_AND_ASSIGN(CustomView);
 };
 
-void CheckScrollbarVisibility(const ScrollView* scroll_view,
+void CheckScrollbarVisibility(const ScrollView& scroll_view,
                               ScrollBarOrientation orientation,
                               bool should_be_visible) {
   const ScrollBar* scrollbar = orientation == HORIZONTAL
-                                   ? scroll_view->horizontal_scroll_bar()
-                                   : scroll_view->vertical_scroll_bar();
+                                   ? scroll_view.horizontal_scroll_bar()
+                                   : scroll_view.vertical_scroll_bar();
   if (should_be_visible) {
     ASSERT_TRUE(scrollbar);
     EXPECT_TRUE(scrollbar->visible());
@@ -179,16 +179,11 @@
  public:
   ScrollViewTest() {}
 
-  void SetUp() override {
-    ViewsTestBase::SetUp();
-    scroll_view_ = std::make_unique<ScrollView>();
-  }
-
   View* InstallContents() {
     const gfx::Rect default_outer_bounds(0, 0, 100, 100);
     View* contents = new View;
-    scroll_view_->SetContents(contents);
-    scroll_view_->SetBoundsRect(default_outer_bounds);
+    scroll_view_.SetContents(contents);
+    scroll_view_.SetBoundsRect(default_outer_bounds);
     return contents;
   }
 
@@ -213,14 +208,14 @@
  protected:
 #endif
   int VerticalScrollBarWidth() {
-    return scroll_view_->vertical_scroll_bar()->GetThickness();
+    return scroll_view_.vertical_scroll_bar()->GetThickness();
   }
 
   int HorizontalScrollBarHeight() {
-    return scroll_view_->horizontal_scroll_bar()->GetThickness();
+    return scroll_view_.horizontal_scroll_bar()->GetThickness();
   }
 
-  std::unique_ptr<ScrollView> scroll_view_;
+  ScrollView scroll_view_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ScrollViewTest);
@@ -337,7 +332,7 @@
 // Verifies the viewport is sized to fit the available space.
 TEST_F(ScrollViewTest, ViewportSizedToFit) {
   View* contents = InstallContents();
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString());
 }
 
@@ -345,9 +340,9 @@
 // bounded scroll view.
 TEST_F(ScrollViewTest, BoundedViewportSizedToFit) {
   View* contents = InstallContents();
-  scroll_view_->ClipHeightTo(100, 200);
-  scroll_view_->SetBorder(CreateSolidBorder(2, 0));
-  scroll_view_->Layout();
+  scroll_view_.ClipHeightTo(100, 200);
+  scroll_view_.SetBorder(CreateSolidBorder(2, 0));
+  scroll_view_.Layout();
   EXPECT_EQ("2,2 96x96", contents->parent()->bounds().ToString());
 
   // Make sure the width of |contents| is set properly not to overflow the
@@ -360,11 +355,11 @@
 TEST_F(ScrollViewTest, VerticalScrollbarDoesNotAppearUnnecessarily) {
   const gfx::Rect default_outer_bounds(0, 0, 100, 100);
   View* contents = new VerticalResizingView;
-  scroll_view_->SetContents(contents);
-  scroll_view_->SetBoundsRect(default_outer_bounds);
-  scroll_view_->Layout();
-  EXPECT_FALSE(scroll_view_->vertical_scroll_bar()->visible());
-  EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
+  scroll_view_.SetContents(contents);
+  scroll_view_.SetBoundsRect(default_outer_bounds);
+  scroll_view_.Layout();
+  EXPECT_FALSE(scroll_view_.vertical_scroll_bar()->visible());
+  EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
 }
 
 // Verifies the scrollbars are added as necessary.
@@ -374,54 +369,54 @@
 
   // Size the contents such that vertical scrollbar is needed.
   contents->SetBounds(0, 0, 50, 400);
-  scroll_view_->Layout();
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
+  scroll_view_.Layout();
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             contents->parent()->width());
   EXPECT_EQ(100, contents->parent()->height());
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, false);
-  EXPECT_TRUE(!scroll_view_->horizontal_scroll_bar() ||
-              !scroll_view_->horizontal_scroll_bar()->visible());
-  ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, false);
+  EXPECT_TRUE(!scroll_view_.horizontal_scroll_bar() ||
+              !scroll_view_.horizontal_scroll_bar()->visible());
+  ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
+  EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
 
   // Size the contents such that horizontal scrollbar is needed.
   contents->SetBounds(0, 0, 400, 50);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(100, contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(),
             contents->parent()->height());
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, false);
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, false);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
 
   // Both horizontal and vertical.
   contents->SetBounds(0, 0, 300, 400);
-  scroll_view_->Layout();
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
+  scroll_view_.Layout();
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(),
             contents->parent()->height());
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
 
   // Add a border, test vertical scrollbar.
   const int kTopPadding = 1;
   const int kLeftPadding = 2;
   const int kBottomPadding = 3;
   const int kRightPadding = 4;
-  scroll_view_->SetBorder(CreateEmptyBorder(kTopPadding, kLeftPadding,
-                                            kBottomPadding, kRightPadding));
+  scroll_view_.SetBorder(CreateEmptyBorder(kTopPadding, kLeftPadding,
+                                           kBottomPadding, kRightPadding));
   contents->SetBounds(0, 0, 50, 400);
-  scroll_view_->Layout();
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth() - kLeftPadding -
+  scroll_view_.Layout();
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth() - kLeftPadding -
                 kRightPadding,
             contents->parent()->width());
   EXPECT_EQ(100 - kTopPadding - kBottomPadding, contents->parent()->height());
-  EXPECT_TRUE(!scroll_view_->horizontal_scroll_bar() ||
-              !scroll_view_->horizontal_scroll_bar()->visible());
-  ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
-  gfx::Rect bounds = scroll_view_->vertical_scroll_bar()->bounds();
+  EXPECT_TRUE(!scroll_view_.horizontal_scroll_bar() ||
+              !scroll_view_.horizontal_scroll_bar()->visible());
+  ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
+  EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
+  gfx::Rect bounds = scroll_view_.vertical_scroll_bar()->bounds();
   EXPECT_EQ(100 - VerticalScrollBarWidth() - kRightPadding, bounds.x());
   EXPECT_EQ(100 - kRightPadding, bounds.right());
   EXPECT_EQ(kTopPadding, bounds.y());
@@ -429,16 +424,16 @@
 
   // Horizontal with border.
   contents->SetBounds(0, 0, 400, 50);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(100 - kLeftPadding - kRightPadding, contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight() - kTopPadding -
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - kTopPadding -
                 kBottomPadding,
             contents->parent()->height());
-  ASSERT_TRUE(scroll_view_->horizontal_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
-  EXPECT_TRUE(!scroll_view_->vertical_scroll_bar() ||
-              !scroll_view_->vertical_scroll_bar()->visible());
-  bounds = scroll_view_->horizontal_scroll_bar()->bounds();
+  ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
+  EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
+  EXPECT_TRUE(!scroll_view_.vertical_scroll_bar() ||
+              !scroll_view_.vertical_scroll_bar()->visible());
+  bounds = scroll_view_.horizontal_scroll_bar()->bounds();
   EXPECT_EQ(kLeftPadding, bounds.x());
   EXPECT_EQ(100 - kRightPadding, bounds.right());
   EXPECT_EQ(100 - kBottomPadding - HorizontalScrollBarHeight(), bounds.y());
@@ -446,26 +441,26 @@
 
   // Both horizontal and vertical with border.
   contents->SetBounds(0, 0, 300, 400);
-  scroll_view_->Layout();
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth() - kLeftPadding -
+  scroll_view_.Layout();
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth() - kLeftPadding -
                 kRightPadding,
             contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight() - kTopPadding -
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - kTopPadding -
                 kBottomPadding,
             contents->parent()->height());
-  bounds = scroll_view_->horizontal_scroll_bar()->bounds();
+  bounds = scroll_view_.horizontal_scroll_bar()->bounds();
   // Check horiz.
-  ASSERT_TRUE(scroll_view_->horizontal_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
-  bounds = scroll_view_->horizontal_scroll_bar()->bounds();
+  ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
+  EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
+  bounds = scroll_view_.horizontal_scroll_bar()->bounds();
   EXPECT_EQ(kLeftPadding, bounds.x());
   EXPECT_EQ(100 - kRightPadding - VerticalScrollBarWidth(), bounds.right());
   EXPECT_EQ(100 - kBottomPadding - HorizontalScrollBarHeight(), bounds.y());
   EXPECT_EQ(100 - kBottomPadding, bounds.bottom());
   // Check vert.
-  ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
-  bounds = scroll_view_->vertical_scroll_bar()->bounds();
+  ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
+  EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
+  bounds = scroll_view_.vertical_scroll_bar()->bounds();
   EXPECT_EQ(100 - VerticalScrollBarWidth() - kRightPadding, bounds.x());
   EXPECT_EQ(100 - kRightPadding, bounds.right());
   EXPECT_EQ(kTopPadding, bounds.y());
@@ -476,11 +471,11 @@
 // Assertions around adding a header.
 TEST_F(ScrollViewTest, Header) {
   CustomView* header = new CustomView;
-  scroll_view_->SetHeader(header);
+  scroll_view_.SetHeader(header);
   View* header_parent = header->parent();
   View* contents = InstallContents();
 
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   // |header|s preferred size is empty, which should result in all space going
   // to contents.
   EXPECT_EQ("0,0 100x0", header->parent()->bounds().ToString());
@@ -507,7 +502,7 @@
   EXPECT_EQ("0,0 0x0", contents->bounds().ToString());
 
   // Remove the header.
-  scroll_view_->SetHeader(NULL);
+  scroll_view_.SetHeader(NULL);
   // SetHeader(NULL) deletes header.
   header = NULL;
   EXPECT_EQ("0,0 100x0", header_parent->bounds().ToString());
@@ -517,111 +512,111 @@
 // Verifies the scrollbars are added as necessary when a header is present.
 TEST_F(ScrollViewTest, ScrollBarsWithHeader) {
   CustomView* header = new CustomView;
-  scroll_view_->SetHeader(header);
+  scroll_view_.SetHeader(header);
   View* contents = InstallContents();
 
   header->SetPreferredSize(gfx::Size(10, 20));
 
   // Size the contents such that vertical scrollbar is needed.
   contents->SetBounds(0, 0, 50, 400);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(0, contents->parent()->x());
   EXPECT_EQ(20, contents->parent()->y());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             contents->parent()->width());
   EXPECT_EQ(80, contents->parent()->height());
   EXPECT_EQ(0, header->parent()->x());
   EXPECT_EQ(0, header->parent()->y());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             header->parent()->width());
   EXPECT_EQ(20, header->parent()->height());
-  EXPECT_TRUE(!scroll_view_->horizontal_scroll_bar() ||
-              !scroll_view_->horizontal_scroll_bar()->visible());
-  ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
+  EXPECT_TRUE(!scroll_view_.horizontal_scroll_bar() ||
+              !scroll_view_.horizontal_scroll_bar()->visible());
+  ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
+  EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
   // Make sure the vertical scrollbar overlaps the header for traditional
   // scrollbars and doesn't overlap the header for overlay scrollbars.
   const int expected_scrollbar_y =
-      scroll_view_->vertical_scroll_bar()->OverlapsContent()
+      scroll_view_.vertical_scroll_bar()->OverlapsContent()
           ? header->bounds().bottom()
           : header->y();
-  EXPECT_EQ(expected_scrollbar_y, scroll_view_->vertical_scroll_bar()->y());
+  EXPECT_EQ(expected_scrollbar_y, scroll_view_.vertical_scroll_bar()->y());
   EXPECT_EQ(header->y(), contents->y());
 
   // Size the contents such that horizontal scrollbar is needed.
   contents->SetBounds(0, 0, 400, 50);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(0, contents->parent()->x());
   EXPECT_EQ(20, contents->parent()->y());
   EXPECT_EQ(100, contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight() - 20,
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - 20,
             contents->parent()->height());
   EXPECT_EQ(0, header->parent()->x());
   EXPECT_EQ(0, header->parent()->y());
   EXPECT_EQ(100, header->parent()->width());
   EXPECT_EQ(20, header->parent()->height());
-  ASSERT_TRUE(scroll_view_->horizontal_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
-  EXPECT_TRUE(!scroll_view_->vertical_scroll_bar() ||
-              !scroll_view_->vertical_scroll_bar()->visible());
+  ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
+  EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
+  EXPECT_TRUE(!scroll_view_.vertical_scroll_bar() ||
+              !scroll_view_.vertical_scroll_bar()->visible());
 
   // Both horizontal and vertical.
   contents->SetBounds(0, 0, 300, 400);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(0, contents->parent()->x());
   EXPECT_EQ(20, contents->parent()->y());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             contents->parent()->width());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight() - 20,
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight() - 20,
             contents->parent()->height());
   EXPECT_EQ(0, header->parent()->x());
   EXPECT_EQ(0, header->parent()->y());
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(),
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutWidth(),
             header->parent()->width());
   EXPECT_EQ(20, header->parent()->height());
-  ASSERT_TRUE(scroll_view_->horizontal_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->visible());
-  ASSERT_TRUE(scroll_view_->vertical_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view_->vertical_scroll_bar()->visible());
+  ASSERT_TRUE(scroll_view_.horizontal_scroll_bar() != NULL);
+  EXPECT_TRUE(scroll_view_.horizontal_scroll_bar()->visible());
+  ASSERT_TRUE(scroll_view_.vertical_scroll_bar() != NULL);
+  EXPECT_TRUE(scroll_view_.vertical_scroll_bar()->visible());
 }
 
 // Verifies the header scrolls horizontally with the content.
 TEST_F(ScrollViewTest, HeaderScrollsWithContent) {
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
   CustomView* contents = new CustomView;
-  scroll_view_->SetContents(contents);
+  scroll_view_.SetContents(contents);
   contents->SetPreferredSize(gfx::Size(500, 500));
 
   CustomView* header = new CustomView;
-  scroll_view_->SetHeader(header);
+  scroll_view_.SetHeader(header);
   header->SetPreferredSize(gfx::Size(500, 20));
 
-  scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+  scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
   EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString());
   EXPECT_EQ("0,0", header->origin().ToString());
 
   // Scroll the horizontal scrollbar.
-  ASSERT_TRUE(scroll_view_->horizontal_scroll_bar());
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 1);
+  ASSERT_TRUE(scroll_view_.horizontal_scroll_bar());
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 1);
   EXPECT_EQ("-1,0", test_api.IntegralViewOffset().ToString());
   EXPECT_EQ("-1,0", header->origin().ToString());
 
   // Scrolling the vertical scrollbar shouldn't effect the header.
-  ASSERT_TRUE(scroll_view_->vertical_scroll_bar());
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 1);
+  ASSERT_TRUE(scroll_view_.vertical_scroll_bar());
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 1);
   EXPECT_EQ("-1,-1", test_api.IntegralViewOffset().ToString());
   EXPECT_EQ("-1,0", header->origin().ToString());
 }
 
 // Verifies ScrollRectToVisible() on the child works.
 TEST_F(ScrollViewTest, ScrollRectToVisible) {
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
   CustomView* contents = new CustomView;
-  scroll_view_->SetContents(contents);
+  scroll_view_.SetContents(contents);
   contents->SetPreferredSize(gfx::Size(500, 1000));
 
-  scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
-  scroll_view_->Layout();
+  scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+  scroll_view_.Layout();
   EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString());
 
   // Scroll to y=405 height=10, this should make the y position of the content
@@ -630,7 +625,7 @@
   const int viewport_height = test_api.contents_viewport()->height();
 
   // Expect there to be a horizontal scrollbar, making the viewport shorter.
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight(), viewport_height);
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(), viewport_height);
 
   gfx::ScrollOffset offset = test_api.CurrentOffset();
   EXPECT_EQ(415 - viewport_height, offset.y());
@@ -642,17 +637,17 @@
 
 // Verifies that child scrolls into view when it's focused.
 TEST_F(ScrollViewTest, ScrollChildToVisibleOnFocus) {
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
   CustomView* contents = new CustomView;
-  scroll_view_->SetContents(contents);
+  scroll_view_.SetContents(contents);
   contents->SetPreferredSize(gfx::Size(500, 1000));
   FixedView* child = new FixedView;
   child->SetPreferredSize(gfx::Size(10, 10));
   child->SetPosition(gfx::Point(0, 405));
   contents->AddChildView(child);
 
-  scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
-  scroll_view_->Layout();
+  scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+  scroll_view_.Layout();
   EXPECT_EQ(gfx::Point(), test_api.IntegralViewOffset());
 
   // Set focus to the child control. This should cause the control to scroll to
@@ -662,7 +657,7 @@
   const int viewport_height = test_api.contents_viewport()->height();
 
   // Expect there to be a horizontal scrollbar, making the viewport shorter.
-  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight(), viewport_height);
+  EXPECT_EQ(100 - scroll_view_.GetScrollBarLayoutHeight(), viewport_height);
 
   gfx::ScrollOffset offset = test_api.CurrentOffset();
   EXPECT_EQ(415 - viewport_height, offset.y());
@@ -671,138 +666,138 @@
 // Verifies ClipHeightTo() uses the height of the content when it is between the
 // minimum and maximum height values.
 TEST_F(ScrollViewTest, ClipHeightToNormalContentHeight) {
-  scroll_view_->ClipHeightTo(kMinHeight, kMaxHeight);
+  scroll_view_.ClipHeightTo(kMinHeight, kMaxHeight);
 
   const int kNormalContentHeight = 75;
-  scroll_view_->SetContents(
+  scroll_view_.SetContents(
       new views::StaticSizedView(gfx::Size(kWidth, kNormalContentHeight)));
 
   EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight),
-            scroll_view_->GetPreferredSize());
+            scroll_view_.GetPreferredSize());
 
-  scroll_view_->SizeToPreferredSize();
-  scroll_view_->Layout();
+  scroll_view_.SizeToPreferredSize();
+  scroll_view_.Layout();
 
   EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight),
-            scroll_view_->contents()->size());
-  EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), scroll_view_->size());
+            scroll_view_.contents()->size());
+  EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), scroll_view_.size());
 }
 
 // Verifies ClipHeightTo() uses the minimum height when the content is shorter
 // than the minimum height value.
 TEST_F(ScrollViewTest, ClipHeightToShortContentHeight) {
-  scroll_view_->ClipHeightTo(kMinHeight, kMaxHeight);
+  scroll_view_.ClipHeightTo(kMinHeight, kMaxHeight);
 
   const int kShortContentHeight = 10;
   View* contents =
       new views::StaticSizedView(gfx::Size(kWidth, kShortContentHeight));
-  scroll_view_->SetContents(contents);
+  scroll_view_.SetContents(contents);
 
-  EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_->GetPreferredSize());
+  EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_.GetPreferredSize());
 
-  scroll_view_->SizeToPreferredSize();
-  scroll_view_->Layout();
+  scroll_view_.SizeToPreferredSize();
+  scroll_view_.Layout();
 
   // Layered scrolling requires the contents to fill the viewport.
   if (contents->layer()) {
-    EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_->contents()->size());
+    EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_.contents()->size());
   } else {
     EXPECT_EQ(gfx::Size(kWidth, kShortContentHeight),
-              scroll_view_->contents()->size());
+              scroll_view_.contents()->size());
   }
-  EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_->size());
+  EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view_.size());
 }
 
 // Verifies ClipHeightTo() uses the maximum height when the content is longer
 // thamn the maximum height value.
 TEST_F(ScrollViewTest, ClipHeightToTallContentHeight) {
-  scroll_view_->ClipHeightTo(kMinHeight, kMaxHeight);
+  scroll_view_.ClipHeightTo(kMinHeight, kMaxHeight);
 
   const int kTallContentHeight = 1000;
-  scroll_view_->SetContents(
+  scroll_view_.SetContents(
       new views::StaticSizedView(gfx::Size(kWidth, kTallContentHeight)));
 
-  EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_->GetPreferredSize());
+  EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_.GetPreferredSize());
 
-  scroll_view_->SizeToPreferredSize();
-  scroll_view_->Layout();
+  scroll_view_.SizeToPreferredSize();
+  scroll_view_.Layout();
 
   // The width may be less than kWidth if the scroll bar takes up some width.
-  EXPECT_GE(kWidth, scroll_view_->contents()->width());
-  EXPECT_EQ(kTallContentHeight, scroll_view_->contents()->height());
-  EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_->size());
+  EXPECT_GE(kWidth, scroll_view_.contents()->width());
+  EXPECT_EQ(kTallContentHeight, scroll_view_.contents()->height());
+  EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_.size());
 }
 
 // Verifies that when ClipHeightTo() produces a scrollbar, it reduces the width
 // of the inner content of the ScrollView.
 TEST_F(ScrollViewTest, ClipHeightToScrollbarUsesWidth) {
-  scroll_view_->ClipHeightTo(kMinHeight, kMaxHeight);
+  scroll_view_.ClipHeightTo(kMinHeight, kMaxHeight);
 
   // Create a view that will be much taller than it is wide.
-  scroll_view_->SetContents(new views::ProportionallySizedView(1000));
+  scroll_view_.SetContents(new views::ProportionallySizedView(1000));
 
   // Without any width, it will default to 0,0 but be overridden by min height.
-  scroll_view_->SizeToPreferredSize();
-  EXPECT_EQ(gfx::Size(0, kMinHeight), scroll_view_->GetPreferredSize());
+  scroll_view_.SizeToPreferredSize();
+  EXPECT_EQ(gfx::Size(0, kMinHeight), scroll_view_.GetPreferredSize());
 
-  gfx::Size new_size(kWidth, scroll_view_->GetHeightForWidth(kWidth));
-  scroll_view_->SetSize(new_size);
-  scroll_view_->Layout();
+  gfx::Size new_size(kWidth, scroll_view_.GetHeightForWidth(kWidth));
+  scroll_view_.SetSize(new_size);
+  scroll_view_.Layout();
 
-  int expected_width = kWidth - scroll_view_->GetScrollBarLayoutWidth();
-  EXPECT_EQ(scroll_view_->contents()->size().width(), expected_width);
-  EXPECT_EQ(scroll_view_->contents()->size().height(), 1000 * expected_width);
-  EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_->size());
+  int expected_width = kWidth - scroll_view_.GetScrollBarLayoutWidth();
+  EXPECT_EQ(scroll_view_.contents()->size().width(), expected_width);
+  EXPECT_EQ(scroll_view_.contents()->size().height(), 1000 * expected_width);
+  EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view_.size());
 }
 
 TEST_F(ScrollViewTest, CornerViewVisibility) {
   View* contents = InstallContents();
-  View* corner_view = ScrollViewTestApi(scroll_view_.get()).corner_view();
+  View* corner_view = ScrollViewTestApi(&scroll_view_).corner_view();
 
   contents->SetBounds(0, 0, 200, 200);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
 
   // Corner view should not exist if using overlay scrollbars.
-  if (scroll_view_->vertical_scroll_bar()->OverlapsContent()) {
+  if (scroll_view_.vertical_scroll_bar()->OverlapsContent()) {
     EXPECT_FALSE(corner_view->parent());
     return;
   }
 
   // Corner view should be visible when both scrollbars are visible.
-  EXPECT_EQ(scroll_view_.get(), corner_view->parent());
+  EXPECT_EQ(&scroll_view_, corner_view->parent());
   EXPECT_TRUE(corner_view->visible());
 
   // Corner view should be aligned to the scrollbars.
-  EXPECT_EQ(scroll_view_->vertical_scroll_bar()->x(), corner_view->x());
-  EXPECT_EQ(scroll_view_->horizontal_scroll_bar()->y(), corner_view->y());
-  EXPECT_EQ(scroll_view_->GetScrollBarLayoutWidth(), corner_view->width());
-  EXPECT_EQ(scroll_view_->GetScrollBarLayoutHeight(), corner_view->height());
+  EXPECT_EQ(scroll_view_.vertical_scroll_bar()->x(), corner_view->x());
+  EXPECT_EQ(scroll_view_.horizontal_scroll_bar()->y(), corner_view->y());
+  EXPECT_EQ(scroll_view_.GetScrollBarLayoutWidth(), corner_view->width());
+  EXPECT_EQ(scroll_view_.GetScrollBarLayoutHeight(), corner_view->height());
 
   // Corner view should be removed when only the vertical scrollbar is visible.
   contents->SetBounds(0, 0, 50, 200);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_FALSE(corner_view->parent());
 
   // ... or when only the horizontal scrollbar is visible.
   contents->SetBounds(0, 0, 200, 50);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_FALSE(corner_view->parent());
 
   // ... or when no scrollbar is visible.
   contents->SetBounds(0, 0, 50, 50);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_FALSE(corner_view->parent());
 
   // Corner view should reappear when both scrollbars reappear.
   contents->SetBounds(0, 0, 200, 200);
-  scroll_view_->Layout();
-  EXPECT_EQ(scroll_view_.get(), corner_view->parent());
+  scroll_view_.Layout();
+  EXPECT_EQ(&scroll_view_, corner_view->parent());
   EXPECT_TRUE(corner_view->visible());
 }
 
 TEST_F(ScrollViewTest, ChildWithLayerTest) {
   View* contents = InstallContents();
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
 
   if (test_api.contents_viewport()->layer())
     return;
@@ -817,7 +812,7 @@
   EXPECT_TRUE(test_api.contents_viewport()->layer()->fills_bounds_opaquely());
 
   // Setting a transparent color should make fills opaquely false.
-  scroll_view_->SetBackgroundColor(SK_ColorTRANSPARENT);
+  scroll_view_.SetBackgroundColor(SK_ColorTRANSPARENT);
   EXPECT_FALSE(test_api.contents_viewport()->layer()->fills_bounds_opaquely());
 
   child->DestroyLayer();
@@ -834,12 +829,12 @@
 // is added to the ScrollView's viewport.
 TEST_F(ScrollViewTest, DontCreateLayerOnViewportIfLayerOnScrollViewCreated) {
   View* contents = InstallContents();
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
 
   if (test_api.contents_viewport()->layer())
     return;
 
-  scroll_view_->SetPaintToLayer();
+  scroll_view_.SetPaintToLayer();
 
   View* child = new View();
   contents->AddChildView(child);
@@ -858,35 +853,35 @@
   // Size the contents such that vertical scrollbar is needed.
   // Since it is overlaid, the ViewPort size should match the ScrollView.
   contents->SetBounds(0, 0, 50, 400);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(100, contents->parent()->width());
   EXPECT_EQ(100, contents->parent()->height());
-  EXPECT_EQ(0, scroll_view_->GetScrollBarLayoutWidth());
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, false);
+  EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutWidth());
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, false);
 
   // Size the contents such that horizontal scrollbar is needed.
   contents->SetBounds(0, 0, 400, 50);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(100, contents->parent()->width());
   EXPECT_EQ(100, contents->parent()->height());
-  EXPECT_EQ(0, scroll_view_->GetScrollBarLayoutHeight());
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, false);
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
+  EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutHeight());
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, false);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
 
   // Both horizontal and vertical scrollbars.
   contents->SetBounds(0, 0, 300, 400);
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(100, contents->parent()->width());
   EXPECT_EQ(100, contents->parent()->height());
-  EXPECT_EQ(0, scroll_view_->GetScrollBarLayoutWidth());
-  EXPECT_EQ(0, scroll_view_->GetScrollBarLayoutHeight());
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
+  EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutWidth());
+  EXPECT_EQ(0, scroll_view_.GetScrollBarLayoutHeight());
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
 
   // Make sure the horizontal and vertical scrollbars don't overlap each other.
-  gfx::Rect vert_bounds = scroll_view_->vertical_scroll_bar()->bounds();
-  gfx::Rect horiz_bounds = scroll_view_->horizontal_scroll_bar()->bounds();
+  gfx::Rect vert_bounds = scroll_view_.vertical_scroll_bar()->bounds();
+  gfx::Rect horiz_bounds = scroll_view_.horizontal_scroll_bar()->bounds();
   EXPECT_EQ(vert_bounds.x(), horiz_bounds.right());
   EXPECT_EQ(horiz_bounds.y(), vert_bounds.bottom());
 
@@ -987,11 +982,11 @@
 // Test that increasing the size of the viewport "below" scrolled content causes
 // the content to scroll up so that it still fills the viewport.
 TEST_F(ScrollViewTest, ConstrainScrollToBounds) {
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
 
   View* contents = InstallContents();
   contents->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
-  scroll_view_->Layout();
+  scroll_view_.Layout();
 
   EXPECT_EQ(gfx::ScrollOffset(), test_api.CurrentOffset());
 
@@ -1001,49 +996,49 @@
   EXPECT_NE(gfx::ScrollOffset(), fully_scrolled);
 
   // Making the viewport 55 pixels taller should scroll up the same amount.
-  scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 155));
-  scroll_view_->Layout();
+  scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 100, 155));
+  scroll_view_.Layout();
   EXPECT_EQ(fully_scrolled.y() - 55, test_api.CurrentOffset().y());
   EXPECT_EQ(fully_scrolled.x(), test_api.CurrentOffset().x());
 
   // And 77 pixels wider should scroll left. Also make it short again: the y-
   // offset from the last change should remain.
-  scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 177, 100));
-  scroll_view_->Layout();
+  scroll_view_.SetBoundsRect(gfx::Rect(0, 0, 177, 100));
+  scroll_view_.Layout();
   EXPECT_EQ(fully_scrolled.y() - 55, test_api.CurrentOffset().y());
   EXPECT_EQ(fully_scrolled.x() - 77, test_api.CurrentOffset().x());
 }
 
 // Calling Layout on ScrollView should not reset the scroll location.
 TEST_F(ScrollViewTest, ContentScrollNotResetOnLayout) {
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
 
   CustomView* contents = new CustomView;
   contents->SetPreferredSize(gfx::Size(300, 300));
-  scroll_view_->SetContents(contents);
-  scroll_view_->ClipHeightTo(0, 150);
-  scroll_view_->SizeToPreferredSize();
+  scroll_view_.SetContents(contents);
+  scroll_view_.ClipHeightTo(0, 150);
+  scroll_view_.SizeToPreferredSize();
   // ScrollView preferred width matches that of |contents|, with the height
   // capped at the value we clipped to.
-  EXPECT_EQ(gfx::Size(300, 150), scroll_view_->size());
+  EXPECT_EQ(gfx::Size(300, 150), scroll_view_.size());
 
   // Scroll down.
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 25);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), 25);
   EXPECT_EQ(25, test_api.CurrentOffset().y());
   // Call Layout; no change to scroll position.
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(25, test_api.CurrentOffset().y());
   // Change contents of |contents|, call Layout; still no change to scroll
   // position.
   contents->SetPreferredSize(gfx::Size(300, 500));
   contents->InvalidateLayout();
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(25, test_api.CurrentOffset().y());
 
   // Change |contents| to be shorter than the ScrollView's clipped height.
   // This /will/ change the scroll location due to ConstrainScrollToBounds.
   contents->SetPreferredSize(gfx::Size(300, 50));
-  scroll_view_->Layout();
+  scroll_view_.Layout();
   EXPECT_EQ(0, test_api.CurrentOffset().y());
 }
 
@@ -1051,16 +1046,16 @@
 TEST_F(ScrollViewTest, VerticalOverflowIndicators) {
   const int kWidth = 100;
 
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
 
   // Set up with vertical scrollbar.
   FixedView* contents = new FixedView;
   contents->SetPreferredSize(gfx::Size(kWidth, kMaxHeight * 5));
-  scroll_view_->SetContents(contents);
-  scroll_view_->ClipHeightTo(0, kMaxHeight);
+  scroll_view_.SetContents(contents);
+  scroll_view_.ClipHeightTo(0, kMaxHeight);
 
   // Make sure the size is set such that no horizontal scrollbar gets shown.
-  scroll_view_->SetSize(
+  scroll_view_.SetSize(
       gfx::Size(kWidth + test_api.GetBaseScrollBar(VERTICAL)->GetThickness(),
                 kMaxHeight));
 
@@ -1069,8 +1064,8 @@
 
   // The vertical scroll bar should be visible and the horizontal scroll bar
   // should not.
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, false);
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, false);
 
   // The overflow indicator on the bottom should be visible.
   EXPECT_TRUE(test_api.more_content_bottom()->visible());
@@ -1084,7 +1079,7 @@
 
   // Now scroll the view to someplace in the middle of the scrollable region.
   int offset = kMaxHeight * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
 
   // At this point, both overflow indicators on the top and bottom should be
@@ -1098,7 +1093,7 @@
 
   // Finally scroll the view to end of the scrollable region.
   offset = kMaxHeight * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
 
   // The overflow indicator on the bottom should not be visible.
@@ -1116,15 +1111,15 @@
   const int kWidth = 100;
   const int kHeight = 100;
 
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
 
   // Set up with horizontal scrollbar.
   FixedView* contents = new FixedView;
   contents->SetPreferredSize(gfx::Size(kWidth * 5, kHeight));
-  scroll_view_->SetContents(contents);
+  scroll_view_.SetContents(contents);
 
   // Make sure the size is set such that no vertical scrollbar gets shown.
-  scroll_view_->SetSize(gfx::Size(
+  scroll_view_.SetSize(gfx::Size(
       kWidth, kHeight + test_api.GetBaseScrollBar(HORIZONTAL)->GetThickness()));
 
   contents->SetBounds(0, 0, kWidth * 5, kHeight);
@@ -1134,8 +1129,8 @@
 
   // The horizontal scroll bar should be visible and the vertical scroll bar
   // should not.
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, false);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, false);
 
   // The overflow indicator on the right should be visible.
   EXPECT_TRUE(test_api.more_content_right()->visible());
@@ -1149,7 +1144,7 @@
 
   // Now scroll the view to someplace in the middle of the scrollable region.
   int offset = kWidth * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(offset, 0), test_api.CurrentOffset());
 
   // At this point, both overflow indicators on the left and right should be
@@ -1163,7 +1158,7 @@
 
   // Finally scroll the view to end of the scrollable region.
   offset = kWidth * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(offset, 0), test_api.CurrentOffset());
 
   // The overflow indicator on the right should not be visible.
@@ -1181,22 +1176,22 @@
   const int kWidth = 100;
   const int kHeight = 100;
 
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
 
   // Set up with both horizontal and vertical scrollbars.
   FixedView* contents = new FixedView;
   contents->SetPreferredSize(gfx::Size(kWidth * 5, kHeight * 5));
-  scroll_view_->SetContents(contents);
+  scroll_view_.SetContents(contents);
 
   // Make sure the size is set such that both scrollbars are shown.
-  scroll_view_->SetSize(gfx::Size(kWidth, kHeight));
+  scroll_view_.SetSize(gfx::Size(kWidth, kHeight));
 
   // Make sure the initial origin is 0,0
   EXPECT_EQ(gfx::ScrollOffset(0, 0), test_api.CurrentOffset());
 
   // The horizontal and vertical scroll bars should be visible.
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, true);
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, true);
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
 
   // The overflow indicators on the right and bottom should not be visible since
   // they are against the scrollbars.
@@ -1210,8 +1205,8 @@
   // Now scroll the view to someplace in the middle of the horizontal scrollable
   // region.
   int offset_x = kWidth * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
-                                 offset_x);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
+                                offset_x);
   EXPECT_EQ(gfx::ScrollOffset(offset_x, 0), test_api.CurrentOffset());
 
   // Since there is a vertical scrollbar only the overflow indicator on the left
@@ -1225,8 +1220,8 @@
 
   // Next, scroll the view to end of the scrollable region.
   offset_x = kWidth * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
-                                 offset_x);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
+                                offset_x);
   EXPECT_EQ(gfx::ScrollOffset(offset_x, 0), test_api.CurrentOffset());
 
   // The overflow indicator on the right should still not be visible.
@@ -1242,7 +1237,7 @@
   EXPECT_FALSE(test_api.more_content_bottom()->visible());
 
   // Return the view back to the horizontal origin.
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 0);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL), 0);
   EXPECT_EQ(gfx::ScrollOffset(0, 0), test_api.CurrentOffset());
 
   // The overflow indicators on the right and bottom should not be visible since
@@ -1258,7 +1253,7 @@
   // Now scroll the view to somplace in the middle of the vertical scrollable
   // region.
   int offset_y = kHeight * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
   EXPECT_EQ(gfx::ScrollOffset(0, offset_y), test_api.CurrentOffset());
 
   // Similar to the above, since there is a horizontal scrollbar only the
@@ -1273,7 +1268,7 @@
 
   // Finally, for the vertical test scroll the region all the way to the end.
   offset_y = kHeight * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset_y);
   EXPECT_EQ(gfx::ScrollOffset(0, offset_y), test_api.CurrentOffset());
 
   // The overflow indicator on the bottom should still not be visible.
@@ -1291,8 +1286,8 @@
   // Back to the horizontal. Scroll all the way to the end in the horizontal
   // direction.
   offset_x = kWidth * 4;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
-                                 offset_x);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(HORIZONTAL),
+                                offset_x);
   EXPECT_EQ(gfx::ScrollOffset(offset_x, offset_y), test_api.CurrentOffset());
 
   // The overflow indicator on the bottom and right should still not be visible.
@@ -1307,19 +1302,19 @@
 TEST_F(ScrollViewTest, VerticalWithHeaderOverflowIndicators) {
   const int kWidth = 100;
 
-  ScrollViewTestApi test_api(scroll_view_.get());
+  ScrollViewTestApi test_api(&scroll_view_);
 
   // Set up with vertical scrollbar and a header.
   FixedView* contents = new FixedView;
   CustomView* header = new CustomView;
   contents->SetPreferredSize(gfx::Size(kWidth, kMaxHeight * 5));
-  scroll_view_->SetContents(contents);
+  scroll_view_.SetContents(contents);
   header->SetPreferredSize(gfx::Size(10, 20));
-  scroll_view_->SetHeader(header);
-  scroll_view_->ClipHeightTo(0, kMaxHeight + header->height());
+  scroll_view_.SetHeader(header);
+  scroll_view_.ClipHeightTo(0, kMaxHeight + header->height());
 
   // Make sure the size is set such that no horizontal scrollbar gets shown.
-  scroll_view_->SetSize(
+  scroll_view_.SetSize(
       gfx::Size(kWidth + test_api.GetBaseScrollBar(VERTICAL)->GetThickness(),
                 kMaxHeight + header->height()));
 
@@ -1328,8 +1323,8 @@
 
   // The vertical scroll bar should be visible and the horizontal scroll bar
   // should not.
-  CheckScrollbarVisibility(scroll_view_.get(), VERTICAL, true);
-  CheckScrollbarVisibility(scroll_view_.get(), HORIZONTAL, false);
+  CheckScrollbarVisibility(scroll_view_, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view_, HORIZONTAL, false);
 
   // The overflow indicator on the bottom should be visible.
   EXPECT_TRUE(test_api.more_content_bottom()->visible());
@@ -1343,7 +1338,7 @@
 
   // Now scroll the view to someplace in the middle of the scrollable region.
   int offset = kMaxHeight * 2;
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
 
   // At this point, only the overflow indicator on the bottom should be visible
@@ -1358,7 +1353,7 @@
 
   // Finally scroll the view to end of the scrollable region.
   offset = test_api.GetBaseScrollBar(VERTICAL)->GetMaxPosition();
-  scroll_view_->ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
+  scroll_view_.ScrollToPosition(test_api.GetBaseScrollBar(VERTICAL), offset);
   EXPECT_EQ(gfx::ScrollOffset(0, offset), test_api.CurrentOffset());
 
   // The overflow indicator on the bottom should not be visible now.
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
index f499e20..082ea64 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
+++ b/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
@@ -32,10 +32,7 @@
 
 class TabbedPaneTest : public ViewsTestBase {
  public:
-  TabbedPaneTest() = default;
-
-  void SetUp() override {
-    ViewsTestBase::SetUp();
+  TabbedPaneTest() {
     tabbed_pane_ = std::make_unique<TabbedPane>();
     tabbed_pane_->set_owned_by_client();
   }
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index f12108ad..638037a 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -537,7 +537,8 @@
 }
 
 void Textfield::ShowImeIfNeeded() {
-  if (enabled() && !read_only())
+  // GetInputMethod() may return nullptr in tests.
+  if (enabled() && !read_only() && GetInputMethod())
     GetInputMethod()->ShowImeIfNeeded();
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index dbe61e9..97b54ace8 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -241,9 +241,7 @@
 }
 
 bool DesktopWindowTreeHostPlatform::IsActive() const {
-  // TODO: needs PlatformWindow support.
-  NOTIMPLEMENTED_LOG_ONCE();
-  return false;
+  return is_active_;
 }
 
 void DesktopWindowTreeHostPlatform::Maximize() {
@@ -416,6 +414,7 @@
 }
 
 void DesktopWindowTreeHostPlatform::OnActivationChanged(bool active) {
+  is_active_ = active;
   aura::WindowTreeHostPlatform::OnActivationChanged(active);
   desktop_native_widget_aura_->HandleActivationChanged(active);
 }
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
index 0791f11..e9bc8641 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -104,6 +104,8 @@
 
   bool got_on_closed_ = false;
 
+  bool is_active_ = false;
+
   base::WeakPtrFactory<DesktopWindowTreeHostPlatform> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostPlatform);