diff --git a/.gitignore b/.gitignore
index c5c6e0e7..25c049b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,6 +54,7 @@
 Thumbs.db
 v8.log
 vs-chromium-project.txt
+/.clangd/
 /.clangd-index/
 # Settings directories for eclipse
 /.externalToolBuilders/
diff --git a/AUTHORS b/AUTHORS
index 7da923c..a7bde11f 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -979,6 +979,7 @@
 Yuhong Sha <yuhong.sha@samsung.com>
 Yumikiyo Osanai <yumios.art@gmail.com>
 Yunchao He <yunchao.he@intel.com>
+Yupei Lin <yplam@yplam.com>
 Yupei Wang <perryuwang@tencent.com>
 Yura Yaroshevich <yura.yaroshevich@gmail.com>
 Yuri Gorobets <yuri.gorobets@gmail.com>
diff --git a/BUILD.gn b/BUILD.gn
index cca75ae..fc8c50c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -403,6 +403,7 @@
       "//ash:ash_unittests",
       "//ash/app_list:app_list_demo",
       "//ash/app_list:app_list_unittests",
+      "//chrome/test:usage_time_limit_unittests",
       "//chromeos:chromeos_unittests",
       "//chromeos/components:chromeos_components_unittests",
       "//chromeos/components/proximity_auth:proximity_auth_unittests",
diff --git a/DEPS b/DEPS
index f5cf945d..7b4fe455a 100644
--- a/DEPS
+++ b/DEPS
@@ -133,11 +133,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'f4438d56e989745868ad2fc289894a1553d68ab6',
+  'skia_revision': 'aefecad7c0d2c29c147a05ea385a2ad855cbbc20',
   # 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': '3f6dd8f7b0462a669f3ed1c52519d19625a42d42',
+  'v8_revision': '4181d035d41f0831644d836f5ebe6c81efbec3e5',
   # 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.
@@ -145,15 +145,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '2fb6563bf50375dffcc92aab6c7865da4c555df7',
+  'angle_revision': 'de52ca373d98db8b1de1a5a049cf960b78610052',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'a2749f39f47dd61b6f18972f6471993c6b5c1928',
+  'swiftshader_revision': '1b8cd2d9ce2c0c0cc0213da6eab7d8d47bef4ab3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'b271c06e57ba997a2f109e5311f84af8c804da9a',
+  'pdfium_revision': 'bcb9892d16d3b86d3c8fe70cc8ba0430618ff7d4',
   # 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.
@@ -188,7 +188,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
-  'harfbuzz_revision': '4f37ab63de9705d7bf74ee75364747e41b7c06a1',
+  'harfbuzz_revision': '8aaab78efcac81a05ec919be13792c98741ea1b5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Emoji Segmenter
   # and whatever else without interference from each other.
@@ -248,7 +248,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': 'e545522146af37cc84f6b16e51ebbed96edd334c',
+  'spv_tools_revision': '2ac348b5c0a58c64305379baca778c2e58873cd6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -264,7 +264,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '5625b63202797c54ff1f5a40d9ee664ca23cfce8',
+  'dawn_revision': '931311700c7c4b76a15c23eee8792dda125fb97e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -409,7 +409,7 @@
   },
 
     'src/ios/third_party/edo/src': {
-      'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '0146bd6e1f057160bb80e596c644414e05267e9e',
+      'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '57586e7213892461228ca5543fd37f89ca0e7591',
       'condition': 'checkout_ios',
   },
 
@@ -761,7 +761,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '69d4958ee9b3375a35c8e2f88173187a5b89594b',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '35b4e4c679389f7ea0852b16a97530b93eea852e',
       'condition': 'checkout_linux',
   },
 
@@ -786,7 +786,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1c2fa0fdda124fad7f41d30d19efb901df7e4408',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '04600b4f26bdd5534788d437d0f82a5a47d97deb',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1128,7 +1128,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '8320e6d2b742e5ecde2c60ca535a1d3c8f4c0bdb',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '34e6c9d3d1b6a30263b13ac18b782c79e66f9825',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1340,7 +1340,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b58fe2ab9436b6e35ef3527b8fbf4e7f81c4c98a',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@798a5f3dda67bf4cfa914cec4d3463c90f37d336',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index 733477f..ff58c634 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -651,6 +651,13 @@
   }
   if (mouse_event.type() == ui::ET_MOUSE_PRESSED && HasAutocompleteText())
     AcceptAutocompleteText();
+
+  // Don't activate search box for context menu click.
+  if (mouse_event.type() == ui::ET_MOUSE_PRESSED &&
+      mouse_event.IsOnlyRightMouseButton()) {
+    return false;
+  }
+
   return search_box::SearchBoxViewBase::HandleMouseEvent(sender, mouse_event);
 }
 
diff --git a/ash/app_list/views/search_result_page_view.cc b/ash/app_list/views/search_result_page_view.cc
index cba02d7..cf3a116a 100644
--- a/ash/app_list/views/search_result_page_view.cc
+++ b/ash/app_list/views/search_result_page_view.cc
@@ -335,6 +335,9 @@
 
 void SearchResultPageView::OnSearchResultContainerResultFocused(
     SearchResultBaseView* focused_result_view) {
+  if (!focused_result_view->result())
+    return;
+
   views::Textfield* search_box =
       AppListPage::contents_view()->GetSearchBoxView()->search_box();
   if (focused_result_view->result()->result_type() ==
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc
index a515da0..6a6cda78a 100644
--- a/ash/wm/default_state.cc
+++ b/ash/wm/default_state.cc
@@ -389,10 +389,14 @@
 // static
 void DefaultState::SetBounds(WindowState* window_state,
                              const SetBoundsEvent* event) {
-  if (!event->animate() &&
-      (window_state->is_dragged() || window_state->allow_set_bounds_direct())) {
-    // TODO(oshima|varkha): Is this still needed? crbug.com/485612.
-    window_state->SetBoundsDirect(event->requested_bounds());
+  if (window_state->is_dragged() || window_state->allow_set_bounds_direct()) {
+    if (event->animate()) {
+      window_state->SetBoundsDirectAnimated(event->requested_bounds(),
+                                            event->duration());
+    } else {
+      // TODO(oshima|varkha): Is this still needed? crbug.com/485612.
+      window_state->SetBoundsDirect(event->requested_bounds());
+    }
   } else if (!SetMaximizedOrFullscreenBounds(window_state)) {
     if (event->animate()) {
       window_state->SetBoundsDirectAnimated(event->requested_bounds(),
diff --git a/base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java b/base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java
index 2934bca..3c947ce 100644
--- a/base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java
+++ b/base/android/java/src/org/chromium/base/task/SingleThreadTaskRunnerImpl.java
@@ -4,7 +4,10 @@
 
 package org.chromium.base.task;
 
+import android.annotation.SuppressLint;
+import android.os.Build;
 import android.os.Handler;
+import android.os.Message;
 import android.support.annotation.Nullable;
 
 import org.chromium.base.annotations.JNINamespace;
@@ -18,16 +21,26 @@
 public class SingleThreadTaskRunnerImpl extends TaskRunnerImpl implements SingleThreadTaskRunner {
     @Nullable
     private final Handler mHandler;
+    private final boolean mPostTaskAtFrontOfQueue;
 
     /**
-     * @param handler The backing Handler if any. Note this must run tasks on the same thread that
-     * the native code runs a task with |traits|.  If handler is null then tasks won't run until
-     * native has initialized.
-     * @param traits The TaskTraits associated with this SingleThreadTaskRunnerImpl.
+     * @param handler                The backing Handler if any. Note this must run tasks on the
+     *                               same thread that the native code runs a task with |traits|.
+     *                               If handler is null then tasks won't run until native has
+     *                               initialized.
+     * @param traits                 The TaskTraits associated with this SingleThreadTaskRunnerImpl.
+     * @param postTaskAtFrontOfQueue If true, tasks posted to the backing Handler will be posted at
+     *                               the front of the queue.
      */
-    public SingleThreadTaskRunnerImpl(Handler handler, TaskTraits traits) {
+    public SingleThreadTaskRunnerImpl(
+            Handler handler, TaskTraits traits, boolean postTaskAtFrontOfQueue) {
         super(traits, "SingleThreadTaskRunnerImpl", TaskRunnerType.SINGLE_THREAD);
         mHandler = handler;
+        mPostTaskAtFrontOfQueue = postTaskAtFrontOfQueue;
+    }
+
+    public SingleThreadTaskRunnerImpl(Handler handler, TaskTraits traits) {
+        this(handler, traits, false);
     }
 
     @Override
@@ -42,6 +55,26 @@
     @Override
     protected void schedulePreNativeTask() {
         // if |mHandler| is null then pre-native task execution is not supported.
-        if (mHandler != null) mHandler.post(mRunPreNativeTaskClosure);
+        if (mHandler == null) {
+            return;
+        } else if (mPostTaskAtFrontOfQueue) {
+            postAtFrontOfQueue();
+        } else {
+            mHandler.post(mRunPreNativeTaskClosure);
+        }
+    }
+
+    @SuppressLint("NewApi")
+    private void postAtFrontOfQueue() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            // The mHandler.postAtFrontOfQueue() API uses fences which batches messages up per
+            // frame. We want to bypass that for performance, hence we use async messages where
+            // possible.
+            Message message = Message.obtain(mHandler, mRunPreNativeTaskClosure);
+            message.setAsynchronous(true);
+            mHandler.sendMessageAtFrontOfQueue(message);
+        } else {
+            mHandler.postAtFrontOfQueue(mRunPreNativeTaskClosure);
+        }
     }
 }
diff --git a/base/android/javatests/src/org/chromium/base/task/SingleThreadTaskRunnerImplTest.java b/base/android/javatests/src/org/chromium/base/task/SingleThreadTaskRunnerImplTest.java
index ee29c4a..41754a1 100644
--- a/base/android/javatests/src/org/chromium/base/task/SingleThreadTaskRunnerImplTest.java
+++ b/base/android/javatests/src/org/chromium/base/task/SingleThreadTaskRunnerImplTest.java
@@ -56,7 +56,7 @@
     @Test
     @SmallTest
     public void testPreNativePostTask() {
-        TaskRunner taskQueue = new SingleThreadTaskRunnerImpl(mHandler, new TaskTraits());
+        TaskRunner taskQueue = new SingleThreadTaskRunnerImpl(mHandler, new TaskTraits(), false);
         List<Integer> orderList = new ArrayList<>();
         SchedulerTestHelpers.postRecordOrderTask(taskQueue, orderList, 1);
         SchedulerTestHelpers.postRecordOrderTask(taskQueue, orderList, 2);
@@ -72,7 +72,7 @@
     public void testBelongsToCurrentThread() {
         // The handler created during test setup belongs to a different thread.
         SingleThreadTaskRunner taskQueue =
-                new SingleThreadTaskRunnerImpl(mHandler, new TaskTraits());
+                new SingleThreadTaskRunnerImpl(mHandler, new TaskTraits(), false);
         try {
             Assert.assertFalse(taskQueue.belongsToCurrentThread());
         } finally {
@@ -82,11 +82,42 @@
         // We create a handler belonging to current thread.
         Looper.prepare();
         SingleThreadTaskRunner taskQueueCurrentThread =
-                new SingleThreadTaskRunnerImpl(new Handler(), new TaskTraits());
+                new SingleThreadTaskRunnerImpl(new Handler(), new TaskTraits(), false);
         try {
             Assert.assertTrue(taskQueueCurrentThread.belongsToCurrentThread());
         } finally {
             taskQueueCurrentThread.destroy();
         }
     }
+
+    @Test
+    @SmallTest
+    public void testPrioritization() {
+        TaskRunner highPriorityQueue =
+                new SingleThreadTaskRunnerImpl(mHandler, new TaskTraits(), true);
+        TaskRunner lowPriorityQueue =
+                new SingleThreadTaskRunnerImpl(mHandler, new TaskTraits(), false);
+        try {
+            List<Integer> orderList = new ArrayList<>();
+            // We want to post all these tasks atomically but we're not on the mHandlerThread so
+            // we need to post a task to do that for us.
+            lowPriorityQueue.postTask(new Runnable() {
+                @Override
+                public void run() {
+                    SchedulerTestHelpers.postRecordOrderTask(lowPriorityQueue, orderList, 1);
+                    SchedulerTestHelpers.postRecordOrderTask(lowPriorityQueue, orderList, 2);
+                    SchedulerTestHelpers.postRecordOrderTask(lowPriorityQueue, orderList, 3);
+                    SchedulerTestHelpers.postRecordOrderTask(highPriorityQueue, orderList, 10);
+                    SchedulerTestHelpers.postRecordOrderTask(highPriorityQueue, orderList, 20);
+                    SchedulerTestHelpers.postRecordOrderTask(highPriorityQueue, orderList, 30);
+                }
+            });
+
+            SchedulerTestHelpers.preNativeRunUntilIdle(mHandlerThread);
+            assertThat(orderList, contains(10, 20, 30, 1, 2, 3));
+        } finally {
+            highPriorityQueue.destroy();
+            lowPriorityQueue.destroy();
+        }
+    }
 }
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index a1481f37..5e1de56 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -172,8 +172,9 @@
 }
 
 if (use_debug_fission == "default") {
-  use_debug_fission = is_debug && !is_android && !is_fuchsia && !is_win &&
-                      (use_gold || use_lld) && cc_wrapper == ""
+  use_debug_fission =
+      is_debug && !is_android && !is_fuchsia && !is_ios && !is_mac && !is_win &&
+      (use_gold || use_lld) && cc_wrapper == ""
 }
 
 # default_include_dirs ---------------------------------------------------------
@@ -2254,40 +2255,38 @@
       }
     }
   } else {
-    if (is_mac || is_ios) {
-      cflags = [ "-gdwarf-2" ]
-      if (is_mac && enable_dsyms) {
-        # If generating dSYMs, specify -fno-standalone-debug. This was
-        # originally specified for https://crbug.com/479841 because dsymutil
-        # could not handle a 4GB dSYM file. But dsymutil from Xcodes prior to
-        # version 7 also produces debug data that is incompatible with Breakpad
-        # dump_syms, so this is still required (https://crbug.com/622406).
-        cflags += [ "-fno-standalone-debug" ]
-      }
-    } else {
-      cflags = []
-      if (!use_debug_fission && current_cpu == "arm") {
-        # dump_syms has issues with dwarf4 on arm, https://crbug.com/744956
-        # TODO(thakis): Remove this again once dump_syms is fixed.
-        #
-        # debug fission needs DWARF DIEs to be emitted at version 4.
-        # Chrome OS emits Debug Frame in DWARF1 to make breakpad happy. [1]
-        # Unless Android needs debug fission, DWARF3 is the simplest solution.
-        #
-        # [1] crrev.com/a81d5ade0b043208e06ad71a38bcf9c348a1a52f
-        cflags += [ "-gdwarf-3" ]
-      }
-
-      # The gcc-based nacl compilers don't support -fdebug-compilation-dir (see
-      # elsewhere in this file), so they can't have build-dir-independent output.
-      # Disable symbols for nacl object files to get deterministic,
-      # build-directory-independent output. pnacl and nacl-clang do support that
-      # flag, so we can use use -g1 for pnacl and nacl-clang compiles.
-      # gcc nacl is is_nacl && !is_clang, pnacl and nacl-clang are && is_clang.
-      if (!is_nacl || is_clang) {
-        cflags += [ "-g2" ]
-      }
+    cflags = []
+    if (is_mac && enable_dsyms) {
+      # If generating dSYMs, specify -fno-standalone-debug. This was
+      # originally specified for https://crbug.com/479841 because dsymutil
+      # could not handle a 4GB dSYM file. But dsymutil from Xcodes prior to
+      # version 7 also produces debug data that is incompatible with Breakpad
+      # dump_syms, so this is still required (https://crbug.com/622406).
+      cflags += [ "-fno-standalone-debug" ]
     }
+    if (!use_debug_fission && current_cpu == "arm") {
+      # dump_syms has issues with dwarf4 on arm, https://crbug.com/744956
+      # TODO(thakis): Remove this again once dump_syms is fixed.
+      #
+      # debug fission needs DWARF DIEs to be emitted at version 4.
+      # Chrome OS emits Debug Frame in DWARF2's .debug_frame v1 to make breakpad
+      # happy [1].
+      # Unless Android needs debug fission, DWARF3 is the simplest solution.
+      #
+      # [1] crrev.com/a81d5ade0b043208e06ad71a38bcf9c348a1a52f
+      cflags += [ "-gdwarf-3" ]
+    }
+
+    # The gcc-based nacl compilers don't support -fdebug-compilation-dir (see
+    # elsewhere in this file), so they can't have build-dir-independent output.
+    # Disable symbols for nacl object files to get deterministic,
+    # build-directory-independent output. pnacl and nacl-clang do support that
+    # flag, so we can use use -g1 for pnacl and nacl-clang compiles.
+    # gcc nacl is is_nacl && !is_clang, pnacl and nacl-clang are && is_clang.
+    if (!is_nacl || is_clang) {
+      cflags += [ "-g2" ]
+    }
+
     if (use_debug_fission && !is_nacl && !is_android) {
       # NOTE: Some Chrome OS builds globally set |use_debug_fission| to true,
       # but they also build some targets against Android toolchains which aren't
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 1ef3795..d36df5f 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-ddcb12bc41acc7d54223765e22f78a305954bcbc
\ No newline at end of file
+644d5b59c0682caf40ef946b411fa699a9d95cdc
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 077fa9d8..643ebc4 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-bf01df1020cecebcf7bcc39fdd72c783bb14a923
\ No newline at end of file
+e34cc49eab53073ada98d13d2991fa6b92ddebd6
\ No newline at end of file
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc
index 33c4bc6..5b54d9b 100644
--- a/cc/animation/animation_host.cc
+++ b/cc/animation/animation_host.cc
@@ -129,6 +129,11 @@
   SetNeedsPushProperties();
 }
 
+void AnimationHost::InitClientAnimationState() {
+  for (auto map_entry : element_to_animations_map_)
+    map_entry.second->InitClientAnimationState();
+}
+
 void AnimationHost::RegisterElement(ElementId element_id,
                                     ElementListType list_type) {
   scoped_refptr<ElementAnimations> element_animations =
diff --git a/cc/animation/animation_host.h b/cc/animation/animation_host.h
index 7473db7e..9927f36 100644
--- a/cc/animation/animation_host.h
+++ b/cc/animation/animation_host.h
@@ -90,6 +90,8 @@
       bool supports_impl_scrolling) const override;
   void ClearMutators() override;
 
+  void InitClientAnimationState() override;
+
   void RegisterElement(ElementId element_id,
                        ElementListType list_type) override;
   void UnregisterElement(ElementId element_id,
diff --git a/cc/animation/element_animations.cc b/cc/animation/element_animations.cc
index 4926dbce..66aaa8c2 100644
--- a/cc/animation/element_animations.cc
+++ b/cc/animation/element_animations.cc
@@ -312,6 +312,14 @@
                            keyframe_model);
 }
 
+void ElementAnimations::InitClientAnimationState() {
+  // Clear current states so that UpdateClientAnimationState() will send all
+  // (instead of only changed) recalculated current states to the client.
+  pending_state_.Clear();
+  active_state_.Clear();
+  UpdateClientAnimationState();
+}
+
 void ElementAnimations::UpdateClientAnimationState() {
   if (!element_id())
     return;
diff --git a/cc/animation/element_animations.h b/cc/animation/element_animations.h
index 7e8f124..5f0904d 100644
--- a/cc/animation/element_animations.h
+++ b/cc/animation/element_animations.h
@@ -124,6 +124,13 @@
   bool ScrollOffsetAnimationWasInterrupted() const;
 
   void SetNeedsPushProperties();
+
+  // Initializes client animation state by calling client's
+  // ElementIsAnimatingChanged() method with the current animation state.
+  void InitClientAnimationState();
+  // Updates client animation state by calling client's
+  // ElementIsAnimatingChanged() method with the state containing properties
+  // that have changed since the last update.
   void UpdateClientAnimationState();
 
   void NotifyClientFloatAnimated(float opacity,
diff --git a/cc/trees/mutator_host.h b/cc/trees/mutator_host.h
index 03aa3fd..21551b9 100644
--- a/cc/trees/mutator_host.h
+++ b/cc/trees/mutator_host.h
@@ -42,6 +42,8 @@
 
   virtual void ClearMutators() = 0;
 
+  virtual void InitClientAnimationState() = 0;
+
   virtual void RegisterElement(ElementId element_id,
                                ElementListType list_type) = 0;
   virtual void UnregisterElement(ElementId element_id,
diff --git a/chrome/OWNERS b/chrome/OWNERS
index f656e8d..e5f0451b 100644
--- a/chrome/OWNERS
+++ b/chrome/OWNERS
@@ -2,6 +2,7 @@
 # where possible.
 
 # Reviewers (in CET):
+blundell@chromium.org
 droger@chromium.org
 treib@chromium.org
 vasilii@chromium.org
diff --git a/chrome/VERSION b/chrome/VERSION
index 97d9170..be99ed47 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=75
 MINOR=0
-BUILD=3734
+BUILD=3735
 PATCH=0
diff --git a/chrome/android/java/res/layout/contextual_search_term_view.xml b/chrome/android/java/res/layout/contextual_search_term_view.xml
index acaf0c31..1eefacd 100644
--- a/chrome/android/java/res/layout/contextual_search_term_view.xml
+++ b/chrome/android/java/res/layout/contextual_search_term_view.xml
@@ -13,7 +13,7 @@
         style="@style/ContextualSearchTextView"
         android:layout_width="match_parent"
         android:layout_gravity="bottom"
-        android:background="#FFF"
+        android:background="@color/overlay_panel_bar_background_color"
         android:layout_marginStart="7dp"
         android:layout_marginEnd="7dp" />
 </FrameLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/ephemeral_tab_text_view.xml b/chrome/android/java/res/layout/ephemeral_tab_text_view.xml
index 92df4dc..681ae4a 100644
--- a/chrome/android/java/res/layout/ephemeral_tab_text_view.xml
+++ b/chrome/android/java/res/layout/ephemeral_tab_text_view.xml
@@ -14,7 +14,7 @@
         style="@style/ContextualSearchTextView"
         android:layout_width="match_parent"
         android:layout_gravity="bottom"
-        android:background="@android:color/white"
+        android:background="@color/overlay_panel_bar_background_color"
         android:layout_marginStart="7dp"
         android:layout_marginEnd="7dp" />
 </FrameLayout>
diff --git a/chrome/android/java/res/layout/search_activity.xml b/chrome/android/java/res/layout/search_activity.xml
index 85c7246..6977aac 100644
--- a/chrome/android/java/res/layout/search_activity.xml
+++ b/chrome/android/java/res/layout/search_activity.xml
@@ -22,7 +22,7 @@
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="@dimen/toolbar_height_no_shadow"
-            android:background="@android:color/white"
+            android:background="@color/toolbar_background_primary"
             android:paddingStart="@dimen/toolbar_edge_padding"
             android:paddingEnd="@dimen/toolbar_edge_padding"
             android:clickable="true" >
diff --git a/chrome/android/java/res/layout/tile_no_text_view_condensed.xml b/chrome/android/java/res/layout/tile_no_text_view_condensed.xml
new file mode 100644
index 0000000..392c8fd
--- /dev/null
+++ b/chrome/android/java/res/layout/tile_no_text_view_condensed.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<!-- An icon tile. -->
+<merge
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools" >
+
+    <!-- The icon background. -->
+    <View
+        android:id="@+id/tile_view_icon_background"
+        android:layout_width="@dimen/tile_view_icon_size"
+        android:layout_height="@dimen/tile_view_icon_size"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/tile_view_icon_background_margin_top_modern"
+        android:background="@drawable/tile_view_icon_background_modern" />
+
+    <!-- The main icon. -->
+    <ImageView
+        android:id="@+id/tile_view_icon"
+        android:layout_width="@dimen/tile_view_icon_size_modern"
+        android:layout_height="@dimen/tile_view_icon_size_modern"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/tile_view_icon_margin_top_modern"
+        tools:ignore="ContentDescription" />
+
+    <!-- The touch highlight. -->
+    <View
+        android:id="@+id/tile_view_highlight"
+        android:layout_width="@dimen/tile_view_icon_size"
+        android:layout_height="@dimen/tile_view_icon_size"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/tile_view_icon_background_margin_top_modern"
+        android:background="@drawable/tile_view_highlight" />
+
+    <!-- The offline badge. -->
+    <ImageView
+        android:id="@+id/offline_badge"
+        android:layout_width="@dimen/tile_view_offline_badge_size_modern"
+        android:layout_height="@dimen/tile_view_offline_badge_size_modern"
+        android:layout_gravity="top|end"
+        android:layout_marginTop="@dimen/tile_view_offline_badge_margin_top_modern_condensed"
+        android:layout_marginEnd="@dimen/tile_view_offline_badge_margin_end_modern_condensed"
+        android:visibility="gone"
+        android:contentDescription="@string/accessibility_ntp_offline_badge"
+        app:srcCompat="@drawable/ic_offline_pin_blue_white" />
+</merge>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/tile_view_modern_condensed.xml b/chrome/android/java/res/layout/tile_view_modern_condensed.xml
index b212111..d08d852 100644
--- a/chrome/android/java/res/layout/tile_view_modern_condensed.xml
+++ b/chrome/android/java/res/layout/tile_view_modern_condensed.xml
@@ -9,44 +9,7 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools" >
 
-    <!-- The icon background. -->
-    <View
-        android:id="@+id/tile_view_icon_background"
-        android:layout_width="@dimen/tile_view_icon_size"
-        android:layout_height="@dimen/tile_view_icon_size"
-        android:layout_gravity="center_horizontal"
-        android:layout_marginTop="@dimen/tile_view_icon_background_margin_top_modern"
-        android:background="@drawable/tile_view_icon_background_modern" />
-
-    <!-- The main icon. -->
-    <ImageView
-        android:id="@+id/tile_view_icon"
-        android:layout_width="@dimen/tile_view_icon_size_modern"
-        android:layout_height="@dimen/tile_view_icon_size_modern"
-        android:layout_gravity="center_horizontal"
-        android:layout_marginTop="@dimen/tile_view_icon_margin_top_modern"
-        tools:ignore="ContentDescription" />
-
-    <!-- The touch highlight. -->
-    <View
-        android:id="@+id/tile_view_highlight"
-        android:layout_width="@dimen/tile_view_icon_size"
-        android:layout_height="@dimen/tile_view_icon_size"
-        android:layout_gravity="center_horizontal"
-        android:layout_marginTop="@dimen/tile_view_icon_background_margin_top_modern"
-        android:background="@drawable/tile_view_highlight" />
-
-    <!-- The offline badge. -->
-    <ImageView
-        android:id="@+id/offline_badge"
-        android:layout_width="@dimen/tile_view_offline_badge_size_modern"
-        android:layout_height="@dimen/tile_view_offline_badge_size_modern"
-        android:layout_gravity="top|end"
-        android:layout_marginTop="@dimen/tile_view_offline_badge_margin_top_modern_condensed"
-        android:layout_marginEnd="@dimen/tile_view_offline_badge_margin_end_modern_condensed"
-        android:visibility="gone"
-        android:contentDescription="@string/accessibility_ntp_offline_badge"
-        app:srcCompat="@drawable/ic_offline_pin_blue_white" />
+    <include layout="@layout/tile_no_text_view_condensed" />
 
     <!-- The title. -->
     <TextView
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index 76d28d9e..4d26b82 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -520,7 +520,7 @@
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:layout_gravity">bottom</item>
-        <item name="android:background">#FFF</item>
+        <item name="android:background">@color/overlay_panel_bar_background_color</item>
         <item name="android:visibility">invisible</item>
         <!-- 60dp padding minus 7dp for fading edge -->
         <item name="android:paddingStart">53dp</item>
@@ -555,7 +555,7 @@
         <item name="android:layout_gravity">bottom</item>
         <item name="android:layout_marginStart">7dp</item>
         <item name="android:layout_marginEnd">7dp</item>
-        <item name="android:background">#FFF</item>
+        <item name="android:background">@color/overlay_panel_bar_background_color</item>
         <item name="android:ellipsize">end</item>
         <item name="android:includeFontPadding">false</item>
         <item name="android:singleLine">true</item>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index a13f8f1..0914c95a 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -120,8 +120,11 @@
     <!-- Incognito NTP Colors. -->
     <color name="incognito_emphasis">@android:color/white</color>
 
+    <!-- Overlay Panel colors -->
+    <color name="overlay_panel_bar_background_color">@color/default_bg_color_elev_2</color>
+
     <!-- Contextual Search colors -->
-    <color name="contextual_search_promo_background_color">@color/modern_grey_200</color>
+    <color name="contextual_search_promo_background_color">@color/default_bg_color_elev_0</color>
     <color name="contextual_search_promo_border_color">#C2C2C2</color>
 
     <!-- Progress Bar colors -->
@@ -134,7 +137,7 @@
     <color name="incognito_modern_primary_color">@color/modern_grey_800</color>
 
     <!-- Toolbar colors -->
-    <color name="toolbar_background_primary">@android:color/white</color>
+    <color name="toolbar_background_primary">@color/default_bg_color_elev_3</color>
     <color name="toolbar_background_primary_incognito">@color/modern_grey_800</color>
     <color name="toolbar_text_box_background">@color/modern_grey_100</color>
     <color name="toolbar_shadow_color">@color/black_alpha_11</color>
diff --git a/chrome/android/java/res_night/OWNERS b/chrome/android/java/res_night/OWNERS
new file mode 100644
index 0000000..b6cb286
--- /dev/null
+++ b/chrome/android/java/res_night/OWNERS
@@ -0,0 +1,9 @@
+# This restriction is in place to avoid accidental addition to our top level
+# layout files, such as adding duplicated assets, or introducing new colors when
+# we don't want them.
+set noparent
+
+file://ui/android/java/res/OWNERS
+
+# COMPONENT: UI>Browser>Mobile
+# OS: Android
diff --git a/chrome/android/java/res_night/values-night/colors.xml b/chrome/android/java/res_night/values-night/colors.xml
index af70351..55e9f97 100644
--- a/chrome/android/java/res_night/values-night/colors.xml
+++ b/chrome/android/java/res_night/values-night/colors.xml
@@ -9,7 +9,6 @@
     <color name="default_red">@color/default_red_light</color>
     <color name="default_green">@color/default_green_light</color>
 
-    <color name="toolbar_background_primary">@color/modern_grey_900_with_white_alpha_8</color>
     <color name="toolbar_text_box_background">@color/modern_grey_800</color>
 
     <color name="bottom_system_nav_color">@android:color/black</color>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index d40c8d4e..0eb5b3f2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -271,7 +271,6 @@
     private CompositorViewHolder mCompositorViewHolder;
     private InsetObserverView mInsetObserverView;
     private ContextualSearchManager mContextualSearchManager;
-    private EphemeralTabPanel mEphemeralTabPanel;
     protected ReaderModeManager mReaderModeManager;
     private SnackbarManager mSnackbarManager;
     private AppMenuPropertiesDelegate mAppMenuPropertiesDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
index 156427f..656a41a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
@@ -5,6 +5,8 @@
 package org.chromium.chrome.browser.compositor.bottombar;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.support.annotation.ColorInt;
 import android.support.annotation.Nullable;
 import android.view.ViewGroup;
 
@@ -102,6 +104,12 @@
     /** The height of the Bar when the Panel is maximized, in dps. */
     private final float mBarHeightMaximized;
 
+    /** The background color of the Bar. */
+    private final @ColorInt int mBarBackgroundColor;
+
+    /** The tint used for icons (e.g. arrow icon, close icon). */
+    private final @ColorInt int mIconColor;
+
     /**
      * The Y coordinate to apply to the Base Page in order to keep the selection
      * in view when the Overlay Panel is in its EXPANDED state.
@@ -136,6 +144,11 @@
         mBarBorderHeight = BAR_BORDER_HEIGHT_DP;
 
         mBarHeight = mBarHeightPeeking;
+
+        final Resources resources = mContext.getResources();
+        mBarBackgroundColor = ApiCompatibilityUtils.getColor(
+                resources, R.color.overlay_panel_bar_background_color);
+        mIconColor = ApiCompatibilityUtils.getColor(resources, R.color.default_icon_color);
     }
 
     // ============================================================================================
@@ -429,6 +442,20 @@
     }
 
     /**
+     * @return The background color of the Bar.
+     */
+    public int getBarBackgroundColor() {
+        return mBarBackgroundColor;
+    }
+
+    /**
+     * @return The tint used for icons.
+     */
+    public int getIconColor() {
+        return mIconColor;
+    }
+
+    /**
      * @return The opacity of the arrow icon.
      */
     public float getArrowIconOpacity() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java
index c3fa0b9..14dab02 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java
@@ -23,7 +23,13 @@
 import org.chromium.chrome.browser.compositor.layouts.eventfilter.OverlayPanelEventFilter;
 import org.chromium.chrome.browser.compositor.scene_layer.EphemeralTabSceneLayer;
 import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer;
+import org.chromium.chrome.browser.tab.SadTab;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
+import org.chromium.chrome.browser.tabmodel.TabSelectionType;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.PageTransition;
@@ -47,6 +53,10 @@
     /** Url for which this epehemral tab was created. */
     private String mUrl;
 
+    /** Observers detecting various signals indicating the panel needs closing. */
+    private TabModelSelectorTabModelObserver mTabModelObserver;
+    private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
+
     /**
      * Checks if this feature (a.k.a. "Preview page/image") is supported.
      * @return {@code true} if the feature is enabled.
@@ -82,11 +92,62 @@
     }
 
     @Override
+    public void destroy() {
+        stopListeningForCloseConditions();
+    }
+
+    @Override
     public OverlayPanelContent createNewOverlayPanelContent() {
+        if (mTabModelObserver == null) startListeningForCloseConditions();
         return new OverlayPanelContent(new OverlayContentDelegate(), new PanelProgressObserver(),
                 mActivity, mIsIncognito, getBarHeight());
     }
 
+    private void startListeningForCloseConditions() {
+        TabModelSelector selector = mActivity.getTabModelSelector();
+        mTabModelObserver = new TabModelSelectorTabModelObserver(selector) {
+            @Override
+            public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) {
+                closeTab();
+            }
+
+            @Override
+            public void didAddTab(Tab tab, @TabLaunchType int type) {
+                closeTab();
+            }
+        };
+        mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(selector) {
+            @Override
+            public void onPageLoadStarted(Tab tab, String url) {
+                // Hides the panel if the base page navigates.
+                closeTab();
+            }
+
+            @Override
+            public void onCrash(Tab tab) {
+                // Hides the panel if the foreground tab crashed
+                if (SadTab.isShowing(tab)) closeTab();
+            }
+
+            @Override
+            public void onClosingStateChanged(Tab tab, boolean closing) {
+                if (closing) closeTab();
+            }
+        };
+    }
+
+    private void stopListeningForCloseConditions() {
+        if (mTabModelObserver == null) return;
+        mTabModelObserver.destroy();
+        mTabModelSelectorTabObserver.destroy();
+        mTabModelObserver = null;
+        mTabModelSelectorTabObserver = null;
+    }
+
+    private void closeTab() {
+        closePanel(StateChangeReason.UNKNOWN, false);
+    }
+
     @Override
     protected float getPeekedHeight() {
         return getBarHeightPeeking() * 1.5f;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
index 4cc0dc2..15b3fcd5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
@@ -458,6 +458,7 @@
         mSceneChangeObservers.clear();
         if (mStaticLayout != null) mStaticLayout.destroy();
         if (mOverlayPanelManager != null) mOverlayPanelManager.destroy();
+        if (mEphemeralTabPanel != null) mEphemeralTabPanel.destroy();
         if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.destroy();
         if (mTabModelSelectorObserver != null) {
             getTabModelSelector().removeObserver(mTabModelSelectorObserver);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
index 6e83f950..938c44a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
@@ -57,6 +57,7 @@
         }
         mImageControl = imageControl;
 
+        final int searchBarBackgroundColor = panel.getBarBackgroundColor();
         int searchContextViewId = searchBarControl.getSearchContextViewId();
         int searchTermViewId = searchBarControl.getSearchTermViewId();
         int searchCaptionViewId = searchBarControl.getCaptionViewId();
@@ -103,6 +104,7 @@
         boolean searchBarShadowVisible = panel.getBarShadowVisible();
         float searchBarShadowOpacity = panel.getBarShadowOpacity();
 
+        final int iconColor = panel.getIconColor();
         float arrowIconOpacity = panel.getArrowIconOpacity();
         float arrowIconRotation = panel.getArrowIconRotation();
 
@@ -128,9 +130,9 @@
         WebContents panelWebContents = panel.getWebContents();
 
         nativeUpdateContextualSearchLayer(mNativePtr, R.drawable.contextual_search_bar_background,
-                searchContextViewId, searchTermViewId, searchCaptionViewId,
-                R.drawable.modern_toolbar_shadow, R.drawable.ic_logo_googleg_24dp,
-                quickActionIconResId, R.drawable.breadcrumb_arrow,
+                searchBarBackgroundColor, searchContextViewId, searchTermViewId,
+                searchCaptionViewId, R.drawable.modern_toolbar_shadow,
+                R.drawable.ic_logo_googleg_24dp, quickActionIconResId, R.drawable.breadcrumb_arrow,
                 ContextualSearchPanel.CLOSE_ICON_DRAWABLE_ID, R.drawable.progress_bar_background,
                 R.drawable.progress_bar_foreground, searchPromoViewId,
                 R.drawable.contextual_search_promo_ripple, searchBarBannerTextViewId, mDpToPx,
@@ -146,11 +148,11 @@
                 searchCaptionVisible, searchBarBorderVisible, searchBarBorderHeight * mDpToPx,
                 searchBarShadowVisible, searchBarShadowOpacity, quickActionIconVisible,
                 thumbnailVisible, thumbnailUrl, customImageVisibilityPercentage, barImageSize,
-                arrowIconOpacity, arrowIconRotation, closeIconOpacity, isProgressBarVisible,
-                progressBarHeight * mDpToPx, progressBarOpacity, progressBarCompletion,
-                dividerLineVisibilityPercentage, dividerLineWidth, dividerLineHeight,
-                dividerLineColor, dividerLineXOffset, touchHighlightVisible, touchHighlightXOffset,
-                touchHighlightWidth, Profile.getLastUsedProfile());
+                iconColor, arrowIconOpacity, arrowIconRotation, closeIconOpacity,
+                isProgressBarVisible, progressBarHeight * mDpToPx, progressBarOpacity,
+                progressBarCompletion, dividerLineVisibilityPercentage, dividerLineWidth,
+                dividerLineHeight, dividerLineColor, dividerLineXOffset, touchHighlightVisible,
+                touchHighlightXOffset, touchHighlightWidth, Profile.getLastUsedProfile());
     }
 
     @CalledByNative
@@ -199,10 +201,11 @@
     private native void nativeHideTree(
             long nativeContextualSearchSceneLayer);
     private native void nativeUpdateContextualSearchLayer(long nativeContextualSearchSceneLayer,
-            int searchBarBackgroundResourceId, int searchContextResourceId,
-            int searchTermResourceId, int searchCaptionResourceId, int searchBarShadowResourceId,
-            int searchProviderIconResourceId, int quickActionIconResourceId, int arrowUpResourceId,
-            int closeIconResourceId, int progressBarBackgroundResourceId, int progressBarResourceId,
+            int searchBarBackgroundResourceId, int searchBarBackgroundColor,
+            int searchContextResourceId, int searchTermResourceId, int searchCaptionResourceId,
+            int searchBarShadowResourceId, int searchProviderIconResourceId,
+            int quickActionIconResourceId, int arrowUpResourceId, int closeIconResourceId,
+            int progressBarBackgroundResourceId, int progressBarResourceId,
             int searchPromoResourceId, int barBannerRippleResourceId, int barBannerTextResourceId,
             float dpToPx, float layoutWidth, float layoutHeight, float basePageBrightness,
             float basePageYOffset, WebContents webContents, boolean searchPromoVisible,
@@ -217,10 +220,11 @@
             boolean searchBarBorderVisible, float searchBarBorderHeight,
             boolean searchBarShadowVisible, float searchBarShadowOpacity,
             boolean quickActionIconVisible, boolean thumbnailVisible, String thumbnailUrl,
-            float customImageVisibilityPercentage, int barImageSize, float arrowIconOpacity,
-            float arrowIconRotation, float closeIconOpacity, boolean isProgressBarVisible,
-            float progressBarHeight, float progressBarOpacity, int progressBarCompletion,
-            float dividerLineVisibilityPercentage, float dividerLineWidth, float dividerLineHeight,
-            int dividerLineColor, float dividerLineXOffset, boolean touchHighlightVisible,
-            float touchHighlightXOffset, float toucHighlightWidth, Profile profile);
+            float customImageVisibilityPercentage, int barImageSize, int iconColor,
+            float arrowIconOpacity, float arrowIconRotation, float closeIconOpacity,
+            boolean isProgressBarVisible, float progressBarHeight, float progressBarOpacity,
+            int progressBarCompletion, float dividerLineVisibilityPercentage,
+            float dividerLineWidth, float dividerLineHeight, int dividerLineColor,
+            float dividerLineXOffset, boolean touchHighlightVisible, float touchHighlightXOffset,
+            float toucHighlightWidth, Profile profile);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java
index 2ecd971..d2091e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java
@@ -80,9 +80,10 @@
                 panel.getBasePageBrightness(), panel.getBasePageY() * mDpToPx, panelWebContents,
                 panel.getOffsetX() * mDpToPx, panel.getOffsetY() * mDpToPx,
                 panel.getWidth() * mDpToPx, panel.getHeight() * mDpToPx,
-                panel.getBarMarginSide() * mDpToPx, panel.getBarHeight() * mDpToPx,
-                panel.isBarBorderVisible(), panel.getBarBorderHeight() * mDpToPx,
-                panel.getBarShadowVisible(), panel.getBarShadowOpacity(), isProgressBarVisible,
+                panel.getBarBackgroundColor(), panel.getBarMarginSide() * mDpToPx,
+                panel.getBarHeight() * mDpToPx, panel.isBarBorderVisible(),
+                panel.getBarBorderHeight() * mDpToPx, panel.getBarShadowVisible(),
+                panel.getBarShadowOpacity(), panel.getIconColor(), isProgressBarVisible,
                 progressBarHeight * mDpToPx, progressBarOpacity, progressBarCompletion);
     }
 
@@ -131,8 +132,9 @@
             float titleCaptionSpacing, boolean captionVisible, int progressBarBackgroundResourceId,
             int progressBarResourceId, float dpToPx, float basePageBrightness,
             float basePageYOffset, WebContents webContents, float panelX, float panelY,
-            float panelWidth, float panelHeight, float barMarginSide, float barHeight,
-            boolean barBorderVisible, float barBorderHeight, boolean barShadowVisible,
-            float barShadowOpacity, boolean isProgressBarVisible, float progressBarHeight,
-            float progressBarOpacity, int progressBarCompletion);
+            float panelWidth, float panelHeight, int barBackgroundColor, float barMarginSide,
+            float barHeight, boolean barBorderVisible, float barBorderHeight,
+            boolean barShadowVisible, float barShadowOpacity, int iconColor,
+            boolean isProgressBarVisible, float progressBarHeight, float progressBarOpacity,
+            int progressBarCompletion);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 3e3be8f5..f882588a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -37,11 +37,9 @@
 import org.chromium.chrome.browser.tab.SadTab;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
-import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabLaunchType;
-import org.chromium.chrome.browser.tabmodel.TabModel;
-import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
 import org.chromium.chrome.browser.tabmodel.TabSelectionType;
 import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager;
@@ -123,7 +121,6 @@
     private final ChromeActivity mActivity;
     private final ContextualSearchTabPromotionDelegate mTabPromotionDelegate;
     private final ViewTreeObserver.OnGlobalFocusChangeListener mOnFocusChangeListener;
-    private final TabModelObserver mTabModelObserver;
 
     /**
      * The {@link ContextualSearchInteractionRecorder} to use to record user interactions and apply
@@ -150,6 +147,7 @@
     private ViewGroup mParentView;
     private TabRedirectHandler mTabRedirectHandler;
     private OverlayPanelContentViewDelegate mSearchContentViewDelegate;
+    private TabModelSelectorTabModelObserver mTabModelObserver;
     private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
     private FindToolbarManager mFindToolbarManager;
     private FindToolbarObserver mFindToolbarObserver;
@@ -237,25 +235,6 @@
             }
         };
 
-        mTabModelObserver = new EmptyTabModelObserver() {
-            @Override
-            public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) {
-                if ((!mIsPromotingToTab && tab.getId() != lastId)
-                        || mActivity.getTabModelSelector().isIncognitoSelected()) {
-                    hideContextualSearch(StateChangeReason.UNKNOWN);
-                    mSelectionController.onTabSelected();
-                }
-            }
-
-            @Override
-            public void didAddTab(Tab tab, @TabLaunchType int type) {
-                // If we're in the process of promoting this tab, just return and don't mess with
-                // this state.
-                if (tab.getWebContents() == getSearchPanelWebContents()) return;
-                hideContextualSearch(StateChangeReason.UNKNOWN);
-            }
-        };
-
         mSelectionController = new ContextualSearchSelectionController(activity, this);
         mNetworkCommunicator = this;
         mPolicy = new ContextualSearchPolicy(mSelectionController, mNetworkCommunicator);
@@ -573,7 +552,24 @@
     /** Listens for notifications that should hide the Contextual Search bar. */
     private void listenForTabModelSelectorNotifications() {
         TabModelSelector selector = mActivity.getTabModelSelector();
+        mTabModelObserver = new TabModelSelectorTabModelObserver(selector) {
+            @Override
+            public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) {
+                if ((!mIsPromotingToTab && tab.getId() != lastId)
+                        || mActivity.getTabModelSelector().isIncognitoSelected()) {
+                    hideContextualSearch(StateChangeReason.UNKNOWN);
+                    mSelectionController.onTabSelected();
+                }
+            }
 
+            @Override
+            public void didAddTab(Tab tab, @TabLaunchType int type) {
+                // If we're in the process of promoting this tab, just return and don't mess with
+                // this state.
+                if (tab.getWebContents() == getSearchPanelWebContents()) return;
+                hideContextualSearch(StateChangeReason.UNKNOWN);
+            }
+        };
         mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(selector) {
             @Override
             public void onPageLoadStarted(Tab tab, String url) {
@@ -594,22 +590,14 @@
                 if (closing) hideContextualSearch(StateChangeReason.UNKNOWN);
             }
         };
-
-        for (TabModel tabModel : selector.getModels()) {
-            tabModel.addObserver(mTabModelObserver);
-        }
     }
 
     /** Stops listening for notifications that should hide the Contextual Search bar. */
     private void stopListeningForHideNotifications() {
+        if (mTabModelObserver != null) mTabModelObserver.destroy();
         if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.destroy();
-
-        TabModelSelector selector = mActivity.getTabModelSelector();
-        if (selector != null) {
-            for (TabModel tabModel : selector.getModels()) {
-                tabModel.removeObserver(mTabModelObserver);
-            }
-        }
+        mTabModelObserver = null;
+        mTabModelSelectorTabObserver = null;
     }
 
     /** Clears our private member referencing the native manager. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index 3b37eeb5..012606f2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -73,6 +73,7 @@
 import org.chromium.chrome.browser.share.ShareHelper;
 import org.chromium.chrome.browser.sync.SyncController;
 import org.chromium.chrome.browser.util.ConversionUtils;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.webapps.WebApkVersionManager;
 import org.chromium.chrome.browser.webapps.WebappRegistry;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
@@ -153,6 +154,8 @@
      */
     protected void handlePreNativeInitialization() {
         BrowserTaskExecutor.register();
+        BrowserTaskExecutor.setShouldPrioritizeBootstrapTasks(
+                FeatureUtilities.shouldPrioritizeBootstrapTasks());
 
         Context application = ContextUtils.getApplicationContext();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index 696311b..0f0bc7ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -136,7 +136,7 @@
     @Override
     protected void triggerLayoutInflation() {
         mSnackbarManager = new SnackbarManager(this, null);
-        mSearchBoxDataProvider = new SearchBoxDataProvider();
+        mSearchBoxDataProvider = new SearchBoxDataProvider(getResources());
 
         mContentView = createContentView();
         setContentView(mContentView);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
index a2a3c82..0da17a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.searchwidget;
 
+import android.content.res.Resources;
+import android.support.annotation.ColorInt;
 import android.support.annotation.ColorRes;
 
 import org.chromium.base.library_loader.LibraryLoader;
@@ -12,12 +14,21 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
+import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
 
 class SearchBoxDataProvider implements ToolbarDataProvider {
+    private final @ColorInt int mPrimaryColor;
     private Tab mTab;
 
     /**
+     * @param resources The {@link Resources} for accessing colors.
+     */
+    SearchBoxDataProvider(Resources resources) {
+        mPrimaryColor = ColorUtils.getPrimaryBackgroundColor(resources, isIncognito());
+    }
+
+    /**
      * Called when native library is loaded and a tab has been initialized.
      * @param tab The tab to use.
      */
@@ -65,7 +76,7 @@
 
     @Override
     public int getPrimaryColor() {
-        return 0;
+        return mPrimaryColor;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileView.java
new file mode 100644
index 0000000..779d9ff1
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileView.java
@@ -0,0 +1,63 @@
+// Copyright 2019 The Chromium 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.widget.tile;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import org.chromium.chrome.R;
+
+/**
+ * The view for a tile with icon and text.
+ *
+ * Displays the title of the site beneath a large icon.
+ */
+public class TileView extends FrameLayout {
+    private ImageView mBadgeView;
+    protected ImageView mIconView;
+
+    /**
+     * Constructor for inflating from XML.
+     */
+    public TileView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mIconView = findViewById(R.id.tile_view_icon);
+        mBadgeView = findViewById(R.id.offline_badge);
+    }
+
+    /**
+     * Initializes the view. This should be called immediately after inflation.
+     *
+     * @param title The title of the tile.
+     * @param showOfflineBadge Whether to show the offline badge.
+     * @param icon The icon to display on the tile.
+     * @param titleLines The number of text lines to use for the tile title.
+     */
+    public void initialize(boolean showOfflineBadge, Drawable icon) {
+        setOfflineBadgeVisibility(showOfflineBadge);
+        setIconDrawable(icon);
+    }
+
+    /**
+     * Renders the icon or clears it from the view if the icon is null.
+     */
+    public void setIconDrawable(Drawable icon) {
+        mIconView.setImageDrawable(icon);
+    }
+
+    /** Shows or hides the offline badge to reflect the offline availability. */
+    public void setOfflineBadgeVisibility(boolean showOfflineBadge) {
+        mBadgeView.setVisibility(showOfflineBadge ? VISIBLE : GONE);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java
index ab99f13..9dd12a7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java
@@ -7,8 +7,6 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
@@ -18,10 +16,8 @@
  *
  * Displays the title of the site beneath a large icon.
  */
-public class TileWithTextView extends FrameLayout {
+public class TileWithTextView extends TileView {
     private TextView mTitleView;
-    private ImageView mBadgeView;
-    protected ImageView mIconView;
 
     /**
      * Constructor for inflating from XML.
@@ -35,8 +31,6 @@
         super.onFinishInflate();
 
         mTitleView = findViewById(R.id.tile_view_title);
-        mIconView = findViewById(R.id.tile_view_icon);
-        mBadgeView = findViewById(R.id.offline_badge);
     }
 
     /**
@@ -48,9 +42,8 @@
      * @param titleLines The number of text lines to use for the tile title.
      */
     public void initialize(String title, boolean showOfflineBadge, Drawable icon, int titleLines) {
+        super.initialize(showOfflineBadge, icon);
         setTitle(title, titleLines);
-        setOfflineBadgeVisibility(showOfflineBadge);
-        setIconDrawable(icon);
     }
 
     /** Sets the title text and number lines. */
@@ -58,16 +51,4 @@
         mTitleView.setLines(titleLines);
         mTitleView.setText(title);
     }
-
-    /**
-     * Renders the icon or clears it from the view if the icon is null.
-     */
-    public void setIconDrawable(Drawable icon) {
-        mIconView.setImageDrawable(icon);
-    }
-
-    /** Shows or hides the offline badge to reflect the offline availability. */
-    public void setOfflineBadgeVisibility(boolean showOfflineBadge) {
-        mBadgeView.setVisibility(showOfflineBadge ? VISIBLE : GONE);
-    }
 }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 764103f..ed22cb4 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1819,6 +1819,7 @@
   "java/src/org/chromium/chrome/browser/widget/textbubble/ArrowBubbleDrawable.java",
   "java/src/org/chromium/chrome/browser/widget/textbubble/ImageTextBubble.java",
   "java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java",
+  "java/src/org/chromium/chrome/browser/widget/tile/TileView.java",
   "java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java",
 ]
 
@@ -1832,6 +1833,7 @@
     "touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsController.java",
+    "touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsTileView.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsViewHolderFactory.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPage.java",
diff --git a/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml b/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml
new file mode 100644
index 0000000..293e37c
--- /dev/null
+++ b/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<org.chromium.chrome.browser.touchless.SiteSuggestionsTileView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/tile_view_width"
+    android:layout_height="wrap_content" >
+    <include
+        layout="@layout/tile_no_text_view_condensed"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</org.chromium.chrome.browser.touchless.SiteSuggestionsTileView>
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java
index cdf470e..b5a73d62 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java
@@ -7,12 +7,9 @@
 import static org.chromium.chrome.browser.touchless.SiteSuggestionsController.SUGGESTIONS_KEY;
 
 import android.content.Context;
-import android.graphics.drawable.BitmapDrawable;
-import android.widget.ImageView;
 
 import org.chromium.chrome.browser.suggestions.SiteSuggestion;
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
-import org.chromium.chrome.touchless.R;
 import org.chromium.ui.modelutil.ForwardingListObservable;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.RecyclerViewAdapter;
@@ -56,9 +53,8 @@
             int position, Void payload) {
         SiteSuggestion item =
                 mModel.get(SUGGESTIONS_KEY).get(position % mModel.get(SUGGESTIONS_KEY).size());
-        // TODO(chili): Update when tileview is created with no textview.
-        ImageView image = holder.itemView.findViewById(R.id.tile_view_icon);
-        image.setImageDrawable(new BitmapDrawable(
-                mContext.getResources(), mIconGenerator.generateIconForText(item.title)));
+        SiteSuggestionsTileView image = (SiteSuggestionsTileView) holder.itemView;
+        image.initialize(mIconGenerator);
+        image.updateIcon(null, item.title);
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsTileView.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsTileView.java
new file mode 100644
index 0000000..f58dc5f
--- /dev/null
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsTileView.java
@@ -0,0 +1,61 @@
+// Copyright 2019 The Chromium 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.touchless;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+
+import org.chromium.chrome.browser.util.ViewUtils;
+import org.chromium.chrome.browser.widget.RoundedIconGenerator;
+import org.chromium.chrome.browser.widget.tile.TileView;
+import org.chromium.chrome.touchless.R;
+
+/**
+ * View for a category name and site tiles.
+ */
+public class SiteSuggestionsTileView extends TileView {
+    private final int mIconSizePx;
+
+    // Used to generate textual icons.
+    private RoundedIconGenerator mIconGenerator;
+
+    public SiteSuggestionsTileView(Context ctx, AttributeSet attrs) {
+        super(ctx, attrs);
+        mIconSizePx = getResources().getDimensionPixelSize(R.dimen.tile_view_icon_size);
+    }
+
+    public void initialize(RoundedIconGenerator generator) {
+        mIconGenerator = generator;
+    }
+
+    /**
+     * Updates the icon in the tile.
+     *
+     * @param iconImage Bitmap icon to update.
+     * @param text Text to generate scrabble text from.
+     */
+    public void updateIcon(Bitmap iconImage, String text) {
+        setIconDrawable(getDrawableForBitmap(iconImage, text));
+    }
+
+    /**
+     * Generates a Drawable from the Bitmap version of an icon.
+     *
+     * @param image The Bitmap image. Can be null.
+     * @param text The text to generate a scrabble text from if the bitmap is null.
+     * @return Drawable encapsulating either the scrabble tile or the bitmap.
+     */
+    public Drawable getDrawableForBitmap(Bitmap image, String text) {
+        if (image == null) {
+            return new BitmapDrawable(getResources(), mIconGenerator.generateIconForText(text));
+        }
+        return ViewUtils.createRoundedBitmapDrawable(
+                Bitmap.createScaledBitmap(image, mIconSizePx, mIconSizePx, false),
+                ViewUtils.DEFAULT_FAVICON_CORNER_RADIUS);
+    }
+}
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsViewHolderFactory.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsViewHolderFactory.java
index 0b783ce3..5682079 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsViewHolderFactory.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsViewHolderFactory.java
@@ -30,6 +30,6 @@
     public SiteSuggestionsViewHolder createViewHolder(ViewGroup parent, int viewType) {
         return new SiteSuggestionsViewHolder(
                 LayoutInflater.from(parent.getContext())
-                        .inflate(R.layout.explore_sites_tile_view, parent, false));
+                        .inflate(R.layout.touchless_suggestions_tile_view, parent, false));
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/app/md_extensions_strings.grdp b/chrome/app/md_extensions_strings.grdp
index 807efad..8e372f0 100644
--- a/chrome/app/md_extensions_strings.grdp
+++ b/chrome/app/md_extensions_strings.grdp
@@ -166,6 +166,9 @@
   <message name="IDS_MD_EXTENSIONS_ACTIVITY_ARGUMENTS_HEADING" desc="The heading for the arguments list for an activity log stream entry.">
     API function arguments
   </message>
+  <message name="IDS_MD_EXTENSIONS_WEB_REQUEST_INFO_HEADING" desc="The heading for the web request info for an activity log stream entry.">
+    Web request info
+  </message>
   <message name="IDS_MD_EXTENSIONS_ITEM_ID" desc="The text for the label next to the extension id.">
     &lt;span&gt;ID: &lt;/span&gt;<ph name="EXTENSION_ID">$1<ex>cfhdojbkjhnklbpkdaibdccddilifddb</ex></ph>
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 00f5271..8c9c515 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3295,6 +3295,7 @@
       "//chrome/common/importer:interfaces",
       "//chrome/services/app_service:lib",
       "//chrome/services/app_service/public/cpp:app_update",
+      "//chrome/services/app_service/public/cpp:icon_loader",
       "//components/feedback",
       "//components/keep_alive_registry",
       "//components/vector_icons",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index cd01abad..12266b2 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2909,19 +2909,6 @@
 #endif  // !defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
-    {"enable-stylus-virtual-keyboard",
-     flag_descriptions::kEnableStylusVirtualKeyboardName,
-     flag_descriptions::kEnableStylusVirtualKeyboardDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kEnableStylusVirtualKeyboard)},
-    {"enable-fullscreen-handwriting-virtual-keyboard",
-     flag_descriptions::kEnableFullscreenHandwritingVirtualKeyboardName,
-     flag_descriptions::kEnableFullscreenHandwritingVirtualKeyboardDescription,
-     kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kEnableFullscreenHandwritingVirtualKeyboard)},
-    {"enable-virtual-keyboard-ukm",
-     flag_descriptions::kEnableVirtualKeyboardUkmName,
-     flag_descriptions::kEnableVirtualKeyboardUkmDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kEnableVirtualKeyboardUkm)},
     {"handwriting-gesture", flag_descriptions::kHandwritingGestureName,
      flag_descriptions::kHandwritingGestureDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kHandwritingGesture)},
diff --git a/chrome/browser/android/compositor/layer/contextual_search_layer.cc b/chrome/browser/android/compositor/layer/contextual_search_layer.cc
index 29aec59..bedd6415 100644
--- a/chrome/browser/android/compositor/layer/contextual_search_layer.cc
+++ b/chrome/browser/android/compositor/layer/contextual_search_layer.cc
@@ -35,6 +35,7 @@
 
 void ContextualSearchLayer::SetProperties(
     int panel_shadow_resource_id,
+    int search_bar_background_color,
     int search_context_resource_id,
     int search_term_resource_id,
     int search_caption_resource_id,
@@ -79,6 +80,7 @@
     bool thumbnail_visible,
     float custom_image_visibility_percentage,
     int bar_image_size,
+    int icon_color,
     float arrow_icon_opacity,
     float arrow_icon_rotation,
     float close_icon_opacity,
@@ -116,10 +118,11 @@
   // -----------------------------------------------------------------
   OverlayPanelLayer::SetProperties(
       dp_to_px, content_layer, content_view_top, search_panel_x, search_panel_y,
-      search_panel_width, search_panel_height, search_bar_margin_side,
-      search_bar_height, search_bar_top, search_term_opacity,
-      should_render_bar_border, search_bar_border_height,
-      search_bar_shadow_visible, search_bar_shadow_opacity, close_icon_opacity);
+      search_panel_width, search_panel_height, search_bar_background_color,
+      search_bar_margin_side, search_bar_height, search_bar_top,
+      search_term_opacity, should_render_bar_border, search_bar_border_height,
+      search_bar_shadow_visible, search_bar_shadow_opacity, icon_color,
+      close_icon_opacity);
 
   bool is_rtl = l10n_util::IsLayoutRtl();
 
@@ -151,7 +154,7 @@
     // be an interpolation between the background color of the Search Bar and
     // a lighter shade of the background color of the Ripple.
     bar_banner_container_->SetBackgroundColor(color_utils::AlphaBlend(
-        kBarBannerRippleBackgroundColor, kSearchBarBackgroundColor,
+        kBarBannerRippleBackgroundColor, search_bar_background_color,
         0.25f * search_bar_banner_ripple_opacity));
 
     // -----------------------------------------------------------------
@@ -224,8 +227,9 @@
   // Arrow Icon
   // ---------------------------------------------------------------------------
   // Grabs the arrow icon resource.
-  ui::Resource* arrow_icon_resource = resource_manager_->GetResource(
-      ui::ANDROID_RESOURCE_TYPE_STATIC, arrow_up_resource_id);
+  ui::Resource* arrow_icon_resource =
+      resource_manager_->GetStaticResourceWithTint(arrow_up_resource_id,
+                                                   icon_color);
 
   // Positions the icon at the end of the bar.
   float arrow_icon_left;
diff --git a/chrome/browser/android/compositor/layer/contextual_search_layer.h b/chrome/browser/android/compositor/layer/contextual_search_layer.h
index 7a4c31b..c45ae4b 100644
--- a/chrome/browser/android/compositor/layer/contextual_search_layer.h
+++ b/chrome/browser/android/compositor/layer/contextual_search_layer.h
@@ -32,6 +32,7 @@
       ui::ResourceManager* resource_manager);
 
   void SetProperties(int panel_shadow_resource_id,
+                     int search_bar_background_color,
                      int search_context_resource_id,
                      int search_term_resource_id,
                      int search_caption_resource_id,
@@ -76,6 +77,7 @@
                      bool thumbnail_visible,
                      float custom_image_visibility_percentage,
                      int bar_image_size,
+                     int icon_color,
                      float arrow_icon_opacity,
                      float arrow_icon_rotation,
                      float close_icon_opacity,
diff --git a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc
index eb59385..f13cb29 100644
--- a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc
+++ b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc
@@ -33,12 +33,14 @@
     float panel_y,
     float panel_width,
     float panel_height,
+    int bar_background_color,
     float bar_margin_side,
     float bar_height,
     bool bar_border_visible,
     float bar_border_height,
     bool bar_shadow_visible,
     float bar_shadow_opacity,
+    int icon_color,
     bool progress_bar_visible,
     float progress_bar_height,
     float progress_bar_opacity,
@@ -55,9 +57,9 @@
   float title_opacity = 0.f;
   OverlayPanelLayer::SetProperties(
       dp_to_px, content_layer, bar_height, panel_x, panel_y, panel_width,
-      panel_height, bar_margin_side, bar_height, 0.0f, title_opacity,
-      bar_border_visible, bar_border_height, bar_shadow_visible,
-      bar_shadow_opacity, 1.0f /* icon opacity */);
+      panel_height, bar_background_color, bar_margin_side, bar_height, 0.0f,
+      title_opacity, bar_border_visible, bar_border_height, bar_shadow_visible,
+      bar_shadow_opacity, icon_color, 1.0f /* icon opacity */);
 
   SetupTextLayer(bar_top, bar_height, text_layer_min_height,
                  caption_view_resource_id, caption_animation_percentage,
diff --git a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h
index aa68719..c0d864b 100644
--- a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h
+++ b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h
@@ -37,12 +37,14 @@
                      float panel_y,
                      float panel_width,
                      float panel_height,
+                     int bar_background_color,
                      float bar_margin_side,
                      float bar_height,
                      bool bar_border_visible,
                      float bar_border_height,
                      bool bar_shadow_visible,
                      float bar_shadow_opacity,
+                     int icon_color,
                      bool progress_bar_visible,
                      float progress_bar_height,
                      float progress_bar_opacity,
diff --git a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc
index 2ce7323..3bdc50b 100644
--- a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc
+++ b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc
@@ -67,6 +67,7 @@
     float panel_y,
     float panel_width,
     float panel_height,
+    int bar_background_color,
     float bar_margin_side,
     float bar_height,
     float bar_offset_y,
@@ -75,6 +76,7 @@
     float bar_border_height,
     bool bar_shadow_visible,
     float bar_shadow_opacity,
+    int icon_tint,
     float close_icon_opacity) {
   // Grabs required static resources.
   ui::NinePatchResource* panel_shadow_resource =
@@ -115,6 +117,7 @@
   gfx::Size background_size(panel_width, bar_height);
   bar_background_->SetBounds(background_size);
   bar_background_->SetPosition(gfx::PointF(0.f, bar_top));
+  bar_background_->SetBackgroundColor(bar_background_color);
 
   // ---------------------------------------------------------------------------
   // Bar Text
@@ -161,8 +164,9 @@
   // Close Icon
   // ---------------------------------------------------------------------------
   // Grab the Close Icon resource.
-  ui::Resource* close_icon_resource = resource_manager_->GetResource(
-      ui::ANDROID_RESOURCE_TYPE_STATIC, close_icon_resource_id_);
+  ui::Resource* close_icon_resource =
+      resource_manager_->GetStaticResourceWithTint(close_icon_resource_id_,
+                                                   icon_tint);
 
   // Positions the icon at the end of the bar.
   float close_icon_left;
@@ -189,6 +193,7 @@
   content_container_->SetPosition(
       gfx::PointF(0.f, content_offset_y));
   content_container_->SetBounds(gfx::Size(panel_width, panel_height));
+  content_container_->SetBackgroundColor(bar_background_color);
   if (content_layer) {
     if (content_layer->parent() != content_container_)
       content_container_->AddChild(content_layer);
diff --git a/chrome/browser/android/compositor/layer/overlay_panel_layer.h b/chrome/browser/android/compositor/layer/overlay_panel_layer.h
index 147def7..51feac2d 100644
--- a/chrome/browser/android/compositor/layer/overlay_panel_layer.h
+++ b/chrome/browser/android/compositor/layer/overlay_panel_layer.h
@@ -37,6 +37,7 @@
                      float panel_y,
                      float panel_width,
                      float panel_height,
+                     int bar_background_color,
                      float bar_margin_side,
                      float bar_height,
                      float bar_offset_y,
@@ -45,6 +46,7 @@
                      float bar_border_height,
                      bool bar_shadow_visible,
                      float bar_shadow_opacity,
+                     int icon_tint,
                      float close_icon_opacity);
 
   scoped_refptr<cc::Layer> layer() override;
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
index a305a01..22ba3e0 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -69,6 +69,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& object,
     jint search_bar_background_resource_id,
+    jint search_bar_background_color,
     jint search_context_resource_id,
     jint search_term_resource_id,
     jint search_caption_resource_id,
@@ -118,6 +119,7 @@
     jstring j_thumbnail_url,
     jfloat custom_image_visibility_percentage,
     jint bar_image_size,
+    jint icon_color,
     jfloat arrow_icon_opacity,
     jfloat arrow_icon_rotation,
     jfloat close_icon_opacity,
@@ -160,15 +162,16 @@
   content_container_->SetPosition(gfx::PointF(0.0f, base_page_offset));
 
   contextual_search_layer_->SetProperties(
-      search_bar_background_resource_id, search_context_resource_id,
-      search_term_resource_id, search_caption_resource_id,
-      search_bar_shadow_resource_id, search_provider_icon_resource_id,
-      quick_action_icon_resource_id, arrow_up_resource_id,
-      close_icon_resource_id, progress_bar_background_resource_id,
-      progress_bar_resource_id, search_promo_resource_id,
-      bar_banner_ripple_resource_id, bar_banner_text_resource_id, dp_to_px,
-      content_layer, search_promo_visible, search_promo_height,
-      search_promo_opacity, search_bar_banner_visible, search_bar_banner_height,
+      search_bar_background_resource_id, search_bar_background_color,
+      search_context_resource_id, search_term_resource_id,
+      search_caption_resource_id, search_bar_shadow_resource_id,
+      search_provider_icon_resource_id, quick_action_icon_resource_id,
+      arrow_up_resource_id, close_icon_resource_id,
+      progress_bar_background_resource_id, progress_bar_resource_id,
+      search_promo_resource_id, bar_banner_ripple_resource_id,
+      bar_banner_text_resource_id, dp_to_px, content_layer,
+      search_promo_visible, search_promo_height, search_promo_opacity,
+      search_bar_banner_visible, search_bar_banner_height,
       search_bar_banner_padding, search_bar_banner_ripple_width,
       search_bar_banner_ripple_opacity, search_bar_banner_text_opacity,
       search_panel_x, search_panel_y, search_panel_width, search_panel_height,
@@ -178,12 +181,13 @@
       search_caption_visible, search_bar_border_visible,
       search_bar_border_height, search_bar_shadow_visible,
       search_bar_shadow_opacity, quick_action_icon_visible, thumbnail_visible,
-      custom_image_visibility_percentage, bar_image_size, arrow_icon_opacity,
-      arrow_icon_rotation, close_icon_opacity, progress_bar_visible,
-      progress_bar_height, progress_bar_opacity, progress_bar_completion,
-      divider_line_visibility_percentage, divider_line_width,
-      divider_line_height, divider_line_color, divider_line_x_offset,
-      touch_highlight_visible, touch_highlight_x_offset, touch_highlight_width);
+      custom_image_visibility_percentage, bar_image_size, icon_color,
+      arrow_icon_opacity, arrow_icon_rotation, close_icon_opacity,
+      progress_bar_visible, progress_bar_height, progress_bar_opacity,
+      progress_bar_completion, divider_line_visibility_percentage,
+      divider_line_width, divider_line_height, divider_line_color,
+      divider_line_x_offset, touch_highlight_visible, touch_highlight_x_offset,
+      touch_highlight_width);
 
   // Make the layer visible if it is not already.
   contextual_search_layer_->layer()->SetHideLayerAndSubtree(false);
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
index 0d0ec1b1..41a6a0a 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
@@ -40,6 +40,7 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& object,
       jint search_bar_background_resource_id,
+      jint search_bar_background_color,
       jint search_context_resource_id,
       jint search_term_resource_id,
       jint search_caption_resource_id,
@@ -89,6 +90,7 @@
       jstring j_thumbnail_url,
       jfloat custom_image_visibility_percentage,
       jint bar_image_size,
+      jint icon_color,
       jfloat arrow_icon_opacity,
       jfloat arrow_icon_rotation,
       jfloat close_icon_opacity,
diff --git a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc
index a6429f91..49fbfa6 100644
--- a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc
@@ -75,12 +75,14 @@
                                     jfloat panel_y,
                                     jfloat panel_width,
                                     jfloat panel_height,
+                                    jint bar_background_color,
                                     jfloat bar_margin_side,
                                     jfloat bar_height,
                                     jboolean bar_border_visible,
                                     jfloat bar_border_height,
                                     jboolean bar_shadow_visible,
                                     jfloat bar_shadow_opacity,
+                                    jint icon_color,
                                     jboolean progress_bar_visible,
                                     jfloat progress_bar_height,
                                     jfloat progress_bar_opacity,
@@ -110,9 +112,10 @@
       title_caption_spacing, caption_visible,
       progress_bar_background_resource_id, progress_bar_resource_id, dp_to_px,
       content_layer, panel_x, panel_y, panel_width, panel_height,
-      bar_margin_side, bar_height, bar_border_visible, bar_border_height,
-      bar_shadow_visible, bar_shadow_opacity, progress_bar_visible,
-      progress_bar_height, progress_bar_opacity, progress_bar_completion);
+      bar_background_color, bar_margin_side, bar_height, bar_border_visible,
+      bar_border_height, bar_shadow_visible, bar_shadow_opacity, icon_color,
+      progress_bar_visible, progress_bar_height, progress_bar_opacity,
+      progress_bar_completion);
   // Make the layer visible if it is not already.
   ephemeral_tab_layer_->layer()->SetHideLayerAndSubtree(false);
 }
diff --git a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h
index 661d59b7..30df0a2 100644
--- a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h
+++ b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h
@@ -61,12 +61,14 @@
               jfloat panel_y,
               jfloat panel_width,
               jfloat panel_height,
+              jint bar_background_color,
               jfloat bar_margin_side,
               jfloat bar_height,
               jboolean bar_border_visible,
               jfloat bar_border_height,
               jboolean bar_shadow_visible,
               jfloat bar_shadow_opacity,
+              jint icon_color,
               jboolean progress_bar_visible,
               jfloat progress_bar_height,
               jfloat progress_bar_opacity,
diff --git a/chrome/browser/apps/app_service/app_service_proxy.cc b/chrome/browser/apps/app_service/app_service_proxy.cc
index 06cc3d3e..97388681 100644
--- a/chrome/browser/apps/app_service/app_service_proxy.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy.cc
@@ -59,33 +59,33 @@
   return cache_;
 }
 
-void AppServiceProxy::LoadIcon(
-    const std::string& app_id,
+apps::mojom::IconKeyPtr AppServiceProxy::GetIconKey(const std::string& app_id) {
+  apps::mojom::IconKeyPtr icon_key;
+  if (app_service_.is_bound()) {
+    cache_.ForOneApp(app_id, [&icon_key](const apps::AppUpdate& update) {
+      icon_key = update.IconKey();
+    });
+  }
+  return icon_key;
+}
+
+std::unique_ptr<apps::IconLoader::Releaser>
+AppServiceProxy::LoadIconFromIconKey(
+    apps::mojom::IconKeyPtr icon_key,
     apps::mojom::IconCompression icon_compression,
     int32_t size_hint_in_dip,
     bool allow_placeholder_icon,
     apps::mojom::Publisher::LoadIconCallback callback) {
-  bool found = false;
-
-  if (app_service_.is_bound()) {
-    cache_.ForOneApp(app_id, [this, &icon_compression, &size_hint_in_dip,
-                              &allow_placeholder_icon, &callback,
-                              &found](const apps::AppUpdate& update) {
-      apps::mojom::IconKeyPtr icon_key = update.IconKey();
-      if (icon_key.is_null()) {
-        return;
-      }
-      found = true;
-      app_service_->LoadIcon(std::move(icon_key), icon_compression,
-                             size_hint_in_dip, allow_placeholder_icon,
-                             std::move(callback));
-    });
-  }
-
-  if (!found) {
-    // On failure, we still run the callback, with the zero IconValue.
+  if (app_service_.is_bound() && !icon_key.is_null()) {
+    // TODO(crbug.com/826982): implement another IconLoader that coalesces
+    // multiple in-flight calls with the same IconLoader::Key, and use it here.
+    app_service_->LoadIcon(std::move(icon_key), icon_compression,
+                           size_hint_in_dip, allow_placeholder_icon,
+                           std::move(callback));
+  } else {
     std::move(callback).Run(apps::mojom::IconValue::New());
   }
+  return nullptr;
 }
 
 void AppServiceProxy::Launch(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/app_service_proxy.h b/chrome/browser/apps/app_service/app_service_proxy.h
index 3fe7d87..5d0a82c 100644
--- a/chrome/browser/apps/app_service/app_service_proxy.h
+++ b/chrome/browser/apps/app_service/app_service_proxy.h
@@ -5,8 +5,11 @@
 #ifndef CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_
 #define CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "chrome/services/app_service/public/cpp/app_registry_cache.h"
+#include "chrome/services/app_service/public/cpp/icon_cache.h"
 #include "chrome/services/app_service/public/mojom/app_service.mojom.h"
 #include "chrome/services/app_service/public/mojom/types.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -28,7 +31,9 @@
 // proxy for a given Profile, and therefore share its caches.
 //
 // See chrome/services/app_service/README.md.
-class AppServiceProxy : public KeyedService, public apps::mojom::Subscriber {
+class AppServiceProxy : public KeyedService,
+                        public apps::IconLoader,
+                        public apps::mojom::Subscriber {
  public:
   static AppServiceProxy* Get(Profile* profile);
 
@@ -39,11 +44,14 @@
   apps::mojom::AppServicePtr& AppService();
   apps::AppRegistryCache& AppRegistryCache();
 
-  void LoadIcon(const std::string& app_id,
-                apps::mojom::IconCompression icon_compression,
-                int32_t size_hint_in_dip,
-                bool allow_placeholder_icon,
-                apps::mojom::Publisher::LoadIconCallback callback);
+  // apps::IconLoader overrides.
+  apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override;
+  std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey(
+      apps::mojom::IconKeyPtr icon_key,
+      apps::mojom::IconCompression icon_compression,
+      int32_t size_hint_in_dip,
+      bool allow_placeholder_icon,
+      apps::mojom::Publisher::LoadIconCallback callback) override;
 
   void Launch(const std::string& app_id,
               int32_t event_flags,
diff --git a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
index e0e27fe7..6bba55f 100644
--- a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
+++ b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
@@ -160,7 +160,8 @@
 }
 
 void BuiltInChromeOsApps::Uninstall(const std::string& app_id) {
-  NOTIMPLEMENTED();
+  LOG(ERROR) << "Uninstall failed, could not remove built-in app with id "
+             << app_id;
 }
 
 void BuiltInChromeOsApps::OpenNativeSettings(const std::string& app_id) {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index f532dbdc..f8a7854b 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -4927,7 +4927,8 @@
 void ChromeContentBrowserClient::WillCreateWebSocket(
     content::RenderFrameHost* frame,
     network::mojom::WebSocketRequest* request,
-    network::mojom::AuthenticationHandlerPtr* auth_handler) {
+    network::mojom::AuthenticationHandlerPtr* auth_handler,
+    network::mojom::TrustedHeaderClientPtr* header_client) {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   auto* web_request_api =
       extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
@@ -4938,7 +4939,8 @@
   if (!web_request_api)
     return;
 
-  web_request_api->MaybeProxyWebSocket(frame, request, auth_handler);
+  web_request_api->MaybeProxyWebSocket(frame, request, auth_handler,
+                                       header_client);
 #endif
 }
 
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 36e37d1..3bfa5c5 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -485,7 +485,8 @@
   void WillCreateWebSocket(
       content::RenderFrameHost* frame,
       network::mojom::WebSocketRequest* request,
-      network::mojom::AuthenticationHandlerPtr* auth_handler) override;
+      network::mojom::AuthenticationHandlerPtr* auth_handler,
+      network::mojom::TrustedHeaderClientPtr* header_client) override;
   void OnNetworkServiceCreated(
       network::mojom::NetworkService* network_service) override;
   network::mojom::NetworkContextPtr CreateNetworkContext(
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.cc b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.cc
new file mode 100644
index 0000000..d9b9c5a
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.cc
@@ -0,0 +1,71 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h"
+
+#include "base/files/dir_reader_posix.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl.h"
+#include "third_party/protobuf/src/google/protobuf/text_format.h"
+
+namespace chromeos {
+namespace time_limit_consistency {
+namespace {
+
+base::FilePath GetGoldensPath() {
+  base::FilePath path;
+  base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
+
+  return path.Append(
+      FILE_PATH_LITERAL("chrome/browser/chromeos/child_accounts/"
+                        "time_limit_consistency_test/goldens"));
+}
+
+}  // namespace
+
+std::vector<GoldenParam> LoadGoldenCases() {
+  return LoadGoldenCasesFromPath(GetGoldensPath());
+}
+
+std::vector<GoldenParam> LoadGoldenCasesFromPath(
+    const base::FilePath& directory_path) {
+  std::vector<GoldenParam> golden_params_list;
+  base::DirReaderPosix dir_reader(directory_path.value().c_str());
+
+  while (dir_reader.Next()) {
+    if (!base::EndsWith(dir_reader.name(), ".textproto",
+                        base::CompareCase::INSENSITIVE_ASCII)) {
+      continue;
+    }
+
+    ConsistencyGolden golden_suite;
+    base::File golden_file(directory_path.Append(dir_reader.name()),
+                           base::File::FLAG_OPEN | base::File::FLAG_READ);
+    google::protobuf::io::FileInputStream stream(golden_file.GetPlatformFile());
+    google::protobuf::TextFormat::Parse(&stream, &golden_suite);
+
+    // Ignore suites that don't include CHROME_OS as a supported platform.
+    bool chromeos_supported =
+        std::count(golden_suite.supported_platforms().begin(),
+                   golden_suite.supported_platforms().end(), CHROME_OS) > 0;
+    if (!chromeos_supported)
+      continue;
+
+    std::string suite_name = dir_reader.name();
+    base::ReplaceFirstSubstringAfterOffset(&suite_name, 0, ".textproto", "");
+    for (int i = 0; i < golden_suite.cases_size(); i++) {
+      golden_params_list.push_back(
+          GoldenParam({suite_name, i, golden_suite.cases(i)}));
+    }
+  }
+
+  return golden_params_list;
+}
+
+}  // namespace time_limit_consistency
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h
new file mode 100644
index 0000000..a9aac373
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A utility for loading golden files to be used by the time limit processor
+// consistency tests.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_CONSISTENCY_GOLDEN_LOADER_H_
+#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_CONSISTENCY_GOLDEN_LOADER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "chrome/browser/chromeos/child_accounts/time_limit_consistency_test/goldens/consistency_golden.pb.h"
+
+namespace chromeos {
+namespace time_limit_consistency {
+
+// Holds information for one golden case and metadata used to generate the name
+// for its test case (i.e. the name of the golden file it belongs and its index
+// inside it).
+struct GoldenParam {
+  const std::string suite_name;
+  const int index;
+  const ConsistencyGoldenCase golden_case;
+};
+
+// Loads all cases from all available golden files into a list of GoldenParams.
+std::vector<GoldenParam> LoadGoldenCases();
+
+// Loads all cases from all golden files from a given path into a list of
+// GoldenParams. LoadGoldenCases() uses this function under the hood. Should not
+// be called directly except for testing the golden loader itself.
+std::vector<GoldenParam> LoadGoldenCasesFromPath(
+    const base::FilePath& directory_path);
+
+}  // namespace time_limit_consistency
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_CONSISTENCY_GOLDEN_LOADER_H_
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader_unittest.cc b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader_unittest.cc
new file mode 100644
index 0000000..b5c7f16
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader_unittest.cc
@@ -0,0 +1,47 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "chrome/browser/chromeos/child_accounts/time_limit_consistency_test/proto_matcher.h"
+#include "chrome/browser/chromeos/child_accounts/time_limit_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace utils = time_limit_test_utils;
+
+namespace time_limit_consistency {
+
+using ConsistencyGoldenLoaderTest = testing::Test;
+
+base::FilePath GetTestGoldensPath() {
+  base::FilePath path;
+  base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
+
+  return path.Append(
+      FILE_PATH_LITERAL("chrome/browser/chromeos/child_accounts/"
+                        "time_limit_consistency_test/test_goldens"));
+}
+
+// Expected outcome is to ignore the test_golden_unsupported suite and return
+// only the case within test_golden.
+TEST_F(ConsistencyGoldenLoaderTest, LoadTestGoldenCases) {
+  std::vector<GoldenParam> goldens_list =
+      LoadGoldenCasesFromPath(GetTestGoldensPath());
+
+  ConsistencyGoldenCase golden_case;
+  golden_case.mutable_current_state()->set_time_millis(42);
+
+  ASSERT_EQ(goldens_list.size(), 1ul);
+  EXPECT_EQ(goldens_list[0].suite_name, "test_golden");
+  EXPECT_EQ(goldens_list[0].index, 0);
+  EXPECT_THAT(goldens_list[0].golden_case, EqualsProto(golden_case));
+}
+
+}  // namespace time_limit_consistency
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/goldens/consistency_golden.proto b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/goldens/consistency_golden.proto
new file mode 100644
index 0000000..c3cec2e
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/goldens/consistency_golden.proto
@@ -0,0 +1,108 @@
+syntax = "proto2";
+
+// Used to generate the ChromeOS C++ namespace
+package chromeos.time_limit_consistency;
+
+// Used to generate the Java package
+option java_package = "com.google.kids.timelimit.consistency";
+option java_multiple_files = true;
+
+// The platforms where the test suite may be supported.
+enum SupportedPlatform {
+  UNSPECIFIED_PLATFORM = 0;
+  ANDROID = 1;
+  CHROME_OS = 2;
+}
+
+// Policies which may be active.
+enum ConsistencyGoldenPolicy {
+  UNSPECIFIED_POLICY = 0;
+  NO_ACTIVE_POLICY = 1;
+  OVERRIDE = 2;
+  FIXED_LIMIT = 3;
+  USAGE_LIMIT = 4;
+}
+
+// Days of the week.
+enum ConsistencyGoldenEffectiveDay {
+  UNSPECIFIED_EFFECTIVE_DAY = 0;
+  MONDAY = 1;
+  TUESDAY = 2;
+  WEDNESDAY = 3;
+  THURSDAY = 4;
+  FRIDAY = 5;
+  SATURDAY = 6;
+  SUNDAY = 7;
+}
+
+// The main object, represents one test suite (and one golden file).
+message ConsistencyGolden {
+  // The platforms where the test is supported. Required
+  repeated SupportedPlatform supported_platforms = 1;
+
+  // A list of test cases. Required
+  repeated ConsistencyGoldenCase cases = 2;
+}
+
+// Message representing one test case
+message ConsistencyGoldenCase {
+  // Input policy data. Required
+  optional ConsistencyGoldenInput input = 1;
+
+  // Simulates the current state when executing. Required
+  optional ConsistencyGoldenCurrentState current_state = 2;
+
+  // The test's output, used for both the expected and the actual results.
+  // Required
+  optional ConsistencyGoldenOutput output = 3;
+}
+
+// The policies configured by the parent.
+message ConsistencyGoldenInput {
+  // List of bedtime configurations for different days of the week.
+  repeated ConsistencyGoldenWindowLimitEntry window_limits = 1;
+}
+
+// Bedtime configuration for a given day.
+message ConsistencyGoldenWindowLimitEntry {
+  // Which day of the week this configuration relates to. Required
+  optional ConsistencyGoldenEffectiveDay effective_day = 1;
+
+  // At which hour and minute this bedtime should start. Required
+  optional ConsistencyGoldenTimeOfDay starts_at = 2;
+
+  // At which hour and minute this bedtime should end. Required
+  optional ConsistencyGoldenTimeOfDay ends_at = 3;
+}
+
+// Represents a moment of a day.
+message ConsistencyGoldenTimeOfDay {
+  // A given hour. [0-23]. Required
+  optional int32 hour = 1;
+
+  // A given minute. [0-59]. Required
+  optional int32 minute = 2;
+}
+
+// Information to represent the current state when executing.
+message ConsistencyGoldenCurrentState {
+  // A timestamp for the desired current time. Required
+  optional int64 time_millis = 1;
+
+  // String representing the desired timezone, formatted like "GMT+2"/"GMT-3"
+  // or "America/Sao_Paulo". Required
+  optional string timezone = 2;
+}
+
+// Information on the output.
+message ConsistencyGoldenOutput {
+  // Whether the device is locked. Required
+  optional bool is_locked = 1;
+
+  // What is the policy currently taking place. Required
+  optional ConsistencyGoldenPolicy active_policy = 2;
+
+  // Timestamp of when is the device supposed to unlock.
+  // This field must be present if and only if the device is locked.
+  optional int64 next_unlocking_time_millis = 3;
+}
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/proto_matcher.h b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/proto_matcher.h
new file mode 100644
index 0000000..8bea859
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/proto_matcher.h
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A gMock matcher for comparing protos and producing a human-readable
+// message if the assertion fails.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_PROTO_MATCHER_H_
+#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_PROTO_MATCHER_H_
+
+#include <string>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/protobuf/src/google/protobuf/text_format.h"
+
+namespace chromeos {
+namespace time_limit_consistency {
+
+MATCHER_P(EqualsProto, message, "equals golden proto") {
+  std::string expected_serialized, actual_serialized;
+  message.SerializeToString(&expected_serialized);
+  arg.SerializeToString(&actual_serialized);
+
+  if (expected_serialized == actual_serialized) {
+    return true;
+  }
+
+  std::string expected_readable, actual_readable;
+  google::protobuf::TextFormat::PrintToString(message, &expected_readable);
+  google::protobuf::TextFormat::PrintToString(arg, &actual_readable);
+
+  *result_listener << "\n\noutput parses to: \n----------\n"
+                   << actual_readable
+                   << "---------\n\n and should be: \n----------\n"
+                   << expected_readable << "----------";
+
+  return expected_serialized == actual_serialized;
+}
+
+}  // namespace time_limit_consistency
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMIT_CONSISTENCY_TEST_PROTO_MATCHER_H_
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/run_all_unittests.cc b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/run_all_unittests.cc
new file mode 100644
index 0000000..d355501
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/run_all_unittests.cc
@@ -0,0 +1,15 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "build/build_config.h"
+
+int main(int argc, char** argv) {
+  base::TestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc, argv,
+      base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden.textproto b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden.textproto
new file mode 100644
index 0000000..aefe7d7
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden.textproto
@@ -0,0 +1,6 @@
+supported_platforms: CHROME_OS
+cases {
+  current_state {
+    time_millis: 42
+  }
+}
diff --git a/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden_unsupported.textproto b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden_unsupported.textproto
new file mode 100644
index 0000000..86c65f4
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/test_golden_unsupported.textproto
@@ -0,0 +1,6 @@
+supported_platforms: ANDROID
+cases {
+  current_state {
+    time_millis: 43
+  }
+}
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 87861d65..69a09f9c6 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -739,7 +739,10 @@
         new default_app_order::ExternalLoader(true /* async */));
   }
 
-  audio::SoundsManager::Create();
+  audio::SoundsManager::Create(
+      content::ServiceManagerConnection::GetForProcess()
+          ->GetConnector()
+          ->Clone());
 
   // |arc_service_launcher_| must be initialized before NoteTakingHelper.
   NoteTakingHelper::Initialize();
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 6f06558b..cffc74b3 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -59,6 +59,7 @@
 #include "services/network/public/cpp/network_connection_tracker.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "storage/browser/fileapi/external_mount_points.h"
+#include "ui/base/window_open_disposition.h"
 
 namespace crostini {
 
@@ -1665,7 +1666,8 @@
     const AppLaunchParams& launch_params,
     const GURL& vsh_in_crosh_url,
     Browser* browser) {
-  ShowApplicationWindow(launch_params, vsh_in_crosh_url, browser);
+  ShowApplicationWindow(launch_params, vsh_in_crosh_url, browser,
+                        WindowOpenDisposition::NEW_FOREGROUND_TAB);
   browser->window()->GetNativeWindow()->SetProperty(
       kOverrideWindowIconResourceIdKey, IDR_LOGO_CROSTINI_TERMINAL);
 }
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index ed2d8e3..4c555e1 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -920,7 +920,9 @@
 
   device::mojom::UsbDeviceManagerPtr usb_manager_;
 
-  bool installer_view_status_;
+  // True when the installer dialog is showing. At that point, it is invalid
+  // to allow Crostini uninstallation.
+  bool installer_view_status_ = false;
   base::ObserverList<InstallerViewStatusObserver>
       installer_view_status_observers_;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index 8add03c0..d5ab34f 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -1434,4 +1434,8 @@
   run_loop()->Run();
 }
 
+TEST_F(CrostiniManagerTest, InstallerStatusInitiallyFalse) {
+  EXPECT_FALSE(crostini_manager()->GetInstallerViewStatus());
+}
+
 }  // namespace crostini
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 6d44a28..659d06f 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -584,6 +584,7 @@
         TestCase("dirContextMenuUsbs"),
         TestCase("dirContextMenuFsp"),
         TestCase("dirContextMenuDocumentsProvider").EnableDocumentsProvider(),
+        TestCase("dirContextMenuUsbDcim"),
         TestCase("dirContextMenuShortcut")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index cb7f726..ddd16eea 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -2313,7 +2313,12 @@
       LOG(WARNING) << "Playing non-existent key = " << key;
       return false;
     }
-    auto handler = std::make_unique<audio::AudioStreamHandler>(iter->second);
+
+    auto handler = std::make_unique<audio::AudioStreamHandler>(
+        content::ServiceManagerConnection::GetForProcess()
+            ->GetConnector()
+            ->Clone(),
+        iter->second);
     if (!handler->IsInitialized()) {
       LOG(WARNING) << "Can't initialize AudioStreamHandler for key = " << key;
       return false;
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_unittest.cc b/chrome/browser/chromeos/login/lock/screen_locker_unittest.cc
index bc12e33..61d8071 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker_unittest.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker_unittest.cc
@@ -30,13 +30,14 @@
 #include "components/account_id/account_id.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/scoped_user_manager.h"
+#include "content/public/common/service_manager_connection.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_service_manager_context.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
-#include "media/audio/audio_manager.h"
 #include "media/audio/test_audio_thread.h"
 #include "services/audio/public/cpp/sounds/audio_stream_handler.h"
 #include "services/audio/public/cpp/sounds/sounds_manager.h"
+#include "services/audio/public/cpp/sounds/test_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -60,7 +61,13 @@
     session_controller_client_->Init();
 
     // Initialize AccessibilityManager and dependencies:
-    audio::SoundsManager::Create();
+    observer_ = std::make_unique<audio::TestObserver>((base::DoNothing()));
+    audio::AudioStreamHandler::SetObserverForTesting(observer_.get());
+
+    audio::SoundsManager::Create(
+        content::ServiceManagerConnection::GetForProcess()
+            ->GetConnector()
+            ->Clone());
     input_method::InputMethodManager::Initialize(
         // Owned by InputMethodManager
         new input_method::MockInputMethodManagerImpl());
@@ -81,11 +88,12 @@
   void TearDown() override {
     input_method::InputMethodManager::Shutdown();
     audio::SoundsManager::Shutdown();
-    media::AudioManager::Get()->Shutdown();
     session_controller_client_.reset();
     chromeos::LoginState::Shutdown();
     BiodClient::Shutdown();
     DBusThreadManager::Shutdown();
+    audio::AudioStreamHandler::SetObserverForTesting(NULL);
+    observer_.reset();
   }
 
  protected:
@@ -108,9 +116,6 @@
   FakeAccessibilityController fake_accessibility_controller_;
   TestAccessibilityFocusRingController
       test_accessibility_focus_ring_controller_;
-  std::unique_ptr<media::AudioManager> audio_manager_{
-      media::AudioManager::CreateForTesting(
-          std::make_unique<media::TestAudioThread>())};
   // * LoginScreenClient dependencies:
   session_manager::SessionManager session_manager_;
   TestLoginScreen test_login_screen_;
@@ -125,6 +130,7 @@
   TestSessionController test_session_controller_;
   std::unique_ptr<SessionControllerClient> session_controller_client_;
 
+  std::unique_ptr<audio::TestObserver> observer_;
   DISALLOW_COPY_AND_ASSIGN(ScreenLockerUnitTest);
 };
 
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
index 9e0867c1..ec1d523 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
@@ -1325,7 +1325,8 @@
   EqualModelPrediction(expected_prediction, events[0].model_prediction());
 }
 
-TEST_F(UserActivityManagerTest, BasicTabs) {
+// Test is flaky. See https://crbug.com/938055.
+TEST_F(UserActivityManagerTest, DISABLED_BasicTabs) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(features::kUserActivityPrediction);
 
diff --git a/chrome/browser/chromeos/smb_client/discovery/mdns_host_locator.cc b/chrome/browser/chromeos/smb_client/discovery/mdns_host_locator.cc
index 51c7b9b..7ad6bc0 100644
--- a/chrome/browser/chromeos/smb_client/discovery/mdns_host_locator.cc
+++ b/chrome/browser/chromeos/smb_client/discovery/mdns_host_locator.cc
@@ -12,6 +12,7 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/public/browser/browser_task_traits.h"
+#include "net/base/net_errors.h"
 #include "net/dns/mdns_client.h"
 #include "net/dns/public/dns_protocol.h"
 #include "net/dns/record_rdata.h"
@@ -188,7 +189,11 @@
 
   socket_factory_ = net::MDnsSocketFactory::CreateDefault();
   mdns_client_ = net::MDnsClient::CreateDefault();
-  return mdns_client_->StartListening(socket_factory_.get());
+  int result = mdns_client_->StartListening(socket_factory_.get());
+  if (result != net::OK) {
+    LOG(ERROR) << "Error starting mDNS client: " << net::ErrorToString(result);
+  }
+  return result == net::OK;
 }
 
 bool MDnsHostLocator::Impl::CreatePtrTransaction() {
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index e3d79a429..1135dd1 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -224,8 +224,7 @@
     // There is both a public and private OnFocus event. The private OnFocus
     // event is only for ChromeOS and contains additional information about pen
     // inputs. We ensure that we only trigger one OnFocus event.
-    if (ExtensionHasListener(input_method_private::OnFocus::kEventName) &&
-        base::FeatureList::IsEnabled(features::kEnableStylusVirtualKeyboard)) {
+    if (ExtensionHasListener(input_method_private::OnFocus::kEventName)) {
       input_method_private::InputContext input_context;
       input_context.context_id = context.id;
       input_context.type = input_method_private::ParseInputContextType(
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index cdac64d..3115421 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -362,10 +362,7 @@
                            keyboard::switches::kDisableGestureTyping)));
   // TODO(https://crbug.com/890134): Implement gesture editing.
   features->AppendString(GenerateFeatureFlag("gestureediting", false));
-  features->AppendString(GenerateFeatureFlag(
-      "fullscreenhandwriting",
-      base::FeatureList::IsEnabled(
-          features::kEnableFullscreenHandwritingVirtualKeyboard)));
+  features->AppendString(GenerateFeatureFlag("fullscreenhandwriting", false));
   features->AppendString(GenerateFeatureFlag("virtualkeyboardmdui", true));
   features->AppendString(GenerateFeatureFlag(
       "imeservice", base::FeatureList::IsEnabled(
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index f0d7fd6..1d6446a 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -1530,13 +1530,13 @@
       browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
   extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
       profile())
-      ->MaybeProxyWebSocket(host, &request, &auth_handler);
+      ->MaybeProxyWebSocket(host, &request, &auth_handler, nullptr);
   content::BrowserContext::GetDefaultStoragePartition(profile())
       ->GetNetworkContext()
       ->CreateWebSocket(std::move(request), network::mojom::kBrowserProcessId,
                         host->GetProcess()->GetID(),
                         url::Origin::Create(GURL("http://example.com")),
-                        std::move(auth_handler));
+                        std::move(auth_handler), nullptr);
   web_socket.reset();
 }
 
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 6c232da..f156b15 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3166,12 +3166,6 @@
     "If enabled and the device supports ARC, the user will be asked to update "
     "the encryption of user data when the user signs in.";
 
-const char kEnableFullscreenHandwritingVirtualKeyboardName[] =
-    "Enable full screen handwriting virtual keyboard";
-const char kEnableFullscreenHandwritingVirtualKeyboardDescription[] =
-    "If enabled, the handwriting virtual keyboard will allow user to write "
-    "anywhere on the screen";
-
 const char kEnableGoogleAssistantName[] = "Enable Google Assistant";
 const char kEnableGoogleAssistantDescription[] =
     "Enable an experimental Assistant implementation that will work on all "
@@ -3209,21 +3203,11 @@
 const char kEnablePlayStoreSearchDescription[] =
     "Enable Play Store search in launcher.";
 
-const char kEnableStylusVirtualKeyboardName[] =
-    "Enable stylus virtual keyboard";
-const char kEnableStylusVirtualKeyboardDescription[] =
-    "If enabled, tapping with a stylus will show the handwriting virtual "
-    "keyboard.";
-
 const char kEnableVideoPlayerNativeControlsName[] =
     "Enable native controls in video player app";
 const char kEnableVideoPlayerNativeControlsDescription[] =
     "Enable native controls in video player app";
 
-const char kEnableVirtualKeyboardUkmName[] = "Enable UKM for virtual keyboard";
-const char kEnableVirtualKeyboardUkmDescription[] =
-    "Enables UKM for virtual keyboard";
-
 const char kEnableZeroStateSuggestionsName[] = "Enable Zero State Suggetions";
 const char kEnableZeroStateSuggestionsDescription[] =
     "Enable Zero State Suggestions feature in Launcher, which will show "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 5577fe28..2cb2f0d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1895,9 +1895,6 @@
 extern const char kEnableEncryptionMigrationName[];
 extern const char kEnableEncryptionMigrationDescription[];
 
-extern const char kEnableFullscreenHandwritingVirtualKeyboardName[];
-extern const char kEnableFullscreenHandwritingVirtualKeyboardDescription[];
-
 extern const char kEnableGoogleAssistantName[];
 extern const char kEnableGoogleAssistantDescription[];
 
@@ -1919,15 +1916,9 @@
 extern const char kEnablePlayStoreSearchName[];
 extern const char kEnablePlayStoreSearchDescription[];
 
-extern const char kEnableStylusVirtualKeyboardName[];
-extern const char kEnableStylusVirtualKeyboardDescription[];
-
 extern const char kEnableVideoPlayerNativeControlsName[];
 extern const char kEnableVideoPlayerNativeControlsDescription[];
 
-extern const char kEnableVirtualKeyboardUkmName[];
-extern const char kEnableVirtualKeyboardUkmDescription[];
-
 extern const char kEnableZeroStateSuggestionsName[];
 extern const char kEnableZeroStateSuggestionsDescription[];
 
diff --git a/chrome/browser/installable/installable_metrics.cc b/chrome/browser/installable/installable_metrics.cc
index 453aabd..14e17539 100644
--- a/chrome/browser/installable/installable_metrics.cc
+++ b/chrome/browser/installable/installable_metrics.cc
@@ -232,7 +232,12 @@
          source == WebappInstallSource::API_CUSTOM_TAB ||
          source == WebappInstallSource::DEVTOOLS ||
          source == WebappInstallSource::AMBIENT_BADGE_BROWSER_TAB ||
-         source == WebappInstallSource::AMBIENT_BADGE_CUSTOM_TAB;
+         source == WebappInstallSource::AMBIENT_BADGE_CUSTOM_TAB ||
+         source == WebappInstallSource::ARC ||
+         source == WebappInstallSource::INTERNAL_DEFAULT ||
+         source == WebappInstallSource::EXTERNAL_DEFAULT ||
+         source == WebappInstallSource::EXTERNAL_POLICY ||
+         source == WebappInstallSource::SYSTEM_DEFAULT;
 }
 
 // static
diff --git a/chrome/browser/installable/installable_metrics.h b/chrome/browser/installable/installable_metrics.h
index ff7e66b..747e8a4 100644
--- a/chrome/browser/installable/installable_metrics.h
+++ b/chrome/browser/installable/installable_metrics.h
@@ -80,6 +80,19 @@
   // Installation via ARC on Chrome OS.
   ARC = 10,
 
+  // An internal default-installed app on Chrome OS (i.e. triggered from code).
+  INTERNAL_DEFAULT = 11,
+
+  // An external default-installed app on Chrome OS (i.e. triggered from an
+  // external source file).
+  EXTERNAL_DEFAULT = 12,
+
+  // A policy-installed app on Chrome OS.
+  EXTERNAL_POLICY = 13,
+
+  // A system app installed on Chrome OS.
+  SYSTEM_DEFAULT = 14,
+
   // Add any new values above this one.
   COUNT,
 };
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js
index fd536309..0d0b886 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js
@@ -125,6 +125,9 @@
       if (data['defaultEnabled']) {
         toggle.setAttribute('checked', '');
       }
+      if (data['toggleDisabled']) {
+        toggle.disabled = true;
+      }
       zippy.appendChild(toggle);
 
       var description = document.createElement('div');
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.js b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.js
index 9f013408a..fcc8da9e 100644
--- a/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.js
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.js
@@ -35,6 +35,9 @@
       assert(Array.isArray(streamItemNames), 'Invalid data for script names.');
     }
 
+    const other = activity.other;
+    const webRequestInfo = other && other.webRequest;
+
     return streamItemNames.map(name => ({
                                  args,
                                  argUrl: activity.argUrl,
@@ -42,6 +45,7 @@
                                  name,
                                  pageUrl: activity.pageUrl,
                                  timestamp,
+                                 webRequestInfo,
                                }));
   }
 
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log_stream_item.html b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream_item.html
index 5d6aaf1..0850e5d 100644
--- a/chrome/browser/resources/md_extensions/activity_log/activity_log_stream_item.html
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream_item.html
@@ -70,13 +70,14 @@
         white-space: nowrap;
       }
 
-      #args-list {
+      #args-list,
+      #web-request-section {
         display: flex;
         flex-direction: column;
         margin-bottom: 10px;
       }
 
-      #args-list-heading {
+      .expanded-data-heading {
         font-weight: 500;
       }
 
@@ -89,11 +90,15 @@
         min-width: 3em; /* Allow 3 digits of space */
       }
 
-      .arg {
-        margin-inline-start: 8px;
+      .arg,
+      #web-request-details {
         overflow: hidden;
         overflow-wrap: break-word;
       }
+
+      #web-request-details {
+        margin-top: 10px;
+      }
     </style>
     <div actionable$="[[isExpandable_]]"
         id="activity-item-main-row"
@@ -113,7 +118,9 @@
             hidden$="[[!hasPageUrl_(data.pageUrl)]]"
             title="[[data.pageUrl]]">[[data.pageUrl]]</a>
         <div id="args-list" hidden$="[[!hasArgs_(argsList_)]]">
-          <span id="args-list-heading">$i18n{activityArgumentsHeading}</span>
+          <span class="expanded-data-heading">
+            $i18n{activityArgumentsHeading}
+          </span>
           <template is="dom-repeat" items="[[argsList_]]">
             <div class="list-item">
               <span class="index">[[item.index]]</span>
@@ -121,6 +128,12 @@
             </div>
           </template>
         </div>
+        <div id="web-request-section"
+            hidden$="[[!hasWebRequestInfo_(data.webRequestInfo)]]">
+          <span class="expanded-data-heading">
+            $i18n{webRequestInfoHeading}</span>
+          <span id="web-request-details">[[data.webRequestInfo]]</span>
+        </div>
       </div>
     </iron-collapse>
   </template>
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log_stream_item.js b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream_item.js
index 9c1ac6e..070500e9 100644
--- a/chrome/browser/resources/md_extensions/activity_log/activity_log_stream_item.js
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream_item.js
@@ -12,7 +12,8 @@
    *   activityType: !chrome.activityLogPrivate.ExtensionActivityFilter,
    *   pageUrl: string,
    *   argUrl: string,
-   *   args: string
+   *   args: string,
+   *   webRequestInfo: (string|undefined)
    * }}
    */
   let StreamItem;
@@ -80,7 +81,7 @@
      * @return {boolean}
      */
     computeIsExpandable_: function() {
-      return this.hasPageUrl_() || this.hasArgs_();
+      return this.hasPageUrl_() || this.hasArgs_() || this.hasWebRequestInfo_();
     },
 
     /**
@@ -106,12 +107,28 @@
      * @private
      * @return {boolean}
      */
+    hasPageUrl_: function() {
+      return !!this.data.pageUrl;
+    },
+
+    /**
+     * @private
+     * @return {boolean}
+     */
     hasArgs_: function() {
       return this.argsList_.length > 0;
     },
 
     /**
      * @private
+     * @return {boolean}
+     */
+    hasWebRequestInfo_: function() {
+      return !!this.data.webRequestInfo && this.data.webRequestInfo != '{}';
+    },
+
+    /**
+     * @private
      * @return {!Array<!extensions.StreamArgItem>}
      */
     computeArgsList_: function() {
@@ -132,14 +149,6 @@
           }));
     },
 
-    /**
-     * @private
-     * @return {boolean}
-     */
-    hasPageUrl_: function() {
-      return !!this.data.pageUrl;
-    },
-
     /** @private */
     onExpandClick_: function() {
       if (this.isExpandable_) {
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
index 28fa3ad2..94671f73 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
+++ b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
@@ -57,7 +57,7 @@
             menu-options="[[fontOptions_]]">
         </settings-dropdown-menu>
       </div>
-      <div class="list-item underbar"
+      <div class="list-item"
           style="
               font-size:[[prefs.webkit.webprefs.default_font_size.value]]px;
               font-family:
@@ -78,7 +78,7 @@
             menu-options="[[fontOptions_]]">
         </settings-dropdown-menu>
       </div>
-      <div class="list-item underbar"
+      <div class="list-item"
           style="
               font-size:[[prefs.webkit.webprefs.default_font_size.value]]px;
               font-family:
@@ -99,7 +99,7 @@
             menu-options="[[fontOptions_]]">
         </settings-dropdown-menu>
       </div>
-      <div class="list-item underbar"
+      <div class="list-item"
           style="
               font-size:[[prefs.webkit.webprefs.default_font_size.value]]px;
               font-family:
diff --git a/chrome/browser/resources/settings/autofill_page/payments_section.html b/chrome/browser/resources/settings/autofill_page/payments_section.html
index 78e241b..2cb349b 100644
--- a/chrome/browser/resources/settings/autofill_page/payments_section.html
+++ b/chrome/browser/resources/settings/autofill_page/payments_section.html
@@ -69,7 +69,7 @@
       </paper-button>
     </div>
     <div class="settings-box two-line" id="migrateCreditCards"
-        hidden$="[[!checkIfMigratable_(creditCards,
+        hidden$="[[!checkIfMigratable_(syncStatus, creditCards,
             prefs.autofill.credit_card_enabled.value)]]"
         on-click="onMigrateCreditCardsClick_" actionable>
       <div class="start">
diff --git a/chrome/browser/resources/settings/autofill_page/payments_section.js b/chrome/browser/resources/settings/autofill_page/payments_section.js
index 903ca26..0eca2bcf 100644
--- a/chrome/browser/resources/settings/autofill_page/payments_section.js
+++ b/chrome/browser/resources/settings/autofill_page/payments_section.js
@@ -120,10 +120,7 @@
      * An array of all saved credit cards.
      * @type {!Array<!PaymentsManager.CreditCardEntry>}
      */
-    creditCards: {
-      type: Array,
-      value: () => [],
-    },
+    creditCards: Array,
 
     /**
      * The model for any credit card related action menus or dialogs.
@@ -138,7 +135,13 @@
     migratableCreditCardsInfo_: String,
 
     /**
-     * Whether prerequisites for local card migration are met.
+     * The current sync status, supplied by SyncBrowserProxy.
+     * @type {?settings.SyncStatus}
+     */
+    syncStatus: Object,
+
+    /**
+     * Whether migration local card on settings page is enabled.
      * @private
      */
     migrationEnabled_: {
@@ -148,6 +151,66 @@
       },
       readOnly: true,
     },
+
+    /**
+     * Whether user has a Google Payments account.
+     * @private
+     */
+    hasGooglePaymentsAccount_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('hasGooglePaymentsAccount');
+      },
+      readOnly: true,
+    },
+
+    /**
+     * Whether Autofill Upstream is enabled.
+     * @private
+     */
+    upstreamEnabled_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('upstreamEnabled');
+      },
+      readOnly: true,
+    },
+
+    /**
+     * Whether the user has a secondary sync passphrase.
+     * @private
+     */
+    isUsingSecondaryPassphrase_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('isUsingSecondaryPassphrase');
+      },
+      readOnly: true,
+    },
+
+    /**
+     * Whether the upload-to-google state is active.
+     * @private
+     */
+    uploadToGoogleActive_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('uploadToGoogleActive');
+      },
+      readOnly: true,
+    },
+
+    /**
+     * Whether the domain of the user's email is allowed.
+     * @private
+     */
+    userEmailDomainAllowed_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('userEmailDomainAllowed');
+      },
+      readOnly: true,
+    },
   },
 
   listeners: {
@@ -175,6 +238,9 @@
    */
   setCreditCardsListener_: null,
 
+  /** @private {?settings.SyncBrowserProxy} */
+  syncBrowserProxy_: null,
+
   /** @override */
   attached: function() {
     // Create listener function.
@@ -196,6 +262,12 @@
     this.paymentsManager_.addCreditCardListChangedListener(
         setCreditCardsListener);
 
+    this.syncBrowserProxy_ = settings.SyncBrowserProxyImpl.getInstance();
+    this.syncBrowserProxy_.getSyncStatus().then(
+        this.handleSyncStatus_.bind(this));
+    this.addWebUIListener(
+        'sync-status-changed', this.handleSyncStatus_.bind(this));
+
     // Record that the user opened the payments settings.
     chrome.metricsPrivate.recordUserAction('AutofillCreditCardsViewed');
   },
@@ -311,22 +383,73 @@
   },
 
   /**
-   * @param {!Array<!PaymentsManager.CreditCardEntry>} creditCards
-   * @param {boolean} creditCardEnabled
-   * @return {boolean} Whether to show the migration button.
+   * Handler for when the sync state is pushed from the browser.
+   * @param {?settings.SyncStatus} syncStatus
    * @private
    */
-  checkIfMigratable_: function(creditCards, creditCardEnabled) {
-    // If migration prerequisites are not met, return false.
+  handleSyncStatus_: function(syncStatus) {
+    this.syncStatus = syncStatus;
+  },
+
+  /**
+   * @param {!settings.SyncStatus} syncStatus
+   * @param {!Array<!PaymentsManager.CreditCardEntry>} creditCards
+   * @param {boolean} creditCardEnabled
+   * @return {boolean} Whether to show the migration button. True iff at
+   *     least
+   * one valid local card, enable migration, signed-in & synced and credit
+   * card pref enabled.
+   * @private
+   */
+  checkIfMigratable_: function(syncStatus, creditCards, creditCardEnabled) {
+    if (syncStatus == undefined) {
+      return false;
+    }
+
+    // If user not enable migration experimental flag, return false.
     if (!this.migrationEnabled_) {
       return false;
     }
 
+    // If user does not have Google Payments Account, return false.
+    if (!this.hasGooglePaymentsAccount_) {
+      return false;
+    }
+
+    // If the Autofill Upstream feature is not enabled, return false.
+    if (!this.upstreamEnabled_) {
+      return false;
+    }
+
+    // Don't offer upload if user has a secondary passphrase. Users who have
+    // enabled a passphrase have chosen to not make their sync information
+    // accessible to Google. Since upload makes credit card data available
+    // to other Google systems, disable it for passphrase users.
+    if (this.isUsingSecondaryPassphrase_) {
+      return false;
+    }
+
+    // If upload-to-Google state is not active, card cannot be saved to
+    // Google Payments. Return false.
+    if (!this.uploadToGoogleActive_) {
+      return false;
+    }
+
+    // The domain of the user's email address is not allowed, return false.
+    if (!this.userEmailDomainAllowed_) {
+      return false;
+    }
+
     // If credit card enabled pref is false, return false.
     if (!creditCardEnabled) {
       return false;
     }
 
+    // If user not signed-in and synced, return false.
+    if (!syncStatus.signedIn || !syncStatus.syncSystemEnabled) {
+      return false;
+    }
+
     const numberOfMigratableCreditCard =
         creditCards.filter(card => card.metadata.isMigratable).length;
     // Check whether exist at least one local valid card for migration.
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_browser_proxy.js b/chrome/browser/resources/settings/crostini_page/crostini_browser_proxy.js
index 6e4c97aa..fd3df48 100644
--- a/chrome/browser/resources/settings/crostini_page/crostini_browser_proxy.js
+++ b/chrome/browser/resources/settings/crostini_page/crostini_browser_proxy.js
@@ -30,6 +30,10 @@
     /** @param {string} path Path to stop sharing. */
     removeCrostiniSharedPath(path) {}
 
+    /* Request chrome send a crostini-installer-status-changed event with the
+    current installer status */
+    requestCrostiniInstallerStatus() {}
+
     /* Export crostini container. */
     exportCrostiniContainer() {}
 
@@ -60,6 +64,11 @@
     }
 
     /** @override */
+    requestCrostiniInstallerStatus() {
+      chrome.send('requestCrostiniInstallerStatus');
+    }
+
+    /** @override */
     exportCrostiniContainer() {
       chrome.send('exportCrostiniContainer');
     }
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_subpage.html b/chrome/browser/resources/settings/crostini_page/crostini_subpage.html
index 0f5db20..e2b9cf0f 100644
--- a/chrome/browser/resources/settings/crostini_page/crostini_subpage.html
+++ b/chrome/browser/resources/settings/crostini_page/crostini_subpage.html
@@ -6,6 +6,7 @@
 <link rel="import" href="crostini_browser_proxy.html">
 <link rel="import" href="../i18n_setup.html">
 <link rel="import" href="../prefs/prefs_behavior.html">
+<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="../settings_shared_css.html">
 
 <dom-module id="settings-crostini-subpage">
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_subpage.js b/chrome/browser/resources/settings/crostini_page/crostini_subpage.js
index c3690f73..702a290 100644
--- a/chrome/browser/resources/settings/crostini_page/crostini_subpage.js
+++ b/chrome/browser/resources/settings/crostini_page/crostini_subpage.js
@@ -10,7 +10,7 @@
 Polymer({
   is: 'settings-crostini-subpage',
 
-  behaviors: [PrefsBehavior],
+  behaviors: [PrefsBehavior, WebUIListenerBehavior],
 
   properties: {
     /** Preferences state. */
@@ -52,12 +52,13 @@
 
   observers: ['onCrostiniEnabledChanged_(prefs.crostini.enabled.value)'],
 
-  created: function() {
+  attached: function() {
     const callback = (status) => {
       this.hideCrostiniUninstall_ = status;
     };
-    cr.addWebUIListener('crostini-installer-status-changed', callback);
-    cr.sendWithPromise('requestCrostiniInstallerStatus').then(callback);
+    this.addWebUIListener('crostini-installer-status-changed', callback);
+    settings.CrostiniBrowserProxyImpl.getInstance()
+        .requestCrostiniInstallerStatus();
   },
 
   /** @private */
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index b0e37317..7d977c5 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -680,7 +680,7 @@
 }
 
 // If the server sends the same cards and addresses again, they should not
-// change on the client.
+// change on the client. We should also not overwrite existing metadata.
 IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
                        SameUpdatesAreIgnored) {
   GetFakeServer()->SetWalletData(
@@ -694,6 +694,19 @@
   ExpectNoHistogramsForCardsDiff();
   ExpectNoHistogramsForAddressesDiff();
 
+  // Refresh the pdm so that it gets data from autofill table.
+  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
+  ASSERT_NE(nullptr, pdm);
+  RefreshAndWaitForOnPersonalDataChanged(pdm);
+
+  // Record use of to get non-default metadata values.
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+  pdm->RecordUseOf(*cards[0]);
+  std::vector<AutofillProfile*> profiles = pdm->GetServerProfiles();
+  ASSERT_EQ(1uL, profiles.size());
+  pdm->RecordUseOf(*profiles[0]);
+
   // Keep the same data (only change the customer data to force the FakeServer
   // to send the full update).
   GetFakeServer()->SetWalletData(
@@ -711,15 +724,13 @@
   ASSERT_TRUE(checker.Wait());
 
   // Refresh the pdm so that it gets cards from autofill table.
-  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
-  ASSERT_NE(nullptr, pdm);
   RefreshAndWaitForOnPersonalDataChanged(pdm);
 
   // Make sure the data is present on the client.
-  std::vector<CreditCard*> cards = pdm->GetCreditCards();
+  cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
   EXPECT_EQ(ASCIIToUTF16("0001"), cards[0]->LastFourDigits());
-  std::vector<AutofillProfile*> profiles = pdm->GetServerProfiles();
+  profiles = pdm->GetServerProfiles();
   ASSERT_EQ(1uL, profiles.size());
   EXPECT_EQ("Company-1", TruncateUTF8(base::UTF16ToUTF8(
                              profiles[0]->GetRawInfo(autofill::COMPANY_NAME))));
@@ -728,6 +739,89 @@
   // Expect correct histograms for the (no) update.
   ExpectCardsDiffInHistograms(/*added=*/0, /*removed=*/0);
   ExpectAddressesDiffInHistograms(/*added=*/0, /*removed=*/0);
+
+  // Test that the non-default metadata values stayed around.
+  std::map<std::string, AutofillMetadata> cards_metadata =
+      GetServerCardsMetadata(0);
+  EXPECT_EQ(1U, cards_metadata.size());
+  EXPECT_EQ(2U, cards_metadata.begin()->second.use_count);
+  std::map<std::string, AutofillMetadata> addresses_metadata =
+      GetServerAddressesMetadata(0);
+  EXPECT_EQ(1U, addresses_metadata.size());
+  // TODO(crbug.com/941498): Once RecordUseOf() is fixed for server addresses,
+  // change this expectation back to 2.
+  EXPECT_EQ(1U, addresses_metadata.begin()->second.use_count);
+}
+
+// If the server sends the same cards and addresses with changed data, they
+// should change on the client.
+IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTestWithDefaultFeatures,
+                       ChangedEntityGetsUpdated) {
+  GetFakeServer()->SetWalletData(
+      {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0002",
+                            kDefaultBillingAddressID),
+       CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-2"),
+       CreateDefaultSyncPaymentsCustomerData()});
+  ASSERT_TRUE(SetupSync());
+
+  // Refresh the pdm so that it gets data from autofill table.
+  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
+  ASSERT_NE(nullptr, pdm);
+  RefreshAndWaitForOnPersonalDataChanged(pdm);
+
+  // Record use of to get non-default metadata values.
+  std::vector<CreditCard*> cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+  pdm->RecordUseOf(*cards[0]);
+  std::vector<AutofillProfile*> profiles = pdm->GetServerProfiles();
+  ASSERT_EQ(1uL, profiles.size());
+  pdm->RecordUseOf(*profiles[0]);
+
+  // Update the data (also change the customer data to force the full update as
+  // FakeServer computes the hash for progress markers only based on ids).
+  GetFakeServer()->SetWalletData(
+      {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
+                            kDefaultBillingAddressID),
+       CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"),
+       CreateSyncPaymentsCustomerData("different")});
+
+  // Constructing the checker captures the current progress marker. Make sure to
+  // do that before triggering the fetch.
+  WaitForNextWalletUpdateChecker checker(GetSyncService(0));
+  // Trigger a sync and wait for the new data to arrive.
+  TriggerSyncForModelTypes(0,
+                           syncer::ModelTypeSet(syncer::AUTOFILL_WALLET_DATA));
+  ASSERT_TRUE(checker.Wait());
+
+  // Refresh the pdm so that it gets cards from autofill table.
+  RefreshAndWaitForOnPersonalDataChanged(pdm);
+
+  // Make sure the data is present on the client.
+  cards = pdm->GetCreditCards();
+  ASSERT_EQ(1uL, cards.size());
+  EXPECT_EQ(ASCIIToUTF16("0001"), cards[0]->LastFourDigits());
+  profiles = pdm->GetServerProfiles();
+  ASSERT_EQ(1uL, profiles.size());
+  EXPECT_EQ("Company-1", TruncateUTF8(base::UTF16ToUTF8(
+                             profiles[0]->GetRawInfo(autofill::COMPANY_NAME))));
+
+  // Expect correct histograms for the (remove&add) update.
+  ExpectCardsDiffInHistograms(/*added=*/1, /*removed=*/1);
+  ExpectAddressesDiffInHistograms(/*added=*/1, /*removed=*/1);
+
+  // Test that the non-default metadata values stayed around.
+  std::map<std::string, AutofillMetadata> cards_metadata =
+      GetServerCardsMetadata(0);
+  EXPECT_EQ(1U, cards_metadata.size());
+  EXPECT_EQ(2U, cards_metadata.begin()->second.use_count);
+  std::map<std::string, AutofillMetadata> addresses_metadata =
+      GetServerAddressesMetadata(0);
+  EXPECT_EQ(1U, addresses_metadata.size());
+  // Metadata for server addresses cannot be preserved because the id changes
+  // since it is generated on the client as a hash of all the data fields. As a
+  // result, the metadata entry gets deleted and recreated under a different id
+  // and has a default use count.
+  EXPECT_EQ(1U, addresses_metadata.begin()->second.use_count);
 }
 
 // If the server sends the same cards again, they should not change on the
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 6d146e9f..9ec6933f 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3497,6 +3497,8 @@
       "views/extensions/media_galleries_dialog_views.h",
       "views/extensions/media_gallery_checkbox_view.cc",
       "views/extensions/media_gallery_checkbox_view.h",
+      "web_applications/system_web_app_ui_utils_chromeos.cc",
+      "web_applications/system_web_app_ui_utils_chromeos.h",
       "web_applications/web_app_dialog_utils.cc",
       "web_applications/web_app_dialog_utils.h",
       "web_applications/web_app_metrics.cc",
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index ec228a4..2f1868aef 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -380,14 +380,15 @@
 
 WebContents* ShowApplicationWindow(const AppLaunchParams& params,
                                    const GURL& url,
-                                   Browser* browser) {
+                                   Browser* browser,
+                                   WindowOpenDisposition disposition) {
   const Extension* const extension = GetExtension(params);
   ui::PageTransition transition =
       (extension ? ui::PAGE_TRANSITION_AUTO_BOOKMARK
                  : ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
 
   NavigateParams nav_params(browser, url, transition);
-  nav_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+  nav_params.disposition = disposition;
   nav_params.opener = params.opener;
   Navigate(&nav_params);
 
@@ -413,7 +414,8 @@
 WebContents* OpenApplicationWindow(const AppLaunchParams& params,
                                    const GURL& url) {
   Browser* browser = CreateApplicationWindow(params, url);
-  return ShowApplicationWindow(params, url, browser);
+  return ShowApplicationWindow(params, url, browser,
+                               WindowOpenDisposition::NEW_FOREGROUND_TAB);
 }
 
 void OpenApplicationWithReenablePrompt(const AppLaunchParams& params) {
diff --git a/chrome/browser/ui/extensions/application_launch.h b/chrome/browser/ui/extensions/application_launch.h
index 80c90bf..6df2cdb 100644
--- a/chrome/browser/ui/extensions/application_launch.h
+++ b/chrome/browser/ui/extensions/application_launch.h
@@ -19,6 +19,8 @@
 class Extension;
 }
 
+enum class WindowOpenDisposition;
+
 // Opens the application, possibly prompting the user to re-enable it.
 void OpenApplicationWithReenablePrompt(const AppLaunchParams& params);
 
@@ -33,7 +35,8 @@
 // Show the application window that's already created.
 content::WebContents* ShowApplicationWindow(const AppLaunchParams& params,
                                             const GURL& url,
-                                            Browser* browser);
+                                            Browser* browser,
+                                            WindowOpenDisposition disposition);
 
 // Open the application in a way specified by |params| in a new window.
 content::WebContents* OpenApplicationWindow(const AppLaunchParams& params,
diff --git a/chrome/browser/ui/settings_window_manager_chromeos.cc b/chrome/browser/ui/settings_window_manager_chromeos.cc
index 9dd55e3..76e9fa7 100644
--- a/chrome/browser/ui/settings_window_manager_chromeos.cc
+++ b/chrome/browser/ui/settings_window_manager_chromeos.cc
@@ -7,38 +7,22 @@
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h"
 #include "chrome/browser/ui/ash/window_properties.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/browser/ui/extensions/app_launch_params.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
 #include "chrome/browser/ui/settings_window_manager_observer_chromeos.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
-#include "chrome/browser/web_applications/web_app_provider.h"
 #include "content/public/browser/web_contents.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/common/extension.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/base/mojo/window_open_disposition.mojom.h"
 #include "ui/base/ui_base_features.h"
 #include "url/gurl.h"
 
-namespace {
-
-base::Optional<std::string> GetSettingsAppId(Profile* profile) {
-  return web_app::WebAppProvider::Get(profile)
-      ->system_web_app_manager()
-      .GetAppIdForSystemApp(web_app::SystemAppType::SETTINGS);
-}
-
-}  // namespace
-
 namespace chrome {
 
 // static
@@ -63,6 +47,20 @@
   if (!profile->IsGuestSession() && profile->IsOffTheRecord())
     profile = profile->GetOriginalProfile();
 
+  // TODO(calamity): Auto-launch the settings app on install if not found, and
+  // figure out how to invoke OnNewSettingsWindow() in that case.
+  if (web_app::SystemWebAppManager::IsEnabled()) {
+    Browser* browser = web_app::LaunchSystemWebApp(
+        profile, web_app::SystemAppType::SETTINGS, gurl);
+    if (!browser)
+      return;
+
+    for (SettingsWindowManagerObserver& observer : observers_)
+      observer.OnNewSettingsWindow(browser);
+
+    return;
+  }
+
   // Look for an existing browser window.
   Browser* browser = FindBrowserForProfile(profile);
   if (browser) {
@@ -74,61 +72,35 @@
       return;
     }
   }
-  if (web_app::SystemWebAppManager::IsEnabled()) {
-    base::Optional<std::string> settings_app_id = GetSettingsAppId(profile);
-    // TODO(calamity): Queue a task to launch app after it is installed.
-    if (!settings_app_id)
-      return;
-
-    const extensions::Extension* extension =
-        extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
-            settings_app_id.value(), extensions::ExtensionRegistry::ENABLED);
-    DCHECK(extension);
-
-    // TODO(calamity): Plumb through better launch sources from callsites.
-    AppLaunchParams params = CreateAppLaunchParamsWithEventFlags(
-        profile, extension, 0, extensions::SOURCE_CHROME_INTERNAL,
-        display::kInvalidDisplayId);
-    params.override_url = gurl;
-    if (browser) {
-      ShowApplicationWindow(params, gurl, browser);
-      return;
-    }
-
-    browser = CreateApplicationWindow(params, gurl);
-    ShowApplicationWindow(params, gurl, browser);
-  } else {
-    if (browser) {
-      NavigateParams params(browser, gurl, ui::PAGE_TRANSITION_AUTO_BOOKMARK);
-      params.window_action = NavigateParams::SHOW_WINDOW;
-      params.user_gesture = true;
-      Navigate(&params);
-      return;
-    }
-
-    // No existing browser window, create one.
-    NavigateParams params(profile, gurl, ui::PAGE_TRANSITION_AUTO_BOOKMARK);
-    params.disposition = WindowOpenDisposition::NEW_POPUP;
-    params.trusted_source = true;
+  if (browser) {
+    NavigateParams params(browser, gurl, ui::PAGE_TRANSITION_AUTO_BOOKMARK);
     params.window_action = NavigateParams::SHOW_WINDOW;
     params.user_gesture = true;
-    params.path_behavior = NavigateParams::IGNORE_AND_NAVIGATE;
     Navigate(&params);
-    browser = params.browser;
+    return;
+  }
 
-    // operator[] not used because SessionID has no default constructor.
-    settings_session_map_.emplace(profile, SessionID::InvalidValue())
-        .first->second = browser->session_id();
-    DCHECK(browser->is_trusted_source());
+  // No existing browser window, create one.
+  NavigateParams params(profile, gurl, ui::PAGE_TRANSITION_AUTO_BOOKMARK);
+  params.disposition = WindowOpenDisposition::NEW_POPUP;
+  params.trusted_source = true;
+  params.window_action = NavigateParams::SHOW_WINDOW;
+  params.user_gesture = true;
+  params.path_behavior = NavigateParams::IGNORE_AND_NAVIGATE;
+  Navigate(&params);
+  browser = params.browser;
 
-    auto* window = browser->window()->GetNativeWindow();
-    window->SetProperty(kOverrideWindowIconResourceIdKey,
-                        IDR_SETTINGS_LOGO_192);
-    // For Mash, this is set by BrowserFrameMash.
-    if (!features::IsUsingWindowService()) {
-      window->SetProperty(aura::client::kAppType,
-                          static_cast<int>(ash::AppType::CHROME_APP));
-    }
+  // operator[] not used because SessionID has no default constructor.
+  settings_session_map_.emplace(profile, SessionID::InvalidValue())
+      .first->second = browser->session_id();
+  DCHECK(browser->is_trusted_source());
+
+  auto* window = browser->window()->GetNativeWindow();
+  window->SetProperty(kOverrideWindowIconResourceIdKey, IDR_SETTINGS_LOGO_192);
+  // For Mash, this is set by BrowserFrameMash.
+  if (!features::IsUsingWindowService()) {
+    window->SetProperty(aura::client::kAppType,
+                        static_cast<int>(ash::AppType::CHROME_APP));
   }
 
   for (SettingsWindowManagerObserver& observer : observers_)
@@ -137,20 +109,8 @@
 
 Browser* SettingsWindowManager::FindBrowserForProfile(Profile* profile) {
   if (web_app::SystemWebAppManager::IsEnabled()) {
-    // TODO(calamity): Determine whether, during startup, we need to wait for
-    // app install and then provide a valid answer here.
-    base::Optional<std::string> settings_app_id = GetSettingsAppId(profile);
-    if (!settings_app_id)
-      return nullptr;
-
-    // Check if any settings windows are already running.
-    std::vector<content::WebContents*> running_apps =
-        AppShortcutLauncherItemController::GetRunningApplications(
-            settings_app_id.value());
-    if (!running_apps.empty())
-      return chrome::FindBrowserWithWebContents(running_apps[0]);
-
-    return nullptr;
+    return web_app::FindSystemWebAppBrowser(profile,
+                                            web_app::SystemAppType::SETTINGS);
   }
 
   auto iter = settings_session_map_.find(profile);
@@ -165,11 +125,10 @@
   if (web_app::SystemWebAppManager::IsEnabled()) {
     // TODO(calamity): Determine whether, during startup, we need to wait for
     // app install and then provide a valid answer here.
-    base::Optional<std::string> settings_app_id = GetSettingsAppId(profile);
-    if (!settings_app_id)
-      return false;
-
-    return browser->hosted_app_controller() &&
+    base::Optional<std::string> settings_app_id =
+        web_app::GetAppIdForSystemWebApp(profile,
+                                         web_app::SystemAppType::SETTINGS);
+    return settings_app_id && browser->hosted_app_controller() &&
            browser->hosted_app_controller()->app_id() ==
                settings_app_id.value();
   } else {
diff --git a/chrome/browser/ui/tabs/window_activity_watcher_unittest.cc b/chrome/browser/ui/tabs/window_activity_watcher_unittest.cc
index 2758c838..3a62ca0 100644
--- a/chrome/browser/ui/tabs/window_activity_watcher_unittest.cc
+++ b/chrome/browser/ui/tabs/window_activity_watcher_unittest.cc
@@ -137,7 +137,8 @@
 };
 
 // Tests UKM logging of two browser windows.
-TEST_F(WindowActivityWatcherTest, Basic) {
+// Test is flaky. See https://crbug.com/938055.
+TEST_F(WindowActivityWatcherTest, DISABLED_Basic) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
       FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
@@ -289,7 +290,8 @@
 }
 
 // Tests that a replaced tab still causes event logging upon being detached.
-TEST_F(WindowActivityWatcherTest, ReplaceTab) {
+// Test is flaky. See https://crbug.com/938055.
+TEST_F(WindowActivityWatcherTest, DISABLED_ReplaceTab) {
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
       FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc
index 31aca8c..208b8a66 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.cc
+++ b/chrome/browser/ui/views/tabs/new_tab_button.cc
@@ -26,6 +26,7 @@
 #include "ui/views/animation/flood_fill_ink_drop_ripple.h"
 #include "ui/views/animation/ink_drop_impl.h"
 #include "ui/views/animation/ink_drop_mask.h"
+#include "ui/views/view_class_properties.h"
 #include "ui/views/widget/widget.h"
 
 #if defined(OS_WIN)
@@ -69,12 +70,9 @@
                               ui::EF_MIDDLE_MOUSE_BUTTON);
 #endif
 
-  // Initialize the ink drop mode for a ripple highlight on button press.
-  ink_drop_container_ = new views::InkDropContainerView();
-  AddChildView(ink_drop_container_);
-  ink_drop_container_->SetVisible(false);
   SetInkDropMode(InkDropMode::ON);
   set_ink_drop_visible_opacity(0.08f);
+  set_ink_drop_highlight_opacity(0.1f);
 
   SetInstallFocusRingOnFocus(true);
 }
@@ -147,55 +145,11 @@
   event->SetHandled();
 }
 
-void NewTabButton::AddInkDropLayer(ui::Layer* ink_drop_layer) {
-  DCHECK(ink_drop_layer->bounds().size() == GetContentsBounds().size());
-  DCHECK(ink_drop_container_->bounds().size() == GetContentsBounds().size());
-  ink_drop_container_->AddInkDropLayer(ink_drop_layer);
-  InstallInkDropMask(ink_drop_layer);
-}
-
-void NewTabButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
-  ResetInkDropMask();
-  ink_drop_container_->RemoveInkDropLayer(ink_drop_layer);
-}
-
-std::unique_ptr<views::InkDropRipple> NewTabButton::CreateInkDropRipple()
-    const {
-  const gfx::Rect contents_bounds = GetContentsBounds();
-  return std::make_unique<views::FloodFillInkDropRipple>(
-      contents_bounds.size(), gfx::Insets(),
-      GetInkDropCenterBasedOnLastEvent() - contents_bounds.OffsetFromOrigin(),
-      GetInkDropBaseColor(), ink_drop_visible_opacity());
-}
-
-std::unique_ptr<views::InkDropHighlight> NewTabButton::CreateInkDropHighlight()
-    const {
-  const gfx::Rect bounds(GetContentsBounds().size());
-  auto highlight = CreateDefaultInkDropHighlight(
-      gfx::RectF(bounds).CenterPoint(), bounds.size());
-  highlight->set_visible_opacity(0.1f);
-  return highlight;
-}
-
 void NewTabButton::NotifyClick(const ui::Event& event) {
   ImageButton::NotifyClick(event);
   GetInkDrop()->AnimateToState(views::InkDropState::ACTION_TRIGGERED);
 }
 
-std::unique_ptr<views::InkDrop> NewTabButton::CreateInkDrop() {
-  std::unique_ptr<views::InkDropImpl> ink_drop =
-      std::make_unique<views::InkDropImpl>(this, GetContentsBounds().size());
-  ink_drop->SetAutoHighlightMode(views::InkDropImpl::AutoHighlightMode::NONE);
-  ink_drop->SetShowHighlightOnHover(true);
-  UpdateInkDropBaseColor();
-  return ink_drop;
-}
-
-std::unique_ptr<views::InkDropMask> NewTabButton::CreateInkDropMask() const {
-  return std::make_unique<views::RoundRectInkDropMask>(
-      GetContentsBounds().size(), gfx::Insets(), GetCornerRadius());
-}
-
 void NewTabButton::PaintButtonContents(gfx::Canvas* canvas) {
   gfx::ScopedCanvas scoped_canvas(canvas);
   canvas->Translate(GetContentsBounds().OffsetFromOrigin());
@@ -203,17 +157,11 @@
   PaintPlusIcon(canvas);
 }
 
-void NewTabButton::Layout() {
-  ImageButton::Layout();
-
-  // TODO(pkasting): Instead of setting this bounds rect, maybe have the
-  // container match the view bounds, then undo the coordinate transforms in
-  // the ink drop creation methods above.
-  const gfx::Rect contents_bounds = GetContentsBounds();
-  ink_drop_container_->SetBoundsRect(contents_bounds);
-
-  focus_ring()->SetPath(
-      GetBorderPath(GetContentsBounds().origin(), 1.0f, false));
+void NewTabButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  ImageButton::OnBoundsChanged(previous_bounds);
+  SetProperty(
+      views::kHighlightPathKey,
+      new SkPath(GetBorderPath(GetContentsBounds().origin(), 1.0f, false)));
 }
 
 gfx::Size NewTabButton::CalculatePreferredSize() const {
@@ -223,11 +171,6 @@
   return size;
 }
 
-void NewTabButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
-  const gfx::Size ink_drop_size = GetContentsBounds().size();
-  GetInkDrop()->HostSizeChanged(ink_drop_size);
-}
-
 bool NewTabButton::GetHitTestMask(SkPath* mask) const {
   DCHECK(mask);
 
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.h b/chrome/browser/ui/views/tabs/new_tab_button.h
index 81dd6a8..344125c 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.h
+++ b/chrome/browser/ui/views/tabs/new_tab_button.h
@@ -14,10 +14,6 @@
 
 class FeaturePromoBubbleView;
 
-namespace views {
-class InkDropContainerView;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // NewTabButton
 //
@@ -69,18 +65,10 @@
   void OnMouseReleased(const ui::MouseEvent& event) override;
 #endif
   void OnGestureEvent(ui::GestureEvent* event) override;
-  void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
-  void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
-  std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
-  std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
-      const override;
   void NotifyClick(const ui::Event& event) override;
-  std::unique_ptr<views::InkDrop> CreateInkDrop() override;
-  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
   void PaintButtonContents(gfx::Canvas* canvas) override;
-  void Layout() override;
-  gfx::Size CalculatePreferredSize() const override;
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+  gfx::Size CalculatePreferredSize() const override;
 
   // views::MaskedTargeterDelegate:
   bool GetHitTestMask(SkPath* mask) const override;
@@ -117,11 +105,6 @@
   // The offset used to paint the background image.
   int background_offset_;
 
-  // In touch-optimized UI, this view holds the ink drop layer so that it's
-  // shifted down to the correct top offset of the button, since the actual
-  // button's y-coordinate is 0 due to Fitt's Law needs.
-  views::InkDropContainerView* ink_drop_container_ = nullptr;
-
   // were we destroyed?
   bool* destroyed_ = nullptr;
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index b1d00fbc..bd1a606 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1435,8 +1435,9 @@
   if (active_tab && !is_dragging)
     active_tab->Paint(paint_info);
 
-  // Paint the New Tab button.
-  new_tab_button_->Paint(paint_info);
+  // Paint the New Tab button, unless it's being painted onto its own Layer.
+  if (!new_tab_button_->layer())
+    new_tab_button_->Paint(paint_info);
 
   // And the dragged tabs.
   for (size_t i = 0; i < tabs_dragging.size(); ++i)
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index abdd422..1455acc 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -740,9 +740,7 @@
   void OnMenuStructureChanged() override {
     if (menu_item_->HasSubmenu()) {
       // Remove all menu items from submenu.
-      views::SubmenuView* submenu = menu_item_->GetSubmenu();
-      while (submenu->child_count() > 0)
-        menu_item_->RemoveMenuItemAt(submenu->child_count() - 1);
+      menu_item_->RemoveAllMenuItems();
 
       // Remove all elements in |AppMenu::command_id_to_entry_| that map to
       // |model_|.
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc b/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc
new file mode 100644
index 0000000..5679cca
--- /dev/null
+++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc
@@ -0,0 +1,102 @@
+// Copyright 2019 The Chromium 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/web_applications/system_web_app_ui_utils_chromeos.h"
+
+#include <string>
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/extensions/app_launch_params.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/extension.h"
+#include "ui/base/mojo/window_open_disposition.mojom.h"
+#include "ui/display/types/display_constants.h"
+
+namespace web_app {
+
+base::Optional<std::string> GetAppIdForSystemWebApp(Profile* profile,
+                                                    SystemAppType app_type) {
+  return WebAppProvider::Get(profile)
+      ->system_web_app_manager()
+      .GetAppIdForSystemApp(app_type);
+}
+
+Browser* LaunchSystemWebApp(Profile* profile,
+                            SystemAppType app_type,
+                            const GURL& url) {
+  Browser* browser = FindSystemWebAppBrowser(profile, app_type);
+  if (browser) {
+    content::WebContents* web_contents =
+        browser->tab_strip_model()->GetWebContentsAt(0);
+    if (web_contents && web_contents->GetURL() == url) {
+      browser->window()->Show();
+      return browser;
+    }
+  }
+
+  base::Optional<std::string> app_id =
+      GetAppIdForSystemWebApp(profile, app_type);
+  // TODO(calamity): Queue a task to launch app after it is installed.
+  if (!app_id)
+    return nullptr;
+
+  const extensions::Extension* extension =
+      extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
+          app_id.value(), extensions::ExtensionRegistry::ENABLED);
+  DCHECK(extension);
+
+  // TODO(calamity): Plumb through better launch sources from callsites.
+  AppLaunchParams params = CreateAppLaunchParamsWithEventFlags(
+      profile, extension, 0, extensions::SOURCE_CHROME_INTERNAL,
+      display::kInvalidDisplayId);
+  params.override_url = url;
+
+  if (!browser)
+    browser = CreateApplicationWindow(params, url);
+
+  ShowApplicationWindow(params, url, browser,
+                        WindowOpenDisposition::CURRENT_TAB);
+  return browser;
+}
+
+Browser* FindSystemWebAppBrowser(Profile* profile, SystemAppType app_type) {
+  // TODO(calamity): Determine whether, during startup, we need to wait for
+  // app install and then provide a valid answer here.
+  base::Optional<std::string> app_id =
+      GetAppIdForSystemWebApp(profile, app_type);
+  if (!app_id)
+    return nullptr;
+
+  const extensions::Extension* extension =
+      extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
+          app_id.value(), extensions::ExtensionRegistry::ENABLED);
+  DCHECK(extension);
+
+  for (auto* browser : *BrowserList::GetInstance()) {
+    if (browser->profile() != profile || !browser->is_app())
+      continue;
+
+    const extensions::Extension* browser_extension =
+        extensions::ExtensionRegistry::Get(browser->profile())
+            ->GetExtensionById(GetAppIdFromApplicationName(browser->app_name()),
+                               extensions::ExtensionRegistry::EVERYTHING);
+    if (browser_extension == extension)
+      return browser;
+  }
+
+  return nullptr;
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.h b/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.h
new file mode 100644
index 0000000..319526c
--- /dev/null
+++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.h
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium 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_WEB_APPLICATIONS_SYSTEM_WEB_APP_UI_UTILS_CHROMEOS_H_
+#define CHROME_BROWSER_UI_WEB_APPLICATIONS_SYSTEM_WEB_APP_UI_UTILS_CHROMEOS_H_
+
+#include "base/optional.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "url/gurl.h"
+
+class Browser;
+class Profile;
+
+namespace web_app {
+
+// Returns the PWA system App ID for the given system app type.
+base::Optional<std::string> GetAppIdForSystemWebApp(Profile* profile,
+                                                    SystemAppType app_type);
+
+// Launches a System App to the given URL, reusing any existing window for the
+// app. Returns the browser for the System App, or nullptr if launch/focus
+// failed.
+Browser* LaunchSystemWebApp(Profile* profile,
+                            SystemAppType app_type,
+                            const GURL& url = GURL());
+
+// Returns a browser that is hosting the given system app type, or nullptr if
+// not found.
+Browser* FindSystemWebAppBrowser(Profile* profile, SystemAppType app_type);
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_UI_WEB_APPLICATIONS_SYSTEM_WEB_APP_UI_UTILS_CHROMEOS_H_
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc
index 787a7a5..9d77c6f 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc
@@ -14,11 +14,36 @@
 #include "chromeos/services/assistant/public/features.h"
 #include "components/arc/arc_prefs.h"
 #include "components/consent_auditor/consent_auditor.h"
+#include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/webui/web_ui_util.h"
 
+namespace {
+
+bool IsScreenContextDefaultEnabled(PrefService* prefs) {
+  const PrefService::Preference* pref =
+      prefs->FindPreference(arc::prefs::kVoiceInteractionContextEnabled);
+
+  if (pref->IsManaged()) {
+    return pref->GetValue()->GetBool();
+  }
+
+  if (pref->GetRecommendedValue()) {
+    return pref->GetRecommendedValue()->GetBool();
+  }
+
+  return true;
+}
+
+bool IsScreenContextToggleDisabled(PrefService* prefs) {
+  return prefs->IsManagedPreference(
+      arc::prefs::kVoiceInteractionContextEnabled);
+}
+
+}  // namespace
+
 namespace chromeos {
 
 void RecordAssistantOptInStatus(AssistantOptInFlowStatus status) {
@@ -106,7 +131,8 @@
 
 // Helper method to create get more screen data.
 base::Value CreateGetMoreData(bool email_optin_needed,
-                              const assistant::EmailOptInUi& email_optin_ui) {
+                              const assistant::EmailOptInUi& email_optin_ui,
+                              PrefService* prefs) {
   base::Value get_more_data(base::Value::Type::LIST);
 
   if (!base::FeatureList::IsEnabled(
@@ -135,7 +161,10 @@
                                    IDS_ASSISTANT_SCREEN_CONTEXT_TITLE)));
   context_data.SetKey("description", base::Value(l10n_util::GetStringUTF16(
                                          IDS_ASSISTANT_SCREEN_CONTEXT_DESC)));
-  context_data.SetKey("defaultEnabled", base::Value(true));
+  context_data.SetKey("defaultEnabled",
+                      base::Value(IsScreenContextDefaultEnabled(prefs)));
+  context_data.SetKey("toggleDisabled",
+                      base::Value(IsScreenContextToggleDisabled(prefs)));
   context_data.SetKey(
       "iconUri",
       base::Value("https://www.gstatic.com/images/icons/material/system/"
@@ -230,5 +259,4 @@
   }
   return false;
 }
-
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h
index 67b5c7e1..269498a 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h
@@ -7,12 +7,14 @@
 
 #include <string>
 
-#include "base/callback.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chromeos/services/assistant/public/mojom/constants.mojom.h"
 #include "chromeos/services/assistant/public/proto/settings_ui.pb.h"
-#include "components/prefs/pref_service.h"
-#include "services/service_manager/public/cpp/connector.h"
+
+class PrefService;
+class Profile;
+
+namespace base {
+class Value;
+}
 
 namespace chromeos {
 
@@ -61,7 +63,8 @@
 
 // Helper method to create get more screen data.
 base::Value CreateGetMoreData(bool email_optin_needed,
-                              const assistant::EmailOptInUi& email_optin_ui);
+                              const assistant::EmailOptInUi& email_optin_ui,
+                              PrefService* prefs);
 
 // Get string constants for settings ui.
 base::Value GetSettingsUiStrings(const assistant::SettingsUi& settings_ui,
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
index 2418c18..4a68cc3fd 100644
--- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/oobe_screen.h"
 #include "chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/assistant/assistant_pref_util.h"
@@ -23,6 +24,7 @@
 #include "components/arc/arc_prefs.h"
 #include "components/login/localized_values_builder.h"
 #include "components/prefs/pref_service.h"
+#include "components/user_manager/user_manager.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace chromeos {
@@ -351,8 +353,11 @@
   // Process get more data.
   email_optin_needed_ = settings_ui.has_email_opt_in_ui() &&
                         settings_ui.email_opt_in_ui().has_title();
+  auto* profile_helper = ProfileHelper::Get();
+  const auto* user = user_manager::UserManager::Get()->GetActiveUser();
   auto get_more_data =
-      CreateGetMoreData(email_optin_needed_, settings_ui.email_opt_in_ui());
+      CreateGetMoreData(email_optin_needed_, settings_ui.email_opt_in_ui(),
+                        profile_helper->GetProfileByUser(user)->GetPrefs());
 
   bool skip_get_more =
       skip_third_party_disclosure && !get_more_data.GetList().size();
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 51723d0..05a7fae2 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -201,6 +201,7 @@
     {"emptyStreamStarted", IDS_MD_EXTENSIONS_EMPTY_STREAM_STARTED},
     {"emptyStreamStopped", IDS_MD_EXTENSIONS_EMPTY_STREAM_STOPPED},
     {"activityArgumentsHeading", IDS_MD_EXTENSIONS_ACTIVITY_ARGUMENTS_HEADING},
+    {"webRequestInfoHeading", IDS_MD_EXTENSIONS_WEB_REQUEST_INFO_HEADING},
     {"appIcon", IDS_MD_EXTENSIONS_APP_ICON},
     {"extensionIcon", IDS_MD_EXTENSIONS_EXTENSION_ICON},
     {"extensionA11yAssociation", IDS_MD_EXTENSIONS_EXTENSION_A11Y_ASSOCIATION},
diff --git a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
index f0cf9ce..d8f69e3 100644
--- a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
@@ -130,12 +130,10 @@
 void CrostiniHandler::HandleCrostiniInstallerStatusRequest(
     const base::ListValue* args) {
   AllowJavascript();
-  CHECK_EQ(1U, args->GetSize());
-  std::string callback_id;
-  CHECK(args->GetString(0, &callback_id));
+  CHECK_EQ(0U, args->GetSize());
   bool status = crostini::CrostiniManager::GetForProfile(profile_)
                     ->GetInstallerViewStatus();
-  ResolveJavascriptCallback(base::Value(callback_id), base::Value(status));
+  OnCrostiniInstallerViewStatusChanged(status);
 }
 
 void CrostiniHandler::OnCrostiniInstallerViewStatusChanged(bool status) {
diff --git a/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc
index 23aa0b7..64d48e3 100644
--- a/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h"
 #include "chromeos/constants/chromeos_switches.h"
+#include "chromeos/services/assistant/public/mojom/constants.mojom.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "content/public/browser/browser_context.h"
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 2cacff7..4422418c 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -31,11 +31,9 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/locale_settings.h"
-#include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/payments/payments_service_url.h"
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/sync_utils.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/google/core/common/google_util.h"
@@ -1568,13 +1566,64 @@
                          autofill::payments::GetManageInstrumentsUrl().spec());
   html_source->AddString("paymentMethodsLearnMoreURL",
                          chrome::kPaymentMethodsLearnMoreURL);
-
   html_source->AddBoolean(
       "migrationEnabled",
-      autofill::IsCreditCardMigrationEnabled(
-          autofill::PersonalDataManagerFactory::GetForProfile(profile),
-          profile->GetPrefs(),
-          ProfileSyncServiceFactory::GetForProfile(profile)));
+      autofill::features::GetLocalCardMigrationExperimentalFlag() ==
+          autofill::features::LocalCardMigrationExperimentalFlag::
+              kMigrationIncludeSettingsPage);
+  html_source->AddBoolean(
+      "upstreamEnabled",
+      base::FeatureList::IsEnabled(autofill::features::kAutofillUpstream));
+
+  autofill::PersonalDataManager* personal_data_manager_ =
+      autofill::PersonalDataManagerFactory::GetForProfile(profile);
+  html_source->AddBoolean(
+      "hasGooglePaymentsAccount",
+      autofill::payments::GetBillingCustomerId(personal_data_manager_,
+                                               profile->GetPrefs()) != 0);
+
+  syncer::SyncService* sync_service =
+      ProfileSyncServiceFactory::GetForProfile(profile);
+  if (sync_service && sync_service->CanSyncFeatureStart() &&
+      sync_service->GetPreferredDataTypes().Has(syncer::AUTOFILL_PROFILE)) {
+    html_source->AddBoolean(
+        "isUsingSecondaryPassphrase",
+        sync_service->GetUserSettings()->IsUsingSecondaryPassphrase());
+    html_source->AddBoolean(
+        "uploadToGoogleActive",
+        syncer::GetUploadToGoogleState(
+            sync_service, syncer::ModelType::AUTOFILL_WALLET_DATA) ==
+            syncer::UploadState::ACTIVE);
+  } else {
+    html_source->AddBoolean("isUsingSecondaryPassphrase", false);
+    html_source->AddBoolean("uploadToGoogleActive", false);
+  }
+
+  bool is_guest_mode = false;
+#if defined(OS_CHROMEOS)
+  is_guest_mode = user_manager::UserManager::Get()->IsLoggedInAsGuest() ||
+                  user_manager::UserManager::Get()->IsLoggedInAsPublicAccount();
+#else   // !defined(OS_CHROMEOS)
+  is_guest_mode = profile->IsOffTheRecord();
+#endif  // defined(OS_CHROMEOS)
+
+  if (is_guest_mode) {
+    html_source->AddBoolean("userEmailDomainAllowed", false);
+  } else {
+    const std::string& user_email =
+        personal_data_manager_->GetAccountInfoForPaymentsServer().email;
+    if (user_email.empty()) {
+      html_source->AddBoolean("userEmailDomainAllowed", false);
+    } else {
+      std::string domain = gaia::ExtractDomainName(user_email);
+      html_source->AddBoolean(
+          "userEmailDomainAllowed",
+          base::FeatureList::IsEnabled(
+              autofill::features::kAutofillUpstreamAllowAllEmailDomains) ||
+              (domain == "googlemail.com" || domain == "gmail.com" ||
+               domain == "google.com" || domain == "chromium.org"));
+    }
+  }
 
   AddLocalizedStringsBulk(html_source, kLocalizedStrings,
                           base::size(kLocalizedStrings));
diff --git a/chrome/browser/vr/sounds_manager_audio_delegate.cc b/chrome/browser/vr/sounds_manager_audio_delegate.cc
index be727cb4..2781c563 100644
--- a/chrome/browser/vr/sounds_manager_audio_delegate.cc
+++ b/chrome/browser/vr/sounds_manager_audio_delegate.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/vr/sounds_manager_audio_delegate.h"
+#include "content/public/common/service_manager_connection.h"
 #include "services/audio/public/cpp/sounds/sounds_manager.h"
 
 namespace vr {
@@ -28,8 +29,12 @@
   DCHECK_NE(id, kSoundNone);
   DCHECK(sounds_.find(id) == sounds_.end());
 
-  if (sounds_.empty())
-    audio::SoundsManager::Create();
+  if (sounds_.empty()) {
+    audio::SoundsManager::Create(
+        content::ServiceManagerConnection::GetForProcess()
+            ->GetConnector()
+            ->Clone());
+  }
 
   sounds_[id] = std::move(data);
   return audio::SoundsManager::Get()->Initialize(id, *sounds_[id]);
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
index 1ba0d6b8..1fb3703 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
@@ -96,10 +96,26 @@
     return;
   }
 
-  // TODO(crbug.com/864904): Use an appropriate install source once source
-  // is plumbed through this class.
+  auto install_source = WebappInstallSource::COUNT;
+  switch (app_info_.install_source) {
+    case web_app::InstallSource::kInternal:
+      install_source = WebappInstallSource::INTERNAL_DEFAULT;
+      break;
+    case web_app::InstallSource::kExternalDefault:
+      install_source = WebappInstallSource::EXTERNAL_DEFAULT;
+      break;
+    case web_app::InstallSource::kExternalPolicy:
+      install_source = WebappInstallSource::EXTERNAL_POLICY;
+      break;
+    case web_app::InstallSource::kSystemInstalled:
+      install_source = WebappInstallSource::SYSTEM_DEFAULT;
+      break;
+    case web_app::InstallSource::kArc:
+      NOTREACHED();
+      break;
+  }
   helper_ = helper_factory_.Run(profile_, *web_app_info, web_contents,
-                                WebappInstallSource::MENU_BROWSER_TAB);
+                                install_source);
 
   switch (app_info_.launch_container) {
     case web_app::LaunchContainer::kDefault:
diff --git a/chrome/services/app_service/public/cpp/BUILD.gn b/chrome/services/app_service/public/cpp/BUILD.gn
index d4616cfa..9300671 100644
--- a/chrome/services/app_service/public/cpp/BUILD.gn
+++ b/chrome/services/app_service/public/cpp/BUILD.gn
@@ -15,6 +15,19 @@
   ]
 }
 
+source_set("icon_loader") {
+  sources = [
+    "icon_cache.cc",
+    "icon_cache.h",
+    "icon_loader.cc",
+    "icon_loader.h",
+  ]
+
+  public_deps = [
+    "//chrome/services/app_service/public/mojom",
+  ]
+}
+
 source_set("manifest") {
   sources = [
     "manifest.cc",
@@ -35,6 +48,7 @@
   sources = [
     "app_registry_cache_unittest.cc",
     "app_update_unittest.cc",
+    "icon_cache_unittest.cc",
   ]
 
   deps = [
diff --git a/chrome/services/app_service/public/cpp/icon_cache.cc b/chrome/services/app_service/public/cpp/icon_cache.cc
new file mode 100644
index 0000000..f3b1ac1
--- /dev/null
+++ b/chrome/services/app_service/public/cpp/icon_cache.cc
@@ -0,0 +1,155 @@
+// Copyright 2019 The Chromium 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/services/app_service/public/cpp/icon_cache.h"
+
+#include <utility>
+
+#include "base/callback.h"
+
+namespace apps {
+
+IconCache::Value::Value()
+    : image_(), is_placeholder_icon_(false), ref_count_(0) {}
+
+apps::mojom::IconValuePtr IconCache::Value::AsIconValue() {
+  auto icon_value = apps::mojom::IconValue::New();
+  icon_value->icon_compression = apps::mojom::IconCompression::kUncompressed;
+  icon_value->uncompressed = image_;
+  icon_value->is_placeholder_icon = is_placeholder_icon_;
+  return icon_value;
+}
+
+IconCache::IconCache(IconLoader* wrapped_loader,
+                     GarbageCollectionPolicy gc_policy)
+    : wrapped_loader_(wrapped_loader), gc_policy_(gc_policy) {}
+
+IconCache::~IconCache() = default;
+
+apps::mojom::IconKeyPtr IconCache::GetIconKey(const std::string& app_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return wrapped_loader_ ? wrapped_loader_->GetIconKey(app_id)
+                         : apps::mojom::IconKey::New();
+}
+
+std::unique_ptr<IconLoader::Releaser> IconCache::LoadIconFromIconKey(
+    apps::mojom::IconKeyPtr icon_key,
+    apps::mojom::IconCompression icon_compression,
+    int32_t size_hint_in_dip,
+    bool allow_placeholder_icon,
+    apps::mojom::Publisher::LoadIconCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  IconLoader::Key key(
+      *icon_key, icon_compression, size_hint_in_dip,
+      // We pass false instead of allow_placeholder_icon, as the Value
+      // already records placeholder-ness. If the allow_placeholder_icon
+      // arg to this function is true, we can re-use a cache hit regardless
+      // of whether the previous call to the underlying wrapped_loader_
+      // returned the placeholder icon or the real icon, so we don't want
+      // to restrict our map lookup to only one flavor.
+      false);
+  Value* cache_hit = nullptr;
+  bool ref_count_incremented = false;
+
+  if (icon_compression == apps::mojom::IconCompression::kUncompressed) {
+    auto iter = map_.find(key);
+    if (iter == map_.end()) {
+      iter = map_.insert(std::make_pair(key, Value())).first;
+    } else if (!iter->second.image_.isNull() &&
+               (allow_placeholder_icon || !iter->second.is_placeholder_icon_)) {
+      cache_hit = &iter->second;
+    }
+
+    iter->second.ref_count_++;
+    ref_count_incremented = true;
+  }
+
+  std::unique_ptr<IconLoader::Releaser> releaser(nullptr);
+  if (cache_hit) {
+    std::move(callback).Run(cache_hit->AsIconValue());
+  } else if (wrapped_loader_) {
+    releaser = wrapped_loader_->LoadIconFromIconKey(
+        std::move(icon_key), icon_compression, size_hint_in_dip,
+        allow_placeholder_icon,
+        base::BindOnce(&IconCache::OnLoadIcon, weak_ptr_factory_.GetWeakPtr(),
+                       key, std::move(callback)));
+  } else {
+    std::move(callback).Run(apps::mojom::IconValue::New());
+  }
+
+  return ref_count_incremented
+             ? std::make_unique<IconLoader::Releaser>(
+                   std::move(releaser),
+                   base::BindOnce(&IconCache::OnRelease,
+                                  weak_ptr_factory_.GetWeakPtr(),
+                                  std::move(key)))
+             : std::move(releaser);
+}
+
+void IconCache::SweepReleasedIcons() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (gc_policy_ != GarbageCollectionPolicy::kExplicit) {
+    return;
+  }
+
+  auto iter = map_.begin();
+  while (iter != map_.end()) {
+    if (iter->second.ref_count_ == 0) {
+      iter = map_.erase(iter);
+    } else {
+      ++iter;
+    }
+  }
+}
+
+void IconCache::Update(const IconLoader::Key& key,
+                       const apps::mojom::IconValue& icon_value) {
+  if (icon_value.icon_compression !=
+      apps::mojom::IconCompression::kUncompressed) {
+    return;
+  }
+
+  auto iter = map_.find(key);
+  if (iter == map_.end()) {
+    return;
+  }
+
+  // Don't let a placeholder overwrite a real icon.
+  if (icon_value.is_placeholder_icon && !iter->second.is_placeholder_icon_) {
+    return;
+  }
+
+  iter->second.image_ = icon_value.uncompressed;
+}
+
+void IconCache::OnLoadIcon(
+    IconLoader::Key key,
+    apps::mojom::Publisher::LoadIconCallback wrapped_callback,
+    apps::mojom::IconValuePtr icon_value) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  Update(key, *icon_value);
+  std::move(wrapped_callback).Run(std::move(icon_value));
+}
+
+void IconCache::OnRelease(IconLoader::Key key) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto iter = map_.find(key);
+  if (iter == map_.end()) {
+    NOTREACHED();
+    return;
+  }
+
+  uint64_t n = iter->second.ref_count_;
+  DCHECK(n > 0);
+  n--;
+  iter->second.ref_count_ = n;
+
+  if ((n == 0) && (gc_policy_ == GarbageCollectionPolicy::kEager)) {
+    map_.erase(iter);
+  }
+}
+
+}  // namespace apps
diff --git a/chrome/services/app_service/public/cpp/icon_cache.h b/chrome/services/app_service/public/cpp/icon_cache.h
new file mode 100644
index 0000000..0f567fc
--- /dev/null
+++ b/chrome/services/app_service/public/cpp/icon_cache.h
@@ -0,0 +1,116 @@
+// Copyright 2019 The Chromium 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_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_CACHE_H_
+#define CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_CACHE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "chrome/services/app_service/public/cpp/icon_loader.h"
+#include "chrome/services/app_service/public/mojom/app_service.mojom.h"
+#include "chrome/services/app_service/public/mojom/types.mojom.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace apps {
+
+// An IconLoader that caches the apps::mojom::IconCompression::kUncompressed
+// results of another (wrapped) IconLoader.
+class IconCache : public IconLoader {
+ public:
+  // What triggers dropping no-longer-used icons from the cache.
+  //
+  // If unsure of which one to use, kEager is a safe choice, with little
+  // overhead above not having an icon cache at all.
+  enum class GarbageCollectionPolicy {
+    // kEager means that we drop icons as soon as their ref-count hits zero
+    // (i.e. all the IconLoader::Releaser's returned by LoadIconFromIconKey
+    // have been destroyed).
+    //
+    // This minimizes the overall memory cost of the cache. Only icons that are
+    // still actively used stay alive in the cache.
+    //
+    // On the other hand, this can result in more cache misses than other
+    // policies. For example, suppose that some UI starts with a widget showing
+    // the "foo" app icon. In response to user input, the UI destroys that
+    // widget and then creates a new widget to show the same "foo" app icon.
+    // With a kEager garbage collection policy, that freshly created widget
+    // might not get a cache hit, if the icon's ref-count hits zero in between
+    // the two widgets' destruction and creation.
+    kEager,
+
+    // kExplicit means that icons can remain in the cache, even if their
+    // ref-count hits zero. Instead, explicit calls to SweepReleasedIcons are
+    // needed to clear cache entries.
+    //
+    // This can use more memory than kEager, but it can also provide a cache
+    // hit in the "destroy and then create" example described above.
+    //
+    // On the other hand, it requires more effort and more thought from the
+    // programmer. They need to make additional calls (to SweepReleasedIcons),
+    // so they can't just drop an IconCache in transparently. The programmer
+    // also needs to think about when is a good time to make those calls. Too
+    // frequent, and you get extra complexity for not much more benefit than
+    // using kEager. Too infrequent, and you have the memory cost of keeping
+    // unused icons around.
+    //
+    // All together, kExplicit might not be the best policy for e.g. a
+    // process-wide icon cache with many clients, each with different usage
+    // patterns.
+    kExplicit,
+  };
+
+  IconCache(IconLoader* wrapped_loader, GarbageCollectionPolicy gc_policy);
+  ~IconCache();
+
+  // IconLoader overrides.
+  apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override;
+  std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey(
+      apps::mojom::IconKeyPtr icon_key,
+      apps::mojom::IconCompression icon_compression,
+      int32_t size_hint_in_dip,
+      bool allow_placeholder_icon,
+      apps::mojom::Publisher::LoadIconCallback callback) override;
+
+  // A hint that now is a good time to garbage-collect any icons that are not
+  // actively held.
+  void SweepReleasedIcons();
+
+ private:
+  class Value {
+   public:
+    gfx::ImageSkia image_;
+    bool is_placeholder_icon_;
+    uint64_t ref_count_;
+
+    Value();
+
+    apps::mojom::IconValuePtr AsIconValue();
+  };
+
+  void Update(const IconLoader::Key&, const apps::mojom::IconValue&);
+  void OnLoadIcon(IconLoader::Key,
+                  apps::mojom::Publisher::LoadIconCallback,
+                  apps::mojom::IconValuePtr);
+  void OnRelease(IconLoader::Key);
+
+  std::map<IconLoader::Key, Value> map_;
+  IconLoader* wrapped_loader_;
+  GarbageCollectionPolicy gc_policy_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<IconCache> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(IconCache);
+};
+
+}  // namespace apps
+
+#endif  // CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_CACHE_H_
diff --git a/chrome/services/app_service/public/cpp/icon_cache_unittest.cc b/chrome/services/app_service/public/cpp/icon_cache_unittest.cc
new file mode 100644
index 0000000..bb3ec36
--- /dev/null
+++ b/chrome/services/app_service/public/cpp/icon_cache_unittest.cc
@@ -0,0 +1,212 @@
+// Copyright 2019 The Chromium 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 <utility>
+
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "chrome/services/app_service/public/cpp/icon_cache.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_skia_rep.h"
+
+class AppsIconCacheTest : public testing::Test {
+ protected:
+  enum class HitOrMiss {
+    kHit,
+    kMiss,
+  };
+
+  using UniqueReleaser = std::unique_ptr<apps::IconLoader::Releaser>;
+  static constexpr HitOrMiss kHit = HitOrMiss::kHit;
+  static constexpr HitOrMiss kMiss = HitOrMiss::kMiss;
+
+  class FakeIconLoader : public apps::IconLoader {
+   public:
+    int NumLoadIconFromIconKeyCalls() { return num_load_calls_; }
+
+    void SetReturnPlaceholderIcons(bool b) { return_placeholder_icons_ = b; }
+
+   private:
+    apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override {
+      return apps::mojom::IconKey::New(apps::mojom::AppType::kWeb, 0, app_id,
+                                       0);
+    }
+
+    std::unique_ptr<Releaser> LoadIconFromIconKey(
+        apps::mojom::IconKeyPtr icon_key,
+        apps::mojom::IconCompression icon_compression,
+        int32_t size_hint_in_dip,
+        bool allow_placeholder_icon,
+        apps::mojom::Publisher::LoadIconCallback callback) override {
+      num_load_calls_++;
+
+      auto iv = apps::mojom::IconValue::New();
+      if (icon_compression == apps::mojom::IconCompression::kUncompressed) {
+        iv->icon_compression = apps::mojom::IconCompression::kUncompressed;
+        iv->uncompressed =
+            gfx::ImageSkia(gfx::ImageSkiaRep(gfx::Size(1, 1), 1.0f));
+        iv->is_placeholder_icon = return_placeholder_icons_;
+      }
+
+      std::move(callback).Run(std::move(iv));
+      return nullptr;
+    }
+
+    int num_load_calls_ = 0;
+    bool return_placeholder_icons_ = false;
+  };
+
+  UniqueReleaser LoadIcon(apps::IconLoader* loader,
+                          FakeIconLoader* fake,
+                          const std::string& app_id,
+                          HitOrMiss expect_hom,
+                          bool allow_placeholder_icon = false) {
+    static constexpr auto icon_compression =
+        apps::mojom::IconCompression::kUncompressed;
+    static constexpr int32_t size_hint_in_dip = 1;
+
+    int before = fake->NumLoadIconFromIconKeyCalls();
+
+    UniqueReleaser releaser =
+        loader->LoadIcon(app_id, icon_compression, size_hint_in_dip,
+                         allow_placeholder_icon, base::DoNothing());
+
+    int after = fake->NumLoadIconFromIconKeyCalls();
+    HitOrMiss actual_hom = (after == before) ? kHit : kMiss;
+    EXPECT_EQ(expect_hom, actual_hom);
+
+    return releaser;
+  }
+
+  void TestBasics(apps::IconCache::GarbageCollectionPolicy gc_policy) {
+    FakeIconLoader fake;
+    apps::IconCache cache(&fake, gc_policy);
+
+    UniqueReleaser a0 = LoadIcon(&cache, &fake, "apricot", kMiss);
+    a0.reset();
+
+    UniqueReleaser b0 = LoadIcon(&cache, &fake, "banana", kMiss);
+    UniqueReleaser b1 = LoadIcon(&cache, &fake, "banana", kHit);
+    b0.reset();
+    b1.reset();
+
+    UniqueReleaser c0 = LoadIcon(&cache, &fake, "cherry", kMiss);
+    UniqueReleaser c1 = LoadIcon(&cache, &fake, "cherry", kHit);
+    UniqueReleaser c2 = LoadIcon(&cache, &fake, "cherry", kHit);
+    c2.reset();
+    c1.reset();
+
+    UniqueReleaser d0 = LoadIcon(&cache, &fake, "durian", kMiss);
+    d0.reset();
+
+    UniqueReleaser c3 = LoadIcon(&cache, &fake, "cherry", kHit);
+    c3.reset();
+
+    if (gc_policy == apps::IconCache::GarbageCollectionPolicy::kExplicit) {
+      cache.SweepReleasedIcons();
+    }
+
+    UniqueReleaser c4 = LoadIcon(&cache, &fake, "cherry", kHit);
+    c4.reset();
+    c0.reset();
+
+    if (gc_policy == apps::IconCache::GarbageCollectionPolicy::kExplicit) {
+      cache.SweepReleasedIcons();
+    }
+
+    UniqueReleaser c5 = LoadIcon(&cache, &fake, "cherry", kMiss);
+    c5.reset();
+  }
+
+  void TestPlaceholder(apps::IconCache::GarbageCollectionPolicy gc_policy) {
+    FakeIconLoader fake;
+    apps::IconCache cache(&fake, gc_policy);
+    bool allow_placeholder_icon;
+
+    fake.SetReturnPlaceholderIcons(true);
+
+    allow_placeholder_icon = true;
+    UniqueReleaser f0 =
+        LoadIcon(&cache, &fake, "fig", kMiss, allow_placeholder_icon);
+
+    fake.SetReturnPlaceholderIcons(false);
+
+    // The next LoadIcon call is a kMiss, even though there is a cache entry,
+    // because the cache entry holds a placeholder icon, but we have
+    // allow_placeholder_icon == false.
+    //
+    // A side effect of the next LoadIcon call is to prime the cache with the
+    // real (non-placeholder) icon.
+
+    allow_placeholder_icon = false;
+    UniqueReleaser f1 =
+        LoadIcon(&cache, &fake, "fig", kMiss, allow_placeholder_icon);
+
+    // The next two LoadIcons are all both kHit's. The real icon can be served
+    // from the cache, regardless of allow_placeholder_icon's value.
+
+    allow_placeholder_icon = false;
+    UniqueReleaser f2 =
+        LoadIcon(&cache, &fake, "fig", kHit, allow_placeholder_icon);
+
+    allow_placeholder_icon = true;
+    UniqueReleaser f3 =
+        LoadIcon(&cache, &fake, "fig", kHit, allow_placeholder_icon);
+  }
+
+  void TestAfterZeroRefcount(
+      apps::IconCache::GarbageCollectionPolicy gc_policy) {
+    FakeIconLoader fake;
+    apps::IconCache cache(&fake, gc_policy);
+
+    UniqueReleaser w0 = LoadIcon(&cache, &fake, "watermelon", kMiss);
+    w0.reset();
+
+    // We now have a zero ref-count. Whether the next LoadIcon call is kHit or
+    // kMiss depends on our gc_policy.
+
+    HitOrMiss expect_hom;
+    switch (gc_policy) {
+      case apps::IconCache::GarbageCollectionPolicy::kEager:
+        expect_hom = kMiss;
+        break;
+      case apps::IconCache::GarbageCollectionPolicy::kExplicit:
+        expect_hom = kHit;
+        break;
+    }
+
+    UniqueReleaser w1 = LoadIcon(&cache, &fake, "watermelon", expect_hom);
+    w1.reset();
+
+    // Once again, we have a zero ref-count, but for a kExplicit gc_policy, we
+    // also explicitly SweepReleasedIcons(), so the next LoadIcon call should
+    // get kMiss.
+
+    if (gc_policy == apps::IconCache::GarbageCollectionPolicy::kExplicit) {
+      cache.SweepReleasedIcons();
+    }
+
+    UniqueReleaser w2 = LoadIcon(&cache, &fake, "watermelon", kMiss);
+    w2.reset();
+  }
+};
+
+TEST_F(AppsIconCacheTest, Eager) {
+  static constexpr apps::IconCache::GarbageCollectionPolicy gc_policy =
+      apps::IconCache::GarbageCollectionPolicy::kEager;
+
+  TestBasics(gc_policy);
+  TestPlaceholder(gc_policy);
+  TestAfterZeroRefcount(gc_policy);
+}
+
+TEST_F(AppsIconCacheTest, Explicit) {
+  static constexpr apps::IconCache::GarbageCollectionPolicy gc_policy =
+      apps::IconCache::GarbageCollectionPolicy::kExplicit;
+
+  TestBasics(gc_policy);
+  TestPlaceholder(gc_policy);
+  TestAfterZeroRefcount(gc_policy);
+}
diff --git a/chrome/services/app_service/public/cpp/icon_loader.cc b/chrome/services/app_service/public/cpp/icon_loader.cc
new file mode 100644
index 0000000..94bfb74
--- /dev/null
+++ b/chrome/services/app_service/public/cpp/icon_loader.cc
@@ -0,0 +1,66 @@
+// Copyright 2019 The Chromium 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/services/app_service/public/cpp/icon_loader.h"
+
+#include <utility>
+
+#include "base/callback.h"
+
+namespace apps {
+
+IconLoader::Releaser::Releaser(std::unique_ptr<IconLoader::Releaser> next,
+                               base::OnceClosure closure)
+    : next_(std::move(next)), closure_(std::move(closure)) {}
+
+IconLoader::Releaser::~Releaser() {
+  std::move(closure_).Run();
+}
+
+IconLoader::Key::Key(const apps::mojom::IconKey& icon_key,
+                     apps::mojom::IconCompression icon_compression,
+                     int32_t size_hint_in_dip,
+                     bool allow_placeholder_icon)
+    : app_type_(icon_key.app_type),
+      s_key_(icon_key.s_key),
+      u_key_(icon_key.u_key),
+      icon_effects_(icon_key.icon_effects),
+      icon_compression_(icon_compression),
+      size_hint_in_dip_(size_hint_in_dip),
+      allow_placeholder_icon_(allow_placeholder_icon) {}
+
+bool IconLoader::Key::operator<(const Key& that) const {
+  if (this->app_type_ != that.app_type_) {
+    return this->app_type_ < that.app_type_;
+  }
+  if (this->u_key_ != that.u_key_) {
+    return this->u_key_ < that.u_key_;
+  }
+  if (this->icon_effects_ != that.icon_effects_) {
+    return this->icon_effects_ < that.icon_effects_;
+  }
+  if (this->icon_compression_ != that.icon_compression_) {
+    return this->icon_compression_ < that.icon_compression_;
+  }
+  if (this->size_hint_in_dip_ != that.size_hint_in_dip_) {
+    return this->size_hint_in_dip_ < that.size_hint_in_dip_;
+  }
+  if (this->allow_placeholder_icon_ != that.allow_placeholder_icon_) {
+    return this->allow_placeholder_icon_ < that.allow_placeholder_icon_;
+  }
+  return this->s_key_ < that.s_key_;
+}
+
+std::unique_ptr<IconLoader::Releaser> IconLoader::LoadIcon(
+    const std::string& app_id,
+    apps::mojom::IconCompression icon_compression,
+    int32_t size_hint_in_dip,
+    bool allow_placeholder_icon,
+    apps::mojom::Publisher::LoadIconCallback callback) {
+  return LoadIconFromIconKey(GetIconKey(app_id), icon_compression,
+                             size_hint_in_dip, allow_placeholder_icon,
+                             std::move(callback));
+}
+
+}  // namespace apps
diff --git a/chrome/services/app_service/public/cpp/icon_loader.h b/chrome/services/app_service/public/cpp/icon_loader.h
new file mode 100644
index 0000000..fa2870d
--- /dev/null
+++ b/chrome/services/app_service/public/cpp/icon_loader.h
@@ -0,0 +1,99 @@
+// Copyright 2019 The Chromium 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_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_LOADER_H_
+#define CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_LOADER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "chrome/services/app_service/public/mojom/app_service.mojom.h"
+#include "chrome/services/app_service/public/mojom/types.mojom.h"
+
+namespace apps {
+
+// An abstract class for something that can load App Service icons, either
+// directly or by wrapping another IconLoader.
+class IconLoader {
+ public:
+  // An RAII-style object that, when destroyed, runs |closure|.
+  //
+  // For example, that |closure| can inform an IconLoader that an icon is no
+  // longer actively used by whoever held this Releaser (an object returned by
+  // IconLoader::LoadIconFromIconKey). This is merely advisory: the IconLoader
+  // is free to ignore the Releaser-was-destroyed hint and to e.g. keep any
+  // cache entries alive for a longer or shorter time.
+  //
+  // These can be chained, so that |this| is the head of a linked list of
+  // Releaser's. Destroying the head will destroy the rest of the list.
+  //
+  // Destruction must happen on the same sequence (in the
+  // base/sequence_checker.h sense) as the LoadIcon or LoadIconFromIconKey call
+  // that returned |this|.
+  class Releaser {
+   public:
+    Releaser(std::unique_ptr<Releaser> next, base::OnceClosure closure);
+    virtual ~Releaser();
+
+   private:
+    std::unique_ptr<Releaser> next_;
+    base::OnceClosure closure_;
+
+    DISALLOW_COPY_AND_ASSIGN(Releaser);
+  };
+
+  // Looks up the IconKey for the given app ID.
+  virtual apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) = 0;
+
+  // This can return nullptr, meaning that the IconLoader does not track when
+  // the icon is no longer actively used by the caller.
+  virtual std::unique_ptr<Releaser> LoadIconFromIconKey(
+      apps::mojom::IconKeyPtr icon_key,
+      apps::mojom::IconCompression icon_compression,
+      int32_t size_hint_in_dip,
+      bool allow_placeholder_icon,
+      apps::mojom::Publisher::LoadIconCallback callback) = 0;
+
+  // Convenience method that calls LoadIconFromIconKey(GetIconKey(app_id), etc).
+  std::unique_ptr<Releaser> LoadIcon(
+      const std::string& app_id,
+      apps::mojom::IconCompression icon_compression,
+      int32_t size_hint_in_dip,
+      bool allow_placeholder_icon,
+      apps::mojom::Publisher::LoadIconCallback callback);
+
+ protected:
+  // A struct containing the arguments (other than the callback) to
+  // Loader::LoadIconFromIconKey, including a flattened apps::mojom::IconKey.
+  //
+  // It implements operator<, so that it can be the "K" in a "map<K, V>".
+  //
+  // Only IconLoader subclasses (i.e. implementations), not IconLoader's
+  // callers, are expected to refer to a Key.
+  class Key {
+   public:
+    // apps::mojom::IconKey fields.
+    apps::mojom::AppType app_type_;
+    std::string s_key_;
+    uint64_t u_key_;
+    uint32_t icon_effects_;
+    // Other fields.
+    apps::mojom::IconCompression icon_compression_;
+    int32_t size_hint_in_dip_;
+    bool allow_placeholder_icon_;
+
+    Key(const apps::mojom::IconKey& icon_key,
+        apps::mojom::IconCompression icon_compression,
+        int32_t size_hint_in_dip,
+        bool allow_placeholder_icon);
+
+    bool operator<(const Key& that) const;
+  };
+};
+
+}  // namespace apps
+
+#endif  // CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_LOADER_H_
diff --git a/chrome/services/app_service/public/mojom/types.mojom b/chrome/services/app_service/public/mojom/types.mojom
index 0e328d4..ee2f92c4 100644
--- a/chrome/services/app_service/public/mojom/types.mojom
+++ b/chrome/services/app_service/public/mojom/types.mojom
@@ -92,6 +92,9 @@
   // A bitmask of icon post-processing effects, such as desaturation to gray
   // and rounding the corners.
   uint32 icon_effects;
+
+  // When adding new fields, also update the IconLoader::Key type in
+  // chrome/services/app_service/public/cpp/icon_loader.*
 };
 
 enum IconCompression {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 65aacb7..382f7ba2 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5945,3 +5945,45 @@
     seed_corpus = "data/safe_browsing/download_protection/"
   }
 }
+
+# Test binary for the ChromeOS usage time limit processor tests.
+if (is_chromeos) {
+  test("usage_time_limit_unittests") {
+    testonly = true
+    sources = [
+      "../browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.cc",
+      "../browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader.h",
+      "../browser/chromeos/child_accounts/time_limit_consistency_test/consistency_golden_loader_unittest.cc",
+      "../browser/chromeos/child_accounts/time_limit_consistency_test/proto_matcher.h",
+      "../browser/chromeos/child_accounts/time_limit_consistency_test/run_all_unittests.cc",
+      "../browser/chromeos/child_accounts/time_limit_override.cc",
+      "../browser/chromeos/child_accounts/time_limit_override.h",
+      "../browser/chromeos/child_accounts/time_limit_test_utils.cc",
+      "../browser/chromeos/child_accounts/time_limit_test_utils.h",
+      "../browser/chromeos/child_accounts/usage_time_limit_processor.cc",
+      "../browser/chromeos/child_accounts/usage_time_limit_processor.h",
+    ]
+    deps = [
+      ":consistency_golden_proto",
+      "//base",
+      "//base/test:test_support",
+      "//chromeos/settings",
+      "//testing/gmock",
+      "//testing/gtest",
+      "//third_party/icu",
+      "//third_party/protobuf:protobuf_full",
+    ]
+    data = [
+      "../browser/chromeos/child_accounts/time_limit_consistency_test/goldens/",
+      "../browser/chromeos/child_accounts/time_limit_consistency_test/test_goldens/",
+    ]
+  }
+
+  proto_library("consistency_golden_proto") {
+    visibility = [ ":usage_time_limit_unittests" ]
+    sources = [
+      "../browser/chromeos/child_accounts/time_limit_consistency_test/goldens/consistency_golden.proto",
+    ]
+    generate_python = false
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/webrequest/framework.js b/chrome/test/data/extensions/api_test/webrequest/framework.js
index 2eb647bf..058341ca 100644
--- a/chrome/test/data/extensions/api_test/webrequest/framework.js
+++ b/chrome/test/data/extensions/api_test/webrequest/framework.js
@@ -259,6 +259,7 @@
     });
   });
 
+  removeListeners();
   eventsCaptured();
 }
 
@@ -536,3 +537,27 @@
 function resetDeclarativeRules() {
   chrome.declarativeWebRequest.onRequest.removeRules();
 }
+
+function checkHeaders(headers, requiredNames, disallowedNames) {
+  var headerMap = {};
+  for (var i = 0; i < headers.length; i++)
+    headerMap[headers[i].name.toLowerCase()] = headers[i].value;
+
+  for (var i = 0; i < requiredNames.length; i++) {
+    chrome.test.assertTrue(!!headerMap[requiredNames[i]],
+        'Missing header: ' + requiredNames[i]);
+  }
+  for (var i = 0; i < disallowedNames.length; i++) {
+    chrome.test.assertFalse(!!headerMap[disallowedNames[i]],
+        'Header should not be present: ' + disallowedNames[i]);
+  }
+}
+
+function removeHeader(headers, name) {
+  for (var i = 0; i < headers.length; i++) {
+    if (headers[i].name.toLowerCase() == name) {
+      headers.splice(i, 1);
+      break;
+    }
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_extra_headers.js b/chrome/test/data/extensions/api_test/webrequest/test_extra_headers.js
index ab163bf..1d012b63 100644
--- a/chrome/test/data/extensions/api_test/webrequest/test_extra_headers.js
+++ b/chrome/test/data/extensions/api_test/webrequest/test_extra_headers.js
@@ -8,30 +8,6 @@
   return getServerURL('set-cookie?' + name + '=' + value);
 }
 
-function checkHeaders(headers, requiredNames, disallowedNames) {
-  var headerMap = {};
-  for (var i = 0; i < headers.length; i++)
-    headerMap[headers[i].name.toLowerCase()] = headers[i].value;
-
-  for (var i = 0; i < requiredNames.length; i++) {
-    chrome.test.assertTrue(!!headerMap[requiredNames[i]],
-        'Missing header: ' + requiredNames[i]);
-  }
-  for (var i = 0; i < disallowedNames.length; i++) {
-    chrome.test.assertFalse(!!headerMap[disallowedNames[i]],
-        'Header should not be present: ' + disallowedNames[i]);
-  }
-}
-
-function removeHeader(headers, name) {
-  for (var i = 0; i < headers.length; i++) {
-    if (headers[i].name.toLowerCase() == name) {
-      headers.splice(i, 1);
-      break;
-    }
-  }
-}
-
 runTests([
   function testSpecialRequestHeadersVisible() {
     // Set a cookie so the cookie request header is set.
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_websocket.js b/chrome/test/data/extensions/api_test/webrequest/test_websocket.js
index 1dd0d30..ccd942e 100644
--- a/chrome/test/data/extensions/api_test/webrequest/test_websocket.js
+++ b/chrome/test/data/extensions/api_test/webrequest/test_websocket.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+var callbackPass = chrome.test.callbackPass;
+
 chrome.tabs.getCurrent(function(tab) {
   runTestsForTab([
     // Opens a WebSocket connection, writes a message to it, and closes the
@@ -78,7 +80,7 @@
         {urls: ['ws://*/*']},  // filter
         ['blocking']  // extraInfoSpec
       );
-      testWebSocketConnection(url, true /* expectedToConnect*/);
+      testWebSocketConnection(url, true /* expectedToConnect */);
     },
 
     // Tries to open a WebSocket connection, with a blocking handler that
@@ -115,7 +117,7 @@
         {urls: ['ws://*/*']},  // filter
         ['blocking']  // extraInfoSpec
       );
-      testWebSocketConnection(url, false /* expectedToConnect*/);
+      testWebSocketConnection(url, false /* expectedToConnect */);
     },
 
     // Opens a WebSocket connection, with a blocking handler that tries to
@@ -195,7 +197,109 @@
         {urls: ['ws://*/*']},  // filter
         ['blocking']  // extraInfoSpec
       );
-      testWebSocketConnection(url, true /* expectedToConnect*/);
+      testWebSocketConnection(url, true /* expectedToConnect */);
+    },
+
+    // Tests that all the requests headers that are added by net/ are visible
+    // if extraHeaders is specified.
+    function testExtraRequestHeadersVisible() {
+      var url = getWSTestURL(testWebSocketPort);
+
+      var extraHeadersListener = callbackPass(function(details) {
+        checkHeaders(details.requestHeaders,
+                     ['user-agent', 'accept-language'], []);
+        chrome.webRequest.onBeforeSendHeaders.removeListener(
+            extraHeadersListener);
+      });
+      chrome.webRequest.onBeforeSendHeaders.addListener(extraHeadersListener,
+          {urls: [url]}, ['requestHeaders', 'extraHeaders']);
+
+      var standardListener = callbackPass(function(details) {
+        checkHeaders(details.requestHeaders,
+                     ['user-agent'], ['accept-language']);
+        chrome.webRequest.onBeforeSendHeaders.removeListener(standardListener);
+      });
+      chrome.webRequest.onBeforeSendHeaders.addListener(standardListener,
+          {urls: [url]}, ['requestHeaders']);
+
+      testWebSocketConnection(url, true /* expectedToConnect */);
+    },
+
+    // Ensure that request headers which are added by net/ could be modified if
+    // the listener uses extraHeaders.
+    function testModifyRequestHeaders() {
+      var url = getWSTestURL(testWebSocketPort);
+
+      var beforeSendHeadersListener = callbackPass(function(details) {
+        // Test removal.
+        removeHeader(details.requestHeaders, 'accept-language');
+
+        // Test modification.
+        for (var i = 0; i < details.requestHeaders.length; i++) {
+          if (details.requestHeaders[i].name == 'User-Agent')
+            details.requestHeaders[i].value = 'Foo';
+        }
+
+        // Test addition.
+        details.requestHeaders.push({name: 'X-New-Header',
+                                     value: 'Bar'});
+
+        return {requestHeaders: details.requestHeaders};
+      });
+      chrome.webRequest.onBeforeSendHeaders.addListener(
+          beforeSendHeadersListener,
+          {urls: [url]}, ['requestHeaders', 'blocking', 'extraHeaders']);
+
+      var sendHeadersListener = callbackPass(function(details) {
+        checkHeaders(details.requestHeaders, ['x-new-header'],
+                     ['accept-language']);
+
+        var seen = false;
+        for (var i = 0; i < details.requestHeaders.length; i++) {
+          if (details.requestHeaders[i].name == 'User-Agent') {
+            chrome.test.assertEq(details.requestHeaders[i].value, 'Foo');
+            seen = true;
+          }
+        }
+        chrome.test.assertTrue(seen);
+
+        chrome.webRequest.onBeforeSendHeaders.removeListener(
+            beforeSendHeadersListener);
+        chrome.webRequest.onSendHeaders.removeListener(sendHeadersListener);
+      });
+      chrome.webRequest.onSendHeaders.addListener(sendHeadersListener,
+          {urls: [url]}, ['requestHeaders', 'extraHeaders']);
+
+      testWebSocketConnection(url, true /* expectedToConnect */);
+    },
+
+    // Ensure that response headers can be modified when extraHeaders is used.
+    function testModifyResponseHeaders() {
+      var url = getWSTestURL(testWebSocketPort);
+
+      var onHeadersReceivedHeadersListener = callbackPass(function(details) {
+        // Test addition.
+        details.responseHeaders.push({name: 'X-New-Header',
+                                      value: 'Bar'});
+
+        return {responseHeaders: details.responseHeaders};
+      });
+      chrome.webRequest.onHeadersReceived.addListener(
+          onHeadersReceivedHeadersListener,
+          {urls: [url]}, ['responseHeaders', 'blocking', 'extraHeaders']);
+
+      var onResponseStartedListener = callbackPass(function(details) {
+        checkHeaders(details.responseHeaders, ['x-new-header'], []);
+
+        chrome.webRequest.onHeadersReceived.removeListener(
+            onHeadersReceivedHeadersListener);
+        chrome.webRequest.onResponseStarted.removeListener(
+            onResponseStartedListener);
+      });
+      chrome.webRequest.onResponseStarted.addListener(onResponseStartedListener,
+          {urls: [url]}, ['responseHeaders', 'extraHeaders']);
+
+      testWebSocketConnection(url, true /* expectedToConnect */);
     },
   ], tab);
 });
diff --git a/chrome/test/data/webui/extensions/activity_log_stream_item_test.js b/chrome/test/data/webui/extensions/activity_log_stream_item_test.js
index b046151f..5cb94da2 100644
--- a/chrome/test/data/webui/extensions/activity_log_stream_item_test.js
+++ b/chrome/test/data/webui/extensions/activity_log_stream_item_test.js
@@ -37,33 +37,40 @@
     document.body.appendChild(activityLogStreamItem);
   });
 
-  test('item not expandable if it has no page URL or args', function() {
-    Polymer.dom.flush();
+  test(
+      'item not expandable if it has no page URL, args or web request info',
+      function() {
+        Polymer.dom.flush();
 
-    testVisible('#activity-item-main-row', true);
-    testVisible('cr-expand-button', false);
-  });
+        testVisible('#activity-item-main-row', true);
+        testVisible('cr-expand-button', false);
+      });
 
-  test('page URL and args visible when item is expanded', function() {
-    testStreamItem = {
-      id: 'testAPI.testMethod1550101623113',
-      name: 'testAPI.testMethod',
-      timestamp: 1550101623113,
-      activityType: chrome.activityLogPrivate.ExtensionActivityType.API_CALL,
-      pageUrl: 'example.url',
-      args: JSON.stringify([null]),
-    };
+  test(
+      'page URL, args and web request info visible when item is expanded',
+      function() {
+        testStreamItem = {
+          id: 'testAPI.testMethod1550101623113',
+          name: 'testAPI.testMethod',
+          timestamp: 1550101623113,
+          activityType:
+              chrome.activityLogPrivate.ExtensionActivityType.API_CALL,
+          pageUrl: 'example.url',
+          args: JSON.stringify([null]),
+          webRequestInfo: 'web request info'
+        };
 
-    activityLogStreamItem.set('data', testStreamItem);
+        activityLogStreamItem.set('data', testStreamItem);
 
-    Polymer.dom.flush();
-    testVisible('cr-expand-button', true);
-    activityLogStreamItem.$$('cr-expand-button').click();
+        Polymer.dom.flush();
+        testVisible('cr-expand-button', true);
+        activityLogStreamItem.$$('cr-expand-button').click();
 
-    Polymer.dom.flush();
-    testVisible('#page-url-link', true);
-    testVisible('#args-list', true);
-  });
+        Polymer.dom.flush();
+        testVisible('#page-url-link', true);
+        testVisible('#args-list', true);
+        testVisible('#web-request-section', true);
+      });
 
   test('placeholder arg values are replaced by the argUrl', function() {
     const argUrl = 'arg.url';
@@ -83,7 +90,7 @@
         "${escapedPlaceholder}",
         ["${placeholder}"],
         {"url":"${escapedPlaceholder}"}
-      ]`
+      ]`,
     };
 
     activityLogStreamItem.set('data', testStreamItem);
diff --git a/chrome/test/data/webui/settings/crostini_page_test.js b/chrome/test/data/webui/settings/crostini_page_test.js
index d6cea68..2663fc4 100644
--- a/chrome/test/data/webui/settings/crostini_page_test.js
+++ b/chrome/test/data/webui/settings/crostini_page_test.js
@@ -84,13 +84,24 @@
         showCrostiniExportImport: true,
       });
 
+      let eventPromise = new Promise((resolve) => {
+                           let v = cr.addWebUIListener(
+                               'crostini-installer-status-changed', () => {
+                                 resolve(v);
+                               });
+                         }).then((v) => {
+        assertTrue(cr.removeWebUIListener(v));
+      });
+
       settings.navigateTo(settings.routes.CROSTINI);
       crostiniPage.$$('#crostini').click();
-      return flushAsync().then(() => {
+
+      let pageLoadPromise = flushAsync().then(() => {
         subpage = crostiniPage.$$('settings-crostini-subpage');
-        subpage.hideCrostiniUninstall_ = false;
         assertTrue(!!subpage);
       });
+
+      return Promise.all([pageLoadPromise, eventPromise]);
     });
 
     test('Sanity', function() {
@@ -134,6 +145,23 @@
       });
     });
 
+    test('RemoveHidden', function() {
+      // Elements are not destroyed when a dom-if stops being shown, but we can
+      // check if their rendered width is non-zero. This should be resilient
+      // against most formatting changes, since we're not relying on them having
+      // any exact size, or on Polymer using any particular means of hiding
+      // elements.
+      assertTrue(!!subpage.shadowRoot.querySelector('#remove').clientWidth);
+      cr.webUIListenerCallback('crostini-installer-status-changed', true);
+      return flushAsync().then(() => {
+        assertFalse(!!subpage.shadowRoot.querySelector('#remove').clientWidth);
+        cr.webUIListenerCallback('crostini-installer-status-changed', false);
+        return flushAsync().then(() => {
+          assertTrue(!!subpage.shadowRoot.querySelector('#remove').clientWidth);
+        });
+      });
+    });
+
     test('HideOnDisable', function() {
       assertEquals(
           settings.getCurrentRoute(), settings.routes.CROSTINI_DETAILS);
diff --git a/chrome/test/data/webui/settings/payments_section_test.js b/chrome/test/data/webui/settings/payments_section_test.js
index 8f1c6489..ccb978b 100644
--- a/chrome/test/data/webui/settings/payments_section_test.js
+++ b/chrome/test/data/webui/settings/payments_section_test.js
@@ -28,6 +28,11 @@
       PolymerTest.clearBody();
       loadTimeData.overrideValues({
         migrationEnabled: true,
+        hasGooglePaymentsAccount: true,
+        upstreamEnabled: true,
+        isUsingSecondaryPassphrase: false,
+        uploadToGoogleActive: true,
+        userEmailDomainAllowed: true,
       });
     });
 
@@ -404,7 +409,8 @@
     });
 
     test('verifyMigrationButtonNotShownIfMigrationNotEnabled', function() {
-      // Mock prerequisites are not met.
+      // Mock the Google Payments account. Disable the migration experimental
+      // flag. Won't show migration button.
       loadTimeData.overrideValues({migrationEnabled: false});
 
       // Add one migratable credit card.
@@ -413,31 +419,196 @@
       const section = createPaymentsSection(
           [creditCard], {credit_card_enabled: {value: true}});
 
+      // Simulate Signed-in and Synced status.
+      sync_test_util.simulateSyncStatus({
+        signedIn: true,
+        syncSystemEnabled: true,
+      });
+
+      // All migration requirements are met but migration experimental flag is
+      // not enabled, verify migration button is hidden.
       assertTrue(section.$$('#migrateCreditCards').hidden);
     });
 
-    test('verifyMigrationButtonNotShownIfCreditCardDisabled', function() {
+    test('verifyMigrationButtonNotShownIfNotSignedIn', function() {
       // Add one migratable credit card.
       const creditCard = FakeDataMaker.creditCardEntry();
       creditCard.metadata.isMigratable = true;
-      // Mock credit card save toggle is turned off by users.
       const section = createPaymentsSection(
-          [creditCard], {credit_card_enabled: {value: false}});
+          [creditCard], {credit_card_enabled: {value: true}});
 
+      // Simulate not Signed-in status. Won't show migration button.
+      sync_test_util.simulateSyncStatus({
+        signedIn: false,
+        syncSystemEnabled: true,
+      });
+
+      // All migration requirements are met but not signed in, verify migration
+      // button is hidden.
       assertTrue(section.$$('#migrateCreditCards').hidden);
     });
 
-    test('verifyMigrationButtonNotShownIfNoCardIsMigratable', function() {
+    test('verifyMigrationButtonNotShownIfNotSynced', function() {
       // Add one migratable credit card.
       const creditCard = FakeDataMaker.creditCardEntry();
-      // Mock credit card is not valid.
+      creditCard.metadata.isMigratable = true;
+      const section = createPaymentsSection(
+          [creditCard], {credit_card_enabled: {value: true}});
+
+      // Simulate not Synced status. Won't show migration button.
+      sync_test_util.simulateSyncStatus({
+        signedIn: true,
+        syncSystemEnabled: false,
+      });
+
+      // All migration requirements are met but not Synced, verify migration
+      // button is hidden.
+      assertTrue(section.$$('#migrateCreditCards').hidden);
+    });
+
+    test('verifyMigrationButtonNotShownIfNoMigratableCard', function() {
+      // Add one credit card but not migratable. Won't show migration button.
+      const creditCard = FakeDataMaker.creditCardEntry();
       creditCard.metadata.isMigratable = false;
       const section = createPaymentsSection(
           [creditCard], {credit_card_enabled: {value: true}});
 
+      // Simulate Signed-in and Synced status.
+      sync_test_util.simulateSyncStatus({
+        signedIn: true,
+        syncSystemEnabled: true,
+      });
+
+      // All migration requirements are met but no migratable credi card, verify
+      // migration button is hidden.
       assertTrue(section.$$('#migrateCreditCards').hidden);
     });
 
+    test('verifyMigrationButtonNotShownWhenCreditCardDisabled', function() {
+      // Add one migratable credit card.
+      const creditCard = FakeDataMaker.creditCardEntry();
+      creditCard.metadata.isMigratable = true;
+      const section = createPaymentsSection(
+          [creditCard], {credit_card_enabled: {value: false}});
+
+      // Simulate Signed-in and Synced status.
+      sync_test_util.simulateSyncStatus({
+        signedIn: true,
+        syncSystemEnabled: true,
+      });
+
+      // All migration requirements are met but credit card is disable, verify
+      // migration button is hidden.
+      assertTrue(section.$$('#migrateCreditCards').hidden);
+    });
+
+    test('verifyMigrationButtonNotShownIfNoGooglePaymentsAccount', function() {
+      // Mocks no Google payments account. Won't show migration button.
+      loadTimeData.overrideValues({hasGooglePaymentsAccount: false});
+
+      // Add one migratable credit card.
+      const creditCard = FakeDataMaker.creditCardEntry();
+      creditCard.metadata.isMigratable = true;
+      const section = createPaymentsSection(
+          [creditCard], {credit_card_enabled: {value: true}});
+
+      // Simulate Signed-in and Synced status.
+      sync_test_util.simulateSyncStatus({
+        signedIn: true,
+        syncSystemEnabled: true,
+      });
+
+      // All migration requirements are met but no Google Payments account,
+      // verify migration button is hidden.
+      assertTrue(section.$$('#migrateCreditCards').hidden);
+    });
+
+    test('verifyMigrationButtonNotShownIfAutofillUpstreamDisabled', function() {
+      loadTimeData.overrideValues({upstreamEnabled: false});
+
+      // Add one migratable credit card.
+      const creditCard = FakeDataMaker.creditCardEntry();
+      creditCard.metadata.isMigratable = true;
+      const section = createPaymentsSection(
+          [creditCard], {credit_card_enabled: {value: true}});
+
+      // Simulate Signed-in and Synced status.
+      sync_test_util.simulateSyncStatus({
+        signedIn: true,
+        syncSystemEnabled: true,
+      });
+
+      // All migration requirements are met but Autofill Upstream is disabled,
+      // verify migration button is hidden.
+      assertTrue(section.$$('#migrateCreditCards').hidden);
+    });
+
+    test(
+        'verifyMigrationButtonNotShownIfUserHasSecondaryPassphrase',
+        function() {
+          loadTimeData.overrideValues({isUsingSecondaryPassphrase: true});
+
+          // Add one migratable credit card.
+          const creditCard = FakeDataMaker.creditCardEntry();
+          creditCard.metadata.isMigratable = true;
+          const section = createPaymentsSection(
+              [creditCard], {credit_card_enabled: {value: true}});
+
+          // Simulate Signed-in and Synced status.
+          sync_test_util.simulateSyncStatus({
+            signedIn: true,
+            syncSystemEnabled: true,
+          });
+
+          // All migration requirements are met but the user has a secondary
+          // passphrase, verify migration button is hidden.
+          assertTrue(section.$$('#migrateCreditCards').hidden);
+        });
+
+    test(
+        'verifyMigrationButtonNotShownIfUploadToGoogleStateIsInactive',
+        function() {
+          loadTimeData.overrideValues({uploadToGoogleActive: false});
+
+          // Add one migratable credit card.
+          const creditCard = FakeDataMaker.creditCardEntry();
+          creditCard.metadata.isMigratable = true;
+          const section = createPaymentsSection(
+              [creditCard], {credit_card_enabled: {value: true}});
+
+          // Simulate Signed-in and Synced status.
+          sync_test_util.simulateSyncStatus({
+            signedIn: true,
+            syncSystemEnabled: true,
+          });
+
+          // All migration requirements are met but upload to Google is
+          // inactive, verify migration button is hidden.
+          assertTrue(section.$$('#migrateCreditCards').hidden);
+        });
+
+    test(
+        'verifyMigrationButtonNotShownIfUserEmailDomainIsNotAllowed',
+        function() {
+          loadTimeData.overrideValues({userEmailDomainAllowed: false});
+
+          // Add one migratable credit card.
+          const creditCard = FakeDataMaker.creditCardEntry();
+          creditCard.metadata.isMigratable = true;
+          const section = createPaymentsSection(
+              [creditCard], {credit_card_enabled: {value: true}});
+
+          // Simulate Signed-in and Synced status.
+          sync_test_util.simulateSyncStatus({
+            signedIn: true,
+            syncSystemEnabled: true,
+          });
+
+          // All migration requirements are met but the user's email domain is
+          // not allowed, verify migration button is hidden.
+          assertTrue(section.$$('#migrateCreditCards').hidden);
+        });
+
     test('verifyMigrationButtonShown', function() {
       // Add one migratable credit card.
       const creditCard = FakeDataMaker.creditCardEntry();
@@ -445,6 +616,13 @@
       const section = createPaymentsSection(
           [creditCard], {credit_card_enabled: {value: true}});
 
+      // Simulate Signed-in and Synced status.
+      sync_test_util.simulateSyncStatus({
+        signedIn: true,
+        syncSystemEnabled: true,
+      });
+
+      // All migration requirements are met, verify migration button is shown.
       assertFalse(section.$$('#migrateCreditCards').hidden);
     });
   });
diff --git a/chrome/test/data/webui/settings/test_crostini_browser_proxy.js b/chrome/test/data/webui/settings/test_crostini_browser_proxy.js
index 660b3a2..6be2f10 100644
--- a/chrome/test/data/webui/settings/test_crostini_browser_proxy.js
+++ b/chrome/test/data/webui/settings/test_crostini_browser_proxy.js
@@ -39,6 +39,10 @@
   removeCrostiniSharedPath(path) {
     this.sharedPaths = this.sharedPaths.filter(p => p !== path);
   }
+  /** @override */
+  requestCrostiniInstallerStatus() {
+    cr.webUIListenerCallback('crostini-installer-status-changed', false);
+  }
 
   /** override */
   exportCrostiniContainer() {
diff --git a/chromeos/services/assistant/media_session/assistant_media_session.cc b/chromeos/services/assistant/media_session/assistant_media_session.cc
index 8465570..26e3a08 100644
--- a/chromeos/services/assistant/media_session/assistant_media_session.cc
+++ b/chromeos/services/assistant/media_session/assistant_media_session.cc
@@ -65,7 +65,7 @@
   audio_focus_ptr_->RequestAudioFocus(
       mojo::MakeRequest(&request_client_ptr_), std::move(media_session),
       GetMediaSessionInfoInternal(), audio_focus_type,
-      base::BindOnce(&AssistantMediaSession::FinishAudioFocusRequest,
+      base::BindOnce(&AssistantMediaSession::FinishInitialAudioFocusRequest,
                      base::Unretained(this), audio_focus_type));
 }
 
@@ -108,6 +108,12 @@
   SetAudioFocusState(State::ACTIVE);
 }
 
+void AssistantMediaSession::FinishInitialAudioFocusRequest(
+    AudioFocusType audio_focus_type,
+    const base::UnguessableToken& request_id) {
+  FinishAudioFocusRequest(audio_focus_type);
+}
+
 void AssistantMediaSession::SetAudioFocusState(State audio_focus_state) {
   if (audio_focus_state == audio_focus_state_)
     return;
diff --git a/chromeos/services/assistant/media_session/assistant_media_session.h b/chromeos/services/assistant/media_session/assistant_media_session.h
index 7b0e3eb..680be60 100644
--- a/chromeos/services/assistant/media_session/assistant_media_session.h
+++ b/chromeos/services/assistant/media_session/assistant_media_session.h
@@ -58,6 +58,8 @@
 
   // Called by AudioFocusManager when an async audio focus request is completed.
   void FinishAudioFocusRequest(media_session::mojom::AudioFocusType type);
+  void FinishInitialAudioFocusRequest(media_session::mojom::AudioFocusType type,
+                                      const base::UnguessableToken& request_id);
 
   // Returns information about |this|.
   media_session::mojom::MediaSessionInfoPtr GetMediaSessionInfoInternal();
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc
index 8c1ed0d..ffc1f9c 100644
--- a/components/autofill/core/browser/autofill_experiments.cc
+++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -12,8 +12,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "components/autofill/core/browser/payments/payments_util.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/suggestion.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_prefs.h"
@@ -106,36 +104,6 @@
   return base::FeatureList::IsEnabled(features::kAutofillUpstream);
 }
 
-bool IsCreditCardMigrationEnabled(PersonalDataManager* personal_data_manager,
-                                  PrefService* pref_service,
-                                  syncer::SyncService* sync_service) {
-  // Confirm that experiment flags are enabled.
-  bool migration_experiment_enabled =
-      features::GetLocalCardMigrationExperimentalFlag() !=
-      features::LocalCardMigrationExperimentalFlag::kMigrationDisabled;
-
-  bool credit_card_upload_enabled = IsCreditCardUploadEnabled(
-      pref_service, sync_service,
-      personal_data_manager->GetAccountInfoForPaymentsServer().email);
-
-  bool has_google_payments_account =
-      autofill::payments::HasGooglePaymentsAccount(personal_data_manager,
-                                                   pref_service);
-
-  AutofillSyncSigninState sync_state =
-      personal_data_manager->GetSyncSigninState();
-
-  return migration_experiment_enabled && credit_card_upload_enabled &&
-         has_google_payments_account &&
-         // User signed-in and turned sync on.
-         (sync_state == AutofillSyncSigninState::kSignedInAndSyncFeature ||
-          // User signed-in but not turned on sync.
-          (sync_state == AutofillSyncSigninState::
-                             kSignedInAndWalletSyncTransportEnabled &&
-           base::FeatureList::IsEnabled(
-               features::kAutofillEnableLocalCardMigrationForNonSyncUser)));
-}
-
 bool IsInAutofillSuggestionsDisabledExperiment() {
   std::string group_name =
       base::FieldTrialList::FindFullName("AutofillEnabled");
diff --git a/components/autofill/core/browser/autofill_experiments.h b/components/autofill/core/browser/autofill_experiments.h
index c5421e5..d4247999 100644
--- a/components/autofill/core/browser/autofill_experiments.h
+++ b/components/autofill/core/browser/autofill_experiments.h
@@ -22,8 +22,6 @@
 
 namespace autofill {
 
-class PersonalDataManager;
-
 // Parameterized Features (grouped with parameter name and options)
 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
 extern const base::Feature kAutofillDropdownLayoutExperiment;
@@ -40,11 +38,6 @@
                                const syncer::SyncService* sync_service,
                                const std::string& user_email);
 
-// Returns true if autofill local card migration flow is enabled.
-bool IsCreditCardMigrationEnabled(PersonalDataManager* personal_data_manager,
-                                  PrefService* pref_service,
-                                  syncer::SyncService* sync_service);
-
 // Returns true if autofill suggestions are disabled via experiment. The
 // disabled experiment isn't the same as disabling autofill completely since we
 // still want to run detection code for metrics purposes. This experiment just
diff --git a/components/autofill/core/browser/payments/local_card_migration_manager.cc b/components/autofill/core/browser/payments/local_card_migration_manager.cc
index 2db9d14b..682ea01f 100644
--- a/components/autofill/core/browser/payments/local_card_migration_manager.cc
+++ b/components/autofill/core/browser/payments/local_card_migration_manager.cc
@@ -190,8 +190,38 @@
 }
 
 bool LocalCardMigrationManager::IsCreditCardMigrationEnabled() {
-  return ::autofill::IsCreditCardMigrationEnabled(
-      personal_data_manager_, client_->GetPrefs(), client_->GetSyncService());
+  // Confirm that the user is signed in, syncing, and the proper experiment
+  // flags are enabled.
+  bool migration_experiment_enabled =
+      features::GetLocalCardMigrationExperimentalFlag() !=
+      features::LocalCardMigrationExperimentalFlag::kMigrationDisabled;
+
+  // If |observer_for_testing_| is set, assume we are in a browsertest and
+  // credit card upload should be enabled by default. Cannot get around this as
+  // Chrome OS testing requires an unsupported email domain (i.e.
+  // stub-user@example.com).
+  bool credit_card_upload_enabled =
+      observer_for_testing_ ||
+      ::autofill::IsCreditCardUploadEnabled(
+          client_->GetPrefs(), client_->GetSyncService(),
+          personal_data_manager_->GetAccountInfoForPaymentsServer().email);
+
+  bool has_google_payments_account =
+      (payments::GetBillingCustomerId(personal_data_manager_,
+                                      payments_client_->GetPrefService()) != 0);
+
+  AutofillSyncSigninState sync_state =
+      personal_data_manager_->GetSyncSigninState();
+
+  return migration_experiment_enabled && credit_card_upload_enabled &&
+         has_google_payments_account &&
+         // User signed-in and turned sync on.
+         (sync_state == AutofillSyncSigninState::kSignedInAndSyncFeature ||
+          // User signed-in but not turned on sync.
+          (sync_state == AutofillSyncSigninState::
+                             kSignedInAndWalletSyncTransportEnabled &&
+           base::FeatureList::IsEnabled(
+               features::kAutofillEnableLocalCardMigrationForNonSyncUser)));
 }
 
 void LocalCardMigrationManager::OnDidGetUploadDetails(
diff --git a/components/autofill/core/browser/payments/payments_util.cc b/components/autofill/core/browser/payments/payments_util.cc
index d14da33..51beb60 100644
--- a/components/autofill/core/browser/payments/payments_util.cc
+++ b/components/autofill/core/browser/payments/payments_util.cc
@@ -17,10 +17,6 @@
 namespace autofill {
 namespace payments {
 
-namespace {
-constexpr int kCustomerHasNoProfileBillingNumber = 0;
-}
-
 int64_t GetBillingCustomerId(PersonalDataManager* personal_data_manager,
                              PrefService* pref_service,
                              bool should_log_validity) {
@@ -62,11 +58,5 @@
       pref_service->GetDouble(prefs::kAutofillBillingCustomerNumber));
 }
 
-bool HasGooglePaymentsAccount(PersonalDataManager* personal_data_manager,
-                              PrefService* pref_service) {
-  return GetBillingCustomerId(personal_data_manager, pref_service) !=
-         kCustomerHasNoProfileBillingNumber;
-}
-
 }  // namespace payments
 }  // namespace autofill
diff --git a/components/autofill/core/browser/payments/payments_util.h b/components/autofill/core/browser/payments/payments_util.h
index 7e099f0f..aeca52b 100644
--- a/components/autofill/core/browser/payments/payments_util.h
+++ b/components/autofill/core/browser/payments/payments_util.h
@@ -23,10 +23,6 @@
                              PrefService* pref_service,
                              bool should_log_validity = false);
 
-// Returns if the customer has an existing Google payments account.
-bool HasGooglePaymentsAccount(PersonalDataManager* personal_data_manager,
-                              PrefService* pref_service);
-
 }  // namespace payments
 }  // namespace autofill
 
diff --git a/components/autofill/core/browser/payments/payments_util_unittest.cc b/components/autofill/core/browser/payments/payments_util_unittest.cc
index 073e30e..9ce775c 100644
--- a/components/autofill/core/browser/payments/payments_util_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_util_unittest.cc
@@ -75,8 +75,8 @@
       features::kAutofillUsePaymentsCustomerData);
   base::HistogramTester histogram_tester;
 
-  // Explicitly do not set PaymentsCustomerData. Nothing crashes and the
-  // returned customer ID is 0.
+  // Explictly do not set PaymentsCustomerData. Nothing crashes and the returned
+  // customer ID is 0.
   EXPECT_EQ(0, GetBillingCustomerId(&personal_data_manager_, &pref_service_,
                                     /*should_log_validity=*/true));
   histogram_tester.ExpectUniqueSample(
@@ -90,7 +90,7 @@
       features::kAutofillUsePaymentsCustomerData);
   base::HistogramTester histogram_tester;
 
-  // Explicitly do not set PaymentsCustomerData but set a fallback to prefs.
+  // Explictly do not set PaymentsCustomerData but set a fallback to prefs.
   pref_service_.SetDouble(prefs::kAutofillBillingCustomerNumber, 123456.0);
 
   // We got the data from prefs and log that the PaymentsCustomerData is
@@ -118,30 +118,11 @@
   scoped_feature_list_.InitAndDisableFeature(
       features::kAutofillUsePaymentsCustomerData);
 
-  // Explicitly do not set Prefs data. Nothing crashes and the returned customer
+  // Explictly do not set Prefs data. Nothing crashes and the returned customer
   // ID is 0.
   EXPECT_EQ(0, GetBillingCustomerId(&personal_data_manager_, &pref_service_,
                                     /*should_log_validity=*/true));
 }
 
-TEST_F(PaymentsUtilTest, HasGooglePaymentsAccount_Normal) {
-  scoped_feature_list_.InitAndDisableFeature(
-      features::kAutofillUsePaymentsCustomerData);
-
-  pref_service_.SetDouble(prefs::kAutofillBillingCustomerNumber, 123456.0);
-
-  EXPECT_TRUE(
-      HasGooglePaymentsAccount(&personal_data_manager_, &pref_service_));
-}
-
-TEST_F(PaymentsUtilTest, HasGooglePaymentsAccount_NoData) {
-  scoped_feature_list_.InitAndDisableFeature(
-      features::kAutofillUsePaymentsCustomerData);
-
-  // Explicitly do not set Prefs data. Nothing crashes and returns false.
-  EXPECT_FALSE(
-      HasGooglePaymentsAccount(&personal_data_manager_, &pref_service_));
-}
-
 }  // namespace payments
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
index cbbf98e..203acff 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
@@ -400,6 +400,14 @@
     std::vector<AutofillProfile> wallet_addresses,
     bool log_diff,
     bool notify_metadata_bridge) {
+  // We do not have to CopyRelevantWalletMetadataFromDisk() because we will
+  // never overwrite the same entity with different data (server_id is generated
+  // based on content so addresses have the same server_id iff they have the
+  // same content). For that reason it is impossible to issue a DELETE and ADD
+  // for the same entity just because some of its fields got changed. As a
+  // result, we do not need to care to have up-to-date use stats for cards
+  // because we never notify on an existing one.
+
   // In the common case, the database won't have changed. Committing an update
   // to the database will require at least one DB page write and will schedule
   // a fsync. To avoid this I/O, it should be more efficient to do a read and
@@ -498,8 +506,11 @@
   std::sort(old_ptrs.begin(), old_ptrs.end(), compare);
   std::sort(new_ptrs.begin(), new_ptrs.end(), compare);
 
-  // Walk over both of them and count added/removed elements.
   AutofillWalletDiff<Item> result;
+  // We collect ADD changes separately to ensure proper order.
+  std::vector<AutofillDataModelChange<Item>> add_changes;
+
+  // Walk over both of them and count added/removed elements.
   auto old_it = old_ptrs.begin();
   auto new_it = new_ptrs.begin();
   while (old_it != old_ptrs.end() || new_it != new_ptrs.end()) {
@@ -522,12 +533,18 @@
       ++new_it;
     } else {
       ++result.items_added;
-      result.changes.emplace_back(AutofillDataModelChange<Item>::ADD,
-                                  (*new_it)->server_id(), *new_it);
+      add_changes.emplace_back(AutofillDataModelChange<Item>::ADD,
+                               (*new_it)->server_id(), *new_it);
       ++new_it;
     }
   }
 
+  // Append ADD changes to make sure they all come after all REMOVE changes.
+  // Since we CopyRelevantWalletMetadataFromDisk(), the ADD contains all current
+  // metadata if we happen to REMOVE and ADD the same entity.
+  result.changes.insert(result.changes.end(), add_changes.begin(),
+                        add_changes.end());
+
   DCHECK_EQ(old_data.size() + result.items_added - result.items_removed,
             new_data.size());
 
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 16d9522..ad41647d 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -1119,19 +1119,19 @@
         return;
       }
     }
-    } else {
-      if (logger)
-        logger->LogMessage(Logger::STRING_PROVISIONALLY_SAVED_FORM_IS_NOT_HTML);
-    }
+  } else {
+    if (logger)
+      logger->LogMessage(Logger::STRING_PROVISIONALLY_SAVED_FORM_IS_NOT_HTML);
+  }
 
-    // Clear all_visible_forms_ after checking all the visible forms.
-    all_visible_forms_.clear();
+  // Clear all_visible_forms_ after checking all the visible forms.
+  all_visible_forms_.clear();
 
-    // Looks like a successful login attempt. Either show an infobar or
-    // automatically save the login data. We prompt when the user hasn't
-    // already given consent, either through previously accepting the infobar
-    // or by having the browser generate the password.
-    OnLoginSuccessful();
+  // Looks like a successful login attempt. Either show an infobar or
+  // automatically save the login data. We prompt when the user hasn't
+  // already given consent, either through previously accepting the infobar
+  // or by having the browser generate the password.
+  OnLoginSuccessful();
 }
 
 void PasswordManager::OnLoginSuccessful() {
diff --git a/components/policy/core/common/cloud/enterprise_metrics.cc b/components/policy/core/common/cloud/enterprise_metrics.cc
index 79748736..08da70c 100644
--- a/components/policy/core/common/cloud/enterprise_metrics.cc
+++ b/components/policy/core/common/cloud/enterprise_metrics.cc
@@ -6,8 +6,6 @@
 
 namespace policy {
 
-const char kMetricToken[] = "Enterprise.DMToken";
-const char kMetricPolicy[] = "Enterprise.Policy";
 const char kMetricUserPolicyRefresh[] = "Enterprise.PolicyRefresh";
 const char kMetricUserPolicyInvalidations[] = "Enterprise.PolicyInvalidations";
 const char kMetricUserPolicyChromeOSSessionAbort[] =
diff --git a/components/policy/core/common/cloud/enterprise_metrics.h b/components/policy/core/common/cloud/enterprise_metrics.h
index 3d11908..d9a4a8c 100644
--- a/components/policy/core/common/cloud/enterprise_metrics.h
+++ b/components/policy/core/common/cloud/enterprise_metrics.h
@@ -12,109 +12,6 @@
 
 // Metrics collected for enterprise events.
 
-// Events related to fetching, saving and loading DM server tokens.
-// These metrics are collected both for device and user tokens.
-// This enum is used to define the buckets for an enumerated UMA histogram.
-// Hence,
-//   (a) existing enumerated constants should never be deleted or reordered, and
-//   (b) new constants should only be appended at the end of the enumeration
-//       (update tools/metrics/histograms/enums.xml as well).
-enum MetricToken {
-  // A cached token was successfully loaded from disk.
-  kMetricTokenLoadSucceeded = 0,
-  // Reading a cached token from disk failed.
-  kMetricTokenLoadFailed = 1,
-
-  // A token fetch request was sent to the DM server.
-  kMetricTokenFetchRequested = 2,
-  // The request was invalid, or the HTTP request failed.
-  kMetricTokenFetchRequestFailed = 3,
-  // Error HTTP status received, or the DM server failed in another way.
-  kMetricTokenFetchServerFailed = 4,
-  // A response to the fetch request was received.
-  kMetricTokenFetchResponseReceived = 5,
-  // The response received was invalid. This happens when some expected data
-  // was not present in the response.
-  kMetricTokenFetchBadResponse = 6,
-  // DM server reported that management is not supported.
-  kMetricTokenFetchManagementNotSupported = 7,
-  // DM server reported that the given device ID was not found.
-  kMetricTokenFetchDeviceNotFound = 8,
-  // DM token successfully retrieved.
-  kMetricTokenFetchOK = 9,
-
-  // Successfully cached a token to disk.
-  kMetricTokenStoreSucceeded = 10,
-  // Caching a token to disk failed.
-  kMetricTokenStoreFailed = 11,
-
-  // DM server reported that the device-id generated is not unique.
-  kMetricTokenFetchDeviceIdConflict = 12,
-  // DM server reported that the serial number we try to register is invalid.
-  kMetricTokenFetchInvalidSerialNumber = 13,
-  // DM server reported that the licenses for the domain have expired or been
-  // exhausted.
-  kMetricMissingLicenses = 14,
-
-  kMetricTokenSize  // Must be the last.
-};
-
-// Events related to fetching, saving and loading user and device policies.
-// This enum is used to define the buckets for an enumerated UMA histogram.
-// Hence,
-//   (a) existing enumerated constants should never be deleted or reordered, and
-//   (b) new constants should only be appended at the end of the enumeration
-//       (update tools/metrics/histograms/enums.xml as well).
-enum MetricPolicy {
-  // A cached policy was successfully loaded from disk.
-  kMetricPolicyLoadSucceeded = 0,
-  // Reading a cached policy from disk failed.
-  kMetricPolicyLoadFailed = 1,
-
-  // A policy fetch request was sent to the DM server.
-  kMetricPolicyFetchRequested = 2,
-  // The request was invalid, or the HTTP request failed.
-  kMetricPolicyFetchRequestFailed = 3,
-  // Error HTTP status received, or the DM server failed in another way.
-  kMetricPolicyFetchServerFailed = 4,
-  // Policy not found for the given user or device.
-  kMetricPolicyFetchNotFound = 5,
-  // DM server didn't accept the token used in the request.
-  kMetricPolicyFetchInvalidToken = 6,
-  // A response to the policy fetch request was received.
-  kMetricPolicyFetchResponseReceived = 7,
-  // The policy response message didn't contain a policy, or other data was
-  // missing.
-  kMetricPolicyFetchBadResponse = 8,
-  // Failed to decode the policy.
-  kMetricPolicyFetchInvalidPolicy = 9,
-  // The device policy was rejected because its signature was invalid.
-  kMetricPolicyFetchBadSignature = 10,
-  // Rejected policy because its timestamp is in the future.
-  kMetricPolicyFetchTimestampInFuture = 11,
-  // Device policy rejected because the device is not managed.
-  kMetricPolicyFetchNonEnterpriseDevice = 12,
-  // The policy was provided for a username that is different from the device
-  // owner, and the policy was rejected.
-  kMetricPolicyFetchUserMismatch = 13,
-  // The policy was rejected for another reason. Currently this can happen
-  // only for device policies, when the SignedSettings fail to store or retrieve
-  // a stored policy.
-  kMetricPolicyFetchOtherFailed = 14,
-  // The fetched policy was accepted.
-  kMetricPolicyFetchOK = 15,
-  // The policy just fetched didn't have any changes compared to the cached
-  // policy.
-  kMetricPolicyFetchNotModified = 16,
-
-  // Successfully cached a policy to disk.
-  kMetricPolicyStoreSucceeded = 17,
-  // Caching a policy to disk failed.
-  kMetricPolicyStoreFailed = 18,
-
-  kMetricPolicySize  // Must be the last.
-};
-
 // Events related to device enrollment.
 // This enum is used to define the buckets for an enumerated UMA histogram.
 // Hence,
@@ -316,8 +213,6 @@
 // Names for the UMA counters. They are shared from here since the events
 // from the same enum above can be triggered in different files, and must use
 // the same UMA histogram name.
-POLICY_EXPORT extern const char kMetricToken[];
-POLICY_EXPORT extern const char kMetricPolicy[];
 POLICY_EXPORT extern const char kMetricUserPolicyRefresh[];
 POLICY_EXPORT extern const char kMetricUserPolicyInvalidations[];
 POLICY_EXPORT extern const char kMetricUserPolicyChromeOSSessionAbort[];
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index c5aa6b7b..74ecd97 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -13,6 +13,7 @@
 #include "base/command_line.h"
 #include "base/containers/queue.h"
 #include "base/debug/alias.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/hash.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
@@ -4544,6 +4545,33 @@
       FrameMsg_Navigate_Type::IsSameDocument(common_params.navigation_type) ||
       !IsURLHandledByNetworkStack(common_params.url));
 
+  // If this is an attempt to commit a URL in an incompatible process, capture a
+  // crash dump to diagnose why it is occurring.
+  // TODO(creis): Remove this check after we've gathered enough information to
+  // debug issues with browser-side security checks. https://crbug.com/931895.
+  auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
+  const GURL& lock_url = GetSiteInstance()->lock_url();
+  if (lock_url != GURL(kUnreachableWebDataURL) &&
+      common_params.url.IsStandard() &&
+      !policy->CanAccessDataForOrigin(GetProcess()->GetID(),
+                                      common_params.url)) {
+    base::debug::SetCrashKeyString(
+        base::debug::AllocateCrashKeyString("lock_url",
+                                            base::debug::CrashKeySize::Size64),
+        lock_url.spec());
+    base::debug::SetCrashKeyString(
+        base::debug::AllocateCrashKeyString("commit_origin",
+                                            base::debug::CrashKeySize::Size64),
+        common_params.url.GetOrigin().spec());
+    base::debug::SetCrashKeyString(
+        base::debug::AllocateCrashKeyString("is_main_frame",
+                                            base::debug::CrashKeySize::Size32),
+        frame_tree_node_->IsMainFrame() ? "true" : "false");
+    NOTREACHED() << "Commiting in incompatible process for URL: " << lock_url
+                 << " lock vs " << common_params.url.GetOrigin();
+    base::debug::DumpWithoutCrashing();
+  }
+
   const bool is_first_navigation = !has_committed_any_navigation_;
   has_committed_any_navigation_ = true;
 
@@ -5645,15 +5673,17 @@
 void RenderFrameHostImpl::CreateWebSocket(
     network::mojom::WebSocketRequest request) {
   network::mojom::AuthenticationHandlerPtr auth_handler;
-  GetContentClient()->browser()->WillCreateWebSocket(this, &request,
-                                                     &auth_handler);
+
+  network::mojom::TrustedHeaderClientPtr header_client;
+  GetContentClient()->browser()->WillCreateWebSocket(
+      this, &request, &auth_handler, &header_client);
 
   // This is to support usage of WebSockets in cases in which there is an
   // associated RenderFrame. This is important for showing the correct security
   // state of the page and also honoring user override of bad certificates.
   WebSocketManager::CreateWebSocket(
       process_->GetID(), routing_id_, last_committed_origin_,
-      std::move(auth_handler), std::move(request));
+      std::move(auth_handler), std::move(header_client), std::move(request));
 }
 
 void RenderFrameHostImpl::CreateDedicatedWorkerHostFactory(
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index ad9bf0b..998cab75 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -710,6 +710,37 @@
     GetNavigatingWebUI()->RenderFrameCreated(navigation_rfh);
   }
 
+  // If this function picked an incompatible process for the URL, capture a
+  // crash dump to diagnose why it is occurring.
+  // TODO(creis): Remove this check after we've gathered enough information to
+  // debug issues with browser-side security checks. https://crbug.com/931895.
+  auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
+  const GURL& lock_url = navigation_rfh->GetSiteInstance()->lock_url();
+  if (lock_url != GURL(kUnreachableWebDataURL) &&
+      request.common_params().url.IsStandard() &&
+      !policy->CanAccessDataForOrigin(navigation_rfh->GetProcess()->GetID(),
+                                      request.common_params().url)) {
+    base::debug::SetCrashKeyString(
+        base::debug::AllocateCrashKeyString("lock_url",
+                                            base::debug::CrashKeySize::Size64),
+        lock_url.spec());
+    base::debug::SetCrashKeyString(
+        base::debug::AllocateCrashKeyString("commit_origin",
+                                            base::debug::CrashKeySize::Size64),
+        request.common_params().url.GetOrigin().spec());
+    base::debug::SetCrashKeyString(
+        base::debug::AllocateCrashKeyString("is_main_frame",
+                                            base::debug::CrashKeySize::Size32),
+        frame_tree_node_->IsMainFrame() ? "true" : "false");
+    base::debug::SetCrashKeyString(
+        base::debug::AllocateCrashKeyString("use_current_rfh",
+                                            base::debug::CrashKeySize::Size32),
+        use_current_rfh ? "true" : "false");
+    NOTREACHED() << "Picked an incompatible process for URL: " << lock_url
+                 << " lock vs " << request.common_params().url.GetOrigin();
+    base::debug::DumpWithoutCrashing();
+  }
+
   return navigation_rfh;
 }
 
diff --git a/content/browser/loader/cors_preflight_cache_browsertest.cc b/content/browser/loader/cors_preflight_cache_browsertest.cc
new file mode 100644
index 0000000..febc09f7
--- /dev/null
+++ b/content/browser/loader/cors_preflight_cache_browsertest.cc
@@ -0,0 +1,129 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/thread_annotations.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/test/embedded_test_server/request_handler_util.h"
+#include "services/network/public/cpp/cors/cors.h"
+#include "services/network/public/cpp/features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+const char kTestPath[] = "/loader/cors_preflight.html";
+const base::string16 kTestDone = base::string16(base::ASCIIToUTF16("DONE"));
+
+// Tests end to end behaviors on CORS preflight and its cache.
+class CorsPreflightCacheBrowserTest : public ContentBrowserTest {
+ protected:
+  CorsPreflightCacheBrowserTest() {
+    scoped_feature_list_.InitWithFeatures({network::features::kOutOfBlinkCors,
+                                           network::features::kNetworkService},
+                                          {});
+  }
+  ~CorsPreflightCacheBrowserTest() override = default;
+
+  void SetUpOnMainThread() override {
+    ASSERT_TRUE(embedded_test_server()->Start());
+
+    cross_origin_test_server_.RegisterRequestHandler(base::BindRepeating(
+        &CorsPreflightCacheBrowserTest::HandleRequest, base::Unretained(this)));
+    ASSERT_TRUE(cross_origin_test_server_.Start());
+  }
+
+ protected:
+  uint16_t cross_origin_port() { return cross_origin_test_server_.port(); }
+  size_t options_count() {
+    base::AutoLock lock(lock_);
+    return options_count_;
+  }
+  size_t get_count() {
+    base::AutoLock lock(lock_);
+    return get_count_;
+  }
+
+ private:
+  std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
+      const net::test_server::HttpRequest& request) {
+    std::unique_ptr<net::test_server::BasicHttpResponse> response =
+        std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_code(net::HTTP_OK);
+    response->AddCustomHeader(
+        network::cors::header_names::kAccessControlAllowOrigin, "*");
+    if (request.method == net::test_server::METHOD_OPTIONS) {
+      response->AddCustomHeader(
+          network::cors::header_names::kAccessControlAllowMethods,
+          "GET, OPTIONS");
+      response->AddCustomHeader(
+          network::cors::header_names::kAccessControlAllowHeaders, "foo");
+      response->AddCustomHeader(
+          network::cors::header_names::kAccessControlMaxAge, "60");
+      base::AutoLock lock(lock_);
+      options_count_++;
+    } else if (request.method == net::test_server::METHOD_GET) {
+      base::AutoLock lock(lock_);
+      get_count_++;
+    }
+    return response;
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+  net::EmbeddedTestServer cross_origin_test_server_;
+  base::Lock lock_;
+
+  size_t options_count_ GUARDED_BY(lock_) = 0;
+  size_t get_count_ GUARDED_BY(lock_) = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(CorsPreflightCacheBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(CorsPreflightCacheBrowserTest, Default) {
+  std::unique_ptr<TitleWatcher> watcher1 =
+      std::make_unique<TitleWatcher>(shell()->web_contents(), kTestDone);
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                   "%s?;%d;default", kTestPath, cross_origin_port()))));
+  EXPECT_EQ(kTestDone, watcher1->WaitAndGetTitle());
+  EXPECT_EQ(1u, options_count());
+  EXPECT_EQ(1u, get_count());
+
+  std::unique_ptr<TitleWatcher> watcher2 =
+      std::make_unique<TitleWatcher>(shell()->web_contents(), kTestDone);
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                   "%s?;%d;default", kTestPath, cross_origin_port()))));
+  EXPECT_EQ(kTestDone, watcher2->WaitAndGetTitle());
+  EXPECT_EQ(1u, options_count());
+  EXPECT_EQ(2u, get_count());
+
+  std::unique_ptr<TitleWatcher> watcher3 =
+      std::make_unique<TitleWatcher>(shell()->web_contents(), kTestDone);
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                   "%s?;%d;reload", kTestPath, cross_origin_port()))));
+  EXPECT_EQ(kTestDone, watcher3->WaitAndGetTitle());
+  EXPECT_EQ(2u, options_count());
+  EXPECT_EQ(3u, get_count());
+}
+
+}  // namespace
+
+}  // namespace content
diff --git a/content/browser/media/session/audio_focus_delegate_default.cc b/content/browser/media/session/audio_focus_delegate_default.cc
index 97b88ee2..ff75f216 100644
--- a/content/browser/media/session/audio_focus_delegate_default.cc
+++ b/content/browser/media/session/audio_focus_delegate_default.cc
@@ -56,6 +56,8 @@
  private:
   // Finishes an async audio focus request.
   void FinishAudioFocusRequest(AudioFocusType type);
+  void FinishInitialAudioFocusRequest(AudioFocusType type,
+                                      const base::UnguessableToken& request_id);
 
   // Ensures that |audio_focus_ptr_| is connected.
   void EnsureServiceConnection();
@@ -114,8 +116,9 @@
         mojo::MakeRequest(&request_client_ptr_), std::move(media_session),
         session_info_.Clone(), audio_focus_type,
         GetAudioFocusGroupId(media_session_),
-        base::BindOnce(&AudioFocusDelegateDefault::FinishAudioFocusRequest,
-                       base::Unretained(this), audio_focus_type));
+        base::BindOnce(
+            &AudioFocusDelegateDefault::FinishInitialAudioFocusRequest,
+            base::Unretained(this), audio_focus_type));
   }
 
   // Return delayed as we make the async call to request audio focus.
@@ -159,6 +162,12 @@
   media_session_->FinishSystemAudioFocusRequest(type, true /* result */);
 }
 
+void AudioFocusDelegateDefault::FinishInitialAudioFocusRequest(
+    AudioFocusType type,
+    const base::UnguessableToken& request_id) {
+  FinishAudioFocusRequest(type);
+}
+
 void AudioFocusDelegateDefault::EnsureServiceConnection() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
diff --git a/content/browser/power_monitor_browsertest.cc b/content/browser/power_monitor_browsertest.cc
index 67b7cfce..e89082e 100644
--- a/content/browser/power_monitor_browsertest.cc
+++ b/content/browser/power_monitor_browsertest.cc
@@ -198,6 +198,11 @@
       shell()->web_contents()->GetMainFrame()->GetProcess();
   BindInterface(rph, &power_monitor_renderer);
 
+  // Ensure that the PowerMonitorTestImpl instance has been created and is
+  // observing power state changes in the child process before simulating a
+  // power state change.
+  power_monitor_renderer.FlushForTesting();
+
   SimulatePowerStateChange(true);
   // Verify renderer process on_battery_power changed to true.
   VerifyPowerStateInChildProcess(power_monitor_renderer.get(), true);
@@ -216,6 +221,11 @@
   run_loop.Run();
   EXPECT_EQ(1, request_count_from_utility());
 
+  // Ensure that the PowerMonitorTestImpl instance has been created and is
+  // observing power state changes in the child process before simulating a
+  // power state change.
+  power_monitor_utility.FlushForTesting();
+
   SimulatePowerStateChange(true);
   // Verify utility process on_battery_power changed to true.
   VerifyPowerStateInChildProcess(power_monitor_utility.get(), true);
@@ -245,6 +255,11 @@
       base::BindOnce(&BindInterfaceForGpuOnIOThread,
                      mojo::MakeRequest(&power_monitor_gpu)));
 
+  // Ensure that the PowerMonitorTestImpl instance has been created and is
+  // observing power state changes in the child process before simulating a
+  // power state change.
+  power_monitor_gpu.FlushForTesting();
+
   SimulatePowerStateChange(true);
   // Verify gpu process on_battery_power changed to true.
   VerifyPowerStateInChildProcess(power_monitor_gpu.get(), true);
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc
index 8e4df0b..b317a37b 100644
--- a/content/browser/renderer_interface_binders.cc
+++ b/content/browser/renderer_interface_binders.cc
@@ -215,8 +215,10 @@
     network::mojom::WebSocketRequest request,
     RenderProcessHost* host,
     const url::Origin& origin) {
+  // TODO(jam): is it ok to not send extraHeaders for sockets created from
+  // shared and service workers?
   WebSocketManager::CreateWebSocket(host->GetID(), MSG_ROUTING_NONE, origin,
-                                    nullptr, std::move(request));
+                                    nullptr, nullptr, std::move(request));
 }
 
 }  // namespace
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index a758bd6..1edfe58 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -832,28 +832,28 @@
   const GURL kOrigin2 = GURL("https://another-origin.example.net/");
   std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints;
 
-  // Host1 (provider_id < -1): process_id=1, origin1.
+  // Host1 : process_id=1, origin1.
   remote_endpoints.emplace_back();
   base::WeakPtr<ServiceWorkerProviderHost> host1 = CreateProviderHostForWindow(
       kRenderProcessId1, true /* is_parent_frame_secure */,
       context()->AsWeakPtr(), &remote_endpoints.back());
   host1->UpdateUrls(kOrigin1, kOrigin1);
 
-  // Host2 (provider_id < -1): process_id=2, origin2.
+  // Host2 : process_id=2, origin2.
   remote_endpoints.emplace_back();
   base::WeakPtr<ServiceWorkerProviderHost> host2 = CreateProviderHostForWindow(
       kRenderProcessId2, true /* is_parent_frame_secure */,
       context()->AsWeakPtr(), &remote_endpoints.back());
   host2->UpdateUrls(kOrigin2, kOrigin2);
 
-  // Host3 (provider_id < -1): process_id=2, origin1.
+  // Host3 : process_id=2, origin1.
   remote_endpoints.emplace_back();
   base::WeakPtr<ServiceWorkerProviderHost> host3 = CreateProviderHostForWindow(
       kRenderProcessId2, true /* is_parent_frame_secure */,
       context()->AsWeakPtr(), &remote_endpoints.back());
   host3->UpdateUrls(kOrigin1, kOrigin1);
 
-  // Host4 (provider_id < -1): process_id=2, origin2, for ServiceWorker.
+  // Host4 : process_id=2, origin2, for ServiceWorker.
   blink::mojom::ServiceWorkerRegistrationOptions registration_opt;
   registration_opt.scope = GURL("https://another-origin.example.net/test/");
   scoped_refptr<ServiceWorkerRegistration> registration =
@@ -872,7 +872,7 @@
           kRenderProcessId2, true /* is_parent_frame_secure */, version.get(),
           context()->AsWeakPtr(), &remote_endpoints.back());
   const int host4_provider_id = host4->provider_id();
-  EXPECT_LT(host4_provider_id, kInvalidServiceWorkerProviderId);
+  EXPECT_NE(host4_provider_id, kInvalidServiceWorkerProviderId);
 
   ServiceWorkerProviderHost* host1_raw = host1.get();
   ServiceWorkerProviderHost* host2_raw = host2.get();
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index c342250..5e4172a 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -56,11 +56,10 @@
 
 namespace {
 
-// This function provides the next ServiceWorkerProviderHost ID, starts at -2
-// and keeps going down.
+// This function provides the next ServiceWorkerProviderHost ID.
 int NextProviderId() {
-  static int g_next_provider_id = -2;
-  return g_next_provider_id--;
+  static int g_next_provider_id = 0;
+  return g_next_provider_id++;
 }
 
 // A request handler derivative used to handle navigation requests when
@@ -100,21 +99,6 @@
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLTrackingRequestHandler);
 };
 
-void RemoveProviderHost(base::WeakPtr<ServiceWorkerContextCore> context,
-                        int provider_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerProviderHost::RemoveProviderHost");
-  if (!context || !context->GetProviderHost(provider_id)) {
-    // In some cases, it is possible for the Mojo endpoint of a pre-created
-    // host to be destroyed before being claimed by the renderer and
-    // having the host become owned by ServiceWorkerContextCore. The owner of
-    // the host is responsible for deleting the host, so just return here.
-    return;
-  }
-  context->RemoveProviderHost(provider_id);
-}
-
 void GetInterfaceImpl(const std::string& interface_name,
                       mojo::ScopedMessagePipeHandle interface_pipe,
                       const url::Origin& origin,
@@ -200,7 +184,7 @@
 
   (*out_provider_info)->provider_id = host->provider_id();
   auto weak_ptr = host->AsWeakPtr();
-  context->AddProviderHost(std::move(host));
+  RegisterToContextCore(context, std::move(host));
   return weak_ptr;
 }
 
@@ -222,7 +206,7 @@
 
   (*out_provider_info)->provider_id = host->provider_id();
   auto weak_ptr = host->AsWeakPtr();
-  context->AddProviderHost(std::move(host));
+  RegisterToContextCore(context, std::move(host));
   return weak_ptr;
 }
 
@@ -243,10 +227,21 @@
 
   (*out_provider_info)->provider_id = host->provider_id();
   auto weak_ptr = host->AsWeakPtr();
-  context->AddProviderHost(std::move(host));
+  RegisterToContextCore(context, std::move(host));
   return weak_ptr;
 }
 
+// static
+void ServiceWorkerProviderHost::RegisterToContextCore(
+    base::WeakPtr<ServiceWorkerContextCore> context,
+    std::unique_ptr<ServiceWorkerProviderHost> host) {
+  DCHECK(host->binding_.is_bound());
+  host->binding_.set_connection_error_handler(
+      base::BindOnce(&ServiceWorkerContextCore::RemoveProviderHost, context,
+                     host->provider_id()));
+  context->AddProviderHost(std::move(host));
+}
+
 ServiceWorkerProviderHost::ServiceWorkerProviderHost(
     blink::mojom::ServiceWorkerProviderType type,
     bool is_parent_frame_secure,
@@ -278,8 +273,6 @@
   DCHECK(client_ptr_info.is_valid() && host_request.is_pending());
   container_.Bind(std::move(client_ptr_info));
   binding_.Bind(std::move(host_request));
-  binding_.set_connection_error_handler(
-      base::BindOnce(&RemoveProviderHost, context_, provider_id_));
 }
 
 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 258fcbc..6136f13 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -492,6 +492,10 @@
   FRIEND_TEST_ALL_PREFIXES(BackgroundSyncManagerTest,
                            RegisterWithoutLiveSWRegistration);
 
+  static void RegisterToContextCore(
+      base::WeakPtr<ServiceWorkerContextCore> context,
+      std::unique_ptr<ServiceWorkerProviderHost> host);
+
   ServiceWorkerProviderHost(
       blink::mojom::ServiceWorkerProviderType type,
       bool is_parent_frame_secure,
diff --git a/content/browser/service_worker/service_worker_script_cache_map.cc b/content/browser/service_worker/service_worker_script_cache_map.cc
index 3ace72a5..d568d80 100644
--- a/content/browser/service_worker/service_worker_script_cache_map.cc
+++ b/content/browser/service_worker/service_worker_script_cache_map.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/service_worker/service_worker_script_cache_map.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/logging.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
@@ -90,16 +92,16 @@
 void ServiceWorkerScriptCacheMap::WriteMetadata(
     const GURL& url,
     const std::vector<uint8_t>& data,
-    const net::CompletionCallback& callback) {
+    net::CompletionOnceCallback callback) {
   if (!context_) {
-    callback.Run(net::ERR_ABORTED);
+    std::move(callback).Run(net::ERR_ABORTED);
     return;
   }
 
   auto found = resource_map_.find(url);
   if (found == resource_map_.end() ||
       found->second.resource_id == kInvalidServiceWorkerResourceId) {
-    callback.Run(net::ERR_FILE_NOT_FOUND);
+    std::move(callback).Run(net::ERR_FILE_NOT_FOUND);
     return;
   }
 
@@ -114,20 +116,21 @@
   raw_writer->WriteMetadata(
       buffer.get(), data.size(),
       base::BindOnce(&ServiceWorkerScriptCacheMap::OnMetadataWritten,
-                     weak_factory_.GetWeakPtr(), std::move(writer), callback));
+                     weak_factory_.GetWeakPtr(), std::move(writer),
+                     std::move(callback)));
 }
 
 void ServiceWorkerScriptCacheMap::ClearMetadata(
     const GURL& url,
-    const net::CompletionCallback& callback) {
-  WriteMetadata(url, std::vector<uint8_t>(), callback);
+    net::CompletionOnceCallback callback) {
+  WriteMetadata(url, std::vector<uint8_t>(), std::move(callback));
 }
 
 void ServiceWorkerScriptCacheMap::OnMetadataWritten(
     std::unique_ptr<ServiceWorkerResponseMetadataWriter> writer,
-    const net::CompletionCallback& callback,
+    net::CompletionOnceCallback callback,
     int result) {
-  callback.Run(result);
+  std::move(callback).Run(result);
 }
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_script_cache_map.h b/content/browser/service_worker/service_worker_script_cache_map.h
index 5617ff4..f1c8399 100644
--- a/content/browser/service_worker/service_worker_script_cache_map.h
+++ b/content/browser/service_worker/service_worker_script_cache_map.h
@@ -15,7 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "content/browser/service_worker/service_worker_database.h"
 #include "content/common/content_export.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_once_callback.h"
 #include "net/url_request/url_request_status.h"
 
 class GURL;
@@ -51,9 +51,9 @@
   // Writes the metadata of the existing script.
   void WriteMetadata(const GURL& url,
                      const std::vector<uint8_t>& data,
-                     const net::CompletionCallback& callback);
+                     net::CompletionOnceCallback callback);
   // Clears the metadata of the existing script.
-  void ClearMetadata(const GURL& url, const net::CompletionCallback& callback);
+  void ClearMetadata(const GURL& url, net::CompletionOnceCallback callback);
 
   size_t size() const { return resource_map_.size(); }
 
@@ -81,7 +81,7 @@
 
   void OnMetadataWritten(
       std::unique_ptr<ServiceWorkerResponseMetadataWriter> writer,
-      const net::CompletionCallback& callback,
+      net::CompletionOnceCallback callback,
       int result);
 
   ServiceWorkerVersion* owner_;
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 3d81cd8..57989c8c 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -1059,8 +1059,8 @@
                            callback_id, "URL", url.spec());
   script_cache_map_.WriteMetadata(
       url, data,
-      base::Bind(&ServiceWorkerVersion::OnSetCachedMetadataFinished,
-                 weak_factory_.GetWeakPtr(), callback_id, data.size()));
+      base::BindOnce(&ServiceWorkerVersion::OnSetCachedMetadataFinished,
+                     weak_factory_.GetWeakPtr(), callback_id, data.size()));
 }
 
 void ServiceWorkerVersion::ClearCachedMetadata(const GURL& url) {
@@ -1069,8 +1069,8 @@
                            "ServiceWorkerVersion::ClearCachedMetadata",
                            callback_id, "URL", url.spec());
   script_cache_map_.ClearMetadata(
-      url, base::Bind(&ServiceWorkerVersion::OnClearCachedMetadataFinished,
-                      weak_factory_.GetWeakPtr(), callback_id));
+      url, base::BindOnce(&ServiceWorkerVersion::OnClearCachedMetadataFinished,
+                          weak_factory_.GetWeakPtr(), callback_id));
 }
 
 void ServiceWorkerVersion::ClaimClients(ClaimClientsCallback callback) {
diff --git a/content/browser/websockets/websocket_manager.cc b/content/browser/websockets/websocket_manager.cc
index b56fd77..58d60498 100644
--- a/content/browser/websockets/websocket_manager.cc
+++ b/content/browser/websockets/websocket_manager.cc
@@ -167,6 +167,7 @@
     int frame_id,
     url::Origin origin,
     network::mojom::AuthenticationHandlerPtr auth_handler,
+    network::mojom::TrustedHeaderClientPtr header_client,
     network::mojom::WebSocketRequest request) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
@@ -178,11 +179,14 @@
     network::mojom::NetworkContext* network_context =
         storage_partition->GetNetworkContext();
     network_context->CreateWebSocket(std::move(request), process_id, frame_id,
-                                     origin, std::move(auth_handler));
+                                     origin, std::move(auth_handler),
+                                     std::move(header_client));
     return;
   }
-  // |auth_handler| is provided only for the network service path.
+  // |auth_handler| and |header_client| are provided only for the network
+  // service path.
   DCHECK(!auth_handler);
+  DCHECK(!header_client);
 
   // Maintain a WebSocketManager per RenderProcessHost. While the instance of
   // WebSocketManager is allocated on the UI thread, it must only be used and
@@ -286,7 +290,7 @@
     url::Origin origin,
     base::TimeDelta delay) {
   return std::make_unique<network::WebSocket>(
-      std::move(delegate), std::move(request), nullptr,
+      std::move(delegate), std::move(request), nullptr, nullptr,
       std::move(pending_connection_tracker), child_id, frame_id,
       std::move(origin), delay);
 }
diff --git a/content/browser/websockets/websocket_manager.h b/content/browser/websockets/websocket_manager.h
index c010f09e..de67e07f22 100644
--- a/content/browser/websockets/websocket_manager.h
+++ b/content/browser/websockets/websocket_manager.h
@@ -39,6 +39,7 @@
       int frame_id,
       url::Origin origin,
       network::mojom::AuthenticationHandlerPtr auth_handler,
+      network::mojom::TrustedHeaderClientPtr header_client,
       network::mojom::WebSocketRequest request);
 
   // net::URLRequestContextGetterObserver implementation.
diff --git a/content/browser/websockets/websocket_manager_unittest.cc b/content/browser/websockets/websocket_manager_unittest.cc
index 9aa0b83..484a5b60 100644
--- a/content/browser/websockets/websocket_manager_unittest.cc
+++ b/content/browser/websockets/websocket_manager_unittest.cc
@@ -33,6 +33,7 @@
       : network::WebSocket(std::move(delegate),
                            std::move(request),
                            nullptr,
+                           nullptr,
                            std::move(pending_connection_tracker),
                            process_id,
                            frame_id,
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc
index d551726..18970614 100644
--- a/content/browser/worker_host/dedicated_worker_host.cc
+++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -234,12 +234,13 @@
       return;
     }
 
-    GetContentClient()->browser()->WillCreateWebSocket(frame, &request,
-                                                       &auth_handler);
+    network::mojom::TrustedHeaderClientPtr header_client;
+    GetContentClient()->browser()->WillCreateWebSocket(
+        frame, &request, &auth_handler, &header_client);
 
-    WebSocketManager::CreateWebSocket(process_id_, ancestor_render_frame_id_,
-                                      origin_, std::move(auth_handler),
-                                      std::move(request));
+    WebSocketManager::CreateWebSocket(
+        process_id_, ancestor_render_frame_id_, origin_,
+        std::move(auth_handler), std::move(header_client), std::move(request));
   }
 
   void CreateDedicatedWorker(
diff --git a/content/common/render_widget_host_ns_view.mojom b/content/common/render_widget_host_ns_view.mojom
index 0726046..0dbe014 100644
--- a/content/common/render_widget_host_ns_view.mojom
+++ b/content/common/render_widget_host_ns_view.mojom
@@ -8,6 +8,7 @@
 import "content/common/input/input_handler.mojom";
 import "mojo/public/mojom/base/string16.mojom";
 import "services/ws/public/mojom/ime/ime.mojom";
+import "ui/base/ime/mojo/ime_types.mojom";
 import "ui/display/mojo/display.mojom";
 import "ui/events/mojo/event.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/BrowserTaskExecutor.java b/content/public/android/java/src/org/chromium/content_public/browser/BrowserTaskExecutor.java
index 957256e..de9e111 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/BrowserTaskExecutor.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/BrowserTaskExecutor.java
@@ -47,8 +47,8 @@
             if (taskRunner != null) return taskRunner;
 
             // TODO(alexclarke): ThreadUtils.getUiThreadHandler shouldn't be in base.
-            taskRunner =
-                    new SingleThreadTaskRunnerImpl(ThreadUtils.getUiThreadHandler(), taskTraits);
+            taskRunner = new SingleThreadTaskRunnerImpl(ThreadUtils.getUiThreadHandler(),
+                    taskTraits, shouldPrioritizeTraits(taskTraits));
             taskRunner.disableLifetimeCheck();
             mTaskRunners.put(taskTraits, taskRunner);
             return taskRunner;
@@ -74,9 +74,34 @@
                 UiThreadTaskTraitsImpl.DESCRIPTOR.getId(), new BrowserTaskExecutor());
     }
 
+    public static boolean getShouldPrioritizeBootstrapTasks() {
+        return sShouldPrioritizeBootstrapTasks;
+    }
+
+    public static void setShouldPrioritizeBootstrapTasks(boolean shouldPrioritizeBootstrapTasks) {
+        sShouldPrioritizeBootstrapTasks = shouldPrioritizeBootstrapTasks;
+    }
+
+    private static boolean shouldPrioritizeTraits(TaskTraits taskTraits) {
+        if (!sShouldPrioritizeBootstrapTasks) return false;
+
+        UiThreadTaskTraitsImpl impl = taskTraits.getExtension(UiThreadTaskTraitsImpl.DESCRIPTOR);
+        if (impl == null) return false;
+
+        switch (impl.getTaskType()) {
+            case BrowserTaskType.BOOTSTRAP:
+            case BrowserTaskType.NAVIGATION:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
     @GuardedBy("mTaskRunners")
     private final WeakHashMap<TaskTraits, SingleThreadTaskRunner> mTaskRunners =
             new WeakHashMap<>();
 
     private static boolean sRegistered;
+    private static boolean sShouldPrioritizeBootstrapTasks;
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/scheduler/UiThreadSchedulerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/scheduler/UiThreadSchedulerTest.java
index 95f4b28..514f3c8 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/scheduler/UiThreadSchedulerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/scheduler/UiThreadSchedulerTest.java
@@ -50,6 +50,7 @@
         mUiThread.start();
         ThreadUtils.setUiThread(mUiThread.getLooper());
         BrowserTaskExecutor.register();
+        BrowserTaskExecutor.setShouldPrioritizeBootstrapTasks(true);
         mHandler = new Handler(mUiThread.getLooper());
     }
 
@@ -80,6 +81,37 @@
 
     @Test
     @MediumTest
+    public void testPrioritizationBeforeNativeLoaded() {
+        TaskRunner defaultTaskRunner =
+                PostTask.createSingleThreadTaskRunner(UiThreadTaskTraits.DEFAULT);
+        TaskRunner bootstrapTaskRunner =
+                PostTask.createSingleThreadTaskRunner(UiThreadTaskTraits.BOOTSTRAP);
+        try {
+            List<Integer> orderList = new ArrayList<>();
+            // We want to enqueue these tasks atomically but we're not on the mUiThread. So
+            // we post a task to enqueue them.
+            PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
+                @Override
+                public void run() {
+                    SchedulerTestHelpers.postRecordOrderTask(defaultTaskRunner, orderList, 1);
+                    SchedulerTestHelpers.postRecordOrderTask(defaultTaskRunner, orderList, 2);
+                    SchedulerTestHelpers.postRecordOrderTask(defaultTaskRunner, orderList, 3);
+                    SchedulerTestHelpers.postRecordOrderTask(bootstrapTaskRunner, orderList, 10);
+                    SchedulerTestHelpers.postRecordOrderTask(bootstrapTaskRunner, orderList, 20);
+                    SchedulerTestHelpers.postRecordOrderTask(bootstrapTaskRunner, orderList, 30);
+                }
+            });
+
+            SchedulerTestHelpers.preNativeRunUntilIdle(mUiThread);
+            assertThat(orderList, contains(10, 20, 30, 1, 2, 3));
+        } finally {
+            defaultTaskRunner.destroy();
+            bootstrapTaskRunner.destroy();
+        }
+    }
+
+    @Test
+    @MediumTest
     public void testUiThreadTaskRunnerMigrationToNative() throws Exception {
         TaskRunner uiThreadTaskRunner =
                 PostTask.createSingleThreadTaskRunner(UiThreadTaskTraits.DEFAULT);
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 2f68bc4e..b3c348a1 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -768,7 +768,8 @@
 void ContentBrowserClient::WillCreateWebSocket(
     RenderFrameHost* frame,
     network::mojom::WebSocketRequest* request,
-    network::mojom::AuthenticationHandlerPtr* auth_handler) {}
+    network::mojom::AuthenticationHandlerPtr* auth_handler,
+    network::mojom::TrustedHeaderClientPtr* header_client) {}
 
 std::vector<std::unique_ptr<URLLoaderRequestInterceptor>>
 ContentBrowserClient::WillCreateURLLoaderRequestInterceptors(
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 81583161..f99a98af 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1250,7 +1250,8 @@
   virtual void WillCreateWebSocket(
       RenderFrameHost* frame,
       network::mojom::WebSocketRequest* request,
-      network::mojom::AuthenticationHandlerPtr* authentication_handler);
+      network::mojom::AuthenticationHandlerPtr* authentication_handler,
+      network::mojom::TrustedHeaderClientPtr* header_client);
 
   // Allows the embedder to returns a list of request interceptors that can
   // intercept a navigation request.
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 2b23b28..062a1ea 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -78,6 +78,9 @@
     content::AutoplayPolicy,
     content::AutoplayPolicy::kNoUserGestureRequired,
     content::AutoplayPolicy::kDocumentUserActivationRequired)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::PreferredColorScheme,
+                              blink::PreferredColorScheme::kNoPreference,
+                              blink::PreferredColorScheme::kLight)
 
 IPC_STRUCT_TRAITS_BEGIN(blink::WebPoint)
   IPC_STRUCT_TRAITS_MEMBER(x)
@@ -239,6 +242,7 @@
   IPC_STRUCT_TRAITS_MEMBER(media_controls_enabled)
   IPC_STRUCT_TRAITS_MEMBER(do_not_update_selection_on_mutating_selection_range)
   IPC_STRUCT_TRAITS_MEMBER(autoplay_policy)
+  IPC_STRUCT_TRAITS_MEMBER(preferred_color_scheme)
   IPC_STRUCT_TRAITS_MEMBER(low_priority_iframes_threshold)
   IPC_STRUCT_TRAITS_MEMBER(picture_in_picture_enabled)
   IPC_STRUCT_TRAITS_MEMBER(translate_service_available)
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index b76f327..19df80e 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -225,6 +225,7 @@
       media_controls_enabled(true),
       do_not_update_selection_on_mutating_selection_range(false),
       autoplay_policy(AutoplayPolicy::kDocumentUserActivationRequired),
+      preferred_color_scheme(blink::PreferredColorScheme::kNoPreference),
       low_priority_iframes_threshold(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
       picture_in_picture_enabled(true),
       translate_service_available(false),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index 9052d1d6..ee9d75c 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -14,6 +14,7 @@
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "net/nqe/effective_connection_type.h"
+#include "third_party/blink/public/common/css/preferred_color_scheme.h"
 #include "third_party/blink/public/mojom/v8_cache_options.mojom.h"
 #include "ui/base/pointer/pointer_device.h"
 #include "url/gurl.h"
@@ -298,6 +299,12 @@
   // Defines the current autoplay policy.
   AutoplayPolicy autoplay_policy;
 
+  // The preferred color scheme for the web content. The scheme is used to
+  // evaluate the prefers-color-scheme media query and resolve UA color scheme
+  // to be used based on the supported-color-schemes META tag and CSS property.
+  blink::PreferredColorScheme preferred_color_scheme =
+      blink::PreferredColorScheme::kNoPreference;
+
   // Network quality threshold below which resources from iframes are assigned
   // either kVeryLow or kVeryLow Blink priority.
   net::EffectiveConnectionType low_priority_iframes_threshold;
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 454098b..393926e 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -16,7 +16,6 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -47,7 +46,6 @@
 #include "content/renderer/render_view_impl.h"
 #include "crypto/openssl_util.h"
 #include "jingle/glue/thread_wrapper.h"
-#include "media/base/bind_to_current_loop.h"
 #include "media/base/media_permission.h"
 #include "media/media_buildflags.h"
 #include "media/video/gpu_video_accelerator_factories.h"
@@ -124,8 +122,7 @@
       signaling_thread_(nullptr),
       worker_thread_(nullptr),
       chrome_signaling_thread_("Chrome_libJingle_Signaling"),
-      chrome_worker_thread_("Chrome_libJingle_WorkerThread"),
-      weak_factory_(this) {
+      chrome_worker_thread_("Chrome_libJingle_WorkerThread") {
   TryScheduleStunProbeTrial();
 }
 
@@ -202,11 +199,20 @@
   base::WaitableEvent create_network_manager_event(
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
+  std::unique_ptr<MdnsResponderAdapter> mdns_responder;
+#if BUILDFLAG(ENABLE_MDNS)
+  if (base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns)) {
+    // Note that MdnsResponderAdapter is created on the main thread to have
+    // access to the connector to the service manager.
+    mdns_responder = std::make_unique<MdnsResponderAdapter>();
+  }
+#endif  // BUILDFLAG(ENABLE_MDNS)
   chrome_worker_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&PeerConnectionDependencyFactory::
                          CreateIpcNetworkManagerOnWorkerThread,
-                     base::Unretained(this), &create_network_manager_event));
+                     base::Unretained(this), &create_network_manager_event,
+                     std::move(mdns_responder)));
 
   start_worker_event.Wait();
   create_network_manager_event.Wait();
@@ -448,12 +454,8 @@
 
   std::unique_ptr<rtc::NetworkManager> network_manager;
   if (port_config.enable_multiple_routes) {
-    auto callback = media::BindToCurrentLoop(base::BindRepeating(
-        &PeerConnectionDependencyFactory::OnEnumeratePermissionChanged,
-        weak_factory_.GetWeakPtr()));
     network_manager = std::make_unique<FilteringNetworkManager>(
-        network_manager_.get(), requesting_origin, media_permission,
-        std::move(callback));
+        network_manager_.get(), requesting_origin, media_permission);
   } else {
     network_manager =
         std::make_unique<EmptyNetworkManager>(network_manager_.get());
@@ -558,10 +560,11 @@
 }
 
 void PeerConnectionDependencyFactory::CreateIpcNetworkManagerOnWorkerThread(
-    base::WaitableEvent* event) {
+    base::WaitableEvent* event,
+    std::unique_ptr<MdnsResponderAdapter> mdns_responder) {
   DCHECK(chrome_worker_thread_.task_runner()->BelongsToCurrentThread());
-  network_manager_ =
-      std::make_unique<IpcNetworkManager>(p2p_socket_dispatcher_.get());
+  network_manager_ = std::make_unique<IpcNetworkManager>(
+      p2p_socket_dispatcher_.get(), std::move(mdns_responder));
   event->Signal();
 }
 
@@ -652,24 +655,4 @@
   return nullptr;
 }
 
-void PeerConnectionDependencyFactory::OnEnumeratePermissionChanged(
-    rtc::NetworkManager::EnumerationPermission new_state) {
-#if BUILDFLAG(ENABLE_MDNS)
-  std::unique_ptr<MdnsResponderAdapter> mdns_responder;
-  if (new_state == rtc::NetworkManager::ENUMERATION_BLOCKED &&
-      base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns)) {
-    // Note that MdnsResponderAdapter is created on the main thread to have
-    // access to the connector to the service manager.
-    mdns_responder = std::make_unique<MdnsResponderAdapter>();
-  }
-  // base::Unretained is safe below because |network_manager_| will be destroyed
-  // only after |chrome_work_thread_| stops, which flushes all tasks. See
-  // PeerConnectionDependencyFactory::CleanupPeerConnectionFactory.
-  chrome_worker_thread_.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&IpcNetworkManager::SetMdnsResponder,
-                                base::Unretained(network_manager_.get()),
-                                base::Passed(&mdns_responder)));
-#endif  // BUILDFLAG(ENABLE_MDNS)
-}
-
 }  // namespace content
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
index 5182cab..137b36ac 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.h
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
@@ -9,7 +9,6 @@
 
 #include "base/files/file.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop_current.h"
 #include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
@@ -43,6 +42,7 @@
 
 class IpcNetworkManager;
 class IpcPacketSocketFactory;
+class MdnsResponderAdapter;
 class P2PPortAllocator;
 class WebRtcAudioDeviceImpl;
 
@@ -150,13 +150,12 @@
   void InitializeWorkerThread(rtc::Thread** thread,
                               base::WaitableEvent* event);
 
-  void CreateIpcNetworkManagerOnWorkerThread(base::WaitableEvent* event);
+  void CreateIpcNetworkManagerOnWorkerThread(
+      base::WaitableEvent* event,
+      std::unique_ptr<MdnsResponderAdapter> mdns_responder);
   void DeleteIpcNetworkManager();
   void CleanupPeerConnectionFactory();
 
-  void OnEnumeratePermissionChanged(
-      rtc::NetworkManager::EnumerationPermission new_state);
-
   // network_manager_ must be deleted on the worker thread. The network manager
   // uses |p2p_socket_dispatcher_|.
   std::unique_ptr<IpcNetworkManager> network_manager_;
@@ -178,9 +177,6 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
-  // The weak pointer MUST only be dereferenced on the main thread.
-  base::WeakPtrFactory<PeerConnectionDependencyFactory> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(PeerConnectionDependencyFactory);
 };
 
diff --git a/content/renderer/p2p/filtering_network_manager.cc b/content/renderer/p2p/filtering_network_manager.cc
index d09315d..0ecd2ed 100644
--- a/content/renderer/p2p/filtering_network_manager.cc
+++ b/content/renderer/p2p/filtering_network_manager.cc
@@ -17,20 +17,18 @@
 FilteringNetworkManager::FilteringNetworkManager(
     rtc::NetworkManager* network_manager,
     const GURL& requesting_origin,
-    media::MediaPermission* media_permission,
-    OnEnumerationPermissionCallback callback)
+    media::MediaPermission* media_permission)
     : network_manager_(network_manager),
       media_permission_(media_permission),
       requesting_origin_(requesting_origin),
-      on_enumeration_permission_cb_(std::move(callback)),
       weak_ptr_factory_(this) {
   thread_checker_.DetachFromThread();
-  SetEnumerationPermissionAndNotify(ENUMERATION_BLOCKED);
+  set_enumeration_permission(ENUMERATION_BLOCKED);
 
   // If the feature is not enabled, just return ALLOWED as it's requested.
   if (!media_permission_) {
     started_permission_check_ = true;
-    SetEnumerationPermissionAndNotify(ENUMERATION_ALLOWED);
+    set_enumeration_permission(ENUMERATION_ALLOWED);
     VLOG(3) << "media_permission is not passed, granting permission";
     return;
   }
@@ -84,6 +82,9 @@
   if (enumeration_permission() == ENUMERATION_ALLOWED)
     network_manager_->GetNetworks(networks);
 
+  for (rtc::Network* network : *networks)
+    network->set_mdns_responder_provider(this);
+
   VLOG(3) << "GetNetworks() returns " << networks->size() << " networks.";
 }
 
@@ -95,6 +96,13 @@
 
 webrtc::MdnsResponderInterface* FilteringNetworkManager::GetMdnsResponder()
     const {
+  if (enumeration_permission() == ENUMERATION_ALLOWED) {
+    // We do not try to destroy the binding to the mDNS responder service host
+    // so that we can still resolve the names created when no permission was
+    // granted. The mDNS responder service just becomes unavailable.
+    return nullptr;
+  }
+
   return network_manager_->GetMdnsResponder();
 }
 
@@ -125,7 +133,7 @@
   --pending_permission_checks_;
 
   if (granted)
-    SetEnumerationPermissionAndNotify(ENUMERATION_ALLOWED);
+    set_enumeration_permission(ENUMERATION_ALLOWED);
 
   // If the IP permission status changed *and* we have an up-to-date network
   // list, fire a network change event.
@@ -133,16 +141,6 @@
     FireEventIfStarted();
 }
 
-void FilteringNetworkManager::SetEnumerationPermissionAndNotify(
-    EnumerationPermission state) {
-  EnumerationPermission old_state = enumeration_permission();
-  if (state != old_state) {
-    set_enumeration_permission(state);
-    if (on_enumeration_permission_cb_)
-      on_enumeration_permission_cb_.Run(state);
-  }
-}
-
 void FilteringNetworkManager::OnNetworksChanged() {
   DCHECK(thread_checker_.CalledOnValidThread());
   pending_network_update_ = false;
diff --git a/content/renderer/p2p/filtering_network_manager.h b/content/renderer/p2p/filtering_network_manager.h
index 47a9f6a..7d3b292c 100644
--- a/content/renderer/p2p/filtering_network_manager.h
+++ b/content/renderer/p2p/filtering_network_manager.h
@@ -5,10 +5,8 @@
 #ifndef CONTENT_RENDERER_P2P_FILTERING_NETWORK_MANAGER_H_
 #define CONTENT_RENDERER_P2P_FILTERING_NETWORK_MANAGER_H_
 
-#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
@@ -39,17 +37,12 @@
 class FilteringNetworkManager : public rtc::NetworkManagerBase,
                                 public sigslot::has_slots<> {
  public:
-  // A callback that will be executed when |enumeration_permission_| changes.
-  using OnEnumerationPermissionCallback =
-      base::RepeatingCallback<void(EnumerationPermission)>;
-
   // This class is created by WebRTC's signaling thread but used by WebRTC's
   // worker thread |task_runner|.
   CONTENT_EXPORT FilteringNetworkManager(
       rtc::NetworkManager* network_manager,
       const GURL& requesting_origin,
-      media::MediaPermission* media_permission,
-      OnEnumerationPermissionCallback callback);
+      media::MediaPermission* media_permission);
 
   CONTENT_EXPORT ~FilteringNetworkManager() override;
 
@@ -71,8 +64,6 @@
   // available.
   void OnPermissionStatus(bool granted);
 
-  void SetEnumerationPermissionAndNotify(EnumerationPermission state);
-
   base::WeakPtr<FilteringNetworkManager> GetWeakPtr();
 
   // Receive callback from the wrapped NetworkManager when the underneath
@@ -126,8 +117,6 @@
 
   GURL requesting_origin_;
 
-  OnEnumerationPermissionCallback on_enumeration_permission_cb_;
-
   base::WeakPtrFactory<FilteringNetworkManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(FilteringNetworkManager);
diff --git a/content/renderer/p2p/filtering_network_manager_unittest.cc b/content/renderer/p2p/filtering_network_manager_unittest.cc
index 1a4c424..87295ec0 100644
--- a/content/renderer/p2p/filtering_network_manager_unittest.cc
+++ b/content/renderer/p2p/filtering_network_manager_unittest.cc
@@ -9,7 +9,6 @@
 #include <memory>
 #include <utility>
 
-#include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/stl_util.h"
@@ -138,8 +137,7 @@
     if (multiple_routes_requested) {
       FilteringNetworkManager* filtering_network_manager =
           new FilteringNetworkManager(mock_network_manager_.get(), GURL(),
-                                      media_permission_.get(),
-                                      base::DoNothing());
+                                      media_permission_.get());
       filtering_network_manager->Initialize();
       network_manager_.reset(filtering_network_manager);
     } else {
diff --git a/content/renderer/p2p/ipc_network_manager.cc b/content/renderer/p2p/ipc_network_manager.cc
index 987aa861..9a847e9 100644
--- a/content/renderer/p2p/ipc_network_manager.cc
+++ b/content/renderer/p2p/ipc_network_manager.cc
@@ -5,21 +5,20 @@
 #include "content/renderer/p2p/ipc_network_manager.h"
 
 #include <string>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/feature_list.h"
 #include "base/location.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/sys_byteorder.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "jingle/glue/utils.h"
 #include "net/base/ip_address.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/network_interfaces.h"
-#include "net/net_buildflags.h"
 #include "third_party/webrtc/rtc_base/socket_address.h"
 
 namespace content {
@@ -46,8 +45,12 @@
 
 }  // namespace
 
-IpcNetworkManager::IpcNetworkManager(NetworkListManager* network_list_manager)
-    : network_list_manager_(network_list_manager), weak_factory_(this) {
+IpcNetworkManager::IpcNetworkManager(
+    NetworkListManager* network_list_manager,
+    std::unique_ptr<MdnsResponderAdapter> mdns_responder)
+    : network_list_manager_(network_list_manager),
+      mdns_responder_(std::move(mdns_responder)),
+      weak_factory_(this) {
   network_list_manager_->AddNetworkListObserver(this);
 }
 
@@ -187,11 +190,6 @@
                            stats.ipv6_network_count);
 }
 
-void IpcNetworkManager::SetMdnsResponder(
-    std::unique_ptr<MdnsResponderAdapter> mdns_responder) {
-  mdns_responder_ = std::move(mdns_responder);
-}
-
 webrtc::MdnsResponderInterface* IpcNetworkManager::GetMdnsResponder() const {
   return mdns_responder_.get();
 }
diff --git a/content/renderer/p2p/ipc_network_manager.h b/content/renderer/p2p/ipc_network_manager.h
index 3e1657b..c0395753 100644
--- a/content/renderer/p2p/ipc_network_manager.h
+++ b/content/renderer/p2p/ipc_network_manager.h
@@ -29,7 +29,9 @@
                           public NetworkListObserver {
  public:
   // Constructor doesn't take ownership of the |network_list_manager|.
-  CONTENT_EXPORT IpcNetworkManager(NetworkListManager* network_list_manager);
+  CONTENT_EXPORT IpcNetworkManager(
+      NetworkListManager* network_list_manager,
+      std::unique_ptr<MdnsResponderAdapter> mdns_responder);
   ~IpcNetworkManager() override;
 
   // rtc:::NetworkManager:
@@ -43,8 +45,6 @@
       const net::IPAddress& default_ipv4_local_address,
       const net::IPAddress& default_ipv6_local_address) override;
 
-  void SetMdnsResponder(std::unique_ptr<MdnsResponderAdapter> mdns_responder);
-
  private:
   void SendNetworksChangedSignal();
 
diff --git a/content/renderer/p2p/ipc_network_manager_unittest.cc b/content/renderer/p2p/ipc_network_manager_unittest.cc
index 06bb29c..26b96cf 100644
--- a/content/renderer/p2p/ipc_network_manager_unittest.cc
+++ b/content/renderer/p2p/ipc_network_manager_unittest.cc
@@ -41,7 +41,8 @@
  public:
   IpcNetworkManagerTest()
       : network_list_manager_(new MockP2PSocketDispatcher()),
-        network_manager_(new IpcNetworkManager(network_list_manager_.get())) {}
+        network_manager_(
+            new IpcNetworkManager(network_list_manager_.get(), nullptr)) {}
 
  protected:
   std::unique_ptr<MockP2PSocketDispatcher> network_list_manager_;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 7b063b1..80fa551 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -952,6 +952,7 @@
       prefs.data_saver_holdback_web_api_enabled);
 
   settings->SetLazyLoadEnabled(prefs.lazy_load_enabled);
+  settings->SetPreferredColorScheme(prefs.preferred_color_scheme);
 
   for (const auto& ect_distance_pair :
        prefs.lazy_frame_loading_distance_thresholds_px) {
diff --git a/content/shell/common/power_monitor_test_impl.cc b/content/shell/common/power_monitor_test_impl.cc
index 226d66c3..29a74fe 100644
--- a/content/shell/common/power_monitor_test_impl.cc
+++ b/content/shell/common/power_monitor_test_impl.cc
@@ -10,9 +10,9 @@
 
 // static
 void PowerMonitorTestImpl::MakeStrongBinding(
-    std::unique_ptr<PowerMonitorTestImpl> instance,
     mojom::PowerMonitorTestRequest request) {
-  mojo::MakeStrongBinding(std::move(instance), std::move(request));
+  mojo::MakeStrongBinding(std::make_unique<PowerMonitorTestImpl>(),
+                          std::move(request));
 }
 
 PowerMonitorTestImpl::PowerMonitorTestImpl() {
diff --git a/content/shell/common/power_monitor_test_impl.h b/content/shell/common/power_monitor_test_impl.h
index 2f6dcfe..fda5193 100644
--- a/content/shell/common/power_monitor_test_impl.h
+++ b/content/shell/common/power_monitor_test_impl.h
@@ -17,7 +17,6 @@
                              public mojom::PowerMonitorTest {
  public:
   static void MakeStrongBinding(
-      std::unique_ptr<PowerMonitorTestImpl> instance,
       mojom::PowerMonitorTestRequest request);
 
   PowerMonitorTestImpl();
diff --git a/content/shell/gpu/shell_content_gpu_client.cc b/content/shell/gpu/shell_content_gpu_client.cc
index 7bbd687..1826e7c 100644
--- a/content/shell/gpu/shell_content_gpu_client.cc
+++ b/content/shell/gpu/shell_content_gpu_client.cc
@@ -18,9 +18,7 @@
 void ShellContentGpuClient::InitializeRegistry(
     service_manager::BinderRegistry* registry) {
   registry->AddInterface<mojom::PowerMonitorTest>(
-      base::BindRepeating(
-          &PowerMonitorTestImpl::MakeStrongBinding,
-          base::Passed(std::make_unique<PowerMonitorTestImpl>())),
+      base::BindRepeating(&PowerMonitorTestImpl::MakeStrongBinding),
       base::ThreadTaskRunnerHandle::Get());
 }
 
diff --git a/content/shell/renderer/shell_content_renderer_client.cc b/content/shell/renderer/shell_content_renderer_client.cc
index a4aab9c..26b675fd 100644
--- a/content/shell/renderer/shell_content_renderer_client.cc
+++ b/content/shell/renderer/shell_content_renderer_client.cc
@@ -116,8 +116,7 @@
       base::Bind(&CreateRendererTestService),
       base::ThreadTaskRunnerHandle::Get());
   registry->AddInterface<mojom::PowerMonitorTest>(
-      base::Bind(&PowerMonitorTestImpl::MakeStrongBinding,
-                 base::Passed(std::make_unique<PowerMonitorTestImpl>())),
+      base::Bind(&PowerMonitorTestImpl::MakeStrongBinding),
       base::ThreadTaskRunnerHandle::Get());
   content::ChildThread::Get()
       ->GetServiceManagerConnection()
diff --git a/content/shell/utility/shell_content_utility_client.cc b/content/shell/utility/shell_content_utility_client.cc
index b46db59..e3b9f1d8 100644
--- a/content/shell/utility/shell_content_utility_client.cc
+++ b/content/shell/utility/shell_content_utility_client.cc
@@ -105,9 +105,7 @@
   registry->AddInterface(base::BindRepeating(&TestUtilityServiceImpl::Create),
                          base::ThreadTaskRunnerHandle::Get());
   registry->AddInterface<mojom::PowerMonitorTest>(
-      base::BindRepeating(
-          &PowerMonitorTestImpl::MakeStrongBinding,
-          base::Passed(std::make_unique<PowerMonitorTestImpl>())),
+      base::BindRepeating(&PowerMonitorTestImpl::MakeStrongBinding),
       base::ThreadTaskRunnerHandle::Get());
   content::ChildThread::Get()
       ->GetServiceManagerConnection()
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 2380506..e8b8450 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -821,6 +821,7 @@
     "../browser/keyboard_lock_browsertest.h",
     "../browser/keyboard_lock_browsertest_mac.mm",
     "../browser/loader/cors_file_origin_browsertest.cc",
+    "../browser/loader/cors_preflight_cache_browsertest.cc",
     "../browser/loader/cross_site_document_blocking_browsertest.cc",
     "../browser/loader/loader_browsertest.cc",
     "../browser/loader/prefetch_browsertest.cc",
diff --git a/content/test/data/loader/cors_preflight.html b/content/test/data/loader/cors_preflight.html
new file mode 100644
index 0000000..aaf3399b
--- /dev/null
+++ b/content/test/data/loader/cors_preflight.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+<script>
+const cors_url = location.protocol + "//" + location.hostname + ":" +
+    location.search.split(';')[1];
+const cache_mode = location.search.split(';')[2];
+fetch(cors_url, {cache: cache_mode, headers: [["foo", "bar"]]}).then(() => {
+  document.title = "DONE";
+});
+</script>
+</head>
+</html>
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 896df6fb..410b9fc2 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -744,7 +744,8 @@
 void WebRequestAPI::MaybeProxyWebSocket(
     content::RenderFrameHost* frame,
     network::mojom::WebSocketRequest* request,
-    network::mojom::AuthenticationHandlerPtr* auth_handler) {
+    network::mojom::AuthenticationHandlerPtr* auth_handler,
+    network::mojom::TrustedHeaderClientPtr* header_client) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!MayHaveProxies())
     return;
@@ -754,6 +755,12 @@
   *request = mojo::MakeRequest(&proxied_socket_ptr_info);
   auto authentication_request = mojo::MakeRequest(auth_handler);
 
+  network::mojom::TrustedHeaderClientRequest header_client_request;
+  if (ExtensionWebRequestEventRouter::GetInstance()->HasAnyExtraHeadersListener(
+          frame->GetProcess()->GetBrowserContext())) {
+    header_client_request = mojo::MakeRequest(header_client);
+  }
+
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::IO},
       base::BindOnce(
@@ -763,7 +770,8 @@
           frame->GetProcess()->GetBrowserContext(),
           frame->GetProcess()->GetBrowserContext()->GetResourceContext(),
           base::Unretained(info_map_), std::move(proxied_socket_ptr_info),
-          std::move(proxied_request), std::move(authentication_request)));
+          std::move(proxied_request), std::move(authentication_request),
+          std::move(header_client_request)));
 }
 
 void WebRequestAPI::ForceProxyForTesting() {
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h
index 6f26f7e..ff6bbea 100644
--- a/extensions/browser/api/web_request/web_request_api.h
+++ b/extensions/browser/api/web_request/web_request_api.h
@@ -224,7 +224,8 @@
   void MaybeProxyWebSocket(
       content::RenderFrameHost* frame,
       network::mojom::WebSocketRequest* request,
-      network::mojom::AuthenticationHandlerPtr* auth_handler);
+      network::mojom::AuthenticationHandlerPtr* auth_handler,
+      network::mojom::TrustedHeaderClientPtr* header_client);
 
   void ForceProxyForTesting();
 
diff --git a/extensions/browser/api/web_request/web_request_proxying_websocket.cc b/extensions/browser/api/web_request/web_request_proxying_websocket.cc
index 69dee4e3..d630a42 100644
--- a/extensions/browser/api/web_request/web_request_proxying_websocket.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_websocket.cc
@@ -25,6 +25,7 @@
     network::mojom::WebSocketPtr proxied_socket,
     network::mojom::WebSocketRequest proxied_request,
     network::mojom::AuthenticationHandlerRequest auth_request,
+    network::mojom::TrustedHeaderClientRequest header_client_request,
     WebRequestAPI::ProxySet* proxies)
     : process_id_(process_id),
       render_frame_id_(render_frame_id),
@@ -37,6 +38,7 @@
       binding_as_websocket_(this),
       binding_as_client_(this),
       binding_as_auth_handler_(this),
+      binding_as_header_client_(this),
       proxies_(proxies),
       weak_factory_(this) {
   binding_as_websocket_.Bind(std::move(proxied_request));
@@ -48,6 +50,9 @@
   binding_as_auth_handler_.set_connection_error_handler(
       base::BindRepeating(&WebRequestProxyingWebSocket::OnError,
                           base::Unretained(this), net::ERR_FAILED));
+
+  if (header_client_request)
+    binding_as_header_client_.Bind(std::move(header_client_request));
 }
 
 WebRequestProxyingWebSocket::~WebRequestProxyingWebSocket() {
@@ -57,6 +62,14 @@
     ExtensionWebRequestEventRouter::GetInstance()->OnRequestWillBeDestroyed(
         browser_context_, &info_.value());
   }
+  if (on_before_send_headers_callback_) {
+    std::move(on_before_send_headers_callback_)
+        .Run(net::ERR_ABORTED, base::nullopt);
+  }
+  if (on_headers_received_callback_) {
+    std::move(on_headers_received_callback_)
+        .Run(net::ERR_ABORTED, base::nullopt, GURL());
+  }
 }
 
 void WebRequestProxyingWebSocket::AddChannelRequest(
@@ -83,9 +96,19 @@
 
   forwarding_client_ = std::move(client);
 
-  auto continuation =
-      base::BindRepeating(&WebRequestProxyingWebSocket::OnBeforeRequestComplete,
-                          weak_factory_.GetWeakPtr());
+  // If the header client will be used, we start the request immediately, and
+  // OnBeforeSendHeaders and OnSendHeaders will be handled there. Otherwise,
+  // send these events before the request starts.
+  base::RepeatingCallback<void(int)> continuation;
+  if (binding_as_header_client_) {
+    continuation = base::BindRepeating(
+        &WebRequestProxyingWebSocket::ContinueToStartRequest,
+        weak_factory_.GetWeakPtr());
+  } else {
+    continuation = base::BindRepeating(
+        &WebRequestProxyingWebSocket::OnBeforeRequestComplete,
+        weak_factory_.GetWeakPtr());
+  }
 
   // TODO(yhirano): Consider having throttling here (probably with aligned with
   // WebRequestProxyingURLLoaderFactory).
@@ -108,7 +131,7 @@
   }
 
   DCHECK_EQ(net::OK, result);
-  OnBeforeRequestComplete(net::OK);
+  continuation.Run(net::OK);
 }
 
 void WebRequestProxyingWebSocket::SendFrame(
@@ -154,23 +177,34 @@
     network::mojom::WebSocketHandshakeResponsePtr response) {
   DCHECK(forwarding_client_);
 
-  response_.headers =
-      base::MakeRefCounted<net::HttpResponseHeaders>(base::StringPrintf(
-          "HTTP/%d.%d %d %s", response->http_version.major_value(),
-          response->http_version.minor_value(), response->status_code,
-          response->status_text.c_str()));
-  for (const auto& header : response->headers) {
-    if (!net::HttpResponseHeaders::IsCookieResponseHeader(header->name)) {
-      // When the renderer process has an access to raw cookie headers, such
-      // headers can be contained in |response|. Here we remove such headers
-      // manually.
+  // response_.headers will be set in OnBeforeSendHeaders if
+  // binding_as_header_client_ is set.
+  if (!binding_as_header_client_) {
+    response_.headers =
+        base::MakeRefCounted<net::HttpResponseHeaders>(base::StringPrintf(
+            "HTTP/%d.%d %d %s", response->http_version.major_value(),
+            response->http_version.minor_value(), response->status_code,
+            response->status_text.c_str()));
+    for (const auto& header : response->headers)
       response_.headers->AddHeader(header->name + ": " + header->value);
-    }
   }
+
   response_.remote_endpoint = response->remote_endpoint;
 
+  // TODO(yhirano): with both network service enabled or disabled,
+  // OnFinishOpeningHandshake is called with the original response headers.
+  // That means if OnHeadersReceived modified them the renderer won't see that
+  // modification. This is the opposite of http(s) requests.
   forwarding_client_->OnFinishOpeningHandshake(std::move(response));
 
+  if (!binding_as_header_client_ || response_.headers) {
+    ContinueToHeadersReceived();
+  } else {
+    waiting_for_header_client_headers_received_ = true;
+  }
+}
+
+void WebRequestProxyingWebSocket::ContinueToHeadersReceived() {
   auto continuation = base::BindRepeating(
       &WebRequestProxyingWebSocket::OnHeadersReceivedComplete,
       weak_factory_.GetWeakPtr());
@@ -265,6 +299,34 @@
   OnHeadersReceivedCompleteForAuth(auth_info, net::OK);
 }
 
+void WebRequestProxyingWebSocket::OnBeforeSendHeaders(
+    const net::HttpRequestHeaders& headers,
+    OnBeforeSendHeadersCallback callback) {
+  DCHECK(binding_as_header_client_);
+
+  request_.headers = headers;
+  on_before_send_headers_callback_ = std::move(callback);
+  OnBeforeRequestComplete(net::OK);
+}
+
+void WebRequestProxyingWebSocket::OnHeadersReceived(
+    const std::string& headers,
+    OnHeadersReceivedCallback callback) {
+  DCHECK(binding_as_header_client_);
+
+  // Note: since there are different pipes used for WebSocketClient and
+  // TrustedHeaderClient, there are no guarantees whether this or
+  // OnFinishOpeningHandshake are called first.
+  on_headers_received_callback_ = std::move(callback);
+  response_.headers = base::MakeRefCounted<net::HttpResponseHeaders>(headers);
+
+  if (!waiting_for_header_client_headers_received_)
+    return;
+
+  waiting_for_header_client_headers_received_ = false;
+  ContinueToHeadersReceived();
+}
+
 void WebRequestProxyingWebSocket::StartProxying(
     int process_id,
     int render_frame_id,
@@ -275,7 +337,8 @@
     InfoMap* info_map,
     network::mojom::WebSocketPtrInfo proxied_socket_ptr_info,
     network::mojom::WebSocketRequest proxied_request,
-    network::mojom::AuthenticationHandlerRequest auth_request) {
+    network::mojom::AuthenticationHandlerRequest auth_request,
+    network::mojom::TrustedHeaderClientRequest header_client_request) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   auto* proxies =
       WebRequestAPI::ProxySet::GetFromResourceContext(resource_context);
@@ -284,13 +347,14 @@
       process_id, render_frame_id, origin, browser_context, resource_context,
       info_map, std::move(request_id_generator),
       network::mojom::WebSocketPtr(std::move(proxied_socket_ptr_info)),
-      std::move(proxied_request), std::move(auth_request), proxies);
+      std::move(proxied_request), std::move(auth_request),
+      std::move(header_client_request), proxies);
 
   proxies->AddProxy(std::move(proxy));
 }
 
 void WebRequestProxyingWebSocket::OnBeforeRequestComplete(int error_code) {
-  DCHECK(!binding_as_client_.is_bound());
+  DCHECK(binding_as_header_client_ || !binding_as_client_.is_bound());
   DCHECK(request_.url.SchemeIsWSOrWSS());
   if (error_code != net::OK) {
     OnError(error_code);
@@ -319,15 +383,26 @@
 }
 
 void WebRequestProxyingWebSocket::OnBeforeSendHeadersComplete(int error_code) {
-  DCHECK(!binding_as_client_.is_bound());
+  DCHECK(binding_as_header_client_ || !binding_as_client_.is_bound());
   if (error_code != net::OK) {
     OnError(error_code);
     return;
   }
 
+  if (binding_as_header_client_) {
+    DCHECK(on_before_send_headers_callback_);
+    std::move(on_before_send_headers_callback_)
+        .Run(error_code, request_.headers);
+  }
+
   ExtensionWebRequestEventRouter::GetInstance()->OnSendHeaders(
       browser_context_, info_map_, &info_.value(), request_.headers);
 
+  if (!binding_as_header_client_)
+    ContinueToStartRequest(net::OK);
+}
+
+void WebRequestProxyingWebSocket::ContinueToStartRequest(int error_code) {
   network::mojom::WebSocketClientPtr proxy;
 
   std::vector<network::mojom::HttpHeaderPtr> additional_headers;
@@ -350,6 +425,19 @@
     OnError(error_code);
     return;
   }
+
+  if (on_headers_received_callback_) {
+    base::Optional<std::string> headers;
+    if (override_headers_)
+      headers = override_headers_->raw_headers();
+    std::move(on_headers_received_callback_).Run(net::OK, headers, GURL());
+  }
+
+  if (override_headers_) {
+    response_.headers = override_headers_;
+    override_headers_ = nullptr;
+  }
+
   ResumeIncomingMethodCallProcessing();
   info_->AddResponseInfoFromResourceResponse(response_);
   ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
@@ -401,11 +489,15 @@
 void WebRequestProxyingWebSocket::PauseIncomingMethodCallProcessing() {
   binding_as_client_.PauseIncomingMethodCallProcessing();
   binding_as_auth_handler_.PauseIncomingMethodCallProcessing();
+  if (binding_as_header_client_)
+    binding_as_header_client_.PauseIncomingMethodCallProcessing();
 }
 
 void WebRequestProxyingWebSocket::ResumeIncomingMethodCallProcessing() {
   binding_as_client_.ResumeIncomingMethodCallProcessing();
   binding_as_auth_handler_.ResumeIncomingMethodCallProcessing();
+  if (binding_as_header_client_)
+    binding_as_header_client_.ResumeIncomingMethodCallProcessing();
 }
 
 void WebRequestProxyingWebSocket::OnError(int error_code) {
diff --git a/extensions/browser/api/web_request/web_request_proxying_websocket.h b/extensions/browser/api/web_request/web_request_proxying_websocket.h
index 173a89d..cac917d 100644
--- a/extensions/browser/api/web_request/web_request_proxying_websocket.h
+++ b/extensions/browser/api/web_request/web_request_proxying_websocket.h
@@ -20,6 +20,7 @@
 #include "net/base/network_delegate.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/websocket.mojom.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -36,7 +37,8 @@
     : public WebRequestAPI::Proxy,
       public network::mojom::WebSocket,
       public network::mojom::WebSocketClient,
-      public network::mojom::AuthenticationHandler {
+      public network::mojom::AuthenticationHandler,
+      public network::mojom::TrustedHeaderClient {
  public:
   WebRequestProxyingWebSocket(
       int process_id,
@@ -49,6 +51,7 @@
       network::mojom::WebSocketPtr proxied_socket,
       network::mojom::WebSocketRequest proxied_request,
       network::mojom::AuthenticationHandlerRequest auth_request,
+      network::mojom::TrustedHeaderClientRequest header_client_request,
       WebRequestAPI::ProxySet* proxies);
   ~WebRequestProxyingWebSocket() override;
 
@@ -88,6 +91,12 @@
                       const net::IPEndPoint& remote_endpoint,
                       OnAuthRequiredCallback callback) override;
 
+  // network::mojom::TrustedHeaderClient methods:
+  void OnBeforeSendHeaders(const net::HttpRequestHeaders& headers,
+                           OnBeforeSendHeadersCallback callback) override;
+  void OnHeadersReceived(const std::string& headers,
+                         OnHeadersReceivedCallback callback) override;
+
   static void StartProxying(
       int process_id,
       int render_frame_id,
@@ -98,12 +107,15 @@
       InfoMap* info_map,
       network::mojom::WebSocketPtrInfo proxied_socket_ptr_info,
       network::mojom::WebSocketRequest proxied_request,
-      network::mojom::AuthenticationHandlerRequest auth_request);
+      network::mojom::AuthenticationHandlerRequest auth_request,
+      network::mojom::TrustedHeaderClientRequest header_client_request);
 
  private:
   void OnBeforeRequestComplete(int error_code);
   void OnBeforeSendHeadersComplete(int error_code);
+  void ContinueToStartRequest(int error_code);
   void OnHeadersReceivedComplete(int error_code);
+  void ContinueToHeadersReceived();
   void OnAuthRequiredComplete(net::NetworkDelegate::AuthRequiredResponse rv);
   void OnHeadersReceivedCompleteForAuth(
       scoped_refptr<net::AuthChallengeInfo> auth_info,
@@ -125,6 +137,7 @@
   mojo::Binding<network::mojom::WebSocket> binding_as_websocket_;
   mojo::Binding<network::mojom::WebSocketClient> binding_as_client_;
   mojo::Binding<network::mojom::AuthenticationHandler> binding_as_auth_handler_;
+  mojo::Binding<network::mojom::TrustedHeaderClient> binding_as_header_client_;
 
   network::ResourceRequest request_;
   network::ResourceResponseHead response_;
@@ -133,8 +146,12 @@
   scoped_refptr<net::HttpResponseHeaders> override_headers_;
   std::vector<std::string> websocket_protocols_;
 
+  OnBeforeSendHeadersCallback on_before_send_headers_callback_;
+  OnHeadersReceivedCallback on_headers_received_callback_;
+
   GURL redirect_url_;
   bool is_done_ = false;
+  bool waiting_for_header_client_headers_received_ = false;
 
   base::Optional<WebRequestInfo> info_;
 
diff --git a/extensions/renderer/gc_callback.cc b/extensions/renderer/gc_callback.cc
index e3c35865..58d19d4 100644
--- a/extensions/renderer/gc_callback.cc
+++ b/extensions/renderer/gc_callback.cc
@@ -9,6 +9,8 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "extensions/renderer/script_context.h"
+#include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/public/web/web_local_frame.h"
 
 namespace extensions {
 
@@ -57,9 +59,18 @@
   // code is RunCallback.
   GCCallback* self = data.GetParameter();
   self->object_.Reset();
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&GCCallback::RunCallback,
-                                self->weak_ptr_factory_.GetWeakPtr()));
+
+  blink::WebLocalFrame* frame = self->context_->web_frame();
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner;
+  if (frame) {
+    task_runner = frame->GetTaskRunner(blink::TaskType::kInternalDefault);
+  } else {
+    // |frame| can be null on tests.
+    task_runner = base::ThreadTaskRunnerHandle::Get();
+  }
+  task_runner->PostTask(FROM_HERE,
+                        base::BindOnce(&GCCallback::RunCallback,
+                                       self->weak_ptr_factory_.GetWeakPtr()));
 }
 
 void GCCallback::RunCallback() {
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index b9fbbb3..1149cf6 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -2884,7 +2884,7 @@
       mixins: "fyi-ci"
     }
     builders {
-      name: "ios-device-goma-canary-latest"
+      name: "ios-device-goma-latest-clobber"
       dimensions: "os:Mac-10.13"
       dimensions: "cores:4"
       mixins: "fyi-ci"
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index d16f2570..65c6f98 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -2419,7 +2419,7 @@
     short_name: "loc"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/chromeos-amd64-generic-rel-goma-latest-client"
+    name: "buildbucket/luci.chromium.ci/chromeos-amd64-generic-rel-goma-latest"
     category: "cros|rel"
   }
   builders {
@@ -2441,7 +2441,7 @@
     category: "android|dbg"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/ios-device-goma-latest-client-clobber"
+    name: "buildbucket/luci.chromium.ci/ios-device-goma-latest-clobber"
     category: "ios"
     short_name: "clb"
   }
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index bfbcf49..591e860 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -307,7 +307,7 @@
   triggers: "chromeos-amd64-generic-cfi-thin-lto-rel"
   triggers: "chromeos-amd64-generic-rel"
   triggers: "chromeos-amd64-generic-rel-goma-canary"
-  triggers: "chromeos-amd64-generic-rel-goma-latest-client"
+  triggers: "chromeos-amd64-generic-rel-goma-latest"
   triggers: "chromeos-amd64-generic-rel-vm-tests"
   triggers: "chromeos-daisy-rel"
   triggers: "chromeos-kevin-rel"
@@ -318,7 +318,7 @@
   triggers: "fuchsia-fyi-x64-rel"
   triggers: "ios-device"
   triggers: "ios-device-goma-canary-clobber"
-  triggers: "ios-device-goma-latest-client-clobber"
+  triggers: "ios-device-goma-latest-clobber"
   triggers: "ios-device-xcode-clang"
   triggers: "ios-simulator"
   triggers: "ios-simulator-cronet"
@@ -4311,22 +4311,22 @@
 }
 
 job {
-  id: "chromeos-amd64-generic-rel-goma-latest-client"
+  id: "chromeos-amd64-generic-rel-goma-latest"
   acl_sets: "default"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
     bucket: "luci.chromium.ci"
-    builder: "chromeos-amd64-generic-rel-goma-latest-client"
+    builder: "chromeos-amd64-generic-rel-goma-latest"
   }
 }
 
 job {
-  id: "ios-device-goma-latest-client-clobber"
+  id: "ios-device-goma-latest-clobber"
   acl_sets: "default"
   buildbucket: {
     server: "cr-buildbucket.appspot.com"
     bucket: "luci.chromium.ci"
-    builder: "ios-device-goma-latest-client-clobber"
+    builder: "ios-device-goma-latest-clobber"
   }
 }
 
diff --git a/ios/build/bots/chromium.fyi/ios-device-goma-latest-clobber.json b/ios/build/bots/chromium.fyi/ios-device-goma-latest-clobber.json
new file mode 100644
index 0000000..2360c2e9
--- /dev/null
+++ b/ios/build/bots/chromium.fyi/ios-device-goma-latest-clobber.json
@@ -0,0 +1,25 @@
+{
+  "comments": [
+    "Goma canary builder for iOS.",
+    "It is chromium.mac/ios-device.json + use_goma_canary, clobber."
+  ],
+  "xcode build version": "10b61",
+  "gn_args": [
+    "goma_dir=\"$(goma_dir)\"",
+    "ios_enable_code_signing=false",
+    "is_component_build=false",
+    "is_debug=false",
+    "target_cpu=\"arm64\"",
+    "target_os=\"ios\"",
+    "use_goma=true"
+  ],
+  "additional_compile_targets": [
+    "all"
+  ],
+  "configuration": "Release",
+  "explain": true,
+  "tests": [
+  ],
+  "clobber": true,
+  "goma_client_type": "latest"
+}
diff --git a/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm b/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm
index 2af8f06..470e31c 100644
--- a/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.mm
@@ -230,12 +230,12 @@
 }
 
 - (NSString*)accessibilityValue {
-  if (self.optionalTextLabel && self.detailTextLabel) {
-    return [@[ self.detailTextLabel.text, self.optionalTextLabel.text ]
-        componentsJoinedByString:@". "];
-  } else {
-    return self.detailTextLabel.text;
+  NSString* value = self.detailTextLabel.text;
+  if (self.optionalTextLabel.text) {
+    value = [NSString
+        stringWithFormat:@"%@.%@", value, self.optionalTextLabel.text];
   }
+  return value;
 }
 
 @end
diff --git a/ios/web/web_state/error_page_inttest.mm b/ios/web/web_state/error_page_inttest.mm
index 91365a2..84da235 100644
--- a/ios/web/web_state/error_page_inttest.mm
+++ b/ios/web/web_state/error_page_inttest.mm
@@ -11,6 +11,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "ios/testing/embedded_test_server_handlers.h"
 #include "ios/web/public/features.h"
+#import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/reload_type.h"
 #include "ios/web/public/security_style.h"
@@ -325,6 +326,25 @@
                                 /*is_post*/ true, /*is_otr*/ false)));
 }
 
+// Loads an item and checks that virtualURL and URL after displaying the error
+// are correct.
+TEST_P(ErrorPageTest, URLAndVirtualURLAfterError) {
+  GURL url(server_.GetURL("/close-socket"));
+  GURL virtual_url("http://virual_url.test");
+  web::NavigationManager::WebLoadParams params(url);
+  params.virtual_url = virtual_url;
+  web::NavigationManager* manager = web_state()->GetNavigationManager();
+  manager->LoadURLWithParams(params);
+  manager->LoadIfNecessary();
+  ASSERT_TRUE(test::WaitForWebViewContainingText(
+      web_state(),
+      GetErrorText(web_state(), url, "NSURLErrorDomain", /*error_code*/ -1005,
+                   /*is_post*/ false, /*is_otr*/ false)));
+
+  EXPECT_EQ(url, manager->GetLastCommittedItem()->GetURL());
+  EXPECT_EQ(virtual_url, manager->GetLastCommittedItem()->GetVirtualURL());
+}
+
 INSTANTIATE_TEST_SUITE_P(ProgrammaticErrorPageTest,
                          ErrorPageTest,
                          ::testing::Values(NavigationManagerChoice::LEGACY,
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 2e6fb711..a538c94 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2335,7 +2335,6 @@
 
 - (void)loadErrorPageForNavigationItem:(web::NavigationItemImpl*)item
                      navigationContext:(web::NavigationContextImpl*)context {
-  const GURL currentURL = item ? item->GetVirtualURL() : GURL::EmptyGURL();
   NSError* error = context->GetError();
   DCHECK(error);
   DCHECK_EQ(item->GetUniqueID(), context->GetNavigationItemUniqueID());
@@ -2351,19 +2350,19 @@
   } else {
     error = web::NetErrorFromError(error);
   }
-  NSString* failing_url = error.userInfo[NSURLErrorFailingURLStringErrorKey];
+  NSString* failingURLString =
+      error.userInfo[NSURLErrorFailingURLStringErrorKey];
+  GURL failingURL(base::SysNSStringToUTF8(failingURLString));
   NSString* errorHTML = nil;
   web::GetWebClient()->PrepareErrorPage(
-      self.webStateImpl, GURL(base::SysNSStringToUTF8(failing_url)), error,
-      context->IsPost(), self.webStateImpl->GetBrowserState()->IsOffTheRecord(),
-      &errorHTML);
-
+      self.webStateImpl, failingURL, error, context->IsPost(),
+      self.webStateImpl->GetBrowserState()->IsOffTheRecord(), &errorHTML);
   WKNavigation* navigation =
       [self.webView loadHTMLString:errorHTML
-                           baseURL:net::NSURLWithGURL(currentURL)];
+                           baseURL:net::NSURLWithGURL(failingURL)];
 
   auto loadHTMLContext = web::NavigationContextImpl::CreateNavigationContext(
-      self.webStateImpl, currentURL,
+      self.webStateImpl, failingURL,
       /*has_user_gesture=*/false, ui::PAGE_TRANSITION_FIRST,
       /*is_renderer_initiated=*/false);
   loadHTMLContext->SetLoadingErrorPage(true);
@@ -2397,7 +2396,7 @@
 
   [self loadCompleteWithSuccess:NO forContext:context];
   self.webStateImpl->SetIsLoading(false);
-  self.webStateImpl->OnPageLoaded(currentURL, NO);
+  self.webStateImpl->OnPageLoaded(failingURL, NO);
 }
 
 - (web::NavigationContextImpl*)
@@ -4888,9 +4887,18 @@
   if (context) {
     web::NavigationManager* navigationManager =
         self.webStateImpl->GetNavigationManager();
-    if ((navigationManager->GetPendingItem() &&
-         navigationManager->GetPendingItem()->GetURL() == webViewURL) ||
-        (context->IsLoadingHtmlString()) ||
+    GURL pendingURL;
+    if (web::features::StorePendingItemInContext() &&
+        navigationManager->GetPendingItemIndex() == -1) {
+      if (context->GetItem()) {
+        pendingURL = context->GetItem()->GetURL();
+      }
+    } else {
+      if (navigationManager->GetPendingItem()) {
+        pendingURL = navigationManager->GetPendingItem()->GetURL();
+      }
+    }
+    if ((pendingURL == webViewURL) || (context->IsLoadingHtmlString()) ||
         (!web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
          ui::PageTransitionCoreTypeIs(context->GetPageTransition(),
                                       ui::PAGE_TRANSITION_RELOAD) &&
diff --git a/ios/web_view/internal/web_view_url_request_context_getter.mm b/ios/web_view/internal/web_view_url_request_context_getter.mm
index c0d482c7..98f3bd3 100644
--- a/ios/web_view/internal/web_view_url_request_context_getter.mm
+++ b/ios/web_view/internal/web_view_url_request_context_getter.mm
@@ -180,7 +180,14 @@
 
 void WebViewURLRequestContextGetter::ShutDown() {
   is_shutting_down_ = true;
+
+  // Clean up some member variables now to avoid a use after free crash with
+  // |net_log_|.
+  transport_security_persister_.reset();
+  storage_.reset();
   url_request_context_.reset();
+  network_delegate_.reset();
+
   net::URLRequestContextGetter::NotifyContextShuttingDown();
 }
 
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index 6cd039e..d8c1bfd 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -48,15 +48,16 @@
   "//third_party/blink/common/typemaps.gni",
   "//third_party/blink/public/public_typemaps.gni",
   "//ui/accessibility/mojom/typemaps.gni",
-  "//ui/base/mojo/typemaps.gni",
   "//ui/base/accelerators/mojo/typemaps.gni",
+  "//ui/base/ime/mojo/typemaps.gni",
+  "//ui/base/mojo/typemaps.gni",
   "//ui/display/mojo/typemaps.gni",
   "//ui/events/devices/mojo/typemaps.gni",
   "//ui/events/mojo/typemaps.gni",
   "//ui/gfx/typemaps.gni",
   "//ui/latency/mojo/typemaps.gni",
-  "//ui/ozone/public/interfaces/typemaps.gni",
   "//ui/message_center/public/mojo/typemaps.gni",
+  "//ui/ozone/public/interfaces/typemaps.gni",
   "//url/mojom/typemaps.gni",
 ]
 
diff --git a/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
index 77b5ea24..503bf21b 100644
--- a/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
@@ -17,6 +17,14 @@
    */
 {% endmacro %}
 
+{%  if generate_closure_exports -%}
+goog.provide('{{module.namespace}}.{{interface.name}}');
+goog.provide('{{module.namespace}}.{{interface.name}}CallbackRouter');
+goog.provide('{{module.namespace}}.{{interface.name}}Interface');
+goog.provide('{{module.namespace}}.{{interface.name}}Proxy');
+goog.provide('{{module.namespace}}.{{interface.name}}Request');
+{% endif %}
+
 /** @export */
 {{module.namespace}}.{{interface.name}}Request = class {
   /** @param {!MojoHandle} handle */
@@ -94,10 +102,6 @@
 {%-  endfor %}
 };
 
-{%  if generate_closure_exports -%}
-goog.provide('{{module.namespace}}.{{interface.name}}');
-{% endif %}
-
 /**
  * An object which receives request messages for the {{interface.name}}
  * mojom interface. Must be constructed over an object which implements that
diff --git a/mojo/public/tools/bindings/generators/js_templates/lite/mojom-lite.js.tmpl b/mojo/public/tools/bindings/generators/js_templates/lite/mojom-lite.js.tmpl
index 55bccb8..a02c7a32 100644
--- a/mojo/public/tools/bindings/generators/js_templates/lite/mojom-lite.js.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/lite/mojom-lite.js.tmpl
@@ -11,8 +11,8 @@
 {% for kind in module.imported_kinds.values() %}
 goog.require('{{kind|lite_js_import_name}}');
 {%- endfor %}
-{% endif %}
-
+{% else %}
 mojo.internal.exportModule('{{module.namespace}}');
+{% endif %}
 
 {% include "lite/module_definition.tmpl" %}
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index efefb8e..2ba73b5 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -192,8 +192,6 @@
     sources += [
       "public/cpp/sounds/audio_stream_handler_unittest.cc",
       "public/cpp/sounds/sounds_manager_unittest.cc",
-      "public/cpp/sounds/test_data.cc",
-      "public/cpp/sounds/test_data.h",
     ]
   }
 
diff --git a/services/audio/public/cpp/BUILD.gn b/services/audio/public/cpp/BUILD.gn
index 1fed011..eb6addd 100644
--- a/services/audio/public/cpp/BUILD.gn
+++ b/services/audio/public/cpp/BUILD.gn
@@ -22,6 +22,8 @@
     "sounds/audio_stream_handler.h",
     "sounds/sounds_manager.cc",
     "sounds/sounds_manager.h",
+    "sounds/test_data.cc",
+    "sounds/test_data.h",
   ]
 
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
diff --git a/services/audio/public/cpp/debug_recording_session.cc b/services/audio/public/cpp/debug_recording_session.cc
index 6c937e2..b9c19cf47 100644
--- a/services/audio/public/cpp/debug_recording_session.cc
+++ b/services/audio/public/cpp/debug_recording_session.cc
@@ -11,7 +11,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
 #include "media/audio/audio_debug_recording_manager.h"
-#include "media/audio/audio_manager.h"
 #include "services/audio/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 
diff --git a/services/audio/public/cpp/sounds/audio_stream_handler.cc b/services/audio/public/cpp/sounds/audio_stream_handler.cc
index ef6cce0..12084c1 100644
--- a/services/audio/public/cpp/sounds/audio_stream_handler.cc
+++ b/services/audio/public/cpp/sounds/audio_stream_handler.cc
@@ -14,11 +14,12 @@
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
+#include "base/task/post_task.h"
 #include "base/time/time.h"
-#include "media/audio/audio_manager.h"
-#include "media/audio/audio_manager_base.h"
 #include "media/audio/wav_audio_handler.h"
 #include "media/base/channel_layout.h"
+#include "media/mojo/interfaces/audio_output_stream.mojom.h"
+#include "services/audio/public/cpp/output_device.h"
 
 namespace audio {
 
@@ -27,106 +28,97 @@
 // Volume percent.
 const double kOutputVolumePercent = 0.8;
 
-// The number of frames each OnMoreData() call will request.
+// The number of frames each Render() call will request.
 const int kDefaultFrameCount = 1024;
 
 // Keep alive timeout for audio stream.
 const int kKeepAliveMs = 1500;
 
 AudioStreamHandler::TestObserver* g_observer_for_testing = NULL;
-media::AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing =
-    NULL;
 
 }  // namespace
 
 class AudioStreamHandler::AudioStreamContainer
-    : public media::AudioOutputStream::AudioSourceCallback {
+    : public media::AudioRendererSink::RenderCallback {
  public:
   explicit AudioStreamContainer(
+      std::unique_ptr<service_manager::Connector> connector,
       std::unique_ptr<media::WavAudioHandler> wav_audio)
-      : audio_manager_(media::AudioManager::Get()),
-        started_(false),
-        stream_(NULL),
+      : started_(false),
         cursor_(0),
         delayed_stop_posted_(false),
         wav_audio_(std::move(wav_audio)) {
-    DCHECK(audio_manager_);
     DCHECK(wav_audio_);
+    task_runner_ = base::SequencedTaskRunnerHandle::Get();
+
+    const media::AudioParameters params(
+        media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+        media::GuessChannelLayout(wav_audio_->num_channels()),
+        wav_audio_->sample_rate(), kDefaultFrameCount);
+
+    if (g_observer_for_testing) {
+      g_observer_for_testing->Initialize(this, params);
+      return;
+    }
+    device_ = std::make_unique<audio::OutputDevice>(
+        std::move(connector), params, this, std::string());
   }
 
   ~AudioStreamContainer() override {
-    DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+    DCHECK(task_runner_->RunsTasksInCurrentSequence());
   }
 
   void Play() {
-    DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
-
-    if (!stream_) {
-      const media::AudioParameters params(
-          media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-          media::GuessChannelLayout(wav_audio_->num_channels()),
-          wav_audio_->sample_rate(), kDefaultFrameCount);
-      stream_ =
-          audio_manager_->MakeAudioOutputStreamProxy(params, std::string());
-      if (!stream_ || !stream_->Open()) {
-        LOG(ERROR) << "Failed to open an output stream.";
-        return;
-      }
-      stream_->SetVolume(kOutputVolumePercent);
-    }
+    DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
     {
       base::AutoLock al(state_lock_);
 
       delayed_stop_posted_ = false;
-      stop_closure_.Reset(base::Bind(&AudioStreamContainer::StopStream,
-                                     base::Unretained(this)));
+      stop_closure_.Reset(base::BindRepeating(&AudioStreamContainer::StopStream,
+                                              base::Unretained(this)));
 
       if (started_) {
         if (wav_audio_->AtEnd(cursor_))
           cursor_ = 0;
         return;
+      } else {
+        if (!g_observer_for_testing)
+          device_->SetVolume(kOutputVolumePercent);
       }
 
       cursor_ = 0;
     }
 
     started_ = true;
-    if (g_audio_source_for_testing)
-      stream_->Start(g_audio_source_for_testing);
-    else
-      stream_->Start(this);
-
     if (g_observer_for_testing)
       g_observer_for_testing->OnPlay();
+    else
+      device_->Play();
   }
 
   void Stop() {
-    DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+    DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
     StopStream();
-    if (stream_)
-      stream_->Close();
-    stream_ = NULL;
     stop_closure_.Cancel();
   }
 
  private:
-  // AudioOutputStream::AudioSourceCallback overrides:
+  // media::AudioRendererSink::RenderCallback overrides:
   // Following methods could be called from *ANY* thread.
-  int OnMoreData(base::TimeDelta /* delay */,
-                 base::TimeTicks /* delay_timestamp */,
-                 int /* prior_frames_skipped */,
-                 media::AudioBus* dest) override {
+  int Render(base::TimeDelta /* delay */,
+             base::TimeTicks /* delay_timestamp */,
+             int /* prior_frames_skipped */,
+             media::AudioBus* dest) override {
     base::AutoLock al(state_lock_);
     size_t bytes_written = 0;
-
     if (wav_audio_->AtEnd(cursor_) ||
         !wav_audio_->CopyTo(dest, cursor_, &bytes_written)) {
       if (delayed_stop_posted_)
         return 0;
       delayed_stop_posted_ = true;
-      audio_manager_->GetTaskRunner()->PostDelayedTask(
+      task_runner_->PostDelayedTask(
           FROM_HERE, stop_closure_.callback(),
           base::TimeDelta::FromMilliseconds(kKeepAliveMs));
       return 0;
@@ -135,30 +127,29 @@
     return dest->frames();
   }
 
-  void OnError() override {
-    LOG(ERROR) << "Error during system sound reproduction.";
-    audio_manager_->GetTaskRunner()->PostTask(
+  void OnRenderError() override {
+    task_runner_->PostTask(
         FROM_HERE,
         base::BindOnce(&AudioStreamContainer::Stop, base::Unretained(this)));
   }
 
   void StopStream() {
-    DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+    DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
-    if (stream_ && started_) {
+    if (started_) {
       // Do not hold the |state_lock_| while stopping the output stream.
-      stream_->Stop();
       if (g_observer_for_testing)
         g_observer_for_testing->OnStop(cursor_);
+      else
+        device_->Pause();
     }
 
     started_ = false;
   }
 
-  // Must only be accessed on the AudioManager::GetTaskRunner() thread.
-  media::AudioManager* const audio_manager_;
   bool started_;
-  media::AudioOutputStream* stream_;
+  std::unique_ptr<audio::OutputDevice> device_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
   // All variables below must be accessed under |state_lock_| when |started_|.
   base::Lock state_lock_;
@@ -170,13 +161,10 @@
   DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
 };
 
-AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data) {
-  media::AudioManager* manager = media::AudioManager::Get();
-  if (!manager) {
-    LOG(ERROR) << "Can't get access to audio manager.";
-    return;
-  }
-
+AudioStreamHandler::AudioStreamHandler(
+    std::unique_ptr<service_manager::Connector> connector,
+    const base::StringPiece& wav_data) {
+  task_runner_ = base::SequencedTaskRunnerHandle::Get();
   std::unique_ptr<media::WavAudioHandler> wav_audio =
       media::WavAudioHandler::Create(wav_data);
   if (!wav_audio) {
@@ -195,50 +183,49 @@
 
   // Store the duration of the WAV data then pass the handler to |stream_|.
   duration_ = wav_audio->GetDuration();
-  stream_.reset(new AudioStreamContainer(std::move(wav_audio)));
+  stream_.reset(
+      new AudioStreamContainer(std::move(connector), std::move(wav_audio)));
 }
 
 AudioStreamHandler::~AudioStreamHandler() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   if (IsInitialized()) {
-    media::AudioManager::Get()->GetTaskRunner()->PostTask(
-        FROM_HERE, base::BindOnce(&AudioStreamContainer::Stop,
-                                  base::Unretained(stream_.get())));
-    media::AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE,
-                                                            stream_.release());
+    task_runner_->PostTask(FROM_HERE,
+                           base::BindOnce(&AudioStreamContainer::Stop,
+                                          base::Unretained(stream_.get())));
+    task_runner_->DeleteSoon(FROM_HERE, stream_.release());
   }
 }
 
 bool AudioStreamHandler::IsInitialized() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   return !!stream_;
 }
 
 bool AudioStreamHandler::Play() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   if (!IsInitialized())
     return false;
 
-  media::AudioManager::Get()->GetTaskRunner()->PostTask(
+  task_runner_->PostTask(
       FROM_HERE, base::BindOnce(base::IgnoreResult(&AudioStreamContainer::Play),
                                 base::Unretained(stream_.get())));
   return true;
 }
 
 void AudioStreamHandler::Stop() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   if (!IsInitialized())
     return;
 
-  media::AudioManager::Get()->GetTaskRunner()->PostTask(
-      FROM_HERE, base::BindOnce(&AudioStreamContainer::Stop,
-                                base::Unretained(stream_.get())));
+  task_runner_->PostTask(FROM_HERE,
+                         base::BindOnce(&AudioStreamContainer::Stop,
+                                        base::Unretained(stream_.get())));
 }
 
 base::TimeDelta AudioStreamHandler::duration() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   return duration_;
 }
 
@@ -247,10 +234,4 @@
   g_observer_for_testing = observer;
 }
 
-// static
-void AudioStreamHandler::SetAudioSourceForTesting(
-    media::AudioOutputStream::AudioSourceCallback* source) {
-  g_audio_source_for_testing = source;
-}
-
 }  // namespace audio
diff --git a/services/audio/public/cpp/sounds/audio_stream_handler.h b/services/audio/public/cpp/sounds/audio_stream_handler.h
index 3187e26..8d98fe3 100644
--- a/services/audio/public/cpp/sounds/audio_stream_handler.h
+++ b/services/audio/public/cpp/sounds/audio_stream_handler.h
@@ -6,21 +6,23 @@
 #define SERVICES_AUDIO_PUBLIC_CPP_SOUNDS_AUDIO_STREAM_HANDLER_H_
 
 #include <stddef.h>
-
 #include <memory>
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/sequence_checker.h"
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "media/audio/audio_io.h"
 #include "media/base/audio_parameters.h"
+#include "media/base/audio_renderer_sink.h"
 #include "media/base/media_export.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace audio {
 
-// This class sends a sound to the audio manager.
+// This class sends a sound to the audio output device.
 class AudioStreamHandler {
  public:
   class TestObserver {
@@ -29,6 +31,10 @@
 
     // Following methods will be called only from the audio thread.
 
+    // Called when AudioStreamContainer was successfully created.
+    virtual void Initialize(media::AudioRendererSink::RenderCallback* callback,
+                            media::AudioParameters params) = 0;
+
     // Called when AudioOutputStreamProxy::Start() was successfully called.
     virtual void OnPlay() = 0;
 
@@ -37,8 +43,10 @@
   };
 
   // C-tor for AudioStreamHandler. |wav_data| should be a raw
-  // uncompressed WAVE data which will be sent to the audio manager.
-  explicit AudioStreamHandler(const base::StringPiece& wav_data);
+  // uncompressed WAVE data which will be sent to the audio output device.
+  explicit AudioStreamHandler(
+      std::unique_ptr<service_manager::Connector> connector,
+      const base::StringPiece& wav_data);
   virtual ~AudioStreamHandler();
 
   // Returns true iff AudioStreamHandler is correctly initialized;
@@ -58,20 +66,17 @@
   // Get the duration of the WAV data passed in.
   base::TimeDelta duration() const;
 
+  static void SetObserverForTesting(TestObserver* observer);
+
  private:
   friend class AudioStreamHandlerTest;
   friend class SoundsManagerTest;
 
   class AudioStreamContainer;
 
-  static void SetObserverForTesting(TestObserver* observer);
-  static void SetAudioSourceForTesting(
-      media::AudioOutputStream::AudioSourceCallback* source);
-
   base::TimeDelta duration_;
   std::unique_ptr<AudioStreamContainer> stream_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(AudioStreamHandler);
 };
diff --git a/services/audio/public/cpp/sounds/audio_stream_handler_unittest.cc b/services/audio/public/cpp/sounds/audio_stream_handler_unittest.cc
index a2c84251..45346f9 100644
--- a/services/audio/public/cpp/sounds/audio_stream_handler_unittest.cc
+++ b/services/audio/public/cpp/sounds/audio_stream_handler_unittest.cc
@@ -5,6 +5,7 @@
 #include "services/audio/public/cpp/sounds/audio_stream_handler.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -16,11 +17,11 @@
 #include "base/test/test_message_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "media/audio/audio_io.h"
-#include "media/audio/audio_manager.h"
 #include "media/audio/simple_sources.h"
 #include "media/audio/test_audio_thread.h"
-#include "services/audio/public/cpp/sounds/test_data.h"
 #include "media/base/channel_layout.h"
+#include "services/audio/public/cpp/output_device.h"
+#include "services/audio/public/cpp/sounds/test_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace audio {
@@ -31,50 +32,35 @@
   ~AudioStreamHandlerTest() override = default;
 
   void SetUp() override {
-    audio_manager_ = media::AudioManager::CreateForTesting(
-        std::make_unique<media::TestAudioThread>());
-    base::RunLoop().RunUntilIdle();
-
-    base::StringPiece data(kTestAudioData, base::size(kTestAudioData));
-    audio_stream_handler_.reset(new AudioStreamHandler(data));
-  }
-
-  void TearDown() override {
-    audio_stream_handler_.reset();
-    audio_manager_->Shutdown();
-    base::RunLoop().RunUntilIdle();
-  }
-
-  AudioStreamHandler* audio_stream_handler() {
-    return audio_stream_handler_.get();
+    service_manager::mojom::ConnectorRequest connector_request;
+    connector_ = service_manager::Connector::Create(&connector_request);
   }
 
   void SetObserverForTesting(AudioStreamHandler::TestObserver* observer) {
     AudioStreamHandler::SetObserverForTesting(observer);
   }
 
-  void SetAudioSourceForTesting(
-      media::AudioOutputStream::AudioSourceCallback* source) {
-    AudioStreamHandler::SetAudioSourceForTesting(source);
-  }
+  std::unique_ptr<service_manager::Connector> connector_;
 
  private:
   base::TestMessageLoop message_loop_;
-  std::unique_ptr<media::AudioManager> audio_manager_;
-  std::unique_ptr<AudioStreamHandler> audio_stream_handler_;
 };
 
 TEST_F(AudioStreamHandlerTest, Play) {
   base::RunLoop run_loop;
   TestObserver observer(run_loop.QuitClosure());
+  base::StringPiece data(kTestAudioData, kTestAudioDataSize);
+  std::unique_ptr<AudioStreamHandler> audio_stream_handler;
 
   SetObserverForTesting(&observer);
+  audio_stream_handler.reset(
+      new AudioStreamHandler(std::move(connector_), data));
 
-  ASSERT_TRUE(audio_stream_handler()->IsInitialized());
+  ASSERT_TRUE(audio_stream_handler->IsInitialized());
   EXPECT_EQ(base::TimeDelta::FromMicroseconds(20u),
-            audio_stream_handler()->duration());
+            audio_stream_handler->duration());
 
-  ASSERT_TRUE(audio_stream_handler()->Play());
+  ASSERT_TRUE(audio_stream_handler->Play());
 
   run_loop.Run();
 
@@ -88,31 +74,32 @@
 TEST_F(AudioStreamHandlerTest, ConsecutivePlayRequests) {
   base::RunLoop run_loop;
   TestObserver observer(run_loop.QuitClosure());
-  media::SineWaveAudioSource source(media::CHANNEL_LAYOUT_STEREO, 200.0, 8000);
+  base::StringPiece data(kTestAudioData, kTestAudioDataSize);
+  std::unique_ptr<AudioStreamHandler> audio_stream_handler;
 
   SetObserverForTesting(&observer);
-  SetAudioSourceForTesting(&source);
+  audio_stream_handler.reset(
+      new AudioStreamHandler(std::move(connector_), data));
 
-  ASSERT_TRUE(audio_stream_handler()->IsInitialized());
+  ASSERT_TRUE(audio_stream_handler->IsInitialized());
   EXPECT_EQ(base::TimeDelta::FromMicroseconds(20u),
-            audio_stream_handler()->duration());
+            audio_stream_handler->duration());
 
-  ASSERT_TRUE(audio_stream_handler()->Play());
+  ASSERT_TRUE(audio_stream_handler->Play());
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::BindOnce(base::IgnoreResult(&AudioStreamHandler::Play),
-                     base::Unretained(audio_stream_handler())),
+                     base::Unretained(audio_stream_handler.get())),
       base::TimeDelta::FromSeconds(1));
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::BindOnce(&AudioStreamHandler::Stop,
-                     base::Unretained(audio_stream_handler())),
+                     base::Unretained(audio_stream_handler.get())),
       base::TimeDelta::FromSeconds(2));
 
   run_loop.Run();
 
   SetObserverForTesting(NULL);
-  SetAudioSourceForTesting(NULL);
 
   ASSERT_EQ(1, observer.num_play_requests());
   ASSERT_EQ(1, observer.num_stop_requests());
@@ -121,7 +108,8 @@
 TEST_F(AudioStreamHandlerTest, BadWavDataDoesNotInitialize) {
   // The class members and SetUp() will be ignored for this test. Create a
   // handler on the stack with some bad WAV data.
-  AudioStreamHandler handler("RIFF1234WAVEjunkjunkjunkjunk");
+  AudioStreamHandler handler(std::move(connector_),
+                             "RIFF1234WAVEjunkjunkjunkjunk");
   EXPECT_FALSE(handler.IsInitialized());
   EXPECT_FALSE(handler.Play());
   EXPECT_EQ(base::TimeDelta(), handler.duration());
diff --git a/services/audio/public/cpp/sounds/sounds_manager.cc b/services/audio/public/cpp/sounds/sounds_manager.cc
index b3da1a2..520968e 100644
--- a/services/audio/public/cpp/sounds/sounds_manager.cc
+++ b/services/audio/public/cpp/sounds/sounds_manager.cc
@@ -4,11 +4,12 @@
 
 #include "services/audio/public/cpp/sounds/sounds_manager.h"
 
+#include <memory>
+#include <utility>
 #include <vector>
 
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-#include "media/audio/audio_manager.h"
 #include "services/audio/public/cpp/sounds/audio_stream_handler.h"
 
 namespace audio {
@@ -22,7 +23,8 @@
 
 class SoundsManagerImpl : public SoundsManager {
  public:
-  SoundsManagerImpl() = default;
+  SoundsManagerImpl(std::unique_ptr<service_manager::Connector> connector)
+      : connector_(std::move(connector)) {}
   ~SoundsManagerImpl() override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   }
@@ -42,6 +44,7 @@
     std::unique_ptr<AudioStreamHandler> handler;
   };
   std::vector<StreamEntry> handlers_;
+  std::unique_ptr<service_manager::Connector> connector_;
 
   DISALLOW_COPY_AND_ASSIGN(SoundsManagerImpl);
 };
@@ -53,7 +56,8 @@
     return true;
   }
 
-  std::unique_ptr<AudioStreamHandler> handler(new AudioStreamHandler(data));
+  std::unique_ptr<AudioStreamHandler> handler(
+      new AudioStreamHandler(connector_->Clone(), data));
   if (!handler->IsInitialized()) {
     LOG(WARNING) << "Can't initialize AudioStreamHandler for key=" << key;
     return false;
@@ -101,12 +105,13 @@
 }
 
 // static
-void SoundsManager::Create() {
+void SoundsManager::Create(
+    std::unique_ptr<service_manager::Connector> connector) {
   CHECK(!g_instance || g_initialized_for_testing)
       << "SoundsManager::Create() is called twice";
   if (g_initialized_for_testing)
     return;
-  g_instance = new SoundsManagerImpl();
+  g_instance = new SoundsManagerImpl(std::move(connector));
 }
 
 // static
diff --git a/services/audio/public/cpp/sounds/sounds_manager.h b/services/audio/public/cpp/sounds/sounds_manager.h
index e8739f8..2975ad3 100644
--- a/services/audio/public/cpp/sounds/sounds_manager.h
+++ b/services/audio/public/cpp/sounds/sounds_manager.h
@@ -5,11 +5,14 @@
 #ifndef SERVICES_AUDIO_PUBLIC_CPP_SOUNDS_SOUNDS_MANAGER_H_
 #define SERVICES_AUDIO_PUBLIC_CPP_SOUNDS_SOUNDS_MANAGER_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/sequence_checker.h"
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "media/base/media_export.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace audio {
 
@@ -20,7 +23,7 @@
   typedef int SoundKey;
 
   // Creates a singleton instance of the SoundsManager.
-  static void Create();
+  static void Create(std::unique_ptr<service_manager::Connector> connector);
 
   // Removes a singleton instance of the SoundsManager.
   static void Shutdown();
diff --git a/services/audio/public/cpp/sounds/sounds_manager_unittest.cc b/services/audio/public/cpp/sounds/sounds_manager_unittest.cc
index 00d807c..05c3e744 100644
--- a/services/audio/public/cpp/sounds/sounds_manager_unittest.cc
+++ b/services/audio/public/cpp/sounds/sounds_manager_unittest.cc
@@ -2,6 +2,8 @@
 // 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 <vector>
 
 #include "base/compiler_specific.h"
@@ -11,12 +13,11 @@
 #include "base/strings/string_piece.h"
 #include "base/test/test_message_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "media/audio/audio_manager.h"
 #include "media/audio/simple_sources.h"
 #include "media/audio/test_audio_thread.h"
-#include "services/audio/public/cpp/sounds/test_data.h"
 #include "services/audio/public/cpp/sounds/audio_stream_handler.h"
 #include "services/audio/public/cpp/sounds/sounds_manager.h"
+#include "services/audio/public/cpp/sounds/test_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace audio {
@@ -27,15 +28,14 @@
   ~SoundsManagerTest() override = default;
 
   void SetUp() override {
-    audio_manager_ = media::AudioManager::CreateForTesting(
-        std::make_unique<media::TestAudioThread>());
-    SoundsManager::Create();
+    service_manager::mojom::ConnectorRequest connector_request;
+    connector_ = service_manager::Connector::Create(&connector_request);
+    SoundsManager::Create(connector_->Clone());
     base::RunLoop().RunUntilIdle();
   }
 
   void TearDown() override {
     SoundsManager::Shutdown();
-    audio_manager_->Shutdown();
     base::RunLoop().RunUntilIdle();
   }
 
@@ -43,14 +43,10 @@
     AudioStreamHandler::SetObserverForTesting(observer);
   }
 
-  void SetAudioSourceForTesting(
-      media::AudioOutputStream::AudioSourceCallback* source) {
-    AudioStreamHandler::SetAudioSourceForTesting(source);
-  }
+  std::unique_ptr<service_manager::Connector> connector_;
 
  private:
   base::TestMessageLoop message_loop_;
-  std::unique_ptr<media::AudioManager> audio_manager_;
 };
 
 TEST_F(SoundsManagerTest, Play) {
@@ -88,14 +84,6 @@
       kTestAudioKey,
       base::StringPiece(kTestAudioData, base::size(kTestAudioData))));
 
-  // This overrides the wav data set by kTestAudioData and results in
-  // a never-ending sine wave being played.
-  const int kChannels = 1;
-  const double kFreq = 200;
-  const double kSampleFreq = 44100;
-  media::SineWaveAudioSource sine_source(kChannels, kFreq, kSampleFreq);
-  SetAudioSourceForTesting(&sine_source);
-
   ASSERT_EQ(0, observer.num_play_requests());
   ASSERT_EQ(0, observer.num_stop_requests());
 
diff --git a/services/audio/public/cpp/sounds/test_data.cc b/services/audio/public/cpp/sounds/test_data.cc
index 637517e0..995cde6 100644
--- a/services/audio/public/cpp/sounds/test_data.cc
+++ b/services/audio/public/cpp/sounds/test_data.cc
@@ -9,7 +9,7 @@
 
 namespace audio {
 
-TestObserver::TestObserver(const base::Closure& quit)
+TestObserver::TestObserver(const base::RepeatingClosure& quit)
     : task_runner_(base::ThreadTaskRunnerHandle::Get()),
       quit_(quit),
       num_play_requests_(0),
@@ -18,13 +18,34 @@
 
 TestObserver::~TestObserver() = default;
 
+void TestObserver::Initialize(
+    media::AudioRendererSink::RenderCallback* callback,
+    media::AudioParameters params) {
+  callback_ = callback;
+  bus_ = media::AudioBus::Create(params);
+}
+
 void TestObserver::OnPlay() {
   ++num_play_requests_;
+  is_playing = true;
+  task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&TestObserver::Render, base::Unretained(this)));
+}
+
+void TestObserver::Render() {
+  if (!is_playing)
+    return;
+  if (callback_->Render(base::TimeDelta::FromSeconds(0), base::TimeTicks::Now(),
+                        0, bus_.get())) {
+    task_runner_->PostTask(FROM_HERE, base::BindOnce(&TestObserver::Render,
+                                                     base::Unretained(this)));
+  }
 }
 
 void TestObserver::OnStop(size_t cursor) {
   ++num_stop_requests_;
   cursor_ = cursor;
+  is_playing = false;
   task_runner_->PostTask(FROM_HERE, quit_);
 }
 
diff --git a/services/audio/public/cpp/sounds/test_data.h b/services/audio/public/cpp/sounds/test_data.h
index ce3e5e5..f69202b 100644
--- a/services/audio/public/cpp/sounds/test_data.h
+++ b/services/audio/public/cpp/sounds/test_data.h
@@ -6,12 +6,14 @@
 #define SERVICES_AUDIO_PUBLIC_CPP_SOUNDS_TEST_DATA_H_
 
 #include <stddef.h>
+#include <memory>
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "media/base/audio_renderer_sink.h"
 #include "services/audio/public/cpp/sounds/audio_stream_handler.h"
 
 namespace audio {
@@ -24,24 +26,17 @@
     "data\x04\x00\x00\x00\x01\x00\x01\x00";
 const size_t kTestAudioDataSize = base::size(kTestAudioData) - 1;
 
-// Extensible format with 48kHz rate stereo 32 bit PCM samples
-const char kTestExtensibleAudioData[] =
-    "RIFF\x44\x00\x00\x00WAVEfmt \x28\x00\x00\x00"
-    "\xfe\xff\x02\x00\x80\xbb\x00\x00\x00\x77\x01\x00\x02\x00\x20\x00"
-    "\x16\x00\x20\x00\x00\x00\x00\x00"
-    "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-    "data\x08\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00";
-const size_t kTestExtensibleAudioDataSize =
-    base::size(kTestExtensibleAudioData) - 1;
-
 class TestObserver : public AudioStreamHandler::TestObserver {
  public:
-  TestObserver(const base::Closure& quit);
+  TestObserver(const base::RepeatingClosure& quit);
   ~TestObserver() override;
 
   // AudioStreamHandler::TestObserver implementation:
+  void Initialize(media::AudioRendererSink::RenderCallback* callback,
+                  media::AudioParameters params) override;
   void OnPlay() override;
   void OnStop(size_t cursor) override;
+  void Render();
 
   int num_play_requests() const { return num_play_requests_; }
   int num_stop_requests() const { return num_stop_requests_; }
@@ -49,11 +44,14 @@
 
  private:
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  base::Closure quit_;
+  base::RepeatingClosure quit_;
 
   int num_play_requests_;
   int num_stop_requests_;
   int cursor_;
+  int is_playing;
+  media::AudioRendererSink::RenderCallback* callback_;
+  std::unique_ptr<media::AudioBus> bus_;
 
   DISALLOW_COPY_AND_ASSIGN(TestObserver);
 };
diff --git a/services/media_session/audio_focus_manager.cc b/services/media_session/audio_focus_manager.cc
index 84d249f4..d5a095b 100644
--- a/services/media_session/audio_focus_manager.cc
+++ b/services/media_session/audio_focus_manager.cc
@@ -83,8 +83,9 @@
     std::unique_ptr<StackRow> row = owner_->RemoveFocusEntryIfPresent(id());
     DCHECK(row);
 
-    owner_->RequestAudioFocusInternal(std::move(row), type,
-                                      std::move(callback));
+    owner_->RequestAudioFocusInternal(std::move(row), type);
+
+    std::move(callback).Run();
 
     metrics_helper_.OnRequestAudioFocus(
         AudioFocusManagerMetricsHelper::AudioFocusRequestSource::kUpdate,
@@ -112,10 +113,6 @@
       owner_->EnforceAudioFocus();
   }
 
-  void GetRequestId(GetRequestIdCallback callback) override {
-    std::move(callback).Run(id());
-  }
-
   mojom::MediaSession* session() { return session_.get(); }
   const mojom::MediaSessionInfoPtr& info() const { return session_info_; }
   mojom::AudioFocusType audio_focus_type() const { return audio_focus_type_; }
@@ -250,12 +247,16 @@
     mojom::AudioFocusType type,
     const base::UnguessableToken& group_id,
     RequestGroupedAudioFocusCallback callback) {
+  base::UnguessableToken request_id = base::UnguessableToken::Create();
+
   RequestAudioFocusInternal(
-      std::make_unique<StackRow>(
-          this, std::move(request), std::move(media_session),
-          std::move(session_info), type, base::UnguessableToken::Create(),
-          GetBindingSourceName(), group_id),
-      type, std::move(callback));
+      std::make_unique<StackRow>(this, std::move(request),
+                                 std::move(media_session),
+                                 std::move(session_info), type, request_id,
+                                 GetBindingSourceName(), group_id),
+      type);
+
+  std::move(callback).Run(request_id);
 }
 
 void AudioFocusManager::GetFocusRequests(GetFocusRequestsCallback callback) {
@@ -394,10 +395,8 @@
   controller_bindings_.AddBinding(this, std::move(request));
 }
 
-void AudioFocusManager::RequestAudioFocusInternal(
-    std::unique_ptr<StackRow> row,
-    mojom::AudioFocusType type,
-    base::OnceCallback<void()> callback) {
+void AudioFocusManager::RequestAudioFocusInternal(std::unique_ptr<StackRow> row,
+                                                  mojom::AudioFocusType type) {
   row->SetAudioFocusType(type);
   audio_focus_stack_.push_back(std::move(row));
 
@@ -410,10 +409,6 @@
   observers_.ForAllPtrs([&session_state](mojom::AudioFocusObserver* observer) {
     observer->OnFocusGained(session_state.Clone());
   });
-
-  // We always grant the audio focus request but this may not always be the case
-  // in the future.
-  std::move(callback).Run();
 }
 
 void AudioFocusManager::EnforceAudioFocus() {
diff --git a/services/media_session/audio_focus_manager.h b/services/media_session/audio_focus_manager.h
index fb71e664..2a511e8 100644
--- a/services/media_session/audio_focus_manager.h
+++ b/services/media_session/audio_focus_manager.h
@@ -103,8 +103,7 @@
   };
 
   void RequestAudioFocusInternal(std::unique_ptr<StackRow>,
-                                 mojom::AudioFocusType,
-                                 base::OnceCallback<void()>);
+                                 mojom::AudioFocusType);
   void AbandonAudioFocusInternal(RequestId);
 
   void EnforceAudioFocus();
diff --git a/services/media_session/audio_focus_manager_unittest.cc b/services/media_session/audio_focus_manager_unittest.cc
index 3fdd27c..8e471f9 100644
--- a/services/media_session/audio_focus_manager_unittest.cc
+++ b/services/media_session/audio_focus_manager_unittest.cc
@@ -1047,7 +1047,7 @@
     EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive,
               GetState(&media_session_1));
 
-    EXPECT_EQ(media_session_1.GetRequestIdFromClient(),
+    EXPECT_EQ(media_session_1.request_id(),
               observer->active_session()->request_id);
   }
 
diff --git a/services/media_session/media_controller_unittest.cc b/services/media_session/media_controller_unittest.cc
index 68410bca..ace124e 100644
--- a/services/media_session/media_controller_unittest.cc
+++ b/services/media_session/media_controller_unittest.cc
@@ -373,6 +373,11 @@
   {
     test::MockMediaSessionMojoObserver observer(media_session);
     RequestAudioFocus(media_session, mojom::AudioFocusType::kGain);
+    observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive);
+  }
+
+  {
+    test::MockMediaSessionMojoObserver observer(media_session);
     media_session.Stop(mojom::MediaSession::SuspendType::kUI);
     observer.WaitForState(mojom::MediaSessionInfo::SessionState::kInactive);
   }
@@ -652,8 +657,8 @@
   }
 
   mojom::MediaControllerPtr controller;
-  manager()->CreateMediaControllerForSession(
-      mojo::MakeRequest(&controller), media_session_1.GetRequestIdFromClient());
+  manager()->CreateMediaControllerForSession(mojo::MakeRequest(&controller),
+                                             media_session_1.request_id());
   manager().FlushForTesting();
 
   EXPECT_EQ(0, media_session_1.next_track_count());
@@ -713,8 +718,8 @@
   }
 
   mojom::MediaControllerPtr controller;
-  manager()->CreateMediaControllerForSession(
-      mojo::MakeRequest(&controller), media_session.GetRequestIdFromClient());
+  manager()->CreateMediaControllerForSession(mojo::MakeRequest(&controller),
+                                             media_session.request_id());
   manager().FlushForTesting();
 
   EXPECT_EQ(0, media_session.next_track_count());
diff --git a/services/media_session/public/cpp/test/mock_media_session.cc b/services/media_session/public/cpp/test/mock_media_session.cc
index 1389dfd2..9b930f3 100644
--- a/services/media_session/public/cpp/test/mock_media_session.cc
+++ b/services/media_session/public/cpp/test/mock_media_session.cc
@@ -248,70 +248,50 @@
   afr_client_->AbandonAudioFocus();
   afr_client_.FlushForTesting();
   afr_client_.reset();
-}
-
-base::UnguessableToken MockMediaSession::GetRequestIdFromClient() {
-  DCHECK(afr_client_.is_bound());
-  base::UnguessableToken id = base::UnguessableToken::Null();
-
-  afr_client_->GetRequestId(base::BindOnce(
-      [](base::UnguessableToken* id,
-         const base::UnguessableToken& received_id) { *id = received_id; },
-      &id));
-
-  afr_client_.FlushForTesting();
-  DCHECK_NE(base::UnguessableToken::Null(), id);
-  return id;
+  request_id_ = base::UnguessableToken::Null();
 }
 
 base::UnguessableToken MockMediaSession::RequestAudioFocusFromService(
     mojom::AudioFocusManagerPtr& service,
     mojom::AudioFocusType audio_focus_type) {
-  bool result;
-  base::OnceClosure callback =
-      base::BindOnce([](bool* out_result) { *out_result = true; }, &result);
-
   if (afr_client_.is_bound()) {
-    // Request audio focus through the existing request.
-    afr_client_->RequestAudioFocus(GetMediaSessionInfoSync(), audio_focus_type,
-                                   std::move(callback));
-
-    afr_client_.FlushForTesting();
+    RequestAudioFocusFromClient(audio_focus_type);
   } else {
+    DCHECK(request_id_.is_empty());
+
     // Build a new audio focus request.
     mojom::MediaSessionPtr media_session;
     bindings_.AddBinding(this, mojo::MakeRequest(&media_session));
 
     service->RequestAudioFocus(
         mojo::MakeRequest(&afr_client_), std::move(media_session),
-        GetMediaSessionInfoSync(), audio_focus_type, std::move(callback));
+        GetMediaSessionInfoSync(), audio_focus_type,
+        base::BindOnce(
+            [](base::UnguessableToken* id,
+               const base::UnguessableToken& received_id) {
+              *id = received_id;
+            },
+            &request_id_));
 
     service.FlushForTesting();
+    afr_client_.FlushForTesting();
   }
 
-  // If the audio focus was granted then we should set the session state to
-  // active.
-  if (result)
-    SetState(mojom::MediaSessionInfo::SessionState::kActive);
+  DCHECK(!request_id_.is_empty());
+  SetState(mojom::MediaSessionInfo::SessionState::kActive);
 
-  return GetRequestIdFromClient();
+  return request_id_;
 }
 
 base::UnguessableToken MockMediaSession::RequestGroupedAudioFocusFromService(
     mojom::AudioFocusManagerPtr& service,
     mojom::AudioFocusType audio_focus_type,
     const base::UnguessableToken& group_id) {
-  bool result;
-  base::OnceClosure callback =
-      base::BindOnce([](bool* out_result) { *out_result = true; }, &result);
-
   if (afr_client_.is_bound()) {
-    // Request audio focus through the existing request.
-    afr_client_->RequestAudioFocus(GetMediaSessionInfoSync(), audio_focus_type,
-                                   std::move(callback));
-
-    afr_client_.FlushForTesting();
+    RequestAudioFocusFromClient(audio_focus_type);
   } else {
+    DCHECK(request_id_.is_empty());
+
     // Build a new audio focus request.
     mojom::MediaSessionPtr media_session;
     bindings_.AddBinding(this, mojo::MakeRequest(&media_session));
@@ -319,17 +299,21 @@
     service->RequestGroupedAudioFocus(
         mojo::MakeRequest(&afr_client_), std::move(media_session),
         GetMediaSessionInfoSync(), audio_focus_type, group_id,
-        std::move(callback));
+        base::BindOnce(
+            [](base::UnguessableToken* id,
+               const base::UnguessableToken& received_id) {
+              *id = received_id;
+            },
+            &request_id_));
 
     service.FlushForTesting();
+    afr_client_.FlushForTesting();
   }
 
-  // If the audio focus was granted then we should set the session state to
-  // active.
-  if (result)
-    SetState(mojom::MediaSessionInfo::SessionState::kActive);
+  DCHECK(!request_id_.is_empty());
+  SetState(mojom::MediaSessionInfo::SessionState::kActive);
 
-  return GetRequestIdFromClient();
+  return request_id_;
 }
 
 mojom::MediaSessionInfo::SessionState MockMediaSession::GetState() const {
@@ -422,5 +406,19 @@
   });
 }
 
+void MockMediaSession::RequestAudioFocusFromClient(
+    mojom::AudioFocusType audio_focus_type) {
+  DCHECK(afr_client_.is_bound());
+  DCHECK(!request_id_.is_empty());
+
+  bool result = false;
+  afr_client_->RequestAudioFocus(
+      GetMediaSessionInfoSync(), audio_focus_type,
+      base::BindOnce([](bool* out_result) { *out_result = true; }, &result));
+
+  afr_client_.FlushForTesting();
+  DCHECK(result);
+}
+
 }  // namespace test
 }  // namespace media_session
diff --git a/services/media_session/public/cpp/test/mock_media_session.h b/services/media_session/public/cpp/test/mock_media_session.h
index 2be321b..e8a0b0b2 100644
--- a/services/media_session/public/cpp/test/mock_media_session.h
+++ b/services/media_session/public/cpp/test/mock_media_session.h
@@ -12,6 +12,7 @@
 #include "base/containers/flat_map.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
+#include "base/unguessable_token.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
@@ -129,7 +130,6 @@
   void SetPreferStop(bool value) { prefer_stop_ = value; }
 
   void AbandonAudioFocusFromClient();
-  base::UnguessableToken GetRequestIdFromClient();
 
   base::UnguessableToken RequestAudioFocusFromService(
       mojom::AudioFocusManagerPtr& service,
@@ -163,14 +163,20 @@
 
   const GURL& last_image_src() const { return last_image_src_; }
 
+  const base::UnguessableToken& request_id() const { return request_id_; }
+
  private:
   void SetState(mojom::MediaSessionInfo::SessionState);
   void NotifyObservers();
   mojom::MediaSessionInfoPtr GetMediaSessionInfoSync() const;
   void NotifyActionObservers();
 
+  void RequestAudioFocusFromClient(mojom::AudioFocusType audio_focus_type);
+
   mojom::AudioFocusRequestClientPtr afr_client_;
 
+  base::UnguessableToken request_id_;
+
   const bool force_duck_ = false;
   bool is_ducking_ = false;
   bool is_controllable_ = false;
diff --git a/services/media_session/public/mojom/audio_focus.mojom b/services/media_session/public/mojom/audio_focus.mojom
index f5e5c94..6bbfa078 100644
--- a/services/media_session/public/mojom/audio_focus.mojom
+++ b/services/media_session/public/mojom/audio_focus.mojom
@@ -80,7 +80,7 @@
 
 // Controls audio focus for an associated request.
 // Next Method ID: 5
-// Deprecated method IDs: 3
+// Deprecated method IDs: 3, 4
 interface AudioFocusRequestClient {
   // Requests updated audio focus for this request. If the request was granted
   // then the callback will resolve.
@@ -91,10 +91,6 @@
 
   // Notifies the audio focus backend when the associated session info changes.
   MediaSessionInfoChanged@2(MediaSessionInfo session_info);
-
-  // Retrieve a unique ID for this request.
-  [MinVersion=3] GetRequestId@4()
-      => (mojo_base.mojom.UnguessableToken request_id);
 };
 
 // Controls audio focus across the entire system.
@@ -103,11 +99,13 @@
   // Requests audio focus with |type| for the |media_session| with
   // |session_info|. Media sessions should provide a |request| that will
   // provide an AudioFocusRequestClient that can be used to control this
-  // request. The callback will resolve when audio focus has been granted.
+  // request. The callback will resolve with the id of the request when
+  // audio focus has been granted.
   RequestAudioFocus@0(AudioFocusRequestClient& client,
                       MediaSession media_session,
                       MediaSessionInfo session_info,
-                      AudioFocusType type) => ();
+                      AudioFocusType type) =>
+                          (mojo_base.mojom.UnguessableToken request_id);
 
   // Requests audio focus as above but with a |group_id| that is used for
   // grouping sessions together. This is when a group of media sessions
@@ -117,7 +115,8 @@
       MediaSession media_session,
       MediaSessionInfo session_info,
       AudioFocusType type,
-      mojo_base.mojom.UnguessableToken group_id) => ();
+      mojo_base.mojom.UnguessableToken group_id) =>
+          (mojo_base.mojom.UnguessableToken request_id);
 
   // Gets all the information about all |MediaSessions| that have requested
   // audio focus and their current requested type.
diff --git a/services/network/cors/preflight_controller.cc b/services/network/cors/preflight_controller.cc
index d7aba44d..51897df 100644
--- a/services/network/cors/preflight_controller.cc
+++ b/services/network/cors/preflight_controller.cc
@@ -27,6 +27,11 @@
 
 namespace {
 
+int RetrieveCacheFlags(int load_flags) {
+  return load_flags & (net::LOAD_VALIDATE_CACHE | net::LOAD_BYPASS_CACHE |
+                       net::LOAD_DISABLE_CACHE);
+}
+
 base::Optional<std::string> GetHeaderString(
     const scoped_refptr<net::HttpResponseHeaders>& headers,
     const std::string& header_name) {
@@ -81,6 +86,7 @@
 
   preflight_request->fetch_credentials_mode =
       mojom::FetchCredentialsMode::kOmit;
+  preflight_request->load_flags = RetrieveCacheFlags(request.load_flags);
   preflight_request->load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
   preflight_request->load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
   preflight_request->load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
@@ -308,9 +314,8 @@
           CheckPreflightResult(result.get(), original_request_);
     }
 
-    // TODO(toyoshim): Check the spec if we cache |result| regardless of
-    // following checks.
-    if (!detected_error_status) {
+    if (!(original_request_.load_flags & net::LOAD_DISABLE_CACHE) &&
+        !detected_error_status) {
       controller_->AppendToCache(*original_request_.request_initiator,
                                  original_request_.url, std::move(result));
     }
@@ -406,7 +411,7 @@
     base::OnceCallback<void()> preflight_finalizer) {
   DCHECK(request.request_initiator);
 
-  if (!request.is_external_request &&
+  if (!RetrieveCacheFlags(request.load_flags) && !request.is_external_request &&
       cache_.CheckIfRequestCanSkipPreflight(
           request.request_initiator->Serialize(), request.url,
           request.fetch_credentials_mode, request.method, request.headers,
diff --git a/services/network/cors/preflight_controller_unittest.cc b/services/network/cors/preflight_controller_unittest.cc
index 26fb40d2..3b4c0f2 100644
--- a/services/network/cors/preflight_controller_unittest.cc
+++ b/services/network/cors/preflight_controller_unittest.cc
@@ -350,6 +350,25 @@
   EXPECT_EQ(net::OK, net_error());
   ASSERT_FALSE(status());
   EXPECT_EQ(1u, access_count());  // Should be from the preflight cache.
+
+  // Verify if cache related flags work to skip the preflight cache.
+  request.load_flags = net::LOAD_VALIDATE_CACHE;
+  PerformPreflightCheck(request);
+  EXPECT_EQ(net::OK, net_error());
+  ASSERT_FALSE(status());
+  EXPECT_EQ(2u, access_count());
+
+  request.load_flags = net::LOAD_BYPASS_CACHE;
+  PerformPreflightCheck(request);
+  EXPECT_EQ(net::OK, net_error());
+  ASSERT_FALSE(status());
+  EXPECT_EQ(3u, access_count());
+
+  request.load_flags = net::LOAD_DISABLE_CACHE;
+  PerformPreflightCheck(request);
+  EXPECT_EQ(net::OK, net_error());
+  ASSERT_FALSE(status());
+  EXPECT_EQ(4u, access_count());
 }
 
 TEST_F(PreflightControllerTest, CheckTaintedRequest) {
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 0493111c..8e38c3b 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1306,13 +1306,14 @@
     int32_t process_id,
     int32_t render_frame_id,
     const url::Origin& origin,
-    mojom::AuthenticationHandlerPtr auth_handler) {
+    mojom::AuthenticationHandlerPtr auth_handler,
+    mojom::TrustedHeaderClientPtr header_client) {
 #if !defined(OS_IOS)
   if (!websocket_factory_)
     websocket_factory_ = std::make_unique<WebSocketFactory>(this);
-  websocket_factory_->CreateWebSocket(std::move(request),
-                                      std::move(auth_handler), process_id,
-                                      render_frame_id, origin);
+  websocket_factory_->CreateWebSocket(
+      std::move(request), std::move(auth_handler), std::move(header_client),
+      process_id, render_frame_id, origin);
 #endif  // !defined(OS_IOS)
 }
 
diff --git a/services/network/network_context.h b/services/network/network_context.h
index ad9e10f..fc3269f 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -271,7 +271,8 @@
                        int32_t process_id,
                        int32_t render_frame_id,
                        const url::Origin& origin,
-                       mojom::AuthenticationHandlerPtr auth_handler) override;
+                       mojom::AuthenticationHandlerPtr auth_handler,
+                       mojom::TrustedHeaderClientPtr header_client) override;
   void CreateNetLogExporter(mojom::NetLogExporterRequest request) override;
   void ResolveHost(const net::HostPortPair& host,
                    mojom::ResolveHostParametersPtr optional_parameters,
diff --git a/services/network/network_service_network_delegate.cc b/services/network/network_service_network_delegate.cc
index 586218f..3eb375d 100644
--- a/services/network/network_service_network_delegate.cc
+++ b/services/network/network_service_network_delegate.cc
@@ -5,6 +5,7 @@
 #include "services/network/network_service_network_delegate.h"
 
 #include "base/bind.h"
+#include "build/build_config.h"
 #include "services/network/cookie_manager.h"
 #include "services/network/network_context.h"
 #include "services/network/network_service.h"
@@ -13,6 +14,10 @@
 #include "services/network/public/cpp/features.h"
 #include "services/network/url_loader.h"
 
+#if !defined(OS_IOS)
+#include "services/network/websocket.h"
+#endif
+
 namespace network {
 
 namespace {
@@ -38,6 +43,13 @@
   URLLoader* url_loader = URLLoader::ForRequest(*request);
   if (url_loader)
     return url_loader->OnBeforeStartTransaction(std::move(callback), headers);
+
+#if !defined(OS_IOS)
+  WebSocket* web_socket = WebSocket::ForRequest(*request);
+  if (web_socket)
+    return web_socket->OnBeforeStartTransaction(std::move(callback), headers);
+#endif  // !defined(OS_IOS)
+
   return net::OK;
 }
 
@@ -66,6 +78,15 @@
         override_response_headers, allowed_unsafe_redirect_url));
   }
 
+#if !defined(OS_IOS)
+  WebSocket* web_socket = WebSocket::ForRequest(*request);
+  if (web_socket) {
+    chain->AddResult(web_socket->OnHeadersReceived(
+        chain->CreateCallback(), original_response_headers,
+        override_response_headers, allowed_unsafe_redirect_url));
+  }
+#endif  // !defined(OS_IOS)
+
   // Clear-Site-Data header will be handled by |ResourceDispatcherHost| if
   // network service is disabled.
   if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 49057dc..864e557 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -781,11 +781,17 @@
   ClearBadProxiesCache() => ();
 
   // Creates a WebSocket connection.
+  // If |header_client| is set, requests with the kURLLoadOptionUseHeaderClient
+  // option will callback to the |header_client|, allowing the Cookie/Referrer
+  // request headers and Cookie response headers to be modified. This has a
+  // performance impact because of the extra process hops, so use should be
+  // minimized.
   CreateWebSocket(WebSocket& request,
                   int32 process_id,
                   int32 render_frame_id,
                   url.mojom.Origin origin,
-                  AuthenticationHandler? auth_handler);
+                  AuthenticationHandler? auth_handler,
+                  TrustedHeaderClient? header_client);
 
   // Create a NetLogExporter, which helps export NetLog to an existing file.
   // Note that the log is generally global, including all NetworkContexts
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h
index 8083673..7273def 100644
--- a/services/network/test/test_network_context.h
+++ b/services/network/test/test_network_context.h
@@ -137,7 +137,8 @@
                        int32_t process_id,
                        int32_t render_frame_id,
                        const url::Origin& origin,
-                       mojom::AuthenticationHandlerPtr auth_handler) override {}
+                       mojom::AuthenticationHandlerPtr auth_handler,
+                       mojom::TrustedHeaderClientPtr header_client) override {}
   void LookUpProxyForURL(
       const GURL& url,
       ::network::mojom::ProxyLookupClientPtr proxy_lookup_client) override {}
diff --git a/services/network/websocket.cc b/services/network/websocket.cc
index 218637a..1eb88d8 100644
--- a/services/network/websocket.cc
+++ b/services/network/websocket.cc
@@ -128,6 +128,8 @@
 
 void WebSocket::WebSocketEventHandler::OnCreateURLRequest(
     net::URLRequest* url_request) {
+  url_request->SetUserData(WebSocket::kUserDataKey,
+                           std::make_unique<UnownedPointer>(impl_));
   impl_->delegate_->OnCreateURLRequest(impl_->child_id_, impl_->frame_id_,
                                        url_request);
 }
@@ -309,6 +311,7 @@
     std::unique_ptr<Delegate> delegate,
     mojom::WebSocketRequest request,
     mojom::AuthenticationHandlerPtr auth_handler,
+    mojom::TrustedHeaderClientPtr header_client,
     WebSocketThrottler::PendingConnection pending_connection_tracker,
     int child_id,
     int frame_id,
@@ -317,6 +320,7 @@
     : delegate_(std::move(delegate)),
       binding_(this, std::move(request)),
       auth_handler_(std::move(auth_handler)),
+      header_client_(std::move(header_client)),
       pending_connection_tracker_(std::move(pending_connection_tracker)),
       delay_(delay),
       pending_flow_control_quota_(0),
@@ -327,10 +331,20 @@
       weak_ptr_factory_(this) {
   binding_.set_connection_error_handler(
       base::BindOnce(&WebSocket::OnConnectionError, base::Unretained(this)));
+
+  if (header_client_) {
+    // Make sure the request dies if |header_client_| has an error, otherwise
+    // requests can hang.
+    header_client_.set_connection_error_handler(
+        base::BindOnce(&WebSocket::OnConnectionError, base::Unretained(this)));
+  }
 }
 
 WebSocket::~WebSocket() {}
 
+// static
+const void* const WebSocket::kUserDataKey = &WebSocket::kUserDataKey;
+
 void WebSocket::GoAway() {
   StartClosingHandshake(static_cast<uint16_t>(net::kWebSocketErrorGoingAway),
                         "");
@@ -435,6 +449,43 @@
   ignore_result(channel_->StartClosingHandshake(code, reason));
 }
 
+int WebSocket::OnBeforeStartTransaction(net::CompletionOnceCallback callback,
+                                        net::HttpRequestHeaders* headers) {
+  if (header_client_) {
+    header_client_->OnBeforeSendHeaders(
+        *headers, base::BindOnce(&WebSocket::OnBeforeSendHeadersComplete,
+                                 weak_ptr_factory_.GetWeakPtr(),
+                                 std::move(callback), headers));
+    return net::ERR_IO_PENDING;
+  }
+  return net::OK;
+}
+
+int WebSocket::OnHeadersReceived(
+    net::CompletionOnceCallback callback,
+    const net::HttpResponseHeaders* original_response_headers,
+    scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
+    GURL* allowed_unsafe_redirect_url) {
+  if (header_client_) {
+    header_client_->OnHeadersReceived(
+        original_response_headers->raw_headers(),
+        base::BindOnce(&WebSocket::OnHeadersReceivedComplete,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                       override_response_headers, allowed_unsafe_redirect_url));
+    return net::ERR_IO_PENDING;
+  }
+  return net::OK;
+}
+
+// static
+WebSocket* WebSocket::ForRequest(const net::URLRequest& request) {
+  auto* pointer =
+      static_cast<UnownedPointer*>(request.GetUserData(kUserDataKey));
+  if (!pointer)
+    return nullptr;
+  return pointer->get();
+}
+
 void WebSocket::OnConnectionError() {
   DVLOG(3) << "WebSocket::OnConnectionError @" << reinterpret_cast<void*>(this);
 
@@ -492,4 +543,28 @@
   std::move(callback).Run(credentials ? &*credentials : nullptr);
 }
 
+void WebSocket::OnBeforeSendHeadersComplete(
+    net::CompletionOnceCallback callback,
+    net::HttpRequestHeaders* out_headers,
+    int result,
+    const base::Optional<net::HttpRequestHeaders>& headers) {
+  if (headers)
+    *out_headers = headers.value();
+  std::move(callback).Run(result);
+}
+
+void WebSocket::OnHeadersReceivedComplete(
+    net::CompletionOnceCallback callback,
+    scoped_refptr<net::HttpResponseHeaders>* out_headers,
+    GURL* out_allowed_unsafe_redirect_url,
+    int result,
+    const base::Optional<std::string>& headers,
+    const GURL& allowed_unsafe_redirect_url) {
+  if (headers) {
+    *out_headers =
+        base::MakeRefCounted<net::HttpResponseHeaders>(headers.value());
+  }
+  std::move(callback).Run(result);
+}
+
 }  // namespace network
diff --git a/services/network/websocket.h b/services/network/websocket.h
index 8b736249..55fac406 100644
--- a/services/network/websocket.h
+++ b/services/network/websocket.h
@@ -17,6 +17,7 @@
 #include "base/time/time.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "net/websockets/websocket_event_interface.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/websocket.mojom.h"
 #include "services/network/websocket_throttler.h"
 #include "url/origin.h"
@@ -64,6 +65,7 @@
   WebSocket(std::unique_ptr<Delegate> delegate,
             mojom::WebSocketRequest request,
             mojom::AuthenticationHandlerPtr auth_handler,
+            mojom::TrustedHeaderClientPtr header_client,
             WebSocketThrottler::PendingConnection pending_connection_tracker,
             int child_id,
             int frame_id,
@@ -89,9 +91,40 @@
 
   bool handshake_succeeded() const { return handshake_succeeded_; }
 
+  // These methods are called by the network delegate to forward these events to
+  // the |header_client_|.
+  int OnBeforeStartTransaction(net::CompletionOnceCallback callback,
+                               net::HttpRequestHeaders* headers);
+  int OnHeadersReceived(
+      net::CompletionOnceCallback callback,
+      const net::HttpResponseHeaders* original_response_headers,
+      scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
+      GURL* allowed_unsafe_redirect_url);
+
+  // Gets the WebSocket associated with this request.
+  static WebSocket* ForRequest(const net::URLRequest& request);
+
+  static const void* const kUserDataKey;
+
  protected:
   class WebSocketEventHandler;
 
+  // This class is used to set the WebSocket as user data on a URLRequest. This
+  // is used instead of WebSocket directly because SetUserData requires a
+  // std::unique_ptr. This is safe because WebSocket owns the URLRequest, so is
+  // guaranteed to outlive it.
+  class UnownedPointer : public base::SupportsUserData::Data {
+   public:
+    explicit UnownedPointer(WebSocket* pointer) : pointer_(pointer) {}
+
+    WebSocket* get() const { return pointer_; }
+
+   private:
+    WebSocket* const pointer_;
+
+    DISALLOW_COPY_AND_ASSIGN(UnownedPointer);
+  };
+
   void OnConnectionError();
   void AddChannel(const GURL& socket_url,
                   const std::vector<std::string>& requested_protocols,
@@ -100,12 +133,25 @@
   void OnAuthRequiredComplete(
       base::OnceCallback<void(const net::AuthCredentials*)> callback,
       const base::Optional<net::AuthCredentials>& credential);
+  void OnBeforeSendHeadersComplete(
+      net::CompletionOnceCallback callback,
+      net::HttpRequestHeaders* out_headers,
+      int result,
+      const base::Optional<net::HttpRequestHeaders>& headers);
+  void OnHeadersReceivedComplete(
+      net::CompletionOnceCallback callback,
+      scoped_refptr<net::HttpResponseHeaders>* out_headers,
+      GURL* out_allowed_unsafe_redirect_url,
+      int result,
+      const base::Optional<std::string>& headers,
+      const GURL& allowed_unsafe_redirect_url);
 
   std::unique_ptr<Delegate> delegate_;
   mojo::Binding<mojom::WebSocket> binding_;
 
   mojom::WebSocketClientPtr client_;
   mojom::AuthenticationHandlerPtr auth_handler_;
+  mojom::TrustedHeaderClientPtr header_client_;
 
   WebSocketThrottler::PendingConnection pending_connection_tracker_;
 
diff --git a/services/network/websocket_factory.cc b/services/network/websocket_factory.cc
index a933adf..0af069c4 100644
--- a/services/network/websocket_factory.cc
+++ b/services/network/websocket_factory.cc
@@ -102,6 +102,7 @@
 void WebSocketFactory::CreateWebSocket(
     mojom::WebSocketRequest request,
     mojom::AuthenticationHandlerPtr auth_handler,
+    mojom::TrustedHeaderClientPtr header_client,
     int32_t process_id,
     int32_t render_frame_id,
     const url::Origin& origin) {
@@ -114,7 +115,7 @@
   }
   connections_.insert(std::make_unique<WebSocket>(
       std::make_unique<Delegate>(this, process_id), std::move(request),
-      std::move(auth_handler),
+      std::move(auth_handler), std::move(header_client),
       throttler_.IssuePendingConnectionTracker(process_id), process_id,
       render_frame_id, origin, throttler_.CalculateDelay(process_id)));
 }
diff --git a/services/network/websocket_factory.h b/services/network/websocket_factory.h
index d68a1f0..56bfa3f3 100644
--- a/services/network/websocket_factory.h
+++ b/services/network/websocket_factory.h
@@ -9,6 +9,7 @@
 
 #include "base/containers/unique_ptr_adapters.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/websocket.mojom.h"
 #include "services/network/websocket.h"
 #include "services/network/websocket_throttler.h"
@@ -28,6 +29,7 @@
 
   void CreateWebSocket(mojom::WebSocketRequest request,
                        mojom::AuthenticationHandlerPtr auth_handler,
+                       mojom::TrustedHeaderClientPtr header_client,
                        int32_t process_id,
                        int32_t render_frame_id,
                        const url::Origin& origin);
diff --git a/services/ws/public/mojom/BUILD.gn b/services/ws/public/mojom/BUILD.gn
index 31018146..9759d0a0 100644
--- a/services/ws/public/mojom/BUILD.gn
+++ b/services/ws/public/mojom/BUILD.gn
@@ -62,7 +62,7 @@
   deps = [
     "//base",
     "//base/test:test_support",
-    "//services/ws/public/mojom/ime:test_interfaces",
+    "//services/ws/public/mojom/ime",
     "//testing/gtest",
     "//ui/gfx:test_support",
     "//ui/gfx/range/mojo:struct_traits",
diff --git a/services/ws/public/mojom/ime/BUILD.gn b/services/ws/public/mojom/ime/BUILD.gn
index 84c40e1..9484f1f 100644
--- a/services/ws/public/mojom/ime/BUILD.gn
+++ b/services/ws/public/mojom/ime/BUILD.gn
@@ -11,20 +11,10 @@
 
   public_deps = [
     "//mojo/public/mojom/base",
+    "//ui/base/ime/mojo",
     "//ui/events/mojo:interfaces",
     "//ui/gfx/geometry/mojo",
     "//ui/gfx/range/mojo",
     "//ui/platform_window/mojo:interfaces",
   ]
 }
-
-mojom("test_interfaces") {
-  sources = [
-    "ime_struct_traits_test.mojom",
-  ]
-
-  public_deps = [
-    ":ime",
-    "//ui/platform_window/mojo:interfaces",
-  ]
-}
diff --git a/services/ws/public/mojom/ime/ime.mojom b/services/ws/public/mojom/ime/ime.mojom
index b8bb278..5548b31 100644
--- a/services/ws/public/mojom/ime/ime.mojom
+++ b/services/ws/public/mojom/ime/ime.mojom
@@ -6,6 +6,7 @@
 
 import "mojo/public/mojom/base/text_direction.mojom";
 import "mojo/public/mojom/base/string16.mojom";
+import "ui/base/ime/mojo/ime_types.mojom";
 import "ui/events/mojo/event.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/range/mojo/range.mojom";
@@ -99,23 +100,10 @@
   gfx.mojom.Range selection;
 };
 
-// See comments for ui::TextInputMode for more details.
-enum TextInputMode {
-  kDefault,
-  kNone,
-  kText,
-  kTel,
-  kUrl,
-  kEmail,
-  kNumeric,
-  kDecimal,
-  kSearch,
-};
-
 // Represents the text input state of a client.
 struct TextInputState {
   ui.mojom.TextInputType text_input_type;
-  TextInputMode text_input_mode;
+  ui.mojom.TextInputMode text_input_mode;
   mojo_base.mojom.TextDirection text_direction;
   int32 text_input_flags;  // A bitfield of ui::TextInputFlags.
 };
diff --git a/services/ws/public/mojom/ime/ime.typemap b/services/ws/public/mojom/ime/ime.typemap
index fdaa2f7..325e7354 100644
--- a/services/ws/public/mojom/ime/ime.typemap
+++ b/services/ws/public/mojom/ime/ime.typemap
@@ -30,6 +30,4 @@
   "ws.mojom.FocusReason=ui::TextInputClient::FocusReason",
   "ws.mojom.ImeTextSpan=ui::ImeTextSpan",
   "ws.mojom.ImeTextSpanThickness=ui::ImeTextSpan::Thickness",
-  "ws.mojom.TextInputMode=ui::TextInputMode",
-  "ui.mojom.TextInputType=ui::TextInputType",
 ]
diff --git a/services/ws/public/mojom/ime/ime_struct_traits.cc b/services/ws/public/mojom/ime/ime_struct_traits.cc
index 54d0f3bb..156d7b7 100644
--- a/services/ws/public/mojom/ime/ime_struct_traits.cc
+++ b/services/ws/public/mojom/ime/ime_struct_traits.cc
@@ -190,133 +190,4 @@
   return false;
 }
 
-// static
-ws::mojom::TextInputMode
-EnumTraits<ws::mojom::TextInputMode, ui::TextInputMode>::ToMojom(
-    ui::TextInputMode text_input_mode) {
-  switch (text_input_mode) {
-    case ui::TEXT_INPUT_MODE_DEFAULT:
-      return ws::mojom::TextInputMode::kDefault;
-    case ui::TEXT_INPUT_MODE_NONE:
-      return ws::mojom::TextInputMode::kNone;
-    case ui::TEXT_INPUT_MODE_TEXT:
-      return ws::mojom::TextInputMode::kText;
-    case ui::TEXT_INPUT_MODE_TEL:
-      return ws::mojom::TextInputMode::kTel;
-    case ui::TEXT_INPUT_MODE_URL:
-      return ws::mojom::TextInputMode::kUrl;
-    case ui::TEXT_INPUT_MODE_EMAIL:
-      return ws::mojom::TextInputMode::kEmail;
-    case ui::TEXT_INPUT_MODE_NUMERIC:
-      return ws::mojom::TextInputMode::kNumeric;
-    case ui::TEXT_INPUT_MODE_DECIMAL:
-      return ws::mojom::TextInputMode::kDecimal;
-    case ui::TEXT_INPUT_MODE_SEARCH:
-      return ws::mojom::TextInputMode::kSearch;
-  }
-  NOTREACHED();
-  return ws::mojom::TextInputMode::kDefault;
-}
-
-// static
-bool EnumTraits<ws::mojom::TextInputMode, ui::TextInputMode>::FromMojom(
-    ws::mojom::TextInputMode input,
-    ui::TextInputMode* out) {
-  switch (input) {
-    case ws::mojom::TextInputMode::kDefault:
-      *out = ui::TEXT_INPUT_MODE_DEFAULT;
-      return true;
-    case ws::mojom::TextInputMode::kNone:
-      *out = ui::TEXT_INPUT_MODE_NONE;
-      return true;
-    case ws::mojom::TextInputMode::kText:
-      *out = ui::TEXT_INPUT_MODE_TEXT;
-      return true;
-    case ws::mojom::TextInputMode::kTel:
-      *out = ui::TEXT_INPUT_MODE_TEL;
-      return true;
-    case ws::mojom::TextInputMode::kUrl:
-      *out = ui::TEXT_INPUT_MODE_URL;
-      return true;
-    case ws::mojom::TextInputMode::kEmail:
-      *out = ui::TEXT_INPUT_MODE_EMAIL;
-      return true;
-    case ws::mojom::TextInputMode::kNumeric:
-      *out = ui::TEXT_INPUT_MODE_NUMERIC;
-      return true;
-    case ws::mojom::TextInputMode::kDecimal:
-      *out = ui::TEXT_INPUT_MODE_DECIMAL;
-      return true;
-    case ws::mojom::TextInputMode::kSearch:
-      *out = ui::TEXT_INPUT_MODE_SEARCH;
-      return true;
-  }
-  return false;
-}
-
-#define UI_TO_MOJO_TYPE_CASE(name) \
-  case ui::TEXT_INPUT_TYPE_##name: \
-    return ui::mojom::TextInputType::name
-
-// static
-ui::mojom::TextInputType
-EnumTraits<ui::mojom::TextInputType, ui::TextInputType>::ToMojom(
-    ui::TextInputType text_input_type) {
-  switch (text_input_type) {
-    UI_TO_MOJO_TYPE_CASE(NONE);
-    UI_TO_MOJO_TYPE_CASE(TEXT);
-    UI_TO_MOJO_TYPE_CASE(PASSWORD);
-    UI_TO_MOJO_TYPE_CASE(SEARCH);
-    UI_TO_MOJO_TYPE_CASE(EMAIL);
-    UI_TO_MOJO_TYPE_CASE(NUMBER);
-    UI_TO_MOJO_TYPE_CASE(TELEPHONE);
-    UI_TO_MOJO_TYPE_CASE(URL);
-    UI_TO_MOJO_TYPE_CASE(DATE);
-    UI_TO_MOJO_TYPE_CASE(DATE_TIME);
-    UI_TO_MOJO_TYPE_CASE(DATE_TIME_LOCAL);
-    UI_TO_MOJO_TYPE_CASE(MONTH);
-    UI_TO_MOJO_TYPE_CASE(TIME);
-    UI_TO_MOJO_TYPE_CASE(WEEK);
-    UI_TO_MOJO_TYPE_CASE(TEXT_AREA);
-    UI_TO_MOJO_TYPE_CASE(CONTENT_EDITABLE);
-    UI_TO_MOJO_TYPE_CASE(DATE_TIME_FIELD);
-  }
-  NOTREACHED();
-  return ui::mojom::TextInputType::NONE;
-}
-
-#undef UI_TO_MOJO_TYPE_CASE
-
-#define MOJO_TO_UI_TYPE_CASE(name)     \
-  case ui::mojom::TextInputType::name: \
-    *out = ui::TEXT_INPUT_TYPE_##name; \
-    return true;
-
-// static
-bool EnumTraits<ui::mojom::TextInputType, ui::TextInputType>::FromMojom(
-    ui::mojom::TextInputType input,
-    ui::TextInputType* out) {
-  switch (input) {
-    MOJO_TO_UI_TYPE_CASE(NONE);
-    MOJO_TO_UI_TYPE_CASE(TEXT);
-    MOJO_TO_UI_TYPE_CASE(PASSWORD);
-    MOJO_TO_UI_TYPE_CASE(SEARCH);
-    MOJO_TO_UI_TYPE_CASE(EMAIL);
-    MOJO_TO_UI_TYPE_CASE(NUMBER);
-    MOJO_TO_UI_TYPE_CASE(TELEPHONE);
-    MOJO_TO_UI_TYPE_CASE(URL);
-    MOJO_TO_UI_TYPE_CASE(DATE);
-    MOJO_TO_UI_TYPE_CASE(DATE_TIME);
-    MOJO_TO_UI_TYPE_CASE(DATE_TIME_LOCAL);
-    MOJO_TO_UI_TYPE_CASE(MONTH);
-    MOJO_TO_UI_TYPE_CASE(TIME);
-    MOJO_TO_UI_TYPE_CASE(WEEK);
-    MOJO_TO_UI_TYPE_CASE(TEXT_AREA);
-    MOJO_TO_UI_TYPE_CASE(CONTENT_EDITABLE);
-    MOJO_TO_UI_TYPE_CASE(DATE_TIME_FIELD);
-  }
-#undef MOJO_TO_UI_TYPE_CASE
-  return false;
-}
-
 }  // namespace mojo
diff --git a/services/ws/public/mojom/ime/ime_struct_traits.h b/services/ws/public/mojom/ime/ime_struct_traits.h
index 916d4dc..b0974f2 100644
--- a/services/ws/public/mojom/ime/ime_struct_traits.h
+++ b/services/ws/public/mojom/ime/ime_struct_traits.h
@@ -130,18 +130,6 @@
 };
 
 template <>
-struct EnumTraits<ws::mojom::TextInputMode, ui::TextInputMode> {
-  static ws::mojom::TextInputMode ToMojom(ui::TextInputMode text_input_mode);
-  static bool FromMojom(ws::mojom::TextInputMode input, ui::TextInputMode* out);
-};
-
-template <>
-struct EnumTraits<ui::mojom::TextInputType, ui::TextInputType> {
-  static ui::mojom::TextInputType ToMojom(ui::TextInputType text_input_type);
-  static bool FromMojom(ui::mojom::TextInputType input, ui::TextInputType* out);
-};
-
-template <>
 struct EnumTraits<ws::mojom::ImeTextSpanThickness, ui::ImeTextSpan::Thickness> {
   static ws::mojom::ImeTextSpanThickness ToMojom(
       ui::ImeTextSpan::Thickness thickness);
diff --git a/services/ws/public/mojom/ime/ime_struct_traits_test.mojom b/services/ws/public/mojom/ime/ime_struct_traits_test.mojom
deleted file mode 100644
index c15d4470..0000000
--- a/services/ws/public/mojom/ime/ime_struct_traits_test.mojom
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module ws.mojom;
-
-import "services/ws/public/mojom/ime/ime.mojom";
-import "ui/platform_window/mojo/text_input_state.mojom";
-
-interface IMEStructTraitsTest {
-  [Sync]
-  EchoTextInputType(ui.mojom.TextInputType in) => (ui.mojom.TextInputType out);
-  [Sync]
-  EchoTextInputMode(TextInputMode in) => (TextInputMode out);
-};
-
diff --git a/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc b/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc
index 656d3d3..f122553 100644
--- a/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc
+++ b/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc
@@ -6,13 +6,11 @@
 
 #include <utility>
 
-#include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "mojo/public/cpp/base/string16_mojom_traits.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/ws/public/mojom/ime/ime.mojom.h"
-#include "services/ws/public/mojom/ime/ime_struct_traits_test.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/composition_text.h"
 #include "ui/base/ime/ime_text_span.h"
@@ -22,32 +20,11 @@
 
 namespace {
 
-class IMEStructTraitsTest : public testing::Test,
-                            public mojom::IMEStructTraitsTest {
+class IMEStructTraitsTest : public testing::Test {
  public:
   IMEStructTraitsTest() {}
 
- protected:
-  mojom::IMEStructTraitsTestPtr GetTraitsTestProxy() {
-    mojom::IMEStructTraitsTestPtr proxy;
-    traits_test_bindings_.AddBinding(this, mojo::MakeRequest(&proxy));
-    return proxy;
-  }
-
  private:
-  // mojom::IMEStructTraitsTest:
-  void EchoTextInputMode(ui::TextInputMode in,
-                         EchoTextInputModeCallback callback) override {
-    std::move(callback).Run(in);
-  }
-  void EchoTextInputType(ui::TextInputType in,
-                         EchoTextInputTypeCallback callback) override {
-    std::move(callback).Run(in);
-  }
-
-  base::MessageLoop loop_;  // A MessageLoop is needed for Mojo IPC to work.
-  mojo::BindingSet<mojom::IMEStructTraitsTest> traits_test_bindings_;
-
   DISALLOW_COPY_AND_ASSIGN(IMEStructTraitsTest);
 };
 
@@ -130,50 +107,4 @@
   EXPECT_EQ(input, output);
 }
 
-TEST_F(IMEStructTraitsTest, TextInputMode) {
-  const ui::TextInputMode kTextInputModes[] = {
-      ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_MODE_NONE,
-      ui::TEXT_INPUT_MODE_TEXT,    ui::TEXT_INPUT_MODE_TEL,
-      ui::TEXT_INPUT_MODE_URL,     ui::TEXT_INPUT_MODE_EMAIL,
-      ui::TEXT_INPUT_MODE_NUMERIC, ui::TEXT_INPUT_MODE_DECIMAL,
-      ui::TEXT_INPUT_MODE_SEARCH,
-  };
-
-  mojom::IMEStructTraitsTestPtr proxy = GetTraitsTestProxy();
-  for (size_t i = 0; i < base::size(kTextInputModes); i++) {
-    ui::TextInputMode mode_out;
-    ASSERT_TRUE(proxy->EchoTextInputMode(kTextInputModes[i], &mode_out));
-    EXPECT_EQ(kTextInputModes[i], mode_out);
-  }
-}
-
-TEST_F(IMEStructTraitsTest, TextInputType) {
-  const ui::TextInputType kTextInputTypes[] = {
-      ui::TEXT_INPUT_TYPE_NONE,
-      ui::TEXT_INPUT_TYPE_TEXT,
-      ui::TEXT_INPUT_TYPE_PASSWORD,
-      ui::TEXT_INPUT_TYPE_SEARCH,
-      ui::TEXT_INPUT_TYPE_EMAIL,
-      ui::TEXT_INPUT_TYPE_NUMBER,
-      ui::TEXT_INPUT_TYPE_TELEPHONE,
-      ui::TEXT_INPUT_TYPE_URL,
-      ui::TEXT_INPUT_TYPE_DATE,
-      ui::TEXT_INPUT_TYPE_DATE_TIME,
-      ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL,
-      ui::TEXT_INPUT_TYPE_MONTH,
-      ui::TEXT_INPUT_TYPE_TIME,
-      ui::TEXT_INPUT_TYPE_WEEK,
-      ui::TEXT_INPUT_TYPE_TEXT_AREA,
-      ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE,
-      ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD,
-  };
-
-  mojom::IMEStructTraitsTestPtr proxy = GetTraitsTestProxy();
-  for (size_t i = 0; i < base::size(kTextInputTypes); i++) {
-    ui::TextInputType type_out;
-    ASSERT_TRUE(proxy->EchoTextInputType(kTextInputTypes[i], &type_out));
-    EXPECT_EQ(kTextInputTypes[i], type_out);
-  }
-}
-
 }  // namespace ws
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 662151cc..fd8f457e 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -1187,6 +1187,13 @@
         "test": "url_unittests"
       },
       {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "usage_time_limit_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1881,6 +1888,13 @@
         "test": "url_unittests"
       },
       {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "usage_time_limit_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index b314aaf..6fe5c8f4 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -410,17 +410,6 @@
       },
       {
         "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 10
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--disable-features=WebUIPolymer2",
           "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer1_browser_tests.filter"
         ],
@@ -491,17 +480,6 @@
       },
       {
         "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 2
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--enable-perfetto",
           "--gtest_filter=TracingControllerTest.*"
         ],
@@ -512,37 +490,6 @@
         "test": "content_browsertests"
       },
       {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 10
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1072,17 +1019,6 @@
     "gtest_tests": [
       {
         "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 10
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor,UseSkiaRenderer"
         ],
         "name": "skia_renderer_browser_tests",
@@ -1094,17 +1030,6 @@
       },
       {
         "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 2
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor,UseSkiaRenderer"
         ],
         "name": "skia_renderer_content_browsertests",
@@ -1113,37 +1038,6 @@
           "shards": 2
         },
         "test": "content_browsertests"
-      },
-      {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 10
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_unittests"
       }
     ]
   },
@@ -1617,100 +1511,6 @@
       },
       {
         "args": [
-          "--disable-features=VizDisplayCompositor",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "non_viz_content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "non_viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "hard_timeout": 3600,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 2
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
-          "--enable-features=VizDisplayCompositor",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "viz_content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "hard_timeout": 3600,
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 10
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--enable-features=NetworkService",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -2078,17 +1878,6 @@
       },
       {
         "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 10
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=NetworkService,NetworkServiceInProcess"
         ],
         "name": "network_service_in_process_content_browsertests",
@@ -2099,48 +1888,6 @@
         "test": "content_browsertests"
       },
       {
-        "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 2
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 10
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -3366,98 +3113,6 @@
       },
       {
         "args": [
-          "--disable-features=VizDisplayCompositor",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "non_viz_content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "non_viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 2
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
-          "--enable-features=VizDisplayCompositor",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "viz_content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 10
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--enable-features=NetworkService",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -6884,6 +6539,13 @@
         "test": "url_unittests"
       },
       {
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "usage_time_limit_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -11917,24 +11579,6 @@
       },
       {
         "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.14"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 10
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--disable-features=WebUIPolymer2",
           "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer1_browser_tests.filter"
         ],
@@ -12075,24 +11719,6 @@
       },
       {
         "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.14"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 2
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--enable-perfetto",
           "--gtest_filter=TracingControllerTest.*"
         ],
@@ -12110,58 +11736,6 @@
         "test": "content_browsertests"
       },
       {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.14"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 10
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.14"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--disable-features=VizDisplayCompositor"
-        ],
-        "name": "non_viz_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.14"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 96c373e9..eea14d007 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -5514,7 +5514,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5531,7 +5531,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5548,7 +5548,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5564,7 +5564,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5577,7 +5577,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5603,7 +5603,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5627,7 +5627,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5651,7 +5651,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5675,7 +5675,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5703,7 +5703,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5734,7 +5734,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5782,7 +5782,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5822,7 +5822,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5847,7 +5847,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5871,7 +5871,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5895,7 +5895,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
@@ -5920,7 +5920,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.0.5",
+              "gpu": "8086:5912-18.3.3",
               "os": "Ubuntu",
               "pool": "Chrome-GPU"
             }
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 14541c14..88d9d2e 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -4991,6 +4991,16 @@
         "args": [
           "--test-launcher-print-test-stdio=always"
         ],
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "usage_time_limit_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -6517,6 +6527,22 @@
         "args": [
           "--test-launcher-print-test-stdio=always"
         ],
+        "experiment_percentage": 100,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Ubuntu-14.04"
+            }
+          ]
+        },
+        "test": "usage_time_limit_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-print-test-stdio=always"
+        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter b/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter
index cefdd29..06e0b63 100644
--- a/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter
@@ -16,7 +16,7 @@
 
 # Miscellaneous flaky or failing tests:
 # http://crbug.com/941856
--org.chromium.chrome.browser.webapps.WebApkIntegrationTest#testActivateWebApk
+-org.chromium.chrome.browser.webapps.WebApkIntegrationTest.testActivateWebApk
 
 # http://crbug.com/941858
--org.chromium.chrome.browser.payments.PaymentRequestUpdateWithTest#testUpdateWithShippingOptions
+-org.chromium.chrome.browser.payments.PaymentRequestUpdateWithTest.testUpdateWithShippingOptions
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index b00541e4..4569b9f 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -2580,6 +2580,10 @@
     "label": "//url:url_unittests",
     "type": "console_test_launcher",
   },
+  "usage_time_limit_unittests": {
+    "label": "//chrome/test:usage_time_limit_unittests",
+    "type": "console_test_launcher",
+  },
   "usb_descriptors_fuzzer": {
     "label": "//device/usb:usb_descriptors_fuzzer",
     "type": "fuzzer",
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 7a4e3138..eb68f15 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -259,7 +259,7 @@
     # Similar to stable, but with a newer Mesa version.
     'swarming': {
       'dimensions': {
-        'gpu': '8086:5912-18.0.5',
+        'gpu': '8086:5912-18.3.3',
         'os': 'Ubuntu',
         'pool': 'Chrome-GPU',
       },
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 6a97f8a..b3d3a078 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -3763,6 +3763,9 @@
         ],
       },
       'ui_chromeos_unittests': {},
+      'usage_time_limit_unittests': {
+        'experiment_percentage': 100,
+      },
       'wayland_client_perftests': {},
     },
 
@@ -4186,36 +4189,6 @@
       },
     },
 
-    'non_viz_fyi_chromium_gtests': {
-      'non_viz_content_browsertests': {
-        'args': [
-          '--disable-features=VizDisplayCompositor',
-        ],
-        'swarming': {
-          'shards': 2,
-        },
-        'test': 'content_browsertests',
-      },
-    },
-
-    'non_viz_non_android_fyi_chromium_gtests': {
-      'non_viz_browser_tests': {
-        'args': [
-          '--disable-features=VizDisplayCompositor',
-        ],
-        'swarming': {
-          'shards': 10,
-        },
-        'test': 'browser_tests',
-      },
-      'non_viz_content_unittests': {
-        'args': [
-          '--disable-features=VizDisplayCompositor',
-        ],
-        'test': 'content_unittests',
-      },
-    },
-
     'ozone_linux_gtests': {
       'services_unittests': {},
       'ozone_unittests': {
@@ -4675,10 +4648,6 @@
       'non_android_chromium_gtests',
       'non_android_and_cast_and_chromeos_chromium_gtests',
       'non_linux_chromium_gtests',
-      'non_viz_fyi_chromium_gtests',
-      'non_viz_non_android_fyi_chromium_gtests',
-      'viz_gtests',
-      'viz_non_android_fyi_gtests',
     ],
 
     'chromium_mac_gtests': [
@@ -5084,11 +5053,7 @@
     ],
 
     'linux_viz_gtests': [
-      'non_viz_fyi_chromium_gtests',
-      'non_viz_non_android_fyi_chromium_gtests',
       'skia_renderer_fyi_gtests',
-      'viz_gtests',
-      'viz_non_android_fyi_gtests',
     ],
 
     'marshmallow_isolated_scripts': [
@@ -5100,8 +5065,6 @@
     'mojo_android_gtests': [
       'network_service_android_fyi_gtests',
       'network_service_android_gtests',
-      'non_viz_fyi_chromium_gtests',
-      'viz_gtests',
     ],
 
     'mojo_chromiumos_fyi_gtests': [
@@ -5124,10 +5087,6 @@
       'mojo_windows_specific_gtests',
       'network_service_fyi_gtests',
       'network_service_in_process_gtests',
-      'non_viz_fyi_chromium_gtests',
-      'non_viz_non_android_fyi_chromium_gtests',
-      'viz_gtests',
-      'viz_non_android_fyi_gtests',
     ],
 
     'sandboxed_chromium_memory_linux_gtests': [
diff --git a/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py b/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py
index da92ee24..b5df6063 100644
--- a/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py
+++ b/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py
@@ -46,8 +46,8 @@
     return text[:-1] if text[-1] == "s" else text
 
 
-def to_lower_case(name):
-    return name[:1].lower() + name[1:]
+def to_snake_case(name):
+    return NameStyleConverter(name).to_snake_case()
 
 
 def agent_config(config, agent_name, field):
@@ -74,7 +74,7 @@
         lstrip_blocks=True,  # so can indent control flow tags
         trim_blocks=True)
     jinja_env.filters.update({
-        "to_lower_case": to_lower_case,
+        "to_snake_case": to_snake_case,
         "to_singular": to_singular,
         "agent_name_to_class": partial(agent_name_to_class, config),
         "agent_name_to_include": partial(agent_name_to_include, config)})
diff --git a/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_impl.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_impl.cc.tmpl
index d03b833..c9c1de31 100644
--- a/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_impl.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/instrumenting_probes_impl.cc.tmpl
@@ -42,7 +42,7 @@
 
 {% for agent in agents %}
 {% set class_name = agent | agent_name_to_class %}
-{% set getter_name = agent | to_lower_case %}
+{% set getter_name = agent | to_snake_case %}
 
 // static
 unsigned {{sink_class}}::s_numSinksWith{{agent}} = 0;
@@ -81,7 +81,7 @@
 void {{sink_class}}::Trace(Visitor* visitor)
 {
 {% for agent in agents %}
-{% set getter_name = agent | to_lower_case %}
+{% set getter_name = agent | to_snake_case %}
   visitor->Trace({{getter_name}}s_);
 {% endfor %}
 }
diff --git a/third_party/blink/renderer/build/scripts/templates/probe_sink.h.tmpl b/third_party/blink/renderer/build/scripts/templates/probe_sink.h.tmpl
index f4241e9..19a4466 100644
--- a/third_party/blink/renderer/build/scripts/templates/probe_sink.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/probe_sink.h.tmpl
@@ -41,7 +41,7 @@
 
 {% for agent in agents %}
 {% set class_name = agent | agent_name_to_class %}
-{% set getter_name = agent | to_lower_case %}
+{% set getter_name = agent | to_snake_case %}
   bool Has{{agent}}s() const { return !{{getter_name}}s_.IsEmpty(); }
   const HeapListHashSet<Member<{{class_name}}>>& {{class_name}}s() const { return {{getter_name}}s_; }
   void Add{{agent}}({{class_name}}* agent);
@@ -56,7 +56,7 @@
  private:
 {% for agent in agents %}
 {% set class_name = agent | agent_name_to_class %}
-{% set getter_name = agent | to_lower_case %}
+{% set getter_name = agent | to_snake_case %}
   HeapListHashSet<Member<{{class_name}}>> {{getter_name}}s_;
 {% endfor %}
 
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.h b/third_party/blink/renderer/core/animation/compositor_animations.h
index a0cf3f0..12546f27 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations.h
+++ b/third_party/blink/renderer/core/animation/compositor_animations.h
@@ -148,18 +148,6 @@
   static FailureCode CheckCanStartElementOnCompositor(const Element&);
 
   friend class AnimationCompositorAnimationsTest;
-  FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           CanStartElementOnCompositorTransformCAP);
-  FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           CanStartElementOnCompositorEffectCAP);
-  FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           CanStartElementOnCompositorEffect);
-  FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           CannotStartElementOnCompositorEffectSVG);
-  FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           CancelIncompatibleCompositorAnimations);
-  FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           NonAnimatedTransformPropertyChangeGetsUpdated);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index 88255ce..5b5aa8d 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -38,6 +38,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "cc/animation/animation_host.h"
 #include "cc/layers/picture_layer.h"
+#include "cc/trees/transform_node.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/web/web_settings.h"
 #include "third_party/blink/renderer/core/animation/animatable/animatable_double.h"
@@ -67,7 +68,7 @@
 #include "third_party/blink/renderer/platform/geometry/float_box.h"
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
 #include "third_party/blink/renderer/platform/testing/histogram_tester.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
 #include "third_party/blink/renderer/platform/transforms/transform_operations.h"
@@ -78,7 +79,8 @@
 
 using namespace css_test_helpers;
 
-class AnimationCompositorAnimationsTest : public RenderingTest {
+class AnimationCompositorAnimationsTest : public PaintTestConfigurations,
+                                          public RenderingTest {
  protected:
   scoped_refptr<TimingFunction> linear_timing_function_;
   scoped_refptr<TimingFunction> cubic_ease_timing_function_;
@@ -169,6 +171,10 @@
         .Ok();
   }
 
+  bool CheckCanStartElementOnCompositor(const Element& element) {
+    return CompositorAnimations::CheckCanStartElementOnCompositor(element).Ok();
+  }
+
   void GetAnimationOnCompositor(
       Timing& timing,
       StringKeyframeEffectModel& effect,
@@ -506,7 +512,9 @@
 // -----------------------------------------------------------------------
 // -----------------------------------------------------------------------
 
-TEST_F(AnimationCompositorAnimationsTest,
+INSTANTIATE_PAINT_TEST_SUITE_P(AnimationCompositorAnimationsTest);
+
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorKeyframeMultipleCSSProperties) {
   StringKeyframe* keyframe_good_multiple =
       CreateDefaultKeyframe(CSSPropertyOpacity, EffectModel::kCompositeReplace);
@@ -524,7 +532,7 @@
       keyframe_bad_multiple_id));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        IsNotCandidateForCompositorAnimationTransformDependsOnBoxSize) {
   // Absolute transforms can be animated on the compositor.
   String transform = "translateX(2px) translateY(2px)";
@@ -547,7 +555,7 @@
       DuplicateSingleKeyframeAndTestIsCandidateOnResult(bad_keyframe2));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorKeyframeEffectModel) {
   StringKeyframeVector frames_same;
   frames_same.push_back(CreateDefaultKeyframe(
@@ -576,7 +584,7 @@
       timing_, *StringKeyframeEffectModel::Create(frames_mixed_properties)));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorCustomCssProperty) {
   ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
   RegisterProperty(GetDocument(), "--foo", "<number>", "0", false);
@@ -605,7 +613,7 @@
   EXPECT_FALSE(DuplicateSingleKeyframeAndTestIsCandidateOnResult(keyframe));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        ConvertTimingForCompositorStartDelay) {
   timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(20);
 
@@ -618,13 +626,13 @@
   EXPECT_DOUBLE_EQ(2.0, compositor_timing_.scaled_time_offset);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        ConvertTimingForCompositorIterationStart) {
   timing_.iteration_start = 2.2;
   EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        ConvertTimingForCompositorIterationCount) {
   timing_.iteration_count = 5.0;
   EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
@@ -646,7 +654,7 @@
   EXPECT_EQ(-1, compositor_timing_.adjusted_iteration_count);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        ConvertTimingForCompositorIterationsAndStartDelay) {
   timing_.iteration_count = 4.0;
   timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(5);
@@ -665,7 +673,7 @@
   EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest, ConvertTimingForCompositorDirection) {
+TEST_P(AnimationCompositorAnimationsTest, ConvertTimingForCompositorDirection) {
   timing_.direction = Timing::PlaybackDirection::NORMAL;
   EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
   EXPECT_EQ(compositor_timing_.direction, Timing::PlaybackDirection::NORMAL);
@@ -685,7 +693,7 @@
   EXPECT_EQ(compositor_timing_.direction, Timing::PlaybackDirection::REVERSE);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        ConvertTimingForCompositorDirectionIterationsAndStartDelay) {
   timing_.direction = Timing::PlaybackDirection::ALTERNATE_NORMAL;
   timing_.iteration_count = 4.0;
@@ -728,7 +736,7 @@
             Timing::PlaybackDirection::ALTERNATE_REVERSE);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorTimingFunctionLinear) {
   timing_.timing_function = linear_timing_function_;
   EXPECT_TRUE(
@@ -737,7 +745,7 @@
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorTimingFunctionCubic) {
   timing_.timing_function = cubic_ease_timing_function_;
   EXPECT_TRUE(
@@ -752,7 +760,7 @@
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorTimingFunctionSteps) {
   timing_.timing_function = step_timing_function_;
   EXPECT_TRUE(
@@ -761,7 +769,7 @@
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorTimingFunctionFrames) {
   timing_.timing_function = frames_timing_function_;
   EXPECT_TRUE(
@@ -770,7 +778,7 @@
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorTimingFunctionChainedLinear) {
   EXPECT_TRUE(
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_));
@@ -778,7 +786,7 @@
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorNonLinearTimingFunctionOnFirstOrLastFrame) {
   keyframe_vector2_->at(0)->SetEasing(cubic_ease_timing_function_.get());
   keyframe_animation_effect2_ =
@@ -801,7 +809,7 @@
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorFailuresProperties) {
   // An effect with no keyframes has no Properties, so can not be composited.
   StringKeyframeVector empty_keyframe_vector;
@@ -809,9 +817,14 @@
       timing_, *StringKeyframeEffectModel::Create(empty_keyframe_vector)));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartElementOnCompositorEffectOpacity) {
-  ScopedBlinkGenPropertyTreesForTest blink_gen_property_trees(true);
+  // This test doesn't apply for pre-BlinkGenPropertyTrees due to the element id
+  // namespaces.
+  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
+      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+    return;
+
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
 
   LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
@@ -898,7 +911,7 @@
   LayoutObjectProxy::Dispose(new_layout_object);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartElementOnCompositorEffectInvalid) {
   base::Optional<CompositorElementIdSet> none;
   auto style = ComputedStyle::Create();
@@ -987,7 +1000,7 @@
   LayoutObjectProxy::Dispose(layout_object);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartElementOnCompositorEffectFilter) {
   base::Optional<CompositorElementIdSet> none;
 
@@ -1052,9 +1065,14 @@
   LayoutObjectProxy::Dispose(layout_object);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartElementOnCompositorEffectTransform) {
-  ScopedBlinkGenPropertyTreesForTest blink_gen_property_trees(true);
+  // This test doesn't apply for pre-BlinkGenPropertyTrees due to the element id
+  // namespaces.
+  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
+      !RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+    return;
+
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
 
   LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
@@ -1128,7 +1146,7 @@
   LayoutObjectProxy::Dispose(layout_object);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorTimingFunctionChainedCubicMatchingOffsets) {
   keyframe_vector2_->at(0)->SetEasing(cubic_ease_timing_function_.get());
   keyframe_animation_effect2_ =
@@ -1152,7 +1170,7 @@
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorTimingFunctionMixedGood) {
   keyframe_vector5_->at(0)->SetEasing(linear_timing_function_.get());
   keyframe_vector5_->at(1)->SetEasing(cubic_ease_timing_function_.get());
@@ -1164,7 +1182,7 @@
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CanStartEffectOnCompositorTimingFunctionWithStepOrFrameOkay) {
   keyframe_vector2_->at(0)->SetEasing(step_timing_function_.get());
   keyframe_animation_effect2_ =
@@ -1206,7 +1224,7 @@
       CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_));
 }
 
-TEST_F(AnimationCompositorAnimationsTest, CanStartEffectOnCompositorBasic) {
+TEST_P(AnimationCompositorAnimationsTest, CanStartEffectOnCompositorBasic) {
   StringKeyframeVector basic_frames_vector;
   basic_frames_vector.push_back(CreateDefaultKeyframe(
       CSSPropertyOpacity, EffectModel::kCompositeReplace, 0.0));
@@ -1269,7 +1287,7 @@
 // -----------------------------------------------------------------------
 // -----------------------------------------------------------------------
 
-TEST_F(AnimationCompositorAnimationsTest, CreateSimpleOpacityAnimation) {
+TEST_P(AnimationCompositorAnimationsTest, CreateSimpleOpacityAnimation) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
       CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0),
@@ -1303,7 +1321,7 @@
             keyframes[1]->GetTimingFunctionForTesting()->GetType());
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CreateSimpleOpacityAnimationDuration) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
@@ -1325,7 +1343,7 @@
   EXPECT_EQ(kDuration, keyframes[1]->Time() * kDuration);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CreateMultipleKeyframeOpacityAnimationLinear) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
@@ -1375,7 +1393,7 @@
             keyframes[3]->GetTimingFunctionForTesting()->GetType());
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CreateSimpleOpacityAnimationStartDelay) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
@@ -1408,7 +1426,7 @@
   EXPECT_EQ(0.5f, keyframes[1]->Value());
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CreateMultipleKeyframeOpacityAnimationChained) {
   // KeyframeEffect to convert
   StringKeyframeVector frames;
@@ -1467,7 +1485,7 @@
             keyframes[3]->GetTimingFunctionForTesting()->GetType());
 }
 
-TEST_F(AnimationCompositorAnimationsTest, CreateReversedOpacityAnimation) {
+TEST_P(AnimationCompositorAnimationsTest, CreateReversedOpacityAnimation) {
   scoped_refptr<TimingFunction> cubic_easy_flip_timing_function =
       CubicBezierTimingFunction::Create(0.0, 0.0, 0.0, 1.0);
 
@@ -1528,7 +1546,7 @@
             keyframes[3]->GetTimingFunctionForTesting()->GetType());
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CreateReversedOpacityAnimationNegativeStartDelay) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
@@ -1560,7 +1578,7 @@
   ASSERT_EQ(2UL, keyframes.size());
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CreateSimpleOpacityAnimationFillModeNone) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
@@ -1575,7 +1593,7 @@
             keyframe_model->GetFillMode());
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CreateSimpleOpacityAnimationFillModeAuto) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
@@ -1597,7 +1615,7 @@
             keyframe_model->GetFillMode());
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CreateSimpleOpacityAnimationWithTimingFunction) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
@@ -1640,7 +1658,7 @@
             keyframes[1]->GetTimingFunctionForTesting()->GetType());
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CreateSimpleCustomFloatPropertyAnimation) {
   ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
 
@@ -1674,7 +1692,7 @@
             keyframes[1]->GetTimingFunctionForTesting()->GetType());
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CancelIncompatibleCompositorAnimations) {
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
   base::Optional<CompositorElementIdSet> none;
@@ -1760,15 +1778,16 @@
 }
 
 }  // namespace
+TEST_P(AnimationCompositorAnimationsTest,
+       CanStartElementOnCompositorTransformBasedOnPaintProperties) {
+  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+    return;
 
-TEST_F(AnimationCompositorAnimationsTest,
-       CanStartElementOnCompositorTransformCAP) {
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
   LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
   layout_object->EnsureIdForTestingProxy();
   element->SetLayoutObject(layout_object);
 
-  ScopedCompositeAfterPaintForTest enable_cap(true);
   auto& properties = layout_object->GetMutableForPainting()
                          .FirstFragment()
                          .EnsurePaintProperties();
@@ -1777,31 +1796,30 @@
   // animation.
   UpdateDummyTransformNode(properties,
                            CompositingReason::kActiveTransformAnimation);
-  EXPECT_TRUE(
-      CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
+  EXPECT_TRUE(CheckCanStartElementOnCompositor(*element));
 
   // Setting to CompositingReasonNone should produce false.
   UpdateDummyTransformNode(properties, CompositingReason::kNone);
-  EXPECT_FALSE(
-      CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
+  EXPECT_FALSE(CheckCanStartElementOnCompositor(*element));
 
   // Clearing the transform node entirely should also produce false.
   properties.ClearTransform();
-  EXPECT_FALSE(
-      CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
+  EXPECT_FALSE(CheckCanStartElementOnCompositor(*element));
 
   element->SetLayoutObject(nullptr);
   LayoutObjectProxy::Dispose(layout_object);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
-       CanStartElementOnCompositorEffectCAP) {
+TEST_P(AnimationCompositorAnimationsTest,
+       CanStartElementOnCompositorEffectBasedOnPaintProperties) {
+  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+    return;
+
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
   LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
   layout_object->EnsureIdForTestingProxy();
   element->SetLayoutObject(layout_object);
 
-  ScopedCompositeAfterPaintForTest enable_cap(true);
   auto& properties = layout_object->GetMutableForPainting()
                          .FirstFragment()
                          .EnsurePaintProperties();
@@ -1810,24 +1828,21 @@
   // animation.
   UpdateDummyEffectNode(properties,
                         CompositingReason::kActiveTransformAnimation);
-  EXPECT_TRUE(
-      CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
+  EXPECT_TRUE(CheckCanStartElementOnCompositor(*element));
 
   // Setting to CompositingReasonNone should produce false.
   UpdateDummyEffectNode(properties, CompositingReason::kNone);
-  EXPECT_FALSE(
-      CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
+  EXPECT_FALSE(CheckCanStartElementOnCompositor(*element));
 
   // Clearing the effect node entirely should also produce false.
   properties.ClearEffect();
-  EXPECT_FALSE(
-      CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
+  EXPECT_FALSE(CheckCanStartElementOnCompositor(*element));
 
   element->SetLayoutObject(nullptr);
   LayoutObjectProxy::Dispose(layout_object);
 }
 
-TEST_F(AnimationCompositorAnimationsTest, TrackRafAnimation) {
+TEST_P(AnimationCompositorAnimationsTest, TrackRafAnimation) {
   LoadTestData("raf-countdown.html");
 
   cc::AnimationHost* host =
@@ -1856,7 +1871,7 @@
   EXPECT_FALSE(host->NextFrameHasPendingRAF());
 }
 
-TEST_F(AnimationCompositorAnimationsTest, TrackRafAnimationTimeout) {
+TEST_P(AnimationCompositorAnimationsTest, TrackRafAnimationTimeout) {
   LoadTestData("raf-timeout.html");
 
   cc::AnimationHost* host =
@@ -1870,7 +1885,7 @@
   EXPECT_FALSE(host->NextFrameHasPendingRAF());
 }
 
-TEST_F(AnimationCompositorAnimationsTest, TrackRafAnimationNoneRegistered) {
+TEST_P(AnimationCompositorAnimationsTest, TrackRafAnimationNoneRegistered) {
   SetBodyInnerHTML("<div id='box'></div>");
 
   // Run a full frame after loading the test data so that scripted animations
@@ -1891,25 +1906,50 @@
   EXPECT_FALSE(host->NextFrameHasPendingRAF());
 }
 
-TEST_F(AnimationCompositorAnimationsTest, CanStartElementOnCompositorEffect) {
+TEST_P(AnimationCompositorAnimationsTest, CompositedTransformAnimation) {
+  // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+    return;
+
   LoadTestData("transform-animation.html");
   Document* document = GetFrame()->GetDocument();
   Element* target = document->getElementById("target");
   const ObjectPaintProperties* properties =
       target->GetLayoutObject()->FirstFragment().PaintProperties();
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    EXPECT_TRUE(properties->Transform()->HasDirectCompositingReasons());
-  CompositorAnimations::FailureCode code =
-      CompositorAnimations::CheckCanStartElementOnCompositor(*target);
-  EXPECT_EQ(code, CompositorAnimations::FailureCode::None());
+  ASSERT_NE(nullptr, properties);
+  const auto* transform = properties->Transform();
+  ASSERT_NE(nullptr, transform);
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+      RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    EXPECT_TRUE(transform->HasDirectCompositingReasons());
+    EXPECT_TRUE(transform->HasActiveTransformAnimation());
+    // Make sure the animation state is initialized in paint properties.
+    auto* property_trees =
+        document->View()->RootCcLayer()->layer_tree_host()->property_trees();
+    auto* cc_transform = property_trees->transform_tree.Node(
+        property_trees->element_id_to_transform_node_index
+            [transform->GetCompositorElementId()]);
+    ASSERT_NE(nullptr, cc_transform);
+    EXPECT_TRUE(cc_transform->has_potential_animation);
+    EXPECT_TRUE(cc_transform->is_currently_animating);
+  }
+  // Make sure the animation is started on the compositor.
+  EXPECT_TRUE(CheckCanStartElementOnCompositor(*target));
   EXPECT_EQ(document->Timeline().PendingAnimationsCount(), 1u);
   cc::AnimationHost* host = document->View()->GetCompositorAnimationHost();
   EXPECT_EQ(host->MainThreadAnimationsCount(), 0u);
   EXPECT_EQ(host->CompositedAnimationsCount(), 1u);
 }
 
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        NonAnimatedTransformPropertyChangeGetsUpdated) {
+  // This test doesn't apply for pre-BlinkGenPropertyTrees due to the element id
+  // namespaces.
+  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+      // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
+      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+    return;
+
   LoadTestData("transform-animation-update.html");
   Document* document = GetFrame()->GetDocument();
   Element* target = document->getElementById("target");
@@ -1919,11 +1959,19 @@
   const auto* transform = properties->Transform();
   ASSERT_NE(nullptr, transform);
   // Make sure composited animation is running on #target.
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    EXPECT_TRUE(transform->HasDirectCompositingReasons());
-  CompositorAnimations::FailureCode code =
-      CompositorAnimations::CheckCanStartElementOnCompositor(*target);
-  EXPECT_EQ(code, CompositorAnimations::FailureCode::None());
+  EXPECT_TRUE(transform->HasDirectCompositingReasons());
+  EXPECT_TRUE(transform->HasActiveTransformAnimation());
+  EXPECT_TRUE(CheckCanStartElementOnCompositor(*target));
+  // Make sure the animation state is initialized in paint properties.
+  auto* property_trees =
+      document->View()->RootCcLayer()->layer_tree_host()->property_trees();
+  auto* cc_transform = property_trees->transform_tree.Node(
+      property_trees->element_id_to_transform_node_index
+          [transform->GetCompositorElementId()]);
+  ASSERT_NE(nullptr, cc_transform);
+  EXPECT_TRUE(cc_transform->has_potential_animation);
+  EXPECT_TRUE(cc_transform->is_currently_animating);
+  // Make sure the animation is started on the compositor.
   EXPECT_EQ(document->Timeline().PendingAnimationsCount(), 1u);
   cc::AnimationHost* host = document->View()->GetCompositorAnimationHost();
   EXPECT_EQ(host->MainThreadAnimationsCount(), 0u);
@@ -1942,6 +1990,7 @@
       composited_layer_mapping->MainGraphicsLayer()->CcLayer();
   ASSERT_NE(nullptr, layer);
   EXPECT_TRUE(layer->double_sided());
+
   // Change the backface visibility, while the compositor animation is
   // happening.
   target->setAttribute(html_names::kClassAttr, "backface-hidden");
@@ -1951,20 +2000,27 @@
             TransformPaintPropertyNode::BackfaceVisibility::kHidden);
   EXPECT_FALSE(layer->double_sided())
       << "Change to hidden did not get propagated to CC";
+  // Make sure the animation state is initialized in paint properties after
+  // blink pushing new paint properties without animation state change.
+  property_trees =
+      document->View()->RootCcLayer()->layer_tree_host()->property_trees();
+  cc_transform = property_trees->transform_tree.Node(
+      property_trees->element_id_to_transform_node_index
+          [transform->GetCompositorElementId()]);
+  ASSERT_NE(nullptr, cc_transform);
+  EXPECT_TRUE(cc_transform->has_potential_animation);
+  EXPECT_TRUE(cc_transform->is_currently_animating);
 }
 
 // Regression test for https://crbug.com/781305. When we have a transform
 // animation on a SVG element, the effect can be started on compositor but the
 // element itself cannot.
-TEST_F(AnimationCompositorAnimationsTest,
+TEST_P(AnimationCompositorAnimationsTest,
        CannotStartElementOnCompositorEffectSVG) {
   LoadTestData("transform-animation-on-svg.html");
   Document* document = GetFrame()->GetDocument();
   Element* target = document->getElementById("dots");
-  CompositorAnimations::FailureCode code =
-      CompositorAnimations::CheckCanStartElementOnCompositor(*target);
-  EXPECT_EQ(code, CompositorAnimations::FailureCode::NonActionable(
-                      "Element does not paint into own backing"));
+  EXPECT_FALSE(CheckCanStartElementOnCompositor(*target));
   EXPECT_EQ(document->Timeline().PendingAnimationsCount(), 4u);
   cc::AnimationHost* host = document->View()->GetCompositorAnimationHost();
   EXPECT_EQ(host->MainThreadAnimationsCount(), 4u);
diff --git a/third_party/blink/renderer/core/css/BUILD.gn b/third_party/blink/renderer/core/css/BUILD.gn
index a99c53d..fefa55a 100644
--- a/third_party/blink/renderer/core/css/BUILD.gn
+++ b/third_party/blink/renderer/core/css/BUILD.gn
@@ -420,7 +420,6 @@
     "properties/css_parsing_utils.h",
     "properties/css_property.cc",
     "properties/css_property.h",
-    "properties/css_property_base_custom.cc",
     "properties/css_property_ref.cc",
     "properties/css_property_ref.h",
     "properties/css_unresolved_property.cc",
diff --git a/third_party/blink/renderer/core/css/properties/css_property.cc b/third_party/blink/renderer/core/css/properties/css_property.cc
index 905f389..31126bb7 100644
--- a/third_party/blink/renderer/core/css/properties/css_property.cc
+++ b/third_party/blink/renderer/core/css/properties/css_property.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/css/properties/css_property.h"
 
+#include "base/stl_util.h"
 #include "third_party/blink/renderer/core/css/cssom/cross_thread_keyword_value.h"
 #include "third_party/blink/renderer/core/css/cssom/cross_thread_style_value.h"
 #include "third_party/blink/renderer/core/css/cssom/cross_thread_unit_value.h"
@@ -11,6 +12,9 @@
 #include "third_party/blink/renderer/core/css/cssom/css_keyword_value.h"
 #include "third_party/blink/renderer/core/css/cssom/css_unit_value.h"
 #include "third_party/blink/renderer/core/css/cssom/style_value_factory.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/core/style/svg_computed_style.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
 
 namespace blink {
 
@@ -53,4 +57,91 @@
   }
 }
 
+const StylePropertyShorthand& CSSProperty::BorderDirections() {
+  static const CSSProperty* kProperties[4] = {
+      &GetCSSPropertyBorderTop(), &GetCSSPropertyBorderRight(),
+      &GetCSSPropertyBorderBottom(), &GetCSSPropertyBorderLeft()};
+  DEFINE_STATIC_LOCAL(
+      StylePropertyShorthand, border_directions,
+      (CSSPropertyBorder, kProperties, base::size(kProperties)));
+  return border_directions;
+}
+
+const CSSProperty& CSSProperty::ResolveAfterToPhysicalProperty(
+    TextDirection direction,
+    WritingMode writing_mode,
+    const StylePropertyShorthand& shorthand) {
+  const CSSProperty** shorthand_properties = shorthand.properties();
+  if (IsHorizontalWritingMode(writing_mode))
+    return *shorthand_properties[kBottomSide];
+  if (IsFlippedLinesWritingMode(writing_mode))
+    return *shorthand_properties[kRightSide];
+  return *shorthand_properties[kLeftSide];
+}
+
+const CSSProperty& CSSProperty::ResolveBeforeToPhysicalProperty(
+    TextDirection direction,
+    WritingMode writing_mode,
+    const StylePropertyShorthand& shorthand) {
+  const CSSProperty** shorthand_properties = shorthand.properties();
+  if (IsHorizontalWritingMode(writing_mode))
+    return *shorthand_properties[kTopSide];
+  if (IsFlippedLinesWritingMode(writing_mode))
+    return *shorthand_properties[kLeftSide];
+  return *shorthand_properties[kRightSide];
+}
+
+const CSSProperty& CSSProperty::ResolveEndToPhysicalProperty(
+    TextDirection direction,
+    WritingMode writing_mode,
+    const StylePropertyShorthand& shorthand) {
+  const CSSProperty** shorthand_properties = shorthand.properties();
+  if (direction == TextDirection::kLtr) {
+    if (IsHorizontalWritingMode(writing_mode))
+      return *shorthand_properties[kRightSide];
+    return *shorthand_properties[kBottomSide];
+  }
+  if (IsHorizontalWritingMode(writing_mode))
+    return *shorthand_properties[kLeftSide];
+  return *shorthand_properties[kTopSide];
+}
+
+const CSSProperty& CSSProperty::ResolveStartToPhysicalProperty(
+    TextDirection direction,
+    WritingMode writing_mode,
+    const StylePropertyShorthand& shorthand) {
+  const CSSProperty** shorthand_properties = shorthand.properties();
+  if (direction == TextDirection::kLtr) {
+    if (IsHorizontalWritingMode(writing_mode))
+      return *shorthand_properties[kLeftSide];
+    return *shorthand_properties[kTopSide];
+  }
+  if (IsHorizontalWritingMode(writing_mode))
+    return *shorthand_properties[kRightSide];
+  return *shorthand_properties[kBottomSide];
+}
+
+const CSSValue* CSSProperty::CSSValueFromComputedStyle(
+    const ComputedStyle& style,
+    const LayoutObject* layout_object,
+    Node* styled_node,
+    bool allow_visited_style) const {
+  const SVGComputedStyle& svg_style = style.SvgStyle();
+  const CSSProperty& resolved_property =
+      ResolveDirectionAwareProperty(style.Direction(), style.GetWritingMode());
+  return resolved_property.CSSValueFromComputedStyleInternal(
+      style, svg_style, layout_object, styled_node, allow_visited_style);
+}
+
+void CSSProperty::FilterEnabledCSSPropertiesIntoVector(
+    const CSSPropertyID* properties,
+    size_t propertyCount,
+    Vector<const CSSProperty*>& outVector) {
+  for (unsigned i = 0; i < propertyCount; i++) {
+    const CSSProperty& property = Get(properties[i]);
+    if (property.IsEnabled())
+      outVector.push_back(&property);
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/css_property_base_custom.cc b/third_party/blink/renderer/core/css/properties/css_property_base_custom.cc
deleted file mode 100644
index 3748065..0000000
--- a/third_party/blink/renderer/core/css/properties/css_property_base_custom.cc
+++ /dev/null
@@ -1,103 +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.
-
-// This file contains methods of CSSProperty that are not generated.
-
-#include "third_party/blink/renderer/core/css/properties/css_property.h"
-
-#include "base/stl_util.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/core/style/svg_computed_style.h"
-#include "third_party/blink/renderer/core/style_property_shorthand.h"
-
-namespace blink {
-
-const StylePropertyShorthand& CSSProperty::BorderDirections() {
-  static const CSSProperty* kProperties[4] = {
-      &GetCSSPropertyBorderTop(), &GetCSSPropertyBorderRight(),
-      &GetCSSPropertyBorderBottom(), &GetCSSPropertyBorderLeft()};
-  DEFINE_STATIC_LOCAL(
-      StylePropertyShorthand, border_directions,
-      (CSSPropertyBorder, kProperties, base::size(kProperties)));
-  return border_directions;
-}
-
-const CSSProperty& CSSProperty::ResolveAfterToPhysicalProperty(
-    TextDirection direction,
-    WritingMode writing_mode,
-    const StylePropertyShorthand& shorthand) {
-  const CSSProperty** shorthand_properties = shorthand.properties();
-  if (IsHorizontalWritingMode(writing_mode))
-    return *shorthand_properties[kBottomSide];
-  if (IsFlippedLinesWritingMode(writing_mode))
-    return *shorthand_properties[kRightSide];
-  return *shorthand_properties[kLeftSide];
-}
-
-const CSSProperty& CSSProperty::ResolveBeforeToPhysicalProperty(
-    TextDirection direction,
-    WritingMode writing_mode,
-    const StylePropertyShorthand& shorthand) {
-  const CSSProperty** shorthand_properties = shorthand.properties();
-  if (IsHorizontalWritingMode(writing_mode))
-    return *shorthand_properties[kTopSide];
-  if (IsFlippedLinesWritingMode(writing_mode))
-    return *shorthand_properties[kLeftSide];
-  return *shorthand_properties[kRightSide];
-}
-
-const CSSProperty& CSSProperty::ResolveEndToPhysicalProperty(
-    TextDirection direction,
-    WritingMode writing_mode,
-    const StylePropertyShorthand& shorthand) {
-  const CSSProperty** shorthand_properties = shorthand.properties();
-  if (direction == TextDirection::kLtr) {
-    if (IsHorizontalWritingMode(writing_mode))
-      return *shorthand_properties[kRightSide];
-    return *shorthand_properties[kBottomSide];
-  }
-  if (IsHorizontalWritingMode(writing_mode))
-    return *shorthand_properties[kLeftSide];
-  return *shorthand_properties[kTopSide];
-}
-
-const CSSProperty& CSSProperty::ResolveStartToPhysicalProperty(
-    TextDirection direction,
-    WritingMode writing_mode,
-    const StylePropertyShorthand& shorthand) {
-  const CSSProperty** shorthand_properties = shorthand.properties();
-  if (direction == TextDirection::kLtr) {
-    if (IsHorizontalWritingMode(writing_mode))
-      return *shorthand_properties[kLeftSide];
-    return *shorthand_properties[kTopSide];
-  }
-  if (IsHorizontalWritingMode(writing_mode))
-    return *shorthand_properties[kRightSide];
-  return *shorthand_properties[kBottomSide];
-}
-
-const CSSValue* CSSProperty::CSSValueFromComputedStyle(
-    const ComputedStyle& style,
-    const LayoutObject* layout_object,
-    Node* styled_node,
-    bool allow_visited_style) const {
-  const SVGComputedStyle& svg_style = style.SvgStyle();
-  const CSSProperty& resolved_property =
-      ResolveDirectionAwareProperty(style.Direction(), style.GetWritingMode());
-  return resolved_property.CSSValueFromComputedStyleInternal(
-      style, svg_style, layout_object, styled_node, allow_visited_style);
-}
-
-void CSSProperty::FilterEnabledCSSPropertiesIntoVector(
-    const CSSPropertyID* properties,
-    size_t propertyCount,
-    Vector<const CSSProperty*>& outVector) {
-  for (unsigned i = 0; i < propertyCount; i++) {
-    const CSSProperty& property = Get(properties[i]);
-    if (property.IsEnabled())
-      outVector.push_back(&property);
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 17b63b8..b8cbfde 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -4657,8 +4657,10 @@
     if (IsRootEditableElement(*new_focused_element) &&
         !AcceptsEditingFocus(*new_focused_element)) {
       // delegate blocks focus change
-      focus_change_blocked = true;
-      goto SetFocusedElementDone;
+      UpdateStyleAndLayoutTree();
+      if (LocalFrame* frame = GetFrame())
+        frame->Selection().DidChangeFocus();
+      return false;
     }
     // Set focus on the new node
     focused_element_ = new_focused_element;
@@ -4673,18 +4675,13 @@
 
     // Element::setFocused for frames can dispatch events.
     if (focused_element_ != new_focused_element) {
-      focus_change_blocked = true;
-      goto SetFocusedElementDone;
+      UpdateStyleAndLayoutTree();
+      if (LocalFrame* frame = GetFrame())
+        frame->Selection().DidChangeFocus();
+      return false;
     }
     CancelFocusAppearanceUpdate();
     EnsurePaintLocationDataValidForNode(focused_element_);
-    // UpdateStyleAndLayout can call SetFocusedElement (through
-    // InvokeFragmentAnchor called in Document::LayoutUpdated) and clear
-    // focused_element_.
-    if (focused_element_ != new_focused_element) {
-      focus_change_blocked = true;
-      goto SetFocusedElementDone;
-    }
     focused_element_->UpdateFocusAppearanceWithOptions(
         params.selection_behavior, params.options);
 
@@ -4698,8 +4695,10 @@
 
       if (focused_element_ != new_focused_element) {
         // handler shifted focus
-        focus_change_blocked = true;
-        goto SetFocusedElementDone;
+        UpdateStyleAndLayoutTree();
+        if (LocalFrame* frame = GetFrame())
+          frame->Selection().DidChangeFocus();
+        return false;
       }
       // DOM level 3 bubbling focus event.
       focused_element_->DispatchFocusInEvent(event_type_names::kFocusin,
@@ -4708,8 +4707,10 @@
 
       if (focused_element_ != new_focused_element) {
         // handler shifted focus
-        focus_change_blocked = true;
-        goto SetFocusedElementDone;
+        UpdateStyleAndLayoutTree();
+        if (LocalFrame* frame = GetFrame())
+          frame->Selection().DidChangeFocus();
+        return false;
       }
 
       // For DOM level 2 compatibility.
@@ -4721,8 +4722,10 @@
 
       if (focused_element_ != new_focused_element) {
         // handler shifted focus
-        focus_change_blocked = true;
-        goto SetFocusedElementDone;
+        UpdateStyleAndLayoutTree();
+        if (LocalFrame* frame = GetFrame())
+          frame->Selection().DidChangeFocus();
+        return false;
       }
     }
   }
@@ -4741,7 +4744,6 @@
                                                     focused_element_.Get());
   }
 
-SetFocusedElementDone:
   UpdateStyleAndLayoutTree();
   if (LocalFrame* frame = GetFrame())
     frame->Selection().DidChangeFocus();
diff --git a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
index 94b0477..857cdac7b 100644
--- a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
+++ b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
@@ -101,6 +101,7 @@
   EditingStyle* CreateInlineStyle(Element&);
   bool NeedsInlineStyle(const Element&);
   bool ShouldApplyWrappingStyle(const Node&) const;
+  bool ContainsOnlyBRElement(const Element&) const;
 
   StyledMarkupAccumulator* accumulator_;
   Member<Node> last_closed_;
@@ -300,7 +301,8 @@
 
   // FIXME: The interchange newline should be placed in the block that it's in,
   // not after all of the content, unconditionally.
-  if (ShouldAnnotate() && NeedInterchangeNewlineAt(visible_end))
+  if (!(last_closed && IsHTMLBRElement(*last_closed)) && ShouldAnnotate() &&
+      NeedInterchangeNewlineAt(visible_end))
     markup_accumulator.AppendInterchangeNewline();
 
   return markup_accumulator.TakeResults();
@@ -353,8 +355,9 @@
     } else {
       next = Strategy::Next(*n);
       if (IsEnclosingBlock(n) && CanHaveChildrenForEditing(n) &&
-          next == past_end) {
-        // Don't write out empty block containers that aren't fully selected.
+          next == past_end && !ContainsOnlyBRElement(ToElement(*n))) {
+        // Don't write out empty block containers that aren't fully selected
+        // unless the block container only contains br element.
         continue;
       }
 
@@ -372,7 +375,15 @@
 
         // If node has no children, close the tag now.
         if (Strategy::HasChildren(*n)) {
-          ancestors_to_close.push_back(ToContainerNode(n));
+          if (next == past_end && ContainsOnlyBRElement(ToElement(*n))) {
+            // node is not fully selected and node contains only one br element
+            // as child. Close the br tag now.
+            AppendStartMarkup(*next);
+            AppendEndMarkup(*next);
+            last_closed = next;
+          } else {
+            ancestors_to_close.push_back(ToContainerNode(n));
+          }
           continue;
         }
         AppendEndMarkup(*n);
@@ -554,6 +565,15 @@
   return inline_style;
 }
 
+template <typename Strategy>
+bool StyledMarkupTraverser<Strategy>::ContainsOnlyBRElement(
+    const Element& element) const {
+  auto* const first_child = element.firstChild();
+  if (!first_child)
+    return false;
+  return IsHTMLBRElement(first_child) && first_child == element.lastChild();
+}
+
 template class StyledMarkupSerializer<EditingStrategy>;
 template class StyledMarkupSerializer<EditingInFlatTreeStrategy>;
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 665feae..7b875bf 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2458,6 +2458,8 @@
       RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
     if (!print_mode_enabled) {
       auto& composited_element_ids = composited_element_ids_;
+      bool needed_update = !paint_artifact_compositor_ ||
+                           paint_artifact_compositor_->NeedsUpdate();
       PushPaintArtifactToCompositor(composited_element_ids.value());
       ForAllNonThrottledLocalFrameViews(
           [&composited_element_ids](LocalFrameView& frame_view) {
@@ -2466,6 +2468,19 @@
                 DocumentLifecycle::kPaintClean, composited_element_ids);
           });
 
+      // Initialize animation properties in the newly created paint property
+      // nodes according to the current animation state. This is mainly for
+      // the running composited animations which didn't change state during
+      // above UpdateAnimations() but associated with new paint property nodes.
+      if (needed_update) {
+        auto* root_layer = RootCcLayer();
+        if (root_layer && root_layer->layer_tree_host()) {
+          root_layer->layer_tree_host()
+              ->mutator_host()
+              ->InitClientAnimationState();
+        }
+      }
+
       // Notify the controller that the artifact has been pushed and some
       // lifecycle state can be freed (such as raster invalidations).
       if (paint_controller_)
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index c41c4b5..96fab69a 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -3029,10 +3029,9 @@
       array of DataEntry objectStoreDataEntries
       # If true, there are more entries to fetch in the given range.
       boolean hasMore
-
-  # Gets the auto increment number of an object store. Only meaningful
-  # when objectStore.autoIncrement is true.
-  command getKeyGeneratorCurrentNumber
+  
+  # Gets metadata of an object store
+  command getMetadata
     parameters
       # Security origin.
       string securityOrigin
@@ -3041,9 +3040,12 @@
       # Object store name.
       string objectStoreName
     returns
+      # the entries count
+      number entriesCount
       # the current value of key generator, to become the next inserted
-      # key into the object store.
-      number currentNumber
+      # key into the object store. Valid if objectStore.autoIncrement
+      # is true.
+      number keyGeneratorValue
 
   # Requests database with given name in given frame.
   command requestDatabase
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
index e472b20..58b36aa 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -137,6 +137,10 @@
   return false;
 }
 
+bool InspectTool::ForwardEventsToOverlay() {
+  return true;
+}
+
 void InspectTool::Trace(blink::Visitor* visitor) {
   visitor->Trace(overlay_);
 }
@@ -626,85 +630,25 @@
     WebGestureEvent transformed_event = TransformWebGestureEvent(
         frame_impl_->GetFrameView(),
         static_cast<const WebGestureEvent&>(input_event));
-    if (inspect_tool_->HandleGestureTapEvent(transformed_event)) {
-      ScheduleUpdate();
-      return WebInputEventResult::kHandledSuppressed;
-    }
-    return OverlayMainFrame()->GetEventHandler().HandleGestureEvent(
-        transformed_event);
+    return HandleGestureTapEvent(transformed_event);
   }
 
   if (WebInputEvent::IsMouseEventType(input_event.GetType())) {
-    WebMouseEvent mouse_event =
+    WebMouseEvent transformed_event =
         TransformWebMouseEvent(frame_impl_->GetFrameView(),
                                static_cast<const WebMouseEvent&>(input_event));
-
-    bool handled = false;
-    if (mouse_event.GetType() == WebInputEvent::kMouseMove) {
-      handled = inspect_tool_->HandleMouseMove(mouse_event);
-    } else if (mouse_event.GetType() == WebInputEvent::kMouseDown) {
-      handled =
-          inspect_tool_->HandleMouseDown(mouse_event, &swallow_next_mouse_up_);
-    } else if (mouse_event.GetType() == WebInputEvent::kMouseUp) {
-      handled = inspect_tool_->HandleMouseUp(mouse_event);
-    }
-
-    if (handled) {
-      ScheduleUpdate();
-      return WebInputEventResult::kHandledSuppressed;
-    }
-
-    if (mouse_event.GetType() == WebInputEvent::kMouseMove) {
-      return OverlayMainFrame()->GetEventHandler().HandleMouseMoveEvent(
-          mouse_event,
-          TransformWebMouseEventVector(frame_impl_->GetFrameView(),
-                                       std::vector<const WebInputEvent*>()),
-          TransformWebMouseEventVector(frame_impl_->GetFrameView(),
-                                       std::vector<const WebInputEvent*>()));
-    }
-    if (mouse_event.GetType() == WebInputEvent::kMouseDown) {
-      return OverlayMainFrame()->GetEventHandler().HandleMousePressEvent(
-          mouse_event);
-    }
-    if (mouse_event.GetType() == WebInputEvent::kMouseUp) {
-      return OverlayMainFrame()->GetEventHandler().HandleMouseReleaseEvent(
-          mouse_event);
-    }
+    return HandleMouseEvent(transformed_event);
   }
 
   if (WebInputEvent::IsPointerEventType(input_event.GetType())) {
     WebPointerEvent transformed_event = TransformWebPointerEvent(
         frame_impl_->GetFrameView(),
         static_cast<const WebPointerEvent&>(input_event));
-    bool handled = inspect_tool_->HandlePointerEvent(transformed_event);
-    if (handled) {
-      ScheduleUpdate();
-      return WebInputEventResult::kHandledSuppressed;
-    }
-    return OverlayMainFrame()->GetEventHandler().HandlePointerEvent(
-        transformed_event, Vector<WebPointerEvent>(),
-        Vector<WebPointerEvent>());
+    return HandlePointerEvent(transformed_event);
   }
 
   if (WebInputEvent::IsKeyboardEventType(input_event.GetType())) {
-    bool handled = inspect_tool_->HandleKeyboardEvent(
-        static_cast<const WebKeyboardEvent&>(input_event),
-        &swallow_next_escape_up_);
-    if (handled) {
-      ScheduleUpdate();
-      return WebInputEventResult::kHandledSuppressed;
-    }
-
-    // Exit tool upon unhandled Esc.
-    if (input_event.GetType() == WebInputEvent::kRawKeyDown) {
-      auto keyboard_event = static_cast<const WebKeyboardEvent&>(input_event);
-      if (keyboard_event.windows_key_code == VKEY_ESCAPE) {
-        GetFrontend()->inspectModeCanceled();
-        swallow_next_escape_up_ = true;
-        return WebInputEventResult::kHandledSuppressed;
-      }
-    }
-    return OverlayMainFrame()->GetEventHandler().KeyEvent(
+    return HandleKeyboardEvent(
         static_cast<const WebKeyboardEvent&>(input_event));
   }
 
@@ -712,13 +656,107 @@
     WebMouseWheelEvent transformed_event = TransformWebMouseWheelEvent(
         frame_impl_->GetFrameView(),
         static_cast<const WebMouseWheelEvent&>(input_event));
-    return OverlayMainFrame()->GetEventHandler().HandleWheelEvent(
-        transformed_event);
+    return HandleMouseWheelEvent(transformed_event);
   }
 
   return WebInputEventResult::kNotHandled;
 }
 
+WebInputEventResult InspectorOverlayAgent::HandleGestureTapEvent(
+    const WebGestureEvent& gesture_event) {
+  if (inspect_tool_->HandleGestureTapEvent(gesture_event)) {
+    ScheduleUpdate();
+    return WebInputEventResult::kHandledSuppressed;
+  }
+  if (!inspect_tool_->ForwardEventsToOverlay())
+    return WebInputEventResult::kNotHandled;
+
+  return OverlayMainFrame()->GetEventHandler().HandleGestureEvent(
+      gesture_event);
+}
+
+WebInputEventResult InspectorOverlayAgent::HandleMouseEvent(
+    const WebMouseEvent& mouse_event) {
+  bool handled = false;
+  if (mouse_event.GetType() == WebInputEvent::kMouseMove) {
+    handled = inspect_tool_->HandleMouseMove(mouse_event);
+  } else if (mouse_event.GetType() == WebInputEvent::kMouseDown) {
+    handled =
+        inspect_tool_->HandleMouseDown(mouse_event, &swallow_next_mouse_up_);
+  } else if (mouse_event.GetType() == WebInputEvent::kMouseUp) {
+    handled = inspect_tool_->HandleMouseUp(mouse_event);
+  }
+
+  if (handled) {
+    ScheduleUpdate();
+    return WebInputEventResult::kHandledSuppressed;
+  }
+
+  if (!inspect_tool_->ForwardEventsToOverlay())
+    return WebInputEventResult::kNotHandled;
+
+  if (mouse_event.GetType() == WebInputEvent::kMouseMove) {
+    return OverlayMainFrame()->GetEventHandler().HandleMouseMoveEvent(
+        mouse_event,
+        TransformWebMouseEventVector(frame_impl_->GetFrameView(),
+                                     std::vector<const WebInputEvent*>()),
+        TransformWebMouseEventVector(frame_impl_->GetFrameView(),
+                                     std::vector<const WebInputEvent*>()));
+  }
+  if (mouse_event.GetType() == WebInputEvent::kMouseDown) {
+    return OverlayMainFrame()->GetEventHandler().HandleMousePressEvent(
+        mouse_event);
+  }
+  if (mouse_event.GetType() == WebInputEvent::kMouseUp) {
+    return OverlayMainFrame()->GetEventHandler().HandleMouseReleaseEvent(
+        mouse_event);
+  }
+  return WebInputEventResult::kNotHandled;
+}
+
+WebInputEventResult InspectorOverlayAgent::HandlePointerEvent(
+    const WebPointerEvent& pointer_event) {
+  bool handled = inspect_tool_->HandlePointerEvent(pointer_event);
+  if (handled) {
+    ScheduleUpdate();
+    return WebInputEventResult::kHandledSuppressed;
+  }
+
+  if (!inspect_tool_->ForwardEventsToOverlay())
+    return WebInputEventResult::kNotHandled;
+
+  return OverlayMainFrame()->GetEventHandler().HandlePointerEvent(
+      pointer_event, Vector<WebPointerEvent>(), Vector<WebPointerEvent>());
+}
+
+WebInputEventResult InspectorOverlayAgent::HandleKeyboardEvent(
+    const WebKeyboardEvent& keyboard_event) {
+  bool handled = inspect_tool_->HandleKeyboardEvent(keyboard_event,
+                                                    &swallow_next_escape_up_);
+  if (handled) {
+    ScheduleUpdate();
+    return WebInputEventResult::kHandledSuppressed;
+  }
+
+  // Exit tool upon unhandled Esc.
+  if (keyboard_event.GetType() == WebInputEvent::kRawKeyDown) {
+    if (keyboard_event.windows_key_code == VKEY_ESCAPE) {
+      GetFrontend()->inspectModeCanceled();
+      swallow_next_escape_up_ = true;
+      return WebInputEventResult::kHandledSuppressed;
+    }
+  }
+  if (!inspect_tool_->ForwardEventsToOverlay())
+    return WebInputEventResult::kNotHandled;
+
+  return OverlayMainFrame()->GetEventHandler().KeyEvent(keyboard_event);
+}
+
+WebInputEventResult InspectorOverlayAgent::HandleMouseWheelEvent(
+    const WebMouseWheelEvent& wheel_event) {
+  return OverlayMainFrame()->GetEventHandler().HandleWheelEvent(wheel_event);
+}
+
 void InspectorOverlayAgent::InnerHideHighlight() {
   highlight_node_.Clear();
   event_target_node_.Clear();
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
index bd6c0ca9..1e3013e 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
@@ -65,6 +65,7 @@
 class WebGestureEvent;
 class WebKeyboardEvent;
 class WebMouseEvent;
+class WebMouseWheelEvent;
 class WebLocalFrameImpl;
 class WebPointerEvent;
 
@@ -84,6 +85,7 @@
   virtual bool HandlePointerEvent(const WebPointerEvent&);
   virtual bool HandleKeyboardEvent(const WebKeyboardEvent&,
                                    bool* swallow_next_escape_up);
+  virtual bool ForwardEventsToOverlay();
   virtual void Draw(float scale) {}
   virtual void Trace(blink::Visitor* visitor);
   virtual void Dispose() {}
@@ -214,6 +216,14 @@
       protocol::Maybe<protocol::Overlay::HighlightConfig>
           highlight_inspector_object,
       std::unique_ptr<InspectorHighlightConfig>*);
+  WebInputEventResult HandleGestureTapEvent(
+      const WebGestureEvent& gesture_event);
+  WebInputEventResult HandleMouseEvent(const WebMouseEvent& mouse_event);
+  WebInputEventResult HandlePointerEvent(const WebPointerEvent& pointer_event);
+  WebInputEventResult HandleKeyboardEvent(
+      const WebKeyboardEvent& keyboard_event);
+  WebInputEventResult HandleMouseWheelEvent(
+      const WebMouseWheelEvent& wheel_event);
 
   Member<WebLocalFrameImpl> frame_impl_;
   Member<InspectedFrames> inspected_frames_;
diff --git a/third_party/blink/renderer/core/inspector/inspector_protocol_config.json b/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
index 6ed7e71b..ac9da405 100644
--- a/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
+++ b/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
@@ -48,7 +48,7 @@
             },
             {
                 "domain": "IndexedDB",
-                "async": ["requestDatabaseNames", "requestDatabase", "requestData", "getKeyGeneratorCurrentNumber", "deleteObjectStoreEntries", "clearObjectStore", "deleteDatabase"]
+                "async": ["requestDatabaseNames", "requestDatabase", "requestData", "getMetadata", "deleteObjectStoreEntries", "clearObjectStore", "deleteDatabase"]
             },
             {
                 "domain": "LayerTree"
diff --git a/third_party/blink/renderer/core/layout/BUILD.gn b/third_party/blink/renderer/core/layout/BUILD.gn
index 503f7fa..97985c4 100644
--- a/third_party/blink/renderer/core/layout/BUILD.gn
+++ b/third_party/blink/renderer/core/layout/BUILD.gn
@@ -301,7 +301,6 @@
     "ng/geometry/ng_bfc_offset.h",
     "ng/geometry/ng_bfc_rect.cc",
     "ng/geometry/ng_bfc_rect.h",
-    "ng/geometry/ng_border_edges.cc",
     "ng/geometry/ng_border_edges.h",
     "ng/geometry/ng_box_strut.cc",
     "ng/geometry/ng_box_strut.h",
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
index 697e426..9e00ae9 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
@@ -225,11 +225,11 @@
                                           CoordinateSpaceConversion) const;
 
   LayoutPoint FlowThreadPointToVisualPoint(
-      const LayoutPoint& flow_thread_point) const override;
+      const LayoutPoint& flow_thread_point) const final;
   LayoutPoint VisualPointToFlowThreadPoint(
-      const LayoutPoint& visual_point) const override;
+      const LayoutPoint& visual_point) const final;
 
-  LayoutUnit InlineBlockBaseline(LineDirectionMode) const override;
+  LayoutUnit InlineBlockBaseline(LineDirectionMode) const final;
 
   LayoutMultiColumnSet* ColumnSetAtBlockOffset(LayoutUnit,
                                                PageBoundaryRule) const final;
@@ -326,13 +326,13 @@
   void ComputePreferredLogicalWidths() override;
   void ComputeLogicalHeight(LayoutUnit logical_height,
                             LayoutUnit logical_top,
-                            LogicalExtentComputedValues&) const override;
+                            LogicalExtentComputedValues&) const final;
   void UpdateLogicalWidth() override;
   void ContentWasLaidOut(
-      LayoutUnit logical_bottom_in_flow_thread_after_pagination) override;
-  bool CanSkipLayout(const LayoutBox&) const override;
-  MultiColumnLayoutState GetMultiColumnLayoutState() const override;
-  void RestoreMultiColumnLayoutState(const MultiColumnLayoutState&) override;
+      LayoutUnit logical_bottom_in_flow_thread_after_pagination) final;
+  bool CanSkipLayout(const LayoutBox&) const final;
+  MultiColumnLayoutState GetMultiColumnLayoutState() const final;
+  void RestoreMultiColumnLayoutState(const MultiColumnLayoutState&) final;
 
   // The last set we worked on. It's not to be used as the "current set". The
   // concept of a "current set" is difficult, since layout may jump back and
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.h b/third_party/blink/renderer/core/layout/layout_multi_column_set.h
index 26348fe3..5bc47bfa 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_set.h
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.h
@@ -63,7 +63,7 @@
 // (page / column) that the inner multicol container lives in. Each
 // fragmentainer group has its own column height, but the column height is
 // uniform within a group.
-class CORE_EXPORT LayoutMultiColumnSet : public LayoutBlockFlow {
+class CORE_EXPORT LayoutMultiColumnSet final : public LayoutBlockFlow {
  public:
   static LayoutMultiColumnSet* CreateAnonymous(
       LayoutFlowThread&,
diff --git a/third_party/blink/renderer/core/layout/layout_paged_flow_thread.h b/third_party/blink/renderer/core/layout/layout_paged_flow_thread.h
index 2667533..b7a82f1 100644
--- a/third_party/blink/renderer/core/layout/layout_paged_flow_thread.h
+++ b/third_party/blink/renderer/core/layout/layout_paged_flow_thread.h
@@ -14,7 +14,7 @@
 // have what's common between LayoutMultiColumnFlowThread and
 // LayoutPagedFlowThread in LayoutFlowThread, and have both of them inherit
 // from that one.
-class LayoutPagedFlowThread : public LayoutMultiColumnFlowThread {
+class LayoutPagedFlowThread final : public LayoutMultiColumnFlowThread {
  public:
   static LayoutPagedFlowThread* CreateAnonymous(
       Document&,
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index 33f5dfad..c856d15 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -2453,8 +2453,7 @@
     if (!fragments.IsEmpty() &&
         fragments.IsInLayoutNGInlineFormattingContext()) {
       has_abstract_inline_text_box_ = true;
-      return NGAbstractInlineTextBox::GetOrCreate(LineLayoutText(this),
-                                                  **fragments.begin());
+      return NGAbstractInlineTextBox::GetOrCreate(fragments.front());
     }
   }
   return LegacyAbstractInlineTextBox::GetOrCreate(LineLayoutText(this),
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.cc b/third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.cc
deleted file mode 100644
index 12fc8f0..0000000
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.cc
+++ /dev/null
@@ -1,36 +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 "third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h"
-
-namespace blink {
-
-NGBorderEdges NGBorderEdges::FromPhysical(unsigned physical_edges,
-                                          WritingMode writing_mode) {
-  if (writing_mode == WritingMode::kHorizontalTb) {
-    return NGBorderEdges(physical_edges & kTop, physical_edges & kRight,
-                         physical_edges & kBottom, physical_edges & kLeft);
-  }
-  if (writing_mode != WritingMode::kSidewaysLr) {
-    return NGBorderEdges(physical_edges & kRight, physical_edges & kBottom,
-                         physical_edges & kLeft, physical_edges & kTop);
-  }
-  return NGBorderEdges(physical_edges & kLeft, physical_edges & kTop,
-                       physical_edges & kRight, physical_edges & kBottom);
-}
-
-unsigned NGBorderEdges::ToPhysical(WritingMode writing_mode) const {
-  if (writing_mode == WritingMode::kHorizontalTb) {
-    return (block_start ? kTop : 0) | (line_right ? kRight : 0) |
-           (block_end ? kBottom : 0) | (line_left ? kLeft : 0);
-  }
-  if (writing_mode != WritingMode::kSidewaysLr) {
-    return (block_start ? kRight : 0) | (line_right ? kBottom : 0) |
-           (block_end ? kLeft : 0) | (line_left ? kTop : 0);
-  }
-  return (block_start ? kLeft : 0) | (line_right ? kTop : 0) |
-         (block_end ? kRight : 0) | (line_left ? kBottom : 0);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h
index 359eaa5..975cbdf 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h
@@ -36,8 +36,31 @@
     kLeft = 8,
     kAll = kTop | kRight | kBottom | kLeft
   };
-  static NGBorderEdges FromPhysical(unsigned, WritingMode);
-  unsigned ToPhysical(WritingMode) const;
+  static NGBorderEdges FromPhysical(unsigned physical_edges,
+                                    WritingMode writing_mode) {
+    if (writing_mode == WritingMode::kHorizontalTb) {
+      return NGBorderEdges(physical_edges & kTop, physical_edges & kRight,
+                           physical_edges & kBottom, physical_edges & kLeft);
+    }
+    if (writing_mode != WritingMode::kSidewaysLr) {
+      return NGBorderEdges(physical_edges & kRight, physical_edges & kBottom,
+                           physical_edges & kLeft, physical_edges & kTop);
+    }
+    return NGBorderEdges(physical_edges & kLeft, physical_edges & kTop,
+                         physical_edges & kRight, physical_edges & kBottom);
+  }
+  unsigned ToPhysical(WritingMode writing_mode) const {
+    if (writing_mode == WritingMode::kHorizontalTb) {
+      return (block_start ? kTop : 0) | (line_right ? kRight : 0) |
+             (block_end ? kBottom : 0) | (line_left ? kLeft : 0);
+    }
+    if (writing_mode != WritingMode::kSidewaysLr) {
+      return (block_start ? kRight : 0) | (line_right ? kBottom : 0) |
+             (block_end ? kLeft : 0) | (line_left ? kTop : 0);
+    }
+    return (block_start ? kLeft : 0) | (line_right ? kTop : 0) |
+           (block_end ? kRight : 0) | (line_left ? kBottom : 0);
+  }
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc
index 78822e0..74607dc0 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc
@@ -9,56 +9,6 @@
 
 namespace blink {
 
-NGPhysicalBoxStrut NGBoxStrut::ConvertToPhysical(
-    WritingMode writing_mode,
-    TextDirection direction) const {
-  LayoutUnit direction_start = inline_start;
-  LayoutUnit direction_end = inline_end;
-  if (direction == TextDirection::kRtl)
-    std::swap(direction_start, direction_end);
-  switch (writing_mode) {
-    case WritingMode::kHorizontalTb:
-      return NGPhysicalBoxStrut(block_start, direction_end, block_end,
-                                direction_start);
-    case WritingMode::kVerticalRl:
-    case WritingMode::kSidewaysRl:
-      return NGPhysicalBoxStrut(direction_start, block_start, direction_end,
-                                block_end);
-    case WritingMode::kVerticalLr:
-      return NGPhysicalBoxStrut(direction_start, block_end, direction_end,
-                                block_start);
-    case WritingMode::kSidewaysLr:
-      return NGPhysicalBoxStrut(direction_end, block_end, direction_start,
-                                block_start);
-    default:
-      NOTREACHED();
-      return NGPhysicalBoxStrut();
-  }
-}
-
-NGBoxStrut NGPhysicalBoxStrut::ConvertToLogical(WritingMode writing_mode,
-                                                TextDirection direction) const {
-  NGBoxStrut strut;
-  switch (writing_mode) {
-    case WritingMode::kHorizontalTb:
-      strut = {left, right, top, bottom};
-      break;
-    case WritingMode::kVerticalRl:
-    case WritingMode::kSidewaysRl:
-      strut = {top, bottom, right, left};
-      break;
-    case WritingMode::kVerticalLr:
-      strut = {top, bottom, left, right};
-      break;
-    case WritingMode::kSidewaysLr:
-      strut = {bottom, top, left, right};
-      break;
-  }
-  if (direction == TextDirection::kRtl)
-    std::swap(strut.inline_start, strut.inline_end);
-  return strut;
-}
-
 String NGBoxStrut::ToString() const {
   return String::Format("Inline: (%d %d) Block: (%d %d)", inline_start.ToInt(),
                         inline_end.ToInt(), block_start.ToInt(),
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
index 94d59f3b..78b342a 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
@@ -5,6 +5,8 @@
 #ifndef NGBoxStrut_h
 #define NGBoxStrut_h
 
+#include <utility>
+
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
@@ -45,7 +47,7 @@
 
   bool IsEmpty() const { return *this == NGBoxStrut(); }
 
-  NGPhysicalBoxStrut ConvertToPhysical(WritingMode, TextDirection) const;
+  inline NGPhysicalBoxStrut ConvertToPhysical(WritingMode, TextDirection) const;
 
   // The following two operators exist primarily to have an easy way to access
   // the sum of border and padding.
@@ -154,7 +156,28 @@
 
   // Converts physical dimensions to logical ones per
   // https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical
-  NGBoxStrut ConvertToLogical(WritingMode, TextDirection) const;
+  NGBoxStrut ConvertToLogical(WritingMode writing_mode,
+                              TextDirection direction) const {
+    NGBoxStrut strut;
+    switch (writing_mode) {
+      case WritingMode::kHorizontalTb:
+        strut = {left, right, top, bottom};
+        break;
+      case WritingMode::kVerticalRl:
+      case WritingMode::kSidewaysRl:
+        strut = {top, bottom, right, left};
+        break;
+      case WritingMode::kVerticalLr:
+        strut = {top, bottom, left, right};
+        break;
+      case WritingMode::kSidewaysLr:
+        strut = {bottom, top, left, right};
+        break;
+    }
+    if (direction == TextDirection::kRtl)
+      std::swap(strut.inline_start, strut.inline_end);
+    return strut;
+  }
 
   // Converts physical dimensions to line-relative logical ones per
   // https://drafts.csswg.org/css-writing-modes-3/#line-directions
@@ -180,6 +203,33 @@
   LayoutUnit left;
 };
 
+inline NGPhysicalBoxStrut NGBoxStrut::ConvertToPhysical(
+    WritingMode writing_mode,
+    TextDirection direction) const {
+  LayoutUnit direction_start = inline_start;
+  LayoutUnit direction_end = inline_end;
+  if (direction == TextDirection::kRtl)
+    std::swap(direction_start, direction_end);
+  switch (writing_mode) {
+    case WritingMode::kHorizontalTb:
+      return NGPhysicalBoxStrut(block_start, direction_end, block_end,
+                                direction_start);
+    case WritingMode::kVerticalRl:
+    case WritingMode::kSidewaysRl:
+      return NGPhysicalBoxStrut(direction_start, block_start, direction_end,
+                                block_end);
+    case WritingMode::kVerticalLr:
+      return NGPhysicalBoxStrut(direction_start, block_end, direction_end,
+                                block_start);
+    case WritingMode::kSidewaysLr:
+      return NGPhysicalBoxStrut(direction_end, block_end, direction_start,
+                                block_start);
+    default:
+      NOTREACHED();
+      return NGPhysicalBoxStrut();
+  }
+}
+
 }  // namespace blink
 
 #endif  // NGBoxStrut_h
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
index 39036706..478a1d3 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
@@ -19,7 +19,6 @@
     NGAbstractInlineTextBox::g_abstract_inline_text_box_map_ = nullptr;
 
 scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::GetOrCreate(
-    LineLayoutText line_layout_item,
     const NGPaintFragment& fragment) {
   DCHECK(fragment.GetLayoutObject()->IsText()) << fragment.GetLayoutObject();
   if (!g_abstract_inline_text_box_map_) {
@@ -30,7 +29,8 @@
   if (it != g_abstract_inline_text_box_map_->end())
     return it->value;
   scoped_refptr<AbstractInlineTextBox> obj =
-      base::AdoptRef(new NGAbstractInlineTextBox(line_layout_item, fragment));
+      base::AdoptRef(new NGAbstractInlineTextBox(
+          LineLayoutText(ToLayoutText(fragment.GetLayoutObject())), fragment));
   g_abstract_inline_text_box_map_->Set(&fragment, obj);
   return obj;
 }
@@ -110,7 +110,7 @@
   const NGPaintFragment* next_fragment = NextTextFragmentForSameLayoutObject();
   if (!next_fragment)
     return nullptr;
-  return GetOrCreate(GetLineLayoutItem(), *next_fragment);
+  return GetOrCreate(*next_fragment);
 }
 
 LayoutRect NGAbstractInlineTextBox::LocalBounds() const {
@@ -214,7 +214,7 @@
   NGPaintFragmentTraversal cursor(*fragment_->ContainerLineBox(), *fragment_);
   for (cursor.MoveToNext(); !cursor.IsAtEnd(); cursor.MoveToNext()) {
     if (cursor->GetLayoutObject()->IsText())
-      return GetOrCreate(GetLineLayoutItem(), *cursor);
+      return GetOrCreate(*cursor);
   }
   return nullptr;
 }
@@ -228,7 +228,7 @@
   NGPaintFragmentTraversal cursor(*fragment_->ContainerLineBox(), *fragment_);
   for (cursor.MoveToPrevious(); !cursor.IsAtEnd(); cursor.MoveToPrevious()) {
     if (cursor->GetLayoutObject()->IsText())
-      return GetOrCreate(GetLineLayoutItem(), *cursor);
+      return GetOrCreate(*cursor);
   }
   return nullptr;
 }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
index 4932dec9..d74e962 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
@@ -17,11 +17,8 @@
 class CORE_EXPORT NGAbstractInlineTextBox final : public AbstractInlineTextBox {
  private:
   // Returns existing or newly created |NGAbstractInlineTextBox|.
-  // * |line_layout_item| is |LayoutText| associated to |fragment|. For first
-  // letter part, it is remaining part of |LayoutTextFragment|.
   // * |fragment| should be attached to |NGPhysicalTextFragment|.
   static scoped_refptr<AbstractInlineTextBox> GetOrCreate(
-      LineLayoutText line_layout_item,
       const NGPaintFragment& fragment);
   static void WillDestroy(NGPaintFragment*);
 
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc
index a46f67b..d4289a86 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -139,9 +139,8 @@
         request.HttpReferrer());
   }
 
-  auto address_space = fetch_client_settings_object.GetAddressSpace();
-  if (address_space)
-    request.SetExternalRequestStateFromRequestorAddressSpace(*address_space);
+  request.SetExternalRequestStateFromRequestorAddressSpace(
+      fetch_client_settings_object.GetAddressSpace());
 
   scoped_refptr<SecurityOrigin> url_origin =
       SecurityOrigin::Create(request.Url());
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
index aef684a..fa19568 100644
--- a/third_party/blink/renderer/core/paint/link_highlight_impl.cc
+++ b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -102,13 +102,7 @@
   geometry_needs_update_ = true;
 
   EffectPaintPropertyNode::State state;
-  // In theory this value doesn't matter because the actual opacity during
-  // composited animation is controlled by cc. However, this value could prevent
-  // potential glitches at the end of the animation when opacity should be 0.
-  // For web tests we don't fade out.
-  // TODO(crbug.com/935770): Investigate the root cause that seems a timing
-  // issue at the end of a composited animation in BlinkGenPropertyTree mode.
-  state.opacity = WebTestSupport::IsRunningWebTest() ? kStartOpacity : 0;
+  state.opacity = kStartOpacity;
   state.local_transform_space = &TransformPaintPropertyNode::Root();
   state.compositor_element_id = element_id_;
   state.direct_compositing_reasons = CompositingReason::kActiveOpacityAnimation;
diff --git a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
index 9461ae39..0fd0cd8 100644
--- a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
+++ b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
@@ -67,8 +67,7 @@
   return AllowedByNosniff::MimeTypeCheck::kStrict;
 }
 
-base::Optional<mojom::IPAddressSpace>
-FetchClientSettingsObjectImpl::GetAddressSpace() const {
+mojom::IPAddressSpace FetchClientSettingsObjectImpl::GetAddressSpace() const {
   return execution_context_->GetSecurityContext().AddressSpace();
 }
 
diff --git a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
index db59eda..8a448bd 100644
--- a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
+++ b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
@@ -42,7 +42,7 @@
   AllowedByNosniff::MimeTypeCheck MimeTypeCheckForClassicWorkerScript()
       const override;
 
-  base::Optional<mojom::IPAddressSpace> GetAddressSpace() const override;
+  mojom::IPAddressSpace GetAddressSpace() const override;
 
   void Trace(Visitor* visitor) override;
 
diff --git a/third_party/blink/renderer/core/streams/TransformStream.js b/third_party/blink/renderer/core/streams/TransformStream.js
index a339a49b..4b74495 100644
--- a/third_party/blink/renderer/core/streams/TransformStream.js
+++ b/third_party/blink/renderer/core/streams/TransformStream.js
@@ -341,7 +341,8 @@
 
     if (!binding.ReadableStreamDefaultControllerCanCloseOrEnqueue(
             readableController)) {
-      throw binding.getReadableStreamEnqueueError(stream[_readable]);
+      throw binding.getReadableStreamEnqueueError(stream[_readable],
+                                                  readableController);
     }
 
     try {
diff --git a/third_party/blink/renderer/core/streams/transform_stream.cc b/third_party/blink/renderer/core/streams/transform_stream.cc
index b016805d2..97e39f8 100644
--- a/third_party/blink/renderer/core/streams/transform_stream.cc
+++ b/third_party/blink/renderer/core/streams/transform_stream.cc
@@ -163,6 +163,15 @@
                                          ScriptValue writable_strategy,
                                          ScriptValue readable_strategy,
                                          ExceptionState& exception_state) {
+  // Temporarily disable TransformStream constructor with the new implementation
+  // as it will create objects from the old implementation and break stuff.
+  // TODO(ricea): Make a C++ implementation of TransformStream.
+  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
+    exception_state.ThrowTypeError(
+        "TransformStream disabled because StreamsNative is enabled");
+    return nullptr;
+  }
+
   auto* ts = MakeGarbageCollected<TransformStream>();
 
   v8::Local<v8::Value> args[] = {transformer.V8Value(),
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index 7a08fd1..03aaa0ae 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -433,8 +433,7 @@
 
   const AtomicString& timing_allow_origin_string =
       response.HttpHeaderField(http_names::kTimingAllowOrigin);
-  if (timing_allow_origin_string.IsEmpty() ||
-      EqualIgnoringASCIICase(timing_allow_origin_string, "null"))
+  if (timing_allow_origin_string.IsEmpty())
     return false;
 
   // The condition below if only needed for use-counting purposes.
diff --git a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js
index 8121a619..2ece1b2 100644
--- a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js
+++ b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js
@@ -430,22 +430,20 @@
   /**
    * @param {!Resources.IndexedDBModel.DatabaseId} databaseId
    * @param {!Resources.IndexedDBModel.ObjectStore} objectStore
-   * @return {!Promise<?number>}
+   * @return {!Promise<?Resources.IndexedDBModel.ObjectStoreMetadata>}
    */
-  async getKeyGeneratorValue(databaseId, objectStore) {
-    if (!objectStore.autoIncrement)
-      return null;
+  async getMetadata(databaseId, objectStore) {
     const databaseOrigin = databaseId.securityOrigin;
     const databaseName = databaseId.name;
     const objectStoreName = objectStore.name;
-    const response = await this._indexedDBAgent.invoke_getKeyGeneratorCurrentNumber(
-        {securityOrigin: databaseOrigin, databaseName, objectStoreName});
+    const response =
+        await this._indexedDBAgent.invoke_getMetadata({securityOrigin: databaseOrigin, databaseName, objectStoreName});
 
     if (response[Protocol.Error]) {
       console.error('IndexedDBAgent error: ' + response[Protocol.Error]);
       return null;
     }
-    return response.currentNumber;
+    return {entriesCount: response.entriesCount, keyGeneratorValue: response.keyGeneratorValue};
   }
 
   /**
@@ -604,6 +602,14 @@
 };
 
 /**
+ * @typedef {{
+ *      entriesCount: number,
+ *      keyGeneratorValue: number
+ * }}
+ */
+Resources.IndexedDBModel.ObjectStoreMetadata;
+
+/**
  * @unrestricted
  */
 Resources.IndexedDBModel.Index = class {
diff --git a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js
index 7046a28d..2d74f1e 100644
--- a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js
+++ b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js
@@ -134,8 +134,6 @@
 
     this._pageSize = 50;
     this._skipCount = 0;
-    /** @type {?number} */
-    this._keyGeneratorValue = null;
 
     this.update(objectStore, index);
     this._entries = [];
@@ -339,15 +337,6 @@
       this._updatedDataForTests();
     }
 
-    /**
-     * @param {?number} number
-     * @this {Resources.IDBDataView}
-     */
-    function callbackKeyGeneratorValue(number) {
-      this._keyGeneratorValue = number;
-      this._updateSummaryBar();
-    }
-
     const idbKeyRange = key ? window.IDBKeyRange.lowerBound(key) : null;
     if (this._isIndex) {
       this._model.loadIndexData(
@@ -357,18 +346,28 @@
       this._model.loadObjectStoreData(
           this._databaseId, this._objectStore.name, idbKeyRange, skipCount, pageSize, callback.bind(this));
     }
-    this._model.getKeyGeneratorValue(this._databaseId, this._objectStore).then(callbackKeyGeneratorValue.bind(this));
-    this._updateSummaryBar();
+    this._model.getMetadata(this._databaseId, this._objectStore).then(this._updateSummaryBar.bind(this));
   }
 
-  _updateSummaryBar() {
-    if (this._keyGeneratorValue === null)
-      return;
+  /**
+   * @param {?Resources.IndexedDBModel.ObjectStoreMetadata} metadata
+   */
+  _updateSummaryBar(metadata) {
     if (!this._summaryBarElement)
       this._summaryBarElement = this.element.createChild('div', 'object-store-summary-bar');
     this._summaryBarElement.removeChildren();
+    if (!metadata)
+      return;
+
+    const separator = '\u2002\u2758\u2002';
+
     const span = this._summaryBarElement.createChild('span');
-    span.textContent = ls`key generator value: ${String(this._keyGeneratorValue)}`;
+    span.textContent = ls`Total entries: ${String(metadata.entriesCount)}`;
+
+    if (this._objectStore.autoIncrement) {
+      span.textContent += separator;
+      span.textContent += ls`Key generator value: ${String(metadata.keyGeneratorValue)}`;
+    }
   }
 
   _updatedDataForTests() {
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_callbacks.cc b/third_party/blink/renderer/modules/filesystem/file_system_callbacks.cc
index 8b5dd93..7a335f2e 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_callbacks.cc
+++ b/third_party/blink/renderer/modules/filesystem/file_system_callbacks.cc
@@ -71,30 +71,6 @@
     file_system_->RemovePendingCallbacks();
 }
 
-bool FileSystemCallbacksBase::ShouldScheduleCallback() const {
-  return execution_context_ && execution_context_->IsContextPaused();
-}
-
-template <typename CallbackMemberFunction,
-          typename CallbackClass,
-          typename... Args>
-void FileSystemCallbacksBase::InvokeOrScheduleCallback(
-    CallbackMemberFunction&& callback_member_function,
-    CallbackClass&& callback_object,
-    Args&&... args) {
-  DCHECK(callback_object);
-
-  if (ShouldScheduleCallback()) {
-    DOMFileSystem::ScheduleCallback(
-        execution_context_.Get(),
-        WTF::Bind(callback_member_function, WrapPersistent(callback_object),
-                  WrapPersistentIfNeeded(args)...));
-  } else {
-    ((*callback_object).*callback_member_function)(args...);
-  }
-  execution_context_.Clear();
-}
-
 // ScriptErrorCallback --------------------------------------------------------
 
 // static
@@ -177,15 +153,14 @@
                                      file_system_, expected_path_))
                                : static_cast<Entry*>(FileEntry::Create(
                                      file_system_, expected_path_));
-  InvokeOrScheduleCallback(&OnDidGetEntryCallback::OnSuccess,
-                           success_callback_.Release(), entry);
+  success_callback_.Release()->OnSuccess(entry);
 }
 
 void EntryCallbacks::DidFail(base::File::Error error) {
-  if (error_callback_) {
-    InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke,
-                             error_callback_.Release(), error);
-  }
+  if (!error_callback_)
+    return;
+
+  error_callback_.Release()->Invoke(error);
 }
 
 // EntriesCallbacks -----------------------------------------------------------
@@ -224,15 +199,14 @@
   if (!success_callback_)
     return;
 
-  InvokeOrScheduleCallback(&OnDidGetEntriesCallback::OnSuccess,
-                           success_callback_.Get(), entries);
+  success_callback_->OnSuccess(entries);
 }
 
 void EntriesCallbacks::DidFail(base::File::Error error) {
-  if (error_callback_) {
-    InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke,
-                             error_callback_.Release(), error);
-  }
+  if (!error_callback_)
+    return;
+
+  error_callback_.Release()->Invoke(error);
 }
 
 // FileSystemCallbacks --------------------------------------------------------
@@ -277,16 +251,15 @@
   if (!success_callback_)
     return;
 
-  InvokeOrScheduleCallback(
-      &OnDidOpenFileSystemCallback::OnSuccess, success_callback_.Release(),
+  success_callback_.Release()->OnSuccess(
       DOMFileSystem::Create(execution_context_.Get(), name, type_, root_url));
 }
 
 void FileSystemCallbacks::DidFail(base::File::Error error) {
-  if (error_callback_) {
-    InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke,
-                             error_callback_.Release(), error);
-  }
+  if (!error_callback_)
+    return;
+
+  error_callback_.Release()->Invoke(error);
 }
 
 // ResolveURICallbacks --------------------------------------------------------
@@ -321,15 +294,14 @@
           ? static_cast<Entry*>(
                 DirectoryEntry::Create(filesystem, absolute_path))
           : static_cast<Entry*>(FileEntry::Create(filesystem, absolute_path));
-  InvokeOrScheduleCallback(&OnDidGetEntryCallback::OnSuccess,
-                           success_callback_.Release(), entry);
+  success_callback_.Release()->OnSuccess(entry);
 }
 
 void ResolveURICallbacks::DidFail(base::File::Error error) {
-  if (error_callback_) {
-    InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke,
-                             error_callback_.Release(), error);
-  }
+  if (!error_callback_)
+    return;
+
+  error_callback_.Release()->Invoke(error);
 }
 
 // MetadataCallbacks ----------------------------------------------------------
@@ -356,16 +328,14 @@
   if (!success_callback_)
     return;
 
-  InvokeOrScheduleCallback(&OnDidReadMetadataCallback::OnSuccess,
-                           success_callback_.Release(),
-                           Metadata::Create(metadata));
+  success_callback_.Release()->OnSuccess(Metadata::Create(metadata));
 }
 
 void MetadataCallbacks::DidFail(base::File::Error error) {
-  if (error_callback_) {
-    InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke,
-                             error_callback_.Release(), error);
-  }
+  if (!error_callback_)
+    return;
+
+  error_callback_.Release()->Invoke(error);
 }
 
 // FileWriterCallbacks ----------------------------------------------------
@@ -397,15 +367,14 @@
   if (!success_callback_)
     return;
   file_writer_->Initialize(path, length);
-  InvokeOrScheduleCallback(&OnDidCreateFileWriterCallback::OnSuccess,
-                           success_callback_.Release(), file_writer_);
+  success_callback_.Release()->OnSuccess(file_writer_);
 }
 
 void FileWriterCallbacks::DidFail(base::File::Error error) {
-  if (error_callback_) {
-    InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke,
-                             error_callback_.Release(), error);
-  }
+  if (!error_callback_)
+    return;
+
+  error_callback_.Release()->Invoke(error);
 }
 
 // SnapshotFileCallback -------------------------------------------------------
@@ -445,18 +414,15 @@
   // coined a File with a new handle that has the correct type set on it. This
   // allows the blob storage system to track when a temp file can and can't be
   // safely deleted.
-
-  InvokeOrScheduleCallback(&OnDidCreateSnapshotFileCallback::OnSuccess,
-                           success_callback_.Release(),
-                           DOMFileSystemBase::CreateFile(
-                               metadata, url_, file_system_->GetType(), name_));
+  success_callback_.Release()->OnSuccess(DOMFileSystemBase::CreateFile(
+      metadata, url_, file_system_->GetType(), name_));
 }
 
 void SnapshotFileCallback::DidFail(base::File::Error error) {
-  if (error_callback_) {
-    InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke,
-                             error_callback_.Release(), error);
-  }
+  if (!error_callback_)
+    return;
+
+  error_callback_.Release()->Invoke(error);
 }
 
 // VoidCallbacks --------------------------------------------------------------
@@ -495,16 +461,14 @@
   if (!success_callback_)
     return;
 
-  InvokeOrScheduleCallback(&OnDidSucceedCallback::OnSuccess,
-                           success_callback_.Release(),
-                           execution_context_.Get());
+  success_callback_.Release()->OnSuccess(execution_context_.Get());
 }
 
 void VoidCallbacks::DidFail(base::File::Error error) {
-  if (error_callback_) {
-    InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke,
-                             error_callback_.Release(), error);
-  }
+  if (!error_callback_)
+    return;
+
+  error_callback_.Release()->Invoke(error);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_callbacks.h b/third_party/blink/renderer/modules/filesystem/file_system_callbacks.h
index 7268aac6..6ac6a351 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_callbacks.h
+++ b/third_party/blink/renderer/modules/filesystem/file_system_callbacks.h
@@ -81,17 +81,6 @@
                           DOMFileSystemBase*,
                           ExecutionContext*);
 
-  bool ShouldScheduleCallback() const;
-
-  // Invokes the given callback synchronously or asynchronously depending on
-  // the result of |ShouldScheduleCallback|.
-  template <typename CallbackMemberFunction,
-            typename CallbackClass,
-            typename... Args>
-  void InvokeOrScheduleCallback(CallbackMemberFunction&&,
-                                CallbackClass&&,
-                                Args&&...);
-
   Persistent<ErrorCallbackBase> error_callback_;
   Persistent<DOMFileSystemBase> file_system_;
   Persistent<ExecutionContext> execution_context_;
diff --git a/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc b/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
index fbbcd09..d0d970f 100644
--- a/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
+++ b/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.cc
@@ -86,8 +86,8 @@
     DeleteObjectStoreEntriesCallback;
 typedef blink::protocol::IndexedDB::Backend::ClearObjectStoreCallback
     ClearObjectStoreCallback;
-typedef blink::protocol::IndexedDB::Backend::
-    GetKeyGeneratorCurrentNumberCallback GetKeyGeneratorCurrentNumberCallback;
+typedef blink::protocol::IndexedDB::Backend::GetMetadataCallback
+    GetMetadataCallback;
 typedef blink::protocol::IndexedDB::Backend::DeleteDatabaseCallback
     DeleteDatabaseCallback;
 
@@ -830,56 +830,65 @@
       database_name);
 }
 
-class GetKeyGeneratorCurrentNumberListener final : public NativeEventListener {
- public:
-  static GetKeyGeneratorCurrentNumberListener* Create(
-      std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback) {
-    return MakeGarbageCollected<GetKeyGeneratorCurrentNumberListener>(
-        std::move(request_callback));
-  }
+class GetMetadata;
 
-  GetKeyGeneratorCurrentNumberListener(
-      std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback)
-      : request_callback_(std::move(request_callback)) {}
-  ~GetKeyGeneratorCurrentNumberListener() override = default;
+class GetMetadataListener final : public NativeEventListener {
+ public:
+  GetMetadataListener(scoped_refptr<GetMetadata> owner, int64_t* result)
+      : owner_(owner), result_(result) {}
+  ~GetMetadataListener() override = default;
 
   void Invoke(ExecutionContext*, Event* event) override {
     if (event->type() != event_type_names::kSuccess) {
-      request_callback_->sendFailure(
-          Response::Error("Failed to get current number of key generator."));
+      NotifySubtaskDone(owner_, "Failed to get meta data of object store.");
       return;
     }
 
     IDBRequest* idb_request = static_cast<IDBRequest*>(event->target());
     IDBAny* request_result = idb_request->ResultAsAny();
     if (request_result->GetType() != IDBAny::kIntegerType) {
-      request_callback_->sendFailure(
-          Response::Error("Unexpected result type."));
+      NotifySubtaskDone(owner_, "Unexpected result type.");
       return;
     }
-    request_callback_->sendSuccess(request_result->Integer());
+    *result_ = request_result->Integer();
+    NotifySubtaskDone(owner_, String());
   }
 
  private:
-  std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback_;
+  void NotifySubtaskDone(scoped_refptr<GetMetadata> owner,
+                         const String& error) const;
+  scoped_refptr<GetMetadata> owner_;
+  int64_t* result_;
 };
 
-class GetKeyGeneratorCurrentNumber final
-    : public ExecutableWithDatabase<GetKeyGeneratorCurrentNumberCallback> {
+class GetMetadata final : public ExecutableWithDatabase<GetMetadataCallback> {
  public:
-  static scoped_refptr<GetKeyGeneratorCurrentNumber> Create(
+  static scoped_refptr<GetMetadata> Create(
       const String& object_store_name,
-      std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback) {
-    return AdoptRef(new GetKeyGeneratorCurrentNumber(
-        object_store_name, std::move(request_callback)));
+      std::unique_ptr<GetMetadataCallback> request_callback) {
+    return AdoptRef(
+        new GetMetadata(object_store_name, std::move(request_callback)));
+  }
+
+  void NotifySubtaskDone(const String& error) {
+    if (!error.IsNull()) {
+      request_callback_->sendFailure(Response::Error(error));
+      return;
+    }
+    if (--subtask_pending_ == 0) {
+      request_callback_->sendSuccess(entries_count_,
+                                     key_generator_current_number_);
+    }
   }
 
  private:
-  GetKeyGeneratorCurrentNumber(
-      const String& object_store_name,
-      std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback)
+  GetMetadata(const String& object_store_name,
+              std::unique_ptr<GetMetadataCallback> request_callback)
       : object_store_name_(object_store_name),
-        request_callback_(std::move(request_callback)) {}
+        request_callback_(std::move(request_callback)),
+        subtask_pending_(2),
+        entries_count_(-1),
+        key_generator_current_number_(-1) {}
 
   void Execute(IDBDatabase* idb_database, ScriptState* script_state) override {
     IDBTransaction* idb_transaction =
@@ -897,36 +906,64 @@
           Response::Error("Could not get object store"));
       return;
     }
-    IDBRequest* idb_request =
+
+    // subtask 1. get entries count
+    ScriptState::Scope scope(script_state);
+    DummyExceptionStateForTesting exception_state;
+    IDBRequest* idb_request_get_entries_count = idb_object_store->count(
+        script_state, ScriptValue::CreateNull(script_state), exception_state);
+    DCHECK(!exception_state.HadException());
+    if (exception_state.HadException()) {
+      ExceptionCode ec = exception_state.Code();
+      request_callback_->sendFailure(Response::Error(
+          String::Format("Could not count entries in object store '%s': %d",
+                         object_store_name_.Utf8().data(), ec)));
+      return;
+    }
+    GetMetadataListener* listener_get_entries_count =
+        MakeGarbageCollected<GetMetadataListener>(this, &entries_count_);
+    idb_request_get_entries_count->addEventListener(
+        event_type_names::kSuccess, listener_get_entries_count, false);
+    idb_request_get_entries_count->addEventListener(
+        event_type_names::kError, listener_get_entries_count, false);
+
+    // subtask 2. get key generator current number
+    IDBRequest* idb_request_get_key_generator =
         idb_object_store->getKeyGeneratorCurrentNumber(script_state);
-    idb_request->addEventListener(event_type_names::kSuccess,
-                                  GetKeyGeneratorCurrentNumberListener::Create(
-                                      std::move(request_callback_)),
-                                  false);
-    idb_request->addEventListener(event_type_names::kError,
-                                  GetKeyGeneratorCurrentNumberListener::Create(
-                                      std::move(request_callback_)),
-                                  false);
+    GetMetadataListener* listener_get_key_generator =
+        MakeGarbageCollected<GetMetadataListener>(
+            this, &key_generator_current_number_);
+    idb_request_get_key_generator->addEventListener(
+        event_type_names::kSuccess, listener_get_key_generator, false);
+    idb_request_get_key_generator->addEventListener(
+        event_type_names::kError, listener_get_key_generator, false);
   }
 
-  GetKeyGeneratorCurrentNumberCallback* GetRequestCallback() override {
+  GetMetadataCallback* GetRequestCallback() override {
     return request_callback_.get();
   }
 
  private:
   const String object_store_name_;
-  std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback_;
+  std::unique_ptr<GetMetadataCallback> request_callback_;
+  uint8_t subtask_pending_;
+  int64_t entries_count_;
+  int64_t key_generator_current_number_;
 };
 
-void InspectorIndexedDBAgent::getKeyGeneratorCurrentNumber(
+void GetMetadataListener::NotifySubtaskDone(scoped_refptr<GetMetadata> owner,
+                                            const String& error) const {
+  owner->NotifySubtaskDone(error);
+}
+
+void InspectorIndexedDBAgent::getMetadata(
     const String& security_origin,
     const String& database_name,
     const String& object_store_name,
-    std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback) {
-  scoped_refptr<GetKeyGeneratorCurrentNumber> get_auto_increment_number =
-      GetKeyGeneratorCurrentNumber::Create(object_store_name,
-                                           std::move(request_callback));
-  get_auto_increment_number->Start(
+    std::unique_ptr<GetMetadataCallback> request_callback) {
+  scoped_refptr<GetMetadata> get_metadata =
+      GetMetadata::Create(object_store_name, std::move(request_callback));
+  get_metadata->Start(
       inspected_frames_->FrameWithSecurityOrigin(security_origin),
       database_name);
 }
diff --git a/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h b/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h
index 071b11c..c4fa5998 100644
--- a/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h
+++ b/third_party/blink/renderer/modules/indexeddb/inspector_indexed_db_agent.h
@@ -69,11 +69,10 @@
                    int page_size,
                    protocol::Maybe<protocol::IndexedDB::KeyRange>,
                    std::unique_ptr<RequestDataCallback>) override;
-  void getKeyGeneratorCurrentNumber(
-      const String& security_origin,
-      const String& database_name,
-      const String& object_store_name,
-      std::unique_ptr<GetKeyGeneratorCurrentNumberCallback>) override;
+  void getMetadata(const String& security_origin,
+                   const String& database_name,
+                   const String& object_store_name,
+                   std::unique_ptr<GetMetadataCallback>) override;
   void deleteObjectStoreEntries(
       const String& security_origin,
       const String& database_name,
diff --git a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.cc b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.cc
index 6d4782523..d2d37b3b5 100644
--- a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.cc
+++ b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.cc
@@ -4,15 +4,37 @@
 
 #include "third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h"
 
+#include <algorithm>
+
+#include "third_party/blink/public/platform/web_screen_info.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener.h"
 #include "third_party/blink/renderer/platform/keyboard_codes.h"
 
 namespace blink {
 
+namespace {
+
+// Number of seconds to jump when press left/right arrow.
+constexpr int kNumberOfSecondsToJumpForNonTouch = 10;
+
+// Amount of volume to change when press up/down arrow.
+constexpr double kVolumeToChangeForNonTouch = 0.05;
+
+}  // namespace
+
+enum class MediaControlsNonTouchImpl::ArrowDirection {
+  kUp,
+  kDown,
+  kLeft,
+  kRight,
+};
+
 MediaControlsNonTouchImpl::MediaControlsNonTouchImpl(
     HTMLMediaElement& media_element)
     : HTMLDivElement(media_element.GetDocument()),
@@ -65,10 +87,16 @@
       MediaElement().TogglePlayState();
       break;
     case VKEY_LEFT:
+      HandleOrientedArrowPress(OrientArrowPress(ArrowDirection::kLeft));
+      break;
     case VKEY_RIGHT:
+      HandleOrientedArrowPress(OrientArrowPress(ArrowDirection::kRight));
+      break;
     case VKEY_UP:
+      HandleOrientedArrowPress(OrientArrowPress(ArrowDirection::kUp));
+      break;
     case VKEY_DOWN:
-      // do something
+      HandleOrientedArrowPress(OrientArrowPress(ArrowDirection::kDown));
       break;
     default:
       handled = false;
@@ -79,6 +107,102 @@
     event->SetDefaultHandled();
 }
 
+MediaControlsNonTouchImpl::ArrowDirection
+MediaControlsNonTouchImpl::OrientArrowPress(ArrowDirection direction) {
+  switch (GetOrientation()) {
+    case kWebScreenOrientationUndefined:
+    case kWebScreenOrientationPortraitPrimary:
+      return direction;
+    case kWebScreenOrientationPortraitSecondary:
+      switch (direction) {
+        case ArrowDirection::kUp:
+          return ArrowDirection::kDown;
+        case ArrowDirection::kDown:
+          return ArrowDirection::kUp;
+        case ArrowDirection::kLeft:
+          return ArrowDirection::kRight;
+        case ArrowDirection::kRight:
+          return ArrowDirection::kLeft;
+      }
+    case kWebScreenOrientationLandscapePrimary:
+      switch (direction) {
+        case ArrowDirection::kUp:
+          return ArrowDirection::kLeft;
+        case ArrowDirection::kDown:
+          return ArrowDirection::kRight;
+        case ArrowDirection::kLeft:
+          return ArrowDirection::kDown;
+        case ArrowDirection::kRight:
+          return ArrowDirection::kUp;
+      }
+    case kWebScreenOrientationLandscapeSecondary:
+      switch (direction) {
+        case ArrowDirection::kUp:
+          return ArrowDirection::kRight;
+        case ArrowDirection::kDown:
+          return ArrowDirection::kLeft;
+        case ArrowDirection::kLeft:
+          return ArrowDirection::kUp;
+        case ArrowDirection::kRight:
+          return ArrowDirection::kDown;
+      }
+  }
+}
+
+void MediaControlsNonTouchImpl::HandleOrientedArrowPress(
+    ArrowDirection direction) {
+  switch (direction) {
+    case ArrowDirection::kUp:
+      HandleTopButtonPress();
+      break;
+    case ArrowDirection::kDown:
+      HandleBottomButtonPress();
+      break;
+    case ArrowDirection::kLeft:
+      HandleLeftButtonPress();
+      break;
+    case ArrowDirection::kRight:
+      HandleRightButtonPress();
+      break;
+  }
+}
+
+WebScreenOrientationType MediaControlsNonTouchImpl::GetOrientation() {
+  LocalFrame* frame = GetDocument().GetFrame();
+  if (!frame)
+    return kWebScreenOrientationUndefined;
+
+  return frame->GetChromeClient().GetScreenInfo().orientation_type;
+}
+
+void MediaControlsNonTouchImpl::HandleTopButtonPress() {
+  MaybeChangeVolume(kVolumeToChangeForNonTouch);
+}
+
+void MediaControlsNonTouchImpl::HandleBottomButtonPress() {
+  MaybeChangeVolume(kVolumeToChangeForNonTouch * -1);
+}
+
+void MediaControlsNonTouchImpl::HandleLeftButtonPress() {
+  MaybeJump(kNumberOfSecondsToJumpForNonTouch * -1);
+}
+
+void MediaControlsNonTouchImpl::HandleRightButtonPress() {
+  MaybeJump(kNumberOfSecondsToJumpForNonTouch);
+}
+
+void MediaControlsNonTouchImpl::MaybeChangeVolume(double volume_to_change) {
+  double new_volume = std::max(0.0, MediaElement().volume() + volume_to_change);
+  new_volume = std::min(new_volume, 1.0);
+  MediaElement().setVolume(new_volume);
+}
+
+void MediaControlsNonTouchImpl::MaybeJump(int seconds) {
+  double new_time = std::max(0.0, MediaElement().currentTime() + seconds);
+  new_time = std::min(new_time, MediaElement().duration());
+  MediaElement().setCurrentTime(new_time);
+}
+
 void MediaControlsNonTouchImpl::Trace(blink::Visitor* visitor) {
   visitor->Trace(media_event_listener_);
   MediaControls::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h
index cb278933..00ba8c6 100644
--- a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h
+++ b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_IMPL_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_IMPL_H_
 
+#include "third_party/blink/public/common/screen_orientation/web_screen_orientation_type.h"
 #include "third_party/blink/renderer/core/html/html_div_element.h"
 #include "third_party/blink/renderer/core/html/media/media_controls.h"
 #include "third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener_observer.h"
@@ -61,6 +62,20 @@
  private:
   friend class MediaControlsNonTouchImplTest;
 
+  enum class ArrowDirection;
+  ArrowDirection OrientArrowPress(ArrowDirection direction);
+  void HandleOrientedArrowPress(ArrowDirection direction);
+
+  WebScreenOrientationType GetOrientation();
+
+  void HandleTopButtonPress();
+  void HandleBottomButtonPress();
+  void HandleLeftButtonPress();
+  void HandleRightButtonPress();
+
+  void MaybeJump(int);
+  void MaybeChangeVolume(double);
+
   // Node
   bool IsMediaControls() const override { return true; }
 
diff --git a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl_test.cc b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl_test.cc
index dbc8b42d..c8dfcea 100644
--- a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl_test.cc
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
 #include "third_party/blink/renderer/platform/keyboard_codes.h"
 #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 
 namespace blink {
 
@@ -25,7 +26,29 @@
 
 class MockWebMediaPlayerForNonTouchImpl : public EmptyWebMediaPlayer {
  public:
+  WebTimeRanges Seekable() const override { return seekable_; }
   bool HasVideo() const override { return true; }
+
+  WebTimeRanges seekable_;
+};
+
+class MockChromeClientForNonTouchImpl : public EmptyChromeClient {
+ public:
+  explicit MockChromeClientForNonTouchImpl()
+      : orientation_(kWebScreenOrientationPortraitPrimary) {}
+
+  WebScreenInfo GetScreenInfo() const override {
+    WebScreenInfo screen_info;
+    screen_info.orientation_type = orientation_;
+    return screen_info;
+  }
+
+  void SetOrientation(WebScreenOrientationType orientation_type) {
+    orientation_ = orientation_type;
+  }
+
+ private:
+  WebScreenOrientationType orientation_;
 };
 
 class MediaControlsNonTouchImplTest : public PageTestBase {
@@ -35,7 +58,8 @@
   void InitializePage() {
     Page::PageClients clients;
     FillWithEmptyClients(clients);
-    clients.chrome_client = MakeGarbageCollected<EmptyChromeClient>();
+    chrome_client_ = MakeGarbageCollected<MockChromeClientForNonTouchImpl>();
+    clients.chrome_client = chrome_client_;
     SetupPageWithClients(
         &clients, test::MediaStubLocalFrameClient::Create(
                       std::make_unique<MockWebMediaPlayerForNonTouchImpl>()));
@@ -48,6 +72,12 @@
   }
 
   MediaControlsNonTouchImpl& MediaControls() { return *media_controls_; }
+  HTMLMediaElement& MediaElement() { return MediaControls().MediaElement(); }
+
+  MockWebMediaPlayerForNonTouchImpl* WebMediaPlayer() {
+    return static_cast<MockWebMediaPlayerForNonTouchImpl*>(
+        MediaElement().GetWebMediaPlayer());
+  }
 
   void SimulateKeydownEvent(Element& element, int key_code) {
     KeyboardEventInit* keyboard_event_init = KeyboardEventInit::Create();
@@ -58,23 +88,102 @@
     element.DispatchEvent(*keyboard_event);
   }
 
+  void LoadMediaWithDuration(double duration) {
+    MediaElement().SetSrc("https://example.com/foo.mp4");
+    test::RunPendingTasks();
+    WebTimeRange time_range(0.0, duration);
+    WebMediaPlayer()->seekable_.Assign(&time_range, 1);
+    MediaElement().DurationChanged(duration, false /* requestSeek */);
+  }
+
+  void SetScreenOrientation(WebScreenOrientationType orientation_type) {
+    chrome_client_->SetOrientation(orientation_type);
+  }
+
+  void CheckControlKeys(int seek_forward_key,
+                        int seek_backward_key,
+                        int volume_up_key,
+                        int volume_down_key) {
+    const int kNumberOfSecondsToJump = 10;
+    const double kVolumeToChange = 0.05;
+    const int initTime = 10;
+    const double initVolume = 0.5;
+    MediaElement().setCurrentTime(initTime);
+    MediaElement().setVolume(initVolume);
+
+    SimulateKeydownEvent(MediaElement(), seek_forward_key);
+    ASSERT_EQ(MediaElement().currentTime(), initTime + kNumberOfSecondsToJump);
+
+    SimulateKeydownEvent(MediaElement(), seek_backward_key);
+    ASSERT_EQ(MediaElement().currentTime(), initTime);
+
+    SimulateKeydownEvent(MediaElement(), volume_up_key);
+    ASSERT_EQ(MediaElement().volume(), initVolume + kVolumeToChange);
+
+    SimulateKeydownEvent(MediaElement(), volume_down_key);
+    ASSERT_EQ(MediaElement().volume(), initVolume);
+  }
+
  private:
   Persistent<MediaControlsNonTouchImpl> media_controls_;
+  Persistent<MockChromeClientForNonTouchImpl> chrome_client_;
 };
 
 TEST_F(MediaControlsNonTouchImplTest, PlayPause) {
-  MediaControls().MediaElement().SetFocused(true,
-                                            WebFocusType::kWebFocusTypeNone);
-  MediaControls().MediaElement().Play();
-  ASSERT_FALSE(MediaControls().MediaElement().paused());
+  MediaElement().SetFocused(true, WebFocusType::kWebFocusTypeNone);
+  MediaElement().Play();
+  ASSERT_FALSE(MediaElement().paused());
 
   // Press center key and video should be paused.
-  SimulateKeydownEvent(MediaControls().MediaElement(), VKEY_RETURN);
-  ASSERT_TRUE(MediaControls().MediaElement().paused());
+  SimulateKeydownEvent(MediaElement(), VKEY_RETURN);
+  ASSERT_TRUE(MediaElement().paused());
 
   // Press center key and video should be played.
-  SimulateKeydownEvent(MediaControls().MediaElement(), VKEY_RETURN);
-  ASSERT_FALSE(MediaControls().MediaElement().paused());
+  SimulateKeydownEvent(MediaElement(), VKEY_RETURN);
+  ASSERT_FALSE(MediaElement().paused());
+}
+
+TEST_F(MediaControlsNonTouchImplTest, HandlesOrientationForArrowInput) {
+  MediaElement().SetFocused(true, WebFocusType::kWebFocusTypeNone);
+
+  SetScreenOrientation(kWebScreenOrientationPortraitPrimary);
+  CheckControlKeys(VKEY_RIGHT, VKEY_LEFT, VKEY_UP, VKEY_DOWN);
+
+  SetScreenOrientation(kWebScreenOrientationLandscapePrimary);
+  CheckControlKeys(VKEY_DOWN, VKEY_UP, VKEY_RIGHT, VKEY_LEFT);
+
+  SetScreenOrientation(kWebScreenOrientationPortraitSecondary);
+  CheckControlKeys(VKEY_LEFT, VKEY_RIGHT, VKEY_DOWN, VKEY_UP);
+
+  SetScreenOrientation(kWebScreenOrientationLandscapeSecondary);
+  CheckControlKeys(VKEY_UP, VKEY_DOWN, VKEY_LEFT, VKEY_RIGHT);
+}
+
+TEST_F(MediaControlsNonTouchImplTest, ArrowInputEdgeCaseHandling) {
+  const double duration = 100;
+
+  LoadMediaWithDuration(duration);
+  MediaElement().SetFocused(true, WebFocusType::kWebFocusTypeNone);
+
+  // Seek backward at low current time
+  MediaElement().setCurrentTime(1);
+  SimulateKeydownEvent(MediaElement(), VKEY_LEFT);
+  ASSERT_EQ(MediaElement().currentTime(), 0);
+
+  // Seek forward at high current time
+  MediaElement().setCurrentTime(duration - 1);
+  SimulateKeydownEvent(MediaElement(), VKEY_RIGHT);
+  ASSERT_EQ(MediaElement().currentTime(), duration);
+
+  // Volume down at low volume
+  MediaElement().setVolume(0.01);
+  SimulateKeydownEvent(MediaElement(), VKEY_DOWN);
+  ASSERT_EQ(MediaElement().volume(), 0);
+
+  // Volume up at high volume
+  MediaElement().setVolume(0.99);
+  SimulateKeydownEvent(MediaElement(), VKEY_UP);
+  ASSERT_EQ(MediaElement().volume(), 1);
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index cdd15a6..6c52673 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -734,7 +734,10 @@
           "webaudio/wave_shaper_options.idl",
           "webgl/webgl_context_attributes.idl",
           "webgl/webgl_context_event_init.idl",
-          "webgpu/gpu_adapter_descriptor.idl",
+          "webgpu/gpu_device_descriptor.idl",
+          "webgpu/gpu_extensions.idl",
+          "webgpu/gpu_limits.idl",
+          "webgpu/gpu_request_adapter_options.idl",
           "webmidi/midi_connection_event_init.idl",
           "webmidi/midi_message_event_init.idl",
           "webmidi/midi_options.idl",
diff --git a/third_party/blink/renderer/modules/webgpu/BUILD.gn b/third_party/blink/renderer/modules/webgpu/BUILD.gn
index 3b810a96..55b0ec0 100644
--- a/third_party/blink/renderer/modules/webgpu/BUILD.gn
+++ b/third_party/blink/renderer/modules/webgpu/BUILD.gn
@@ -6,6 +6,10 @@
 
 blink_modules_sources("webgpu") {
   sources = [
+    "dawn_control_client_holder.cc",
+    "dawn_control_client_holder.h",
+    "dawn_object.cc",
+    "dawn_object.h",
     "gpu.cc",
     "gpu.h",
     "gpu_adapter.cc",
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.cc b/third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.cc
new file mode 100644
index 0000000..19ce0b7
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.cc
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium 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 "third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.h"
+
+#include "base/logging.h"
+
+namespace blink {
+
+DawnControlClientHolder::DawnControlClientHolder(
+    gpu::webgpu::WebGPUInterface* interface)
+    : interface_(interface), destroyed_(!interface) {}
+
+void DawnControlClientHolder::MarkDestroyed() {
+  destroyed_ = true;
+}
+
+bool DawnControlClientHolder::IsDestroyed() const {
+  return destroyed_;
+}
+
+gpu::webgpu::WebGPUInterface* DawnControlClientHolder::GetInterface() const {
+  DCHECK(!destroyed_);
+  return interface_;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.h b/third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.h
new file mode 100644
index 0000000..61db6e9
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.h
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_DAWN_CONTROL_CLIENT_HOLDER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_DAWN_CONTROL_CLIENT_HOLDER_H_
+
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
+
+namespace gpu {
+namespace webgpu {
+
+class WebGPUInterface;
+
+}  // namespace webgpu
+}  // namespace gpu
+
+namespace blink {
+
+// This class holds the WebGPUInterface and a |destroyed_| flag.
+// DawnControlClientHolder::MarkDestroyed() should be called if the
+// backing WebGPUInterface has been destroyed.
+class DawnControlClientHolder : public RefCounted<DawnControlClientHolder> {
+ public:
+  DawnControlClientHolder(gpu::webgpu::WebGPUInterface* interface);
+
+  void MarkDestroyed();
+  bool IsDestroyed() const;
+
+  gpu::webgpu::WebGPUInterface* GetInterface() const;
+
+ private:
+  friend class RefCounted<DawnControlClientHolder>;
+  ~DawnControlClientHolder() = default;
+
+  gpu::webgpu::WebGPUInterface* interface_;
+  bool destroyed_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_DAWN_CONTROL_CLIENT_HOLDER_H_
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_object.cc b/third_party/blink/renderer/modules/webgpu/dawn_object.cc
new file mode 100644
index 0000000..7886a13b
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/dawn_object.cc
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium 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 "third_party/blink/renderer/modules/webgpu/dawn_object.h"
+
+#include "third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.h"
+
+namespace blink {
+
+DawnObject::DawnObject(
+    scoped_refptr<DawnControlClientHolder> dawn_control_client)
+    : dawn_control_client_(dawn_control_client) {}
+
+DawnObject::~DawnObject() = default;
+
+const scoped_refptr<DawnControlClientHolder>& DawnObject::GetDawnControlClient()
+    const {
+  return dawn_control_client_;
+}
+
+bool DawnObject::IsDawnControlClientDestroyed() const {
+  return dawn_control_client_->IsDestroyed();
+}
+
+gpu::webgpu::WebGPUInterface* DawnObject::GetInterface() const {
+  return dawn_control_client_->GetInterface();
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_object.h b/third_party/blink/renderer/modules/webgpu/dawn_object.h
new file mode 100644
index 0000000..d076646
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/dawn_object.h
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_DAWN_OBJECT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_DAWN_OBJECT_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace gpu {
+namespace webgpu {
+
+class WebGPUInterface;
+
+}  // namespace webgpu
+}  // namespace gpu
+
+namespace blink {
+
+class DawnControlClientHolder;
+
+// This class allows objects to hold onto a DawnControlClientHolder.
+// The DawnControlClientHolder is used to hold the WebGPUInterface and keep
+// track of whether or not the client has been destroyed. If the client is
+// destroyed, we should not call any Dawn functions.
+class DawnObject : public ScriptWrappable {
+ public:
+  DawnObject(scoped_refptr<DawnControlClientHolder> dawn_control_client);
+  ~DawnObject() override;
+
+  const scoped_refptr<DawnControlClientHolder>& GetDawnControlClient() const;
+  bool IsDawnControlClientDestroyed() const;
+  gpu::webgpu::WebGPUInterface* GetInterface() const;
+
+ private:
+  scoped_refptr<DawnControlClientHolder> dawn_control_client_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_DAWN_OBJECT_H_
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
index f6b9f9b..687f2b7 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -9,9 +9,11 @@
 #include "gpu/command_buffer/client/webgpu_interface.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
-#include "third_party/blink/renderer/modules/webgpu/gpu_adapter_descriptor.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_request_adapter_options.h"
 
 namespace blink {
 
@@ -43,7 +45,9 @@
 GPU::GPU(ExecutionContext& execution_context,
          std::unique_ptr<WebGraphicsContext3DProvider> context_provider)
     : ContextLifecycleObserver(&execution_context),
-      context_provider_(std::move(context_provider)) {}
+      context_provider_(std::move(context_provider)),
+      dawn_control_client_(base::MakeRefCounted<DawnControlClientHolder>(
+          context_provider_->WebGPUInterface())) {}
 
 GPU::~GPU() = default;
 
@@ -53,11 +57,20 @@
 }
 
 void GPU::ContextDestroyed(ExecutionContext* execution_context) {
+  dawn_control_client_->MarkDestroyed();
   context_provider_.reset();
 }
 
-GPUAdapter* GPU::getAdapter(const GPUAdapterDescriptor* descriptor) {
-  return GPUAdapter::Create(descriptor->powerPreference());
+ScriptPromise GPU::requestAdapter(ScriptState* script_state,
+                                  const GPURequestAdapterOptions* options) {
+  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+  ScriptPromise promise = resolver->Promise();
+
+  // TODO(enga): Request the adapter from the WebGPUInterface.
+  GPUAdapter* adapter = GPUAdapter::Create("Default", dawn_control_client_);
+
+  resolver->Resolve(adapter);
+  return promise;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.h b/third_party/blink/renderer/modules/webgpu/gpu.h
index 1e74187..897d4ca 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu.h
@@ -5,17 +5,18 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_H_
 
-#include <memory>
-
-#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
 namespace blink {
 
-class GPUAdapter;
-class GPUAdapterDescriptor;
+class GPURequestAdapterOptions;
+class ScriptState;
+class WebGraphicsContext3DProvider;
+class DawnControlClientHolder;
 
 class GPU final : public ScriptWrappable, public ContextLifecycleObserver {
   DEFINE_WRAPPERTYPEINFO();
@@ -33,10 +34,13 @@
   // ContextLifecycleObserver overrides
   void ContextDestroyed(ExecutionContext* execution_context) override;
 
-  GPUAdapter* getAdapter(const GPUAdapterDescriptor*);
+  // gpu.idl
+  ScriptPromise requestAdapter(ScriptState* script_state,
+                               const GPURequestAdapterOptions* options);
 
  private:
   std::unique_ptr<WebGraphicsContext3DProvider> context_provider_;
+  scoped_refptr<DawnControlClientHolder> dawn_control_client_;
 
   DISALLOW_COPY_AND_ASSIGN(GPU);
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.idl b/third_party/blink/renderer/modules/webgpu/gpu.idl
index 55d4bbe3..efc456a 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu.idl
@@ -7,5 +7,8 @@
 [
     RuntimeEnabled=WebGPU
 ] interface GPU {
-    GPUAdapter getAdapter(GPUAdapterDescriptor descriptor);
+    [
+      RuntimeEnabled=WebGPU,
+      CallWith=ScriptState
+    ] Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options);
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
index c96a2cc2..75d46c4 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
@@ -4,23 +4,29 @@
 
 #include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
 
+#include "third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
 
 namespace blink {
 
 // static
-GPUAdapter* GPUAdapter::Create(const String& name) {
-  return MakeGarbageCollected<GPUAdapter>(name);
+GPUAdapter* GPUAdapter::Create(
+    const String& name,
+    scoped_refptr<DawnControlClientHolder> dawn_control_client) {
+  return MakeGarbageCollected<GPUAdapter>(name, std::move(dawn_control_client));
 }
 
+GPUAdapter::GPUAdapter(
+    const String& name,
+    scoped_refptr<DawnControlClientHolder> dawn_control_client)
+    : DawnObject(std::move(dawn_control_client)), name_(name) {}
+
 const String& GPUAdapter::name() const {
   return name_;
 }
 
-GPUDevice* GPUAdapter::createDevice() {
-  return GPUDevice::Create(this);
+GPUDevice* GPUAdapter::createDevice(const GPUDeviceDescriptor* descriptor) {
+  return GPUDevice::Create(GetDawnControlClient(), this, descriptor);
 }
 
-GPUAdapter::GPUAdapter(const String& name) : name_(name) {}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.h b/third_party/blink/renderer/modules/webgpu/gpu_adapter.h
index a993c32..0b93553 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_adapter.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.h
@@ -5,25 +5,29 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_ADAPTER_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_ADAPTER_H_
 
+#include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
 class GPUDevice;
+class GPUDeviceDescriptor;
 
-class GPUAdapter final : public ScriptWrappable {
+class GPUAdapter final : public DawnObject {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static GPUAdapter* Create(const String& name);
-
-  GPUAdapter(const String& name);
+  static GPUAdapter* Create(
+      const String& name,
+      scoped_refptr<DawnControlClientHolder> dawn_control_client);
+  GPUAdapter(const String& name,
+             scoped_refptr<DawnControlClientHolder> dawn_control_client);
 
   const String& name() const;
 
-  GPUDevice* createDevice();
+  GPUDevice* createDevice(const GPUDeviceDescriptor* descriptor);
 
  private:
   String name_;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl b/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
index 01ef4985..b1a98b4 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
@@ -9,5 +9,5 @@
 ] interface GPUAdapter {
     readonly attribute DOMString name;
 
-    GPUDevice createDevice();
+    GPUDevice createDevice(GPUDeviceDescriptor descriptor);
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index dcacac5..a43571e 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -5,15 +5,27 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
 
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/modules/webgpu/dawn_control_client_holder.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.h"
 
 namespace blink {
 
 // static
-GPUDevice* GPUDevice::Create(GPUAdapter* adapter) {
-  return MakeGarbageCollected<GPUDevice>(adapter);
+GPUDevice* GPUDevice::Create(
+    scoped_refptr<DawnControlClientHolder> dawn_control_client,
+    GPUAdapter* adapter,
+    const GPUDeviceDescriptor* descriptor) {
+  return MakeGarbageCollected<GPUDevice>(std::move(dawn_control_client),
+                                         adapter, descriptor);
 }
 
+// TODO(enga): Handle adapter options and device descriptor
+GPUDevice::GPUDevice(scoped_refptr<DawnControlClientHolder> dawn_control_client,
+                     GPUAdapter* adapter,
+                     const GPUDeviceDescriptor* descriptor)
+    : DawnObject(std::move(dawn_control_client)), adapter_(adapter) {}
+
 GPUAdapter* GPUDevice::adapter() const {
   return adapter_;
 }
@@ -23,6 +35,4 @@
   ScriptWrappable::Trace(visitor);
 }
 
-GPUDevice::GPUDevice(GPUAdapter* adapter) : adapter_(adapter) {}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.h b/third_party/blink/renderer/modules/webgpu/gpu_device.h
index 232cbc0..2f415061 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.h
@@ -5,24 +5,31 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_DEVICE_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_DEVICE_H_
 
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
 
 namespace blink {
 
 class GPUAdapter;
+class GPUDeviceDescriptor;
 
-class GPUDevice final : public ScriptWrappable {
+class GPUDevice final : public DawnObject {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static GPUDevice* Create(GPUAdapter*);
+  static GPUDevice* Create(
+      scoped_refptr<DawnControlClientHolder> dawn_control_client,
+      GPUAdapter* adapter,
+      const GPUDeviceDescriptor* descriptor);
+  explicit GPUDevice(scoped_refptr<DawnControlClientHolder> dawn_control_client,
+                     GPUAdapter* adapter,
+                     const GPUDeviceDescriptor* descriptor);
 
-  GPUDevice(GPUAdapter*);
+  void Trace(blink::Visitor* visitor) override;
 
+  // gpu_device.idl
   GPUAdapter* adapter() const;
 
-  void Trace(blink::Visitor*) override;
-
  private:
   Member<GPUAdapter> adapter_;
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl
new file mode 100644
index 0000000..405e1583
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl
@@ -0,0 +1,10 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+
+dictionary GPUDeviceDescriptor {
+    GPUExtensions extensions;
+    GPULimits limits;
+};
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_extensions.idl b/third_party/blink/renderer/modules/webgpu/gpu_extensions.idl
new file mode 100644
index 0000000..600c20aa
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_extensions.idl
@@ -0,0 +1,8 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+
+dictionary GPUExtensions {
+};
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_limits.idl b/third_party/blink/renderer/modules/webgpu/gpu_limits.idl
new file mode 100644
index 0000000..9090a8c
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_limits.idl
@@ -0,0 +1,8 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+
+dictionary GPULimits {
+};
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_request_adapter_options.idl
similarity index 75%
rename from third_party/blink/renderer/modules/webgpu/gpu_adapter_descriptor.idl
rename to third_party/blink/renderer/modules/webgpu/gpu_request_adapter_options.idl
index f2a90b4..978760d 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_adapter_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_request_adapter_options.idl
@@ -5,11 +5,10 @@
 // https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
 
 enum GPUPowerPreference {
-    "default",
     "low-power",
     "high-performance",
 };
 
-dictionary GPUAdapterDescriptor {
-    GPUPowerPreference powerPreference = "default";
+dictionary GPURequestAdapterOptions {
+    GPUPowerPreference powerPreference;
 };
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 9253369c..5b39453 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -12,6 +12,7 @@
 #include "cc/paint/display_item_list.h"
 #include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host.h"
+#include "cc/trees/mutator_host.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index a014033..0b0b798c 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -3355,8 +3355,6 @@
 enum {
   kNoRenderSurface = 0,
   kHasRenderSurface = 1 << 0,
-  kHasOpacityAnimation = 1 << 1,
-  kHasFilterAnimation = 1 << 2,
 };
 
 #define EXPECT_OPACITY(effect_id, expected_opacity, expected_flags)      \
@@ -3365,10 +3363,6 @@
     EXPECT_EQ(expected_opacity, effect->opacity);                        \
     EXPECT_EQ(!!((expected_flags)&kHasRenderSurface),                    \
               effect->has_render_surface);                               \
-    EXPECT_EQ(!!((expected_flags)&kHasOpacityAnimation),                 \
-              effect->has_potential_opacity_animation);                  \
-    EXPECT_EQ(!!((expected_flags)&kHasFilterAnimation),                  \
-              effect->has_potential_filter_animation);                   \
   } while (false)
 
 TEST_P(PaintArtifactCompositorTest, OpacityRenderSurfaces) {
@@ -3475,14 +3469,14 @@
 
   // Effects of layer 0, 1, 5 each has one compositing layer, so don't have
   // render surface.
-  EXPECT_OPACITY(effect_ids[0], 1.f, kHasOpacityAnimation);
-  EXPECT_OPACITY(effect_ids[1], 1.f, kHasOpacityAnimation);
-  EXPECT_OPACITY(effect_ids[5], 1.f, kHasOpacityAnimation);
+  EXPECT_OPACITY(effect_ids[0], 1.f, kNoRenderSurface);
+  EXPECT_OPACITY(effect_ids[1], 1.f, kNoRenderSurface);
+  EXPECT_OPACITY(effect_ids[5], 1.f, kNoRenderSurface);
 
   // Layer 2 and 3 have the same effect state. The effect has render surface
   // because it has two compositing layers.
   EXPECT_EQ(effect_ids[2], effect_ids[3]);
-  EXPECT_OPACITY(effect_ids[2], 1.f, kHasRenderSurface | kHasOpacityAnimation);
+  EXPECT_OPACITY(effect_ids[2], 1.f, kHasRenderSurface);
 
   // TODO(crbug.com/937573): It's an invalid case that an animating effect
   // doesn't have a layer, but we still keep the case in this test case because
@@ -3490,15 +3484,15 @@
   const auto& effect_tree = GetPropertyTrees().effect_tree;
   int id_a = effect_tree.Node(effect_ids[0])->parent_id;
   EXPECT_EQ(id_a, effect_tree.Node(effect_ids[1])->parent_id);
-  EXPECT_OPACITY(id_a, 1.f, kNoRenderSurface | kHasOpacityAnimation);
+  EXPECT_OPACITY(id_a, 1.f, kNoRenderSurface);
 
   // Effect |c| has one direct and one indirect compositing layers, so has
   // render surface.
-  EXPECT_OPACITY(effect_ids[4], 1.f, kHasRenderSurface | kHasOpacityAnimation);
+  EXPECT_OPACITY(effect_ids[4], 1.f, kHasRenderSurface);
 
   // TODO(crbug.com/937573): Same as |a|.
   EXPECT_OPACITY(effect_tree.Node(effect_ids[4])->parent_id, 1.f,
-                 kNoRenderSurface | kHasOpacityAnimation);
+                 kNoRenderSurface);
 }
 
 TEST_P(PaintArtifactCompositorTest, OpacityRenderSurfacesWithBackdropChildren) {
@@ -3593,17 +3587,15 @@
   // layer0's opacity animation needs a render surfafce because it affects
   // both layer0 and layer1.
   int layer0_effect_id = ContentLayerAt(0)->effect_tree_index();
-  EXPECT_OPACITY(layer0_effect_id, 1.f,
-                 kHasRenderSurface | kHasOpacityAnimation);
+  EXPECT_OPACITY(layer0_effect_id, 1.f, kHasRenderSurface);
   // layer1's opacity animation doesn't need a render surface because it
   // affects layer1 only.
   int layer1_effect_id = ContentLayerAt(1)->effect_tree_index();
-  EXPECT_OPACITY(layer1_effect_id, 1.f,
-                 kNoRenderSurface | kHasOpacityAnimation);
+  EXPECT_OPACITY(layer1_effect_id, 1.f, kNoRenderSurface);
   // Though |opacity| affects both layer0 and layer1, layer0's effect has
   // render surface, so |opacity| doesn't need a render surface.
   int opacity_id = effect_tree.Node(layer0_effect_id)->parent_id;
-  EXPECT_OPACITY(opacity_id, 1.f, kNoRenderSurface | kHasOpacityAnimation);
+  EXPECT_OPACITY(opacity_id, 1.f, kNoRenderSurface);
 }
 
 TEST_P(PaintArtifactCompositorTest, FilterCreatesRenderSurface) {
@@ -3633,7 +3625,7 @@
              .Build());
   ASSERT_EQ(1u, ContentLayerCount());
   EXPECT_OPACITY(ContentLayerAt(0)->effect_tree_index(), 1.f,
-                 kHasRenderSurface | kHasFilterAnimation);
+                 kHasRenderSurface);
 }
 
 TEST_P(PaintArtifactCompositorTest,
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index c062424..b4978436 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -276,11 +276,6 @@
     compositor_node.element_id = compositor_element_id;
   }
 
-  // Set has_potential_animation in case we push property tree during an ongoing
-  // animation. This condition should be kept consistent with cc.
-  if (transform_node.IsRunningAnimationOnCompositor())
-    compositor_node.has_potential_animation = true;
-
   // If this transform is a scroll offset translation, create the associated
   // compositor scroll property node and adjust the compositor transform node's
   // scroll offset.
@@ -773,17 +768,6 @@
         effect_node.id;
   }
 
-  // Set has_potential_xxx_animation in case we push property tree during
-  // ongoing animations. The conditions should be kept consistent with cc.
-  if (next_effect.IsRunningOpacityAnimationOnCompositor())
-    effect_node.has_potential_opacity_animation = true;
-  if (next_effect.IsRunningFilterAnimationOnCompositor())
-    effect_node.has_potential_filter_animation = true;
-  // TODO(crbug.com/938679): Set effect_node
-  // .has_potential_backdrop_filter_animation when we have it.
-  // if (next_effect.IsRunningBackdropAnimationOnCompositor())
-  //   effect_node.has_potential_backdrop_filter_animation = true;
-
   effect_stack_.emplace_back(current_);
   SetCurrentEffectState(effect_node, CcEffectType::kEffect, next_effect,
                         *output_clip);
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
index e4db443..ce55f889c 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
@@ -76,9 +76,7 @@
       const = 0;
 
   // https://wicg.github.io/cors-rfc1918/#address-space
-  // TODO(yhirano): Make this non-Optional when https://crbug.com/855189 is
-  // fixed.
-  virtual base::Optional<mojom::IPAddressSpace> GetAddressSpace() const = 0;
+  virtual mojom::IPAddressSpace GetAddressSpace() const = 0;
 
   virtual void Trace(Visitor*) {}
 };
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
index b558c4dd..88ee961 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
@@ -40,7 +40,7 @@
     const String& outgoing_referrer,
     HttpsState https_state,
     AllowedByNosniff::MimeTypeCheck mime_type_check_for_classic_worker_script,
-    base::Optional<mojom::IPAddressSpace> address_space)
+    mojom::IPAddressSpace address_space)
     : global_object_url_(global_object_url),
       base_url_(base_url),
       security_origin_(std::move(security_origin)),
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
index 15b354b..5b22b4f 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
@@ -34,7 +34,7 @@
       String outgoing_referrer,
       HttpsState https_state,
       AllowedByNosniff::MimeTypeCheck mime_type_check_for_classic_worker_script,
-      base::Optional<mojom::IPAddressSpace> address_space)
+      mojom::IPAddressSpace address_space)
       : global_object_url(std::move(global_object_url)),
         base_url(std::move(base_url)),
         security_origin(std::move(security_origin)),
@@ -53,7 +53,7 @@
   const HttpsState https_state;
   const AllowedByNosniff::MimeTypeCheck
       mime_type_check_for_classic_worker_script;
-  const base::Optional<mojom::IPAddressSpace> address_space;
+  const mojom::IPAddressSpace address_space;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(CrossThreadFetchClientSettingsObjectData);
@@ -83,7 +83,7 @@
       const String& outgoing_referrer,
       HttpsState https_state,
       AllowedByNosniff::MimeTypeCheck,
-      base::Optional<mojom::IPAddressSpace> address_space);
+      mojom::IPAddressSpace address_space);
 
   ~FetchClientSettingsObjectSnapshot() override = default;
 
@@ -100,7 +100,7 @@
   }
   HttpsState GetHttpsState() const override { return https_state_; }
 
-  base::Optional<mojom::IPAddressSpace> GetAddressSpace() const override {
+  mojom::IPAddressSpace GetAddressSpace() const override {
     return address_space_;
   }
 
@@ -127,7 +127,7 @@
   const HttpsState https_state_;
   const AllowedByNosniff::MimeTypeCheck
       mime_type_check_for_classic_worker_script_;
-  const base::Optional<mojom::IPAddressSpace> address_space_;
+  mojom::IPAddressSpace address_space_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
index a0aa82a..b27e4cc 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
@@ -13,6 +13,7 @@
 Bug(none) virtual/stable/ [ Skip ]
 
 # For now we track the failures of the base tests of the following virtual suites.
+Bug(none) virtual/binary-for-devtools/http/tests/devtools [ Skip ]
 Bug(none) virtual/exotic-color-space/images/ [ Skip ]
 Bug(none) virtual/gpu-rasterization/images/ [ Skip ]
 Bug(none) virtual/mouseevent_fractional/fast/events/touch/ [ Skip ]
@@ -119,6 +120,7 @@
 Bug(none) compositing/video/video-poster.html [ Failure ]
 Bug(none) compositing/visibility/layer-visible-content.html [ Failure ]
 Bug(none) compositing/visibility/visibility-image-layers-dynamic.html [ Failure ]
+Bug(none) css3/masking/mask-composite-missing-image.html [ Failure ]
 Bug(none) external/wpt/css/css-transforms/transform3d-backface-visibility-006.html [ Failure ]
 Bug(none) external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-overflow.html [ Crash ]
 Bug(none) external/wpt/portals/portals-rendering.html [ Failure ]
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index e5c0334..ef83e7bd 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -221,6 +221,8 @@
 crbug.com/504703 inspector-protocol/debugger/debugger-step-into-dedicated-worker.js [ Slow ]
 crbug.com/548765 http/tests/devtools/console-fetch-logging.js [ Slow ]
 crbug.com/548765 virtual/binary-for-devtools/http/tests/devtools/console-fetch-logging.js [ Slow ]
+crbug.com/937378 http/tests/devtools/service-workers/service-workers-force-update-on-page-load.js [ Slow ]
+crbug.com/937378 virtual/binary-for-devtools/http/tests/devtools/service-workers/service-workers-force-update-on-page-load.js [ Slow ]
 
 crbug.com/419993 [ Debug ] fast/css/giant-stylesheet-crash.html [ Slow ]
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b0054e6..27298d53 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6098,8 +6098,6 @@
 # Sheriff 2019-03-01
 crbug.com/937170 [ Linux Win7 ] external/wpt/IndexedDB/interleaved-cursors-large.html [ Pass Timeout Crash ]
 crbug.com/937312 [ Win7 ] external/wpt/background-fetch/fetch.https.window.html [ Pass Timeout ]
-crbug.com/937378 [ Win7 ] http/tests/devtools/service-workers/service-workers-force-update-on-page-load.js [ Pass Timeout ]
-crbug.com/937378 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/service-workers/service-workers-force-update-on-page-load.js [ Pass Timeout ]
 crbug.com/864994 [ Linux Win7 ] external/wpt/encoding/legacy-mb-korean/euc-kr/euckr-decode-ksc_5601.html [ Timeout Failure Pass ]
 crbug.com/937416 [ Linux Mac ] http/tests/devtools/resource-tree/resource-tree-htmlimports.js [ Pass Failure ]
 crbug.com/937416 [ Linux Mac ] virtual/binary-for-devtools/http/tests/devtools/resource-tree/resource-tree-htmlimports.js [ Pass Failure ]
diff --git a/third_party/blink/web_tests/editing/pasteboard/paste-blockquote-and-paragraph-break-expected.txt b/third_party/blink/web_tests/editing/pasteboard/paste-blockquote-and-paragraph-break-expected.txt
deleted file mode 100644
index 576fe53..0000000
--- a/third_party/blink/web_tests/editing/pasteboard/paste-blockquote-and-paragraph-break-expected.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-We copy and paste a blockquoted paragraph plus a paragraph break.
-The paragraph break shouldn't be inside the blockquote on paste.  
-You should see 'hello' (blockquoted), 'world' (not quoted, black text), 'hello' (blockquoted), empty paragraph.
-See <rdar://problem/5368833<
-
-Before paste:
-| <br>
-| <blockquote>
-|   id="blockquote"
-|   type="cite"
-|   "hello"
-|   <br>
-| <br>
-
-After paste:
-| <blockquote>
-|   id="blockquote"
-|   type="cite"
-|   "hello"
-|   <br>
-| <div>
-|   <#selection-caret>
-|   <br>
-| <blockquote>
-|   id="blockquote"
-|   type="cite"
-|   "hello"
-|   <br>
-| <br>
-
-After inserting "world":
-| <blockquote>
-|   id="blockquote"
-|   type="cite"
-|   "hello"
-|   <br>
-| <div>
-|   "world<#selection-caret>"
-|   <br>
-| <blockquote>
-|   id="blockquote"
-|   type="cite"
-|   "hello"
-|   <br>
-| <br>
diff --git a/third_party/blink/web_tests/editing/pasteboard/paste-blockquote-and-paragraph-break.html b/third_party/blink/web_tests/editing/pasteboard/paste-blockquote-and-paragraph-break.html
index 432aeda..b31c827e 100644
--- a/third_party/blink/web_tests/editing/pasteboard/paste-blockquote-and-paragraph-break.html
+++ b/third_party/blink/web_tests/editing/pasteboard/paste-blockquote-and-paragraph-break.html
@@ -1,36 +1,29 @@
-<!DOCTYPE html>
-<head>
-<style>
-blockquote {
-    color: blue;
-    border-left: 2px solid blue;
-    padding-left: 5px;
-    margin: 0px;
-}
-</style>
-</head>
-<body>
-<p id="description">We copy and paste a blockquoted paragraph plus a paragraph break.
-The paragraph break shouldn't be inside the blockquote on paste.  
-You should see 'hello' (blockquoted), 'world' (not quoted, black text), 'hello' (blockquoted), empty paragraph.
-See &lt;rdar://problem/5368833&lt;</p>
-<div id="div" contenteditable="true"><br><blockquote id="blockquote" type="cite">hello<br></blockquote><br></div>
-<script src="../../resources/dump-as-markup.js"></script>
+<!doctype html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
 <script>
-div = document.getElementById("div");
-blockquote = document.getElementById("blockquote");
-sel = window.getSelection();
-sel.setBaseAndExtent(blockquote, 0, div, 2);
-document.execCommand("Copy");
-sel.collapse(div, 0);
-
-Markup.description(document.getElementById('description').textContent);
-
-Markup.dump(div, 'Before paste');
-document.execCommand("Paste");
-Markup.dump(div, 'After paste');
-document.execCommand("InsertHTML", false, "world");
-Markup.dump(div, 'After inserting "world"');
+selection_test(
+    [
+      '<div contenteditable id="div">',
+        '<br>',
+        '<blockquote type="cite" id="blockquote">^hello<br></blockquote>',
+        '|<br>',
+      '</div>'
+    ].join(''),
+    selection => {
+      const div = selection.document.getElementById("div");
+      selection.document.execCommand('Copy');
+      selection.collapse(div, 0);
+      selection.document.execCommand('Paste');
+    },
+    [
+      '<div contenteditable id="div">',
+        '<blockquote id="blockquote" type="cite">hello|<br></blockquote>',
+        '<blockquote id="blockquote" type="cite">hello<br></blockquote>',
+        '<br>',
+      '</div>'
+    ].join(''),
+    'Copy and paste a blockquoted paragraph plus a paragraph break The',
+    'paragraph break should be inside the blockquote on paste.');
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/editing/pasteboard/paste-text-016.html b/third_party/blink/web_tests/editing/pasteboard/paste-text-016.html
index bcafddf..464da57 100644
--- a/third_party/blink/web_tests/editing/pasteboard/paste-text-016.html
+++ b/third_party/blink/web_tests/editing/pasteboard/paste-text-016.html
@@ -1,51 +1,46 @@
-<html> 
-<head>
-
-<style>
-.editing { 
-    border: 2px solid red; 
-    padding: 12px; 
-    font-size: 24px; 
-}
-p {
-    margin: 0;
-}
-</style>
-<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
-
+<!doctype html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
 <script>
-
-function editingTest() {
-    for (i = 0; i < 5; i++)
-        moveSelectionForwardByLineCommand();
-    extendSelectionForwardByLineCommand();
-    cutCommand();
-    for (i = 0; i < 5; i++)
-        moveSelectionBackwardByLineCommand();
-    moveSelectionForwardByLineCommand();
-    pasteCommand();
-}
-
+selection_test(
+    [
+      '<div contenteditable>',
+        '<p id="p">',
+          'Should be first line of document.<br>',
+          '<br>',
+          'Another line.',
+        '</p>',
+        '<p></p>&nbsp;',
+        '<p></p>&nbsp;',
+        '<p>^***TEST***</p>',
+        '<p>|<br></p>',
+      '</div>'
+    ].join(''),
+    selection => {
+      const p = selection.document.getElementById("p");
+      selection.document.execCommand("Cut");
+      selection.collapse(p, 2);
+      selection.document.execCommand("Paste");
+    },
+    [
+      '<div contenteditable>',
+        '<p id="p">',
+          'Should be first line of document.',
+          '<br>',
+        '</p>',
+        '<p>***TEST***</p>',
+        '<p>|<br></p>',
+        '<p>',
+          'Another line.',
+        '</p>',
+        '<p></p>',
+        String.fromCharCode(0xA0),
+        '<p></p>',
+        String.fromCharCode(0xA0),
+        '<p><br></p>',
+      '</div>'
+    ].join(''),
+    '***TEST*** line should be second, following the first line. The test is',
+    ' a regression test for rdar://problem/3927554.');
 </script>
-
-<title>Editing Test</title> 
-</head> 
-<body contenteditable style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;">
-
-Fixes this bug:
-<a href="rdar://problem/3941203">&lt;rdar://problem/3927554&gt;</a> REGRESSION (Mail): Paste inserts content in wrong place
-
-<br>***TEST*** line should be second, following the first line.
-
-<div style="height: 12px"></div>
-
-<div id="root">
-<div id="test" class="editing"><p>Should be first line of document.<br><br>Another line.</p><p></p>&nbsp;<p></p>&nbsp;<p>***TEST***</p><p><br></p></div>
-</div>
- 
-<script>
-runEditingTest();
-</script>
-
-</body>
-</html>
diff --git a/third_party/blink/web_tests/editing/pasteboard/preserve-line-break-at-end-of-pasted-content-expected.txt b/third_party/blink/web_tests/editing/pasteboard/preserve-line-break-at-end-of-pasted-content-expected.txt
deleted file mode 100644
index 7f6da34f..0000000
--- a/third_party/blink/web_tests/editing/pasteboard/preserve-line-break-at-end-of-pasted-content-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-This tests for a bug where newlines would not be preserved during copy/paste. Below you should see two paragraphs containing "Hello World!" and an empty third paragraph with the caret in it.
-
-Before copy and paste:
-| "<#selection-anchor>Hello World!"
-| <div>
-|   id="div"
-|   <#selection-focus>
-|   <br>
-
-After copy and paste:
-| "Hello World!"
-| <div>
-|   id="div"
-|   "Hello World!"
-|   <br>
-| <div>
-|   <#selection-caret>
-|   <br>
diff --git a/third_party/blink/web_tests/editing/pasteboard/preserve-line-break-at-end-of-pasted-content.html b/third_party/blink/web_tests/editing/pasteboard/preserve-line-break-at-end-of-pasted-content.html
index dbf80f67..3108397 100644
--- a/third_party/blink/web_tests/editing/pasteboard/preserve-line-break-at-end-of-pasted-content.html
+++ b/third_party/blink/web_tests/editing/pasteboard/preserve-line-break-at-end-of-pasted-content.html
@@ -1,26 +1,31 @@
-<!DOCTYPE html>
-<html>
-<body>
-<p id="description">This tests for a bug where newlines would not be preserved during copy/paste. Below you should see two paragraphs containing "Hello World!" and an empty third paragraph with the caret in it.</p>
-<div id="root" contenteditable="true">Hello World!<div id="div"><br></div></div>
-<script src="../../resources/dump-as-markup.js"></script>
+<!doctype html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
 <script>
-
-Markup.description(document.getElementById('description').textContent);
-
-root = document.getElementById("root");
-root.focus();
-document.execCommand("SelectAll");
-document.execCommand("Copy");
-
-Markup.dump(root, 'Before copy and paste');
-
-selection = window.getSelection();
-div = document.getElementById("div");
-selection.collapse(div, 0);
-document.execCommand("Paste");
-
-Markup.dump(root, 'After copy and paste');
+selection_test(
+    [
+      '<div contenteditable="true" id="root">',
+        '^Hello World!',
+        '<div id="div">|<br></div>',
+      '</div>'
+    ].join(''),
+    selection => {
+      const div = selection.document.getElementById("div");
+      selection.document.execCommand('Copy');
+      selection.collapse(div, 0);
+      selection.document.execCommand('Paste');
+    },
+    [
+      '<div contenteditable="true" id="root">',
+        'Hello World!',
+        '<div id="div">',
+          'Hello World!',
+          '<div id="div">|<br></div>',
+        '</div>',
+      '</div>'
+    ].join(''),
+    'This tests for a bug where newlines would not be preserved during',
+    'copy/paste. Below you should see two paragraphs containing "Hello World!"',
+    'and an empty third paragraph with the caret in it.');
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index eb6a3fa4..5351266 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -367425,11 +367425,11 @@
    "testharness"
   ],
   "css/css-properties-values-api/registered-property-computation-expected.txt": [
-   "c657b7c6ade75ac7b55ae10ca699b8d85db53025",
+   "3823a752b99f506d11c50aee36474c6c51c849cd",
    "support"
   ],
   "css/css-properties-values-api/registered-property-computation.html": [
-   "b1e5d23738b9dda1ea280dfd321bc5b2838b519a",
+   "f03b257246e520bd93055203a5cb27188babc8ca",
    "testharness"
   ],
   "css/css-properties-values-api/registered-property-cssom.html": [
@@ -367437,7 +367437,7 @@
    "testharness"
   ],
   "css/css-properties-values-api/registered-property-initial.html": [
-   "d35b14be569f3c74d0b3d04e98fed00ed2f956d5",
+   "17c883a689a15ef5abd4babfc3afb70c3c6745a9",
    "testharness"
   ],
   "css/css-properties-values-api/resources/utils.js": [
@@ -431641,11 +431641,11 @@
    "manual"
   ],
   "html/user-activation/activation-transfer-cross-origin-with-click.sub.tentative.html": [
-   "dca44dde1da873d48c8fc81257ab32166a75ef08",
+   "e7d98c3b194a03da025ab5b08b5d2c47007222c4",
    "testharness"
   ],
   "html/user-activation/activation-transfer-with-click.tentative.html": [
-   "ebb4f5f5122176a30d3eca1d5ab82dd8e00722de",
+   "6b7a2b72967124c5a4cbb7d5df1a7546784b2254",
    "testharness"
   ],
   "html/user-activation/activation-transfer-without-click.tentative.html": [
@@ -474009,7 +474009,7 @@
    "support"
   ],
   "web-nfc/resources/nfc_help.js": [
-   "52d2710fd8173be6f6541b93ae8fa6d9251620f7",
+   "dd336ef3af511a5a1164dd2d30c6caa8e3c7447a",
    "support"
   ],
   "web-share/META.yml": [
diff --git a/third_party/blink/web_tests/external/wpt/lint.whitelist b/third_party/blink/web_tests/external/wpt/lint.whitelist
index 12b3212..fd4d404 100644
--- a/third_party/blink/web_tests/external/wpt/lint.whitelist
+++ b/third_party/blink/web_tests/external/wpt/lint.whitelist
@@ -187,8 +187,9 @@
 SET TIMEOUT: payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub.html
 SET TIMEOUT: preload/single-download-preload.html
 SET TIMEOUT: resize-observer/resources/iframe.html
-SET TIMEOUT: resource-timing/resources/iframe-TAO*
 SET TIMEOUT: resource-timing/resources/nested-contexts.js
+SET TIMEOUT: resource-timing/TAO-null-opaque-origin.sub.html
+SET TIMEOUT: resource-timing/TAO-case-insensitive-null-opaque-origin.sub.html
 SET TIMEOUT: screen-orientation/onchange-event.html
 SET TIMEOUT: secure-contexts/basic-popup-and-iframe-tests.https.js
 SET TIMEOUT: service-workers/cache-storage/script-tests/cache-abort.js
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/TAO-case-insensitive-null-opaque-origin.sub.html b/third_party/blink/web_tests/external/wpt/resource-timing/TAO-case-insensitive-null-opaque-origin.sub.html
new file mode 100644
index 0000000..5b222cdf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/TAO-case-insensitive-null-opaque-origin.sub.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing TAO - "Null" and opaque origin</title>
+<link rel="author" title="Google" href="http://www.google.com/" />
+<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#timing-allow-origin"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const t = async_test("Test case-insensitive null TAO value with opaque origins");
+window.addEventListener("message", t.step_func_done(e=>{
+    assert_equals(e.data, "PASS");
+}));
+</script>
+</head>
+<body>
+<h1>Description</h1>
+<p>This test validates that for a cross origin resource, the timing allow check algorithm will fail when the value of Timing-Allow-Origin is a case-insensitive match to null and the origin is an opaque origin.</p>
+<div id="log"></div>
+<iframe id="frameContext"></iframe>
+<script>
+let frame_content = "data:text/html;utf8,<body>" +
+                    "<script>" +
+                    "const url = '{{location[scheme]}}://{{host}}:{{ports[http][1]}}/resource-timing/resources/TAOResponse.py?tao=Null';" +
+                    "const observe = (list, observer) => {" +
+                    "  const entry = list.getEntries()[0];" +
+                    "  const sum = entry.redirectStart + entry.redirectEnd + entry.domainLookupStart + entry.domainLookupEnd + entry.connectStart +" +
+                    "              entry.connectEnd + entry.secureConnectionStart + entry.requestStart + entry.responseStart + entry.transferSize +" +
+                    "              entry.encodedBodySize + entry.decodedBodySize;" +
+                    "  const result = sum == 0 ? 'PASS' : 'FAIL';" +
+                    "  window.parent.postMessage(result, '*');" +
+                    "};" +
+                    "let observer = new PerformanceObserver(observe);" +
+                    "observer.observe({ entryTypes: ['resource'] });" +
+                    "fetch(url);" +
+                    "</" + "script></body>";
+document.getElementById("frameContext").src = frame_content;
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/TAO-null-opaque-origin.sub.html b/third_party/blink/web_tests/external/wpt/resource-timing/TAO-null-opaque-origin.sub.html
new file mode 100644
index 0000000..c78e590
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/TAO-null-opaque-origin.sub.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing TAO - "null" and opaque origin</title>
+<link rel="author" title="Google" href="http://www.google.com/" />
+<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#timing-allow-origin"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const t = async_test("Test null TAO value with opaque origins");
+window.addEventListener("message", t.step_func_done(e=>{
+    assert_equals(e.data, "PASS");
+}));
+</script>
+</head>
+<body>
+<h1>Description</h1>
+<p>This test validates that for a cross origin resource, the timing allow check algorithm will succeed when the value of Timing-Allow-Origin is null and the origin is an opaque origin.</p>
+<div id="log"></div>
+<iframe id="frameContext"></iframe>
+<script>
+let frame_content = "data:text/html;utf8,<body>" +
+                    "<script>" +
+                    "const url = '{{location[scheme]}}://{{host}}:{{ports[http][1]}}/resource-timing/resources/TAOResponse.py?tao=null';" +
+                    "const observe = (list, observer) => {" +
+                    "  const entry = list.getEntries()[0];" +
+                    "  const sum = entry.redirectStart + entry.redirectEnd + entry.domainLookupStart + entry.domainLookupEnd + entry.connectStart +" +
+                    "              entry.connectEnd + entry.secureConnectionStart + entry.requestStart + entry.responseStart + entry.transferSize +" +
+                    "              entry.encodedBodySize + entry.decodedBodySize;" +
+                    "  const result = sum != 0 ? 'PASS' : 'FAIL';" +
+                    "  window.parent.postMessage(result, '*');" +
+                    "};" +
+                    "let observer = new PerformanceObserver(observe);" +
+                    "observer.observe({ entryTypes: ['resource'] });" +
+                    "fetch(url);" +
+                    "</" + "script></body>";
+document.getElementById("frameContext").src = frame_content;
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py b/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
index d98098c..e8491280 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
@@ -11,8 +11,11 @@
     # wildcard, pass
         response.headers.set('Timing-Allow-Origin', '*')
     elif tao == 'null':
-    # null, fail
+    # null, fail unless it's an opaque origin
         response.headers.set('Timing-Allow-Origin', 'null')
+    elif tao == 'Null':
+    # case-insentive null, fail
+        response.headers.set('Timing-Allow-Origin', 'Null')
     elif tao == 'origin':
     # case-sensitive match for origin, pass
         response.headers.set('Timing-Allow-Origin', origin)
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/resources/nfc_help.js b/third_party/blink/web_tests/external/wpt/web-nfc/resources/nfc_help.js
index 52d2710..dd336ef 100644
--- a/third_party/blink/web_tests/external/wpt/web-nfc/resources/nfc_help.js
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/resources/nfc_help.js
@@ -70,7 +70,7 @@
 function testNDEFMessage(pushedMessage, readOptions, desc) {
   promise_test(async t => {
     const writer = new NFCWriter();
-    const reader = new NFCReader();
+    const reader = new NFCReader(readOptions);
     await writer.push(pushedMessage);
     const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
     reader.start();
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/css3/masking/mask-repeat-space-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/css3/masking/mask-repeat-space-border-expected.png
index 98d968b..88f5afa 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/css3/masking/mask-repeat-space-border-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/css3/masking/mask-repeat-space-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/tabgroup-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/tabgroup-expected.txt
index ee1a760..3e286bb8 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/tabgroup-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/tabgroup-expected.txt
@@ -58,7 +58,7 @@
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [10, 257, 50, 29],
+          "rect": [11, 257, 49, 29],
           "reason": "chunk appeared"
         },
         {
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/text-line-clamp-truncation-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/text-line-clamp-truncation-expected.txt
index 721970f..6c6af40 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/text-line-clamp-truncation-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/text-line-clamp-truncation-expected.txt
@@ -8,7 +8,7 @@
       "paintInvalidations": [
         {
           "object": "EllipsisBox",
-          "rect": [8, 8, 285, 21],
+          "rect": [8, 8, 285, 24],
           "reason": "disappeared"
         },
         {
@@ -33,12 +33,12 @@
         },
         {
           "object": "LayoutDeprecatedFlexibleBox DIV id='container'",
-          "rect": [8, 29, 284, 24],
+          "rect": [8, 32, 284, 21],
           "reason": "incremental"
         },
         {
           "object": "LayoutDeprecatedFlexibleBox DIV id='container'",
-          "rect": [292, 10, 1, 19],
+          "rect": [292, 10, 1, 22],
           "reason": "incremental"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/svg/as-background-image/background-image-preserveaspectRatio-support-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/svg/as-background-image/background-image-preserveaspectRatio-support-expected.png
index 3468c10..d9c715c 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/svg/as-background-image/background-image-preserveaspectRatio-support-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/svg/as-background-image/background-image-preserveaspectRatio-support-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/svg/as-background-image/background-repeat-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/svg/as-background-image/background-repeat-expected.png
index 1de3e50..1f8d2bda 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/svg/as-background-image/background-repeat-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/svg/as-background-image/background-repeat-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-data-expected.txt b/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-data-expected.txt
index 359ea99..255ea6b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-data-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-data-expected.txt
@@ -1,7 +1,9 @@
 Tests that data is correctly loaded by IndexedDBModel from IndexedDB object store and index.
 
-key generator value: 1
-key generator value: 7
+entries count: 6
+key gen value: 1
+entries count: 6
+key gen value: 7
 Dumping values, fromIndex = false, skipCount = 0, pageSize = 2, idbKeyRange = null
     Key = key_01, primaryKey = key_01, value = {"key":"key_01","value":"value_01"}
     Key = key_02, primaryKey = key_02, value = {"key":"key_02","value":"value_02"}
diff --git a/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-data.js b/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-data.js
index 51ddaa8b..164386a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-data.js
+++ b/third_party/blink/web_tests/http/tests/devtools/indexeddb/database-data.js
@@ -112,17 +112,24 @@
 
     async function postFillingActions() {
       await new Promise(resolve => {
-        indexedDBModel.getKeyGeneratorValue(
-          databaseId, {name: objectStoreName1, autoIncrement: true}).then(printKeyGeneratorValue);
-        indexedDBModel.getKeyGeneratorValue(
-          databaseId, {name: objectStoreName2, autoIncrement: true}).then(printKeyGeneratorValue);
+        indexedDBModel.getMetadata(
+          databaseId, {name: objectStoreName1, autoIncrement: true}).then(printMetadata);
+        indexedDBModel.getMetadata(
+          databaseId, {name: objectStoreName2, autoIncrement: true}).then(printMetadata);
         resolve();
       });
       TestRunner.addSniffer(Resources.IndexedDBModel.prototype, '_updateOriginDatabaseNames', refreshDatabase, false);
       indexedDBModel.refreshDatabaseNames();
 
-      function printKeyGeneratorValue(number) {
-        TestRunner.addResult('key generator value: ' + (number ? String(number) : 'null'));
+      function printMetadata(metadata) {
+        if (!metadata) {
+          TestRunner.addResult('backend returns an error response');
+          return;
+        }
+        const entriesCount = metadata.entriesCount;
+        const keyGenNumber = metadata.keyGeneratorValue;
+        TestRunner.addResult('entries count: ' + String(entriesCount));
+        TestRunner.addResult('key gen value: ' + String(keyGenNumber));
       }
     }
   }
diff --git a/third_party/blink/web_tests/http/tests/streams/chromium/transform-stream-enqueue.html b/third_party/blink/web_tests/http/tests/streams/chromium/transform-stream-enqueue.html
new file mode 100644
index 0000000..638f770
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/streams/chromium/transform-stream-enqueue.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+test(() => {
+  try {
+    new TransformStream({
+      start(controller) {
+        controller.terminate();
+        controller.enqueue('a');
+      }
+    });
+    assert_unreached('start() should throw');
+  } catch (e) {
+    assert_equals(e.name, 'TypeError', 'error should be TypeError');
+    assert_true(e.message.includes(
+      'Cannot enqueue a chunk into a readable stream that is closed or has ' +
+        'been requested to be closed'),
+                'message should contain expected string');
+  }
+}, 'exception message for enqueue while closing should be correct');
+
+test(() => {
+  try {
+    new TransformStream({
+      start(controller) {
+        controller.error();
+        controller.enqueue('a');
+      }
+    });
+    assert_unreached('start() should throw');
+  } catch (e) {
+    assert_equals(e.name, 'TypeError', 'error should be TypeError');
+    assert_true(e.message.includes(
+      'Cannot enqueue a chunk into an errored readable stream'),
+                'message should contain expected string');
+  }
+}, 'exception message for enqueue when errored should be correct');
+</script>
diff --git a/third_party/blink/web_tests/platform/linux/editing/pasteboard/paste-text-016-expected.png b/third_party/blink/web_tests/platform/linux/editing/pasteboard/paste-text-016-expected.png
deleted file mode 100644
index 91f60f2c..0000000
--- a/third_party/blink/web_tests/platform/linux/editing/pasteboard/paste-text-016-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/editing/pasteboard/paste-text-016-expected.txt b/third_party/blink/web_tests/platform/linux/editing/pasteboard/paste-text-016-expected.txt
deleted file mode 100644
index 21d070c0..0000000
--- a/third_party/blink/web_tests/platform/linux/editing/pasteboard/paste-text-016-expected.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow (anonymous) at (0,0) size 784x40
-        LayoutText {#text} at (0,0) size 96x19
-          text run at (0,0) width 96: "Fixes this bug: "
-        LayoutInline {A} at (0,0) size 167x19 [color=#0000EE]
-          LayoutText {#text} at (96,0) size 167x19
-            text run at (96,0) width 167: "<rdar://problem/3927554>"
-        LayoutText {#text} at (263,0) size 385x19
-          text run at (263,0) width 385: " REGRESSION (Mail): Paste inserts content in wrong place "
-        LayoutBR {BR} at (0,0) size 0x0
-        LayoutText {#text} at (0,20) size 378x19
-          text run at (0,20) width 378: "***TEST*** line should be second, following the first line."
-      LayoutBlockFlow {DIV} at (0,40) size 784x12
-      LayoutBlockFlow {DIV} at (0,52) size 784x224
-        LayoutBlockFlow {DIV} at (0,0) size 784x224 [border: (2px solid #FF0000)]
-          LayoutBlockFlow {P} at (14,14) size 756x28
-            LayoutText {#text} at (0,0) size 319x27
-              text run at (0,0) width 319: "Should be first line of document."
-            LayoutBR {BR} at (319,21) size 0x0
-          LayoutBlockFlow {P} at (14,42) size 756x28
-            LayoutText {#text} at (0,0) size 130x27
-              text run at (0,0) width 130: "***TEST***"
-          LayoutBlockFlow {DIV} at (14,70) size 756x28
-            LayoutBR {BR} at (0,0) size 0x27
-          LayoutBlockFlow {P} at (14,98) size 756x28
-            LayoutText {#text} at (0,0) size 128x27
-              text run at (0,0) width 128: "Another line."
-          LayoutBlockFlow {P} at (14,126) size 756x0
-          LayoutBlockFlow (anonymous) at (14,126) size 756x28
-            LayoutText {#text} at (0,0) size 6x27
-              text run at (0,0) width 6: " "
-          LayoutBlockFlow {P} at (14,154) size 756x0
-          LayoutBlockFlow (anonymous) at (14,154) size 756x28
-            LayoutText {#text} at (0,0) size 6x27
-              text run at (0,0) width 6: " "
-          LayoutBlockFlow {P} at (14,182) size 756x28
-            LayoutBR {BR} at (0,0) size 0x27
-caret: position 0 of child 0 {BR} of child 2 {DIV} of child 1 {DIV} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/mac/editing/pasteboard/paste-text-016-expected.png b/third_party/blink/web_tests/platform/mac/editing/pasteboard/paste-text-016-expected.png
deleted file mode 100644
index 191bf6dc..0000000
--- a/third_party/blink/web_tests/platform/mac/editing/pasteboard/paste-text-016-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/editing/pasteboard/paste-text-016-expected.txt b/third_party/blink/web_tests/platform/mac/editing/pasteboard/paste-text-016-expected.txt
deleted file mode 100644
index 4d0994fdb..0000000
--- a/third_party/blink/web_tests/platform/mac/editing/pasteboard/paste-text-016-expected.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow (anonymous) at (0,0) size 784x36
-        LayoutText {#text} at (0,0) size 99x18
-          text run at (0,0) width 99: "Fixes this bug: "
-        LayoutInline {A} at (0,0) size 172x18 [color=#0000EE]
-          LayoutText {#text} at (98,0) size 172x18
-            text run at (98,0) width 172: "<rdar://problem/3927554>"
-        LayoutText {#text} at (269,0) size 390x18
-          text run at (269,0) width 390: " REGRESSION (Mail): Paste inserts content in wrong place "
-        LayoutBR {BR} at (0,0) size 0x0
-        LayoutText {#text} at (0,18) size 384x18
-          text run at (0,18) width 384: "***TEST*** line should be second, following the first line."
-      LayoutBlockFlow {DIV} at (0,36) size 784x12
-      LayoutBlockFlow {DIV} at (0,48) size 784x224
-        LayoutBlockFlow {DIV} at (0,0) size 784x224 [border: (2px solid #FF0000)]
-          LayoutBlockFlow {P} at (14,14) size 756x28
-            LayoutText {#text} at (0,0) size 315x28
-              text run at (0,0) width 315: "Should be first line of document."
-            LayoutBR {BR} at (314,22) size 1x0
-          LayoutBlockFlow {P} at (14,42) size 756x28
-            LayoutText {#text} at (0,0) size 130x28
-              text run at (0,0) width 130: "***TEST***"
-          LayoutBlockFlow {DIV} at (14,70) size 756x28
-            LayoutBR {BR} at (0,0) size 0x28
-          LayoutBlockFlow {P} at (14,98) size 756x28
-            LayoutText {#text} at (0,0) size 127x28
-              text run at (0,0) width 127: "Another line."
-          LayoutBlockFlow {P} at (14,126) size 756x0
-          LayoutBlockFlow (anonymous) at (14,126) size 756x28
-            LayoutText {#text} at (0,0) size 6x28
-              text run at (0,0) width 6: " "
-          LayoutBlockFlow {P} at (14,154) size 756x0
-          LayoutBlockFlow (anonymous) at (14,154) size 756x28
-            LayoutText {#text} at (0,0) size 6x28
-              text run at (0,0) width 6: " "
-          LayoutBlockFlow {P} at (14,182) size 756x28
-            LayoutBR {BR} at (0,0) size 0x28
-caret: position 0 of child 0 {BR} of child 2 {DIV} of child 1 {DIV} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/win/editing/pasteboard/paste-text-016-expected.png b/third_party/blink/web_tests/platform/win/editing/pasteboard/paste-text-016-expected.png
deleted file mode 100644
index 5128a83..0000000
--- a/third_party/blink/web_tests/platform/win/editing/pasteboard/paste-text-016-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/editing/pasteboard/paste-text-016-expected.txt b/third_party/blink/web_tests/platform/win/editing/pasteboard/paste-text-016-expected.txt
deleted file mode 100644
index 1cf3c64..0000000
--- a/third_party/blink/web_tests/platform/win/editing/pasteboard/paste-text-016-expected.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow (anonymous) at (0,0) size 784x40
-        LayoutText {#text} at (0,0) size 89x19
-          text run at (0,0) width 89: "Fixes this bug: "
-        LayoutInline {A} at (0,0) size 164x19 [color=#0000EE]
-          LayoutText {#text} at (89,0) size 164x19
-            text run at (89,0) width 164: "<rdar://problem/3927554>"
-        LayoutText {#text} at (253,0) size 367x19
-          text run at (253,0) width 367: " REGRESSION (Mail): Paste inserts content in wrong place "
-        LayoutBR {BR} at (0,0) size 0x0
-        LayoutText {#text} at (0,20) size 355x19
-          text run at (0,20) width 355: "***TEST*** line should be second, following the first line."
-      LayoutBlockFlow {DIV} at (0,40) size 784x12
-      LayoutBlockFlow {DIV} at (0,52) size 784x224
-        LayoutBlockFlow {DIV} at (0,0) size 784x224 [border: (2px solid #FF0000)]
-          LayoutBlockFlow {P} at (14,14) size 756x28
-            LayoutText {#text} at (0,0) size 313x27
-              text run at (0,0) width 313: "Should be first line of document."
-            LayoutBR {BR} at (313,21) size 0x0
-          LayoutBlockFlow {P} at (14,42) size 756x28
-            LayoutText {#text} at (0,0) size 127x27
-              text run at (0,0) width 127: "***TEST***"
-          LayoutBlockFlow {DIV} at (14,70) size 756x28
-            LayoutBR {BR} at (0,0) size 0x27
-          LayoutBlockFlow {P} at (14,98) size 756x28
-            LayoutText {#text} at (0,0) size 126x27
-              text run at (0,0) width 126: "Another line."
-          LayoutBlockFlow {P} at (14,126) size 756x0
-          LayoutBlockFlow (anonymous) at (14,126) size 756x28
-            LayoutText {#text} at (0,0) size 6x27
-              text run at (0,0) width 6: " "
-          LayoutBlockFlow {P} at (14,154) size 756x0
-          LayoutBlockFlow (anonymous) at (14,154) size 756x28
-            LayoutText {#text} at (0,0) size 6x27
-              text run at (0,0) width 6: " "
-          LayoutBlockFlow {P} at (14,182) size 756x28
-            LayoutBR {BR} at (0,0) size 0x27
-caret: position 0 of child 0 {BR} of child 2 {DIV} of child 1 {DIV} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any-expected.txt
index e4a4265..74ac5946 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL Piping through an identity transform stream should close the destination when the source closes Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL Piping through an identity transform stream should close the destination when the source closes Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.serviceworker-expected.txt
index e4a4265..74ac5946 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.serviceworker-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL Piping through an identity transform stream should close the destination when the source closes Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL Piping through an identity transform stream should close the destination when the source closes Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.sharedworker-expected.txt
index e4a4265..74ac5946 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.sharedworker-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL Piping through an identity transform stream should close the destination when the source closes Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL Piping through an identity transform stream should close the destination when the source closes Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.worker-expected.txt
index e4a4265..74ac5946 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/piping/transform-streams.any.worker-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL Piping through an identity transform stream should close the destination when the source closes Failed to execute 'pipeThrough' on 'ReadableStream': pipeThrough disabled because StreamsNative feature is enabled
+FAIL Piping through an identity transform stream should close the destination when the source closes Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any-expected.txt
index e04f45dc..8a83a2f3 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any-expected.txt
@@ -1,18 +1,17 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-PASS backpressure allows no transforms with a default identity transform and no reader
-PASS backpressure only allows one transform() with a identity transform with a readable HWM of 1 and no reader
-PASS transform() should keep being called as long as there is no backpressure
-PASS writes should resolve as soon as transform completes
-PASS calling pull() before the first write() with backpressure should work
-PASS transform() should be able to read the chunk it just enqueued
-PASS blocking transform() should cause backpressure
-PASS writer.closed should resolve after readable is canceled during start
-PASS writer.closed should resolve after readable is canceled with backpressure
-PASS writer.closed should resolve after readable is canceled with no backpressure
-PASS cancelling the readable should cause a pending write to resolve
-FAIL cancelling the readable side of a TransformStream should abort an empty pipe assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
-FAIL cancelling the readable side of a TransformStream should abort an empty pipe after startup assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
-FAIL cancelling the readable side of a TransformStream should abort a full pipe assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
+FAIL backpressure allows no transforms with a default identity transform and no reader Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL backpressure only allows one transform() with a identity transform with a readable HWM of 1 and no reader Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL transform() should keep being called as long as there is no backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writes should resolve as soon as transform completes Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL calling pull() before the first write() with backpressure should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL transform() should be able to read the chunk it just enqueued Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL blocking transform() should cause backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled during start Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled with backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled with no backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable should cause a pending write to resolve Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort an empty pipe Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort an empty pipe after startup Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort a full pipe Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.serviceworker-expected.txt
index e04f45dc..8a83a2f3 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.serviceworker-expected.txt
@@ -1,18 +1,17 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-PASS backpressure allows no transforms with a default identity transform and no reader
-PASS backpressure only allows one transform() with a identity transform with a readable HWM of 1 and no reader
-PASS transform() should keep being called as long as there is no backpressure
-PASS writes should resolve as soon as transform completes
-PASS calling pull() before the first write() with backpressure should work
-PASS transform() should be able to read the chunk it just enqueued
-PASS blocking transform() should cause backpressure
-PASS writer.closed should resolve after readable is canceled during start
-PASS writer.closed should resolve after readable is canceled with backpressure
-PASS writer.closed should resolve after readable is canceled with no backpressure
-PASS cancelling the readable should cause a pending write to resolve
-FAIL cancelling the readable side of a TransformStream should abort an empty pipe assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
-FAIL cancelling the readable side of a TransformStream should abort an empty pipe after startup assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
-FAIL cancelling the readable side of a TransformStream should abort a full pipe assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
+FAIL backpressure allows no transforms with a default identity transform and no reader Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL backpressure only allows one transform() with a identity transform with a readable HWM of 1 and no reader Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL transform() should keep being called as long as there is no backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writes should resolve as soon as transform completes Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL calling pull() before the first write() with backpressure should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL transform() should be able to read the chunk it just enqueued Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL blocking transform() should cause backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled during start Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled with backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled with no backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable should cause a pending write to resolve Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort an empty pipe Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort an empty pipe after startup Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort a full pipe Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.sharedworker-expected.txt
index e04f45dc..8a83a2f3 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.sharedworker-expected.txt
@@ -1,18 +1,17 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-PASS backpressure allows no transforms with a default identity transform and no reader
-PASS backpressure only allows one transform() with a identity transform with a readable HWM of 1 and no reader
-PASS transform() should keep being called as long as there is no backpressure
-PASS writes should resolve as soon as transform completes
-PASS calling pull() before the first write() with backpressure should work
-PASS transform() should be able to read the chunk it just enqueued
-PASS blocking transform() should cause backpressure
-PASS writer.closed should resolve after readable is canceled during start
-PASS writer.closed should resolve after readable is canceled with backpressure
-PASS writer.closed should resolve after readable is canceled with no backpressure
-PASS cancelling the readable should cause a pending write to resolve
-FAIL cancelling the readable side of a TransformStream should abort an empty pipe assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
-FAIL cancelling the readable side of a TransformStream should abort an empty pipe after startup assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
-FAIL cancelling the readable side of a TransformStream should abort a full pipe assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
+FAIL backpressure allows no transforms with a default identity transform and no reader Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL backpressure only allows one transform() with a identity transform with a readable HWM of 1 and no reader Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL transform() should keep being called as long as there is no backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writes should resolve as soon as transform completes Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL calling pull() before the first write() with backpressure should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL transform() should be able to read the chunk it just enqueued Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL blocking transform() should cause backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled during start Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled with backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled with no backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable should cause a pending write to resolve Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort an empty pipe Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort an empty pipe after startup Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort a full pipe Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.worker-expected.txt
index e04f45dc..8a83a2f3 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/backpressure.any.worker-expected.txt
@@ -1,18 +1,17 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-PASS backpressure allows no transforms with a default identity transform and no reader
-PASS backpressure only allows one transform() with a identity transform with a readable HWM of 1 and no reader
-PASS transform() should keep being called as long as there is no backpressure
-PASS writes should resolve as soon as transform completes
-PASS calling pull() before the first write() with backpressure should work
-PASS transform() should be able to read the chunk it just enqueued
-PASS blocking transform() should cause backpressure
-PASS writer.closed should resolve after readable is canceled during start
-PASS writer.closed should resolve after readable is canceled with backpressure
-PASS writer.closed should resolve after readable is canceled with no backpressure
-PASS cancelling the readable should cause a pending write to resolve
-FAIL cancelling the readable side of a TransformStream should abort an empty pipe assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
-FAIL cancelling the readable side of a TransformStream should abort an empty pipe after startup assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
-FAIL cancelling the readable side of a TransformStream should abort a full pipe assert_throws: promise returned from pipeTo() should be rejected function "function() { throw e }" threw object "TypeError: Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled" ("TypeError") expected object "error1: error1 message" ("error1")
+FAIL backpressure allows no transforms with a default identity transform and no reader Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL backpressure only allows one transform() with a identity transform with a readable HWM of 1 and no reader Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL transform() should keep being called as long as there is no backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writes should resolve as soon as transform completes Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL calling pull() before the first write() with backpressure should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL transform() should be able to read the chunk it just enqueued Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL blocking transform() should cause backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled during start Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled with backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.closed should resolve after readable is canceled with no backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable should cause a pending write to resolve Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort an empty pipe Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort an empty pipe after startup Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL cancelling the readable side of a TransformStream should abort a full pipe Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any-expected.txt
new file mode 100644
index 0000000..78c3340d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL brand-checks Uncaught TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any.serviceworker-expected.txt
new file mode 100644
index 0000000..437e8a5
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any.serviceworker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL brand-checks Failed to register a ServiceWorker: ServiceWorker script evaluation failed
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any.sharedworker-expected.txt
new file mode 100644
index 0000000..78c3340d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any.sharedworker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL brand-checks Uncaught TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any.worker-expected.txt
new file mode 100644
index 0000000..78c3340d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/brand-checks.any.worker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL brand-checks Uncaught TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any-expected.txt
new file mode 100644
index 0000000..61ce50d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+FAIL TransformStream constructor should stop after get on size (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable)" but got ""
+FAIL TransformStream constructor should stop after get on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after get on size (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable)" but got ""
+FAIL TransformStream constructor should stop after get on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after get on writableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after validate on writableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after validate on size (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after tonumber on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after validate on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after get on readableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after validate on readableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after validate on size (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after tonumber on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after validate on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after get on transform fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform" but got ""
+FAIL TransformStream constructor should stop after validate on transform fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform" but got ""
+FAIL TransformStream constructor should stop after get on flush fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush" but got ""
+FAIL TransformStream constructor should stop after validate on flush fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush" but got ""
+FAIL TransformStream constructor should stop after get on start fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush,get on start" but got ""
+FAIL TransformStream constructor should stop after validate on start fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush,get on start" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any.serviceworker-expected.txt
new file mode 100644
index 0000000..61ce50d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any.serviceworker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+FAIL TransformStream constructor should stop after get on size (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable)" but got ""
+FAIL TransformStream constructor should stop after get on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after get on size (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable)" but got ""
+FAIL TransformStream constructor should stop after get on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after get on writableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after validate on writableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after validate on size (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after tonumber on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after validate on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after get on readableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after validate on readableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after validate on size (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after tonumber on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after validate on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after get on transform fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform" but got ""
+FAIL TransformStream constructor should stop after validate on transform fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform" but got ""
+FAIL TransformStream constructor should stop after get on flush fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush" but got ""
+FAIL TransformStream constructor should stop after validate on flush fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush" but got ""
+FAIL TransformStream constructor should stop after get on start fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush,get on start" but got ""
+FAIL TransformStream constructor should stop after validate on start fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush,get on start" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any.sharedworker-expected.txt
new file mode 100644
index 0000000..61ce50d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any.sharedworker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+FAIL TransformStream constructor should stop after get on size (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable)" but got ""
+FAIL TransformStream constructor should stop after get on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after get on size (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable)" but got ""
+FAIL TransformStream constructor should stop after get on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after get on writableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after validate on writableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after validate on size (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after tonumber on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after validate on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after get on readableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after validate on readableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after validate on size (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after tonumber on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after validate on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after get on transform fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform" but got ""
+FAIL TransformStream constructor should stop after validate on transform fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform" but got ""
+FAIL TransformStream constructor should stop after get on flush fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush" but got ""
+FAIL TransformStream constructor should stop after validate on flush fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush" but got ""
+FAIL TransformStream constructor should stop after get on start fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush,get on start" but got ""
+FAIL TransformStream constructor should stop after validate on start fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush,get on start" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any.worker-expected.txt
new file mode 100644
index 0000000..61ce50d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/constructor.any.worker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+FAIL TransformStream constructor should stop after get on size (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable)" but got ""
+FAIL TransformStream constructor should stop after get on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after get on size (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable)" but got ""
+FAIL TransformStream constructor should stop after get on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after get on writableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after validate on writableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after validate on size (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType" but got ""
+FAIL TransformStream constructor should stop after tonumber on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after validate on highWaterMark (writable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable)" but got ""
+FAIL TransformStream constructor should stop after get on readableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after validate on readableType fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after validate on size (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType" but got ""
+FAIL TransformStream constructor should stop after tonumber on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after validate on highWaterMark (readable) fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable)" but got ""
+FAIL TransformStream constructor should stop after get on transform fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform" but got ""
+FAIL TransformStream constructor should stop after validate on transform fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform" but got ""
+FAIL TransformStream constructor should stop after get on flush fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush" but got ""
+FAIL TransformStream constructor should stop after validate on flush fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush" but got ""
+FAIL TransformStream constructor should stop after get on start fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush,get on start" but got ""
+FAIL TransformStream constructor should stop after validate on start fails assert_equals: operations should be performed in the right order expected "get on size (writable),get on highWaterMark (writable),get on size (readable),get on highWaterMark (readable),get on writableType,tonumber on highWaterMark (writable),get on readableType,tonumber on highWaterMark (readable),get on transform,get on flush,get on start" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any-expected.txt
new file mode 100644
index 0000000..6f0e513
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any-expected.txt
@@ -0,0 +1,37 @@
+This is a testharness.js-based test.
+FAIL TransformStream errors thrown in transform put the writable and readable in an errored state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream errors thrown in flush put the writable and readable in an errored state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL errored TransformStream should not enqueue new chunks Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream transformer.start() rejected promise should error the stream Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL when controller.error is followed by a rejection, the error reason should come from controller.error Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream constructor should throw when start does assert_throws: constructor should throw function "() => new TransformStream({
+    start() { throw new URIError('start thrown error'); },
+    transform() {}
+  })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL when strategy.size throws inside start(), the constructor should throw the same error assert_throws: constructor should throw the same error strategy.size throws function "() => new TransformStream({
+    start(c) {
+      c.enqueue('a');
+    },
+    transform() {}
+  }, undefined, strategy)" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL when strategy.size calls controller.error() then throws, the constructor should throw the first error assert_throws: the first error should be thrown function "() => new TransformStream({
+    start(c) {
+      controller = c;
+      c.enqueue('a');
+    },
+    transform() {}
+  }, undefined, strategy)" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL cancelling the readable side should error the writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL it should be possible to error the readable between close requested and complete Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL an exception from transform() should error the stream if terminate has been requested but not completed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL abort should set the close reason for the writable when it happens before cancel during start, but cancel should still succeed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL abort should set the close reason for the writable when it happens before cancel during underlying sink write, but cancel should still succeed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing the second time it is called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after writable.abort() has completed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after a transformer method has thrown an exception Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL erroring during write with backpressure should result in the write failing Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a write() that was waiting for backpressure should reject if the writable is aborted Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL the readable should be errored with the reason passed to the writable abort() method Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any.serviceworker-expected.txt
new file mode 100644
index 0000000..6f0e513
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any.serviceworker-expected.txt
@@ -0,0 +1,37 @@
+This is a testharness.js-based test.
+FAIL TransformStream errors thrown in transform put the writable and readable in an errored state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream errors thrown in flush put the writable and readable in an errored state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL errored TransformStream should not enqueue new chunks Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream transformer.start() rejected promise should error the stream Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL when controller.error is followed by a rejection, the error reason should come from controller.error Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream constructor should throw when start does assert_throws: constructor should throw function "() => new TransformStream({
+    start() { throw new URIError('start thrown error'); },
+    transform() {}
+  })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL when strategy.size throws inside start(), the constructor should throw the same error assert_throws: constructor should throw the same error strategy.size throws function "() => new TransformStream({
+    start(c) {
+      c.enqueue('a');
+    },
+    transform() {}
+  }, undefined, strategy)" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL when strategy.size calls controller.error() then throws, the constructor should throw the first error assert_throws: the first error should be thrown function "() => new TransformStream({
+    start(c) {
+      controller = c;
+      c.enqueue('a');
+    },
+    transform() {}
+  }, undefined, strategy)" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL cancelling the readable side should error the writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL it should be possible to error the readable between close requested and complete Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL an exception from transform() should error the stream if terminate has been requested but not completed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL abort should set the close reason for the writable when it happens before cancel during start, but cancel should still succeed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL abort should set the close reason for the writable when it happens before cancel during underlying sink write, but cancel should still succeed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing the second time it is called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after writable.abort() has completed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after a transformer method has thrown an exception Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL erroring during write with backpressure should result in the write failing Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a write() that was waiting for backpressure should reject if the writable is aborted Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL the readable should be errored with the reason passed to the writable abort() method Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any.sharedworker-expected.txt
new file mode 100644
index 0000000..6f0e513
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any.sharedworker-expected.txt
@@ -0,0 +1,37 @@
+This is a testharness.js-based test.
+FAIL TransformStream errors thrown in transform put the writable and readable in an errored state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream errors thrown in flush put the writable and readable in an errored state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL errored TransformStream should not enqueue new chunks Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream transformer.start() rejected promise should error the stream Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL when controller.error is followed by a rejection, the error reason should come from controller.error Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream constructor should throw when start does assert_throws: constructor should throw function "() => new TransformStream({
+    start() { throw new URIError('start thrown error'); },
+    transform() {}
+  })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL when strategy.size throws inside start(), the constructor should throw the same error assert_throws: constructor should throw the same error strategy.size throws function "() => new TransformStream({
+    start(c) {
+      c.enqueue('a');
+    },
+    transform() {}
+  }, undefined, strategy)" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL when strategy.size calls controller.error() then throws, the constructor should throw the first error assert_throws: the first error should be thrown function "() => new TransformStream({
+    start(c) {
+      controller = c;
+      c.enqueue('a');
+    },
+    transform() {}
+  }, undefined, strategy)" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL cancelling the readable side should error the writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL it should be possible to error the readable between close requested and complete Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL an exception from transform() should error the stream if terminate has been requested but not completed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL abort should set the close reason for the writable when it happens before cancel during start, but cancel should still succeed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL abort should set the close reason for the writable when it happens before cancel during underlying sink write, but cancel should still succeed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing the second time it is called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after writable.abort() has completed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after a transformer method has thrown an exception Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL erroring during write with backpressure should result in the write failing Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a write() that was waiting for backpressure should reject if the writable is aborted Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL the readable should be errored with the reason passed to the writable abort() method Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any.worker-expected.txt
new file mode 100644
index 0000000..6f0e513
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/errors.any.worker-expected.txt
@@ -0,0 +1,37 @@
+This is a testharness.js-based test.
+FAIL TransformStream errors thrown in transform put the writable and readable in an errored state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream errors thrown in flush put the writable and readable in an errored state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL errored TransformStream should not enqueue new chunks Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream transformer.start() rejected promise should error the stream Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL when controller.error is followed by a rejection, the error reason should come from controller.error Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream constructor should throw when start does assert_throws: constructor should throw function "() => new TransformStream({
+    start() { throw new URIError('start thrown error'); },
+    transform() {}
+  })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL when strategy.size throws inside start(), the constructor should throw the same error assert_throws: constructor should throw the same error strategy.size throws function "() => new TransformStream({
+    start(c) {
+      c.enqueue('a');
+    },
+    transform() {}
+  }, undefined, strategy)" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL when strategy.size calls controller.error() then throws, the constructor should throw the first error assert_throws: the first error should be thrown function "() => new TransformStream({
+    start(c) {
+      controller = c;
+      c.enqueue('a');
+    },
+    transform() {}
+  }, undefined, strategy)" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "URIError" ("URIError")
+FAIL cancelling the readable side should error the writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL it should be possible to error the readable between close requested and complete Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL an exception from transform() should error the stream if terminate has been requested but not completed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL abort should set the close reason for the writable when it happens before cancel during start, but cancel should still succeed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL abort should set the close reason for the writable when it happens before cancel during underlying sink write, but cancel should still succeed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing the second time it is called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after writable.abort() has completed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() should do nothing after a transformer method has thrown an exception Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL erroring during write with backpressure should result in the write failing Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a write() that was waiting for backpressure should reject if the writable is aborted Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL the readable should be errored with the reason passed to the writable abort() method Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any-expected.txt
new file mode 100644
index 0000000..ba6060c
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL TransformStream flush is called immediately when the writable is closed, if no writes are queued Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush is called after all queued writes finish, once the writable is closed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush gets a chance to enqueue more into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush gets a chance to enqueue more into the readable, and can then async close Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL error() during flush should cause writer.close() to reject Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any.serviceworker-expected.txt
new file mode 100644
index 0000000..ba6060c
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any.serviceworker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL TransformStream flush is called immediately when the writable is closed, if no writes are queued Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush is called after all queued writes finish, once the writable is closed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush gets a chance to enqueue more into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush gets a chance to enqueue more into the readable, and can then async close Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL error() during flush should cause writer.close() to reject Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any.sharedworker-expected.txt
new file mode 100644
index 0000000..ba6060c
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any.sharedworker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL TransformStream flush is called immediately when the writable is closed, if no writes are queued Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush is called after all queued writes finish, once the writable is closed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush gets a chance to enqueue more into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush gets a chance to enqueue more into the readable, and can then async close Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL error() during flush should cause writer.close() to reject Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any.worker-expected.txt
new file mode 100644
index 0000000..ba6060c
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/flush.any.worker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL TransformStream flush is called immediately when the writable is closed, if no writes are queued Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush is called after all queued writes finish, once the writable is closed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush gets a chance to enqueue more into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream flush gets a chance to enqueue more into the readable, and can then async close Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL error() during flush should cause writer.close() to reject Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any-expected.txt
new file mode 100644
index 0000000..b4d549b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any-expected.txt
@@ -0,0 +1,29 @@
+This is a testharness.js-based test.
+FAIL TransformStream can be constructed with a transform function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream can be constructed with no transform function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream instances must have writable and readable properties of the correct types Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream writable starts in the writable state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Identity TransformStream: can read from readable what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser sync TransformStream: can read from readable transformed version of what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser-doubler sync TransformStream: can read both chunks put into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser async TransformStream: can read from readable transformed version of what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser-doubler async TransformStream: can read both chunks put into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable (when there are no queued writes) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable waits for transforms to finish before closing both Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable after sync enqueues and async done Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable after async enqueues and async done Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Transform stream should call transformer methods as methods Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL methods should not not have .apply() or .call() called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream start, transform, and flush should be strictly ordered Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL it should be possible to call transform() synchronously Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL closing the writable should close the readable when there are no queued chunks, even with backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL enqueue() should throw after controller.terminate() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL enqueue() should throw after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() should do nothing the second time it is called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL terminate() should do nothing after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL start() should not be called twice Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL specifying a defined readableType should throw assert_throws: constructor should throw function "() => new TransformStream({ readableType: 'bytes' })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL specifying a defined writableType should throw assert_throws: constructor should throw function "() => new TransformStream({ writableType: 'bytes' })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL Subclassing TransformStream should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any.serviceworker-expected.txt
new file mode 100644
index 0000000..b4d549b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any.serviceworker-expected.txt
@@ -0,0 +1,29 @@
+This is a testharness.js-based test.
+FAIL TransformStream can be constructed with a transform function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream can be constructed with no transform function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream instances must have writable and readable properties of the correct types Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream writable starts in the writable state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Identity TransformStream: can read from readable what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser sync TransformStream: can read from readable transformed version of what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser-doubler sync TransformStream: can read both chunks put into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser async TransformStream: can read from readable transformed version of what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser-doubler async TransformStream: can read both chunks put into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable (when there are no queued writes) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable waits for transforms to finish before closing both Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable after sync enqueues and async done Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable after async enqueues and async done Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Transform stream should call transformer methods as methods Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL methods should not not have .apply() or .call() called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream start, transform, and flush should be strictly ordered Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL it should be possible to call transform() synchronously Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL closing the writable should close the readable when there are no queued chunks, even with backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL enqueue() should throw after controller.terminate() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL enqueue() should throw after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() should do nothing the second time it is called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL terminate() should do nothing after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL start() should not be called twice Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL specifying a defined readableType should throw assert_throws: constructor should throw function "() => new TransformStream({ readableType: 'bytes' })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL specifying a defined writableType should throw assert_throws: constructor should throw function "() => new TransformStream({ writableType: 'bytes' })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL Subclassing TransformStream should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any.sharedworker-expected.txt
new file mode 100644
index 0000000..b4d549b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any.sharedworker-expected.txt
@@ -0,0 +1,29 @@
+This is a testharness.js-based test.
+FAIL TransformStream can be constructed with a transform function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream can be constructed with no transform function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream instances must have writable and readable properties of the correct types Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream writable starts in the writable state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Identity TransformStream: can read from readable what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser sync TransformStream: can read from readable transformed version of what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser-doubler sync TransformStream: can read both chunks put into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser async TransformStream: can read from readable transformed version of what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser-doubler async TransformStream: can read both chunks put into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable (when there are no queued writes) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable waits for transforms to finish before closing both Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable after sync enqueues and async done Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable after async enqueues and async done Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Transform stream should call transformer methods as methods Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL methods should not not have .apply() or .call() called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream start, transform, and flush should be strictly ordered Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL it should be possible to call transform() synchronously Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL closing the writable should close the readable when there are no queued chunks, even with backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL enqueue() should throw after controller.terminate() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL enqueue() should throw after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() should do nothing the second time it is called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL terminate() should do nothing after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL start() should not be called twice Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL specifying a defined readableType should throw assert_throws: constructor should throw function "() => new TransformStream({ readableType: 'bytes' })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL specifying a defined writableType should throw assert_throws: constructor should throw function "() => new TransformStream({ writableType: 'bytes' })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL Subclassing TransformStream should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any.worker-expected.txt
new file mode 100644
index 0000000..b4d549b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/general.any.worker-expected.txt
@@ -0,0 +1,29 @@
+This is a testharness.js-based test.
+FAIL TransformStream can be constructed with a transform function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream can be constructed with no transform function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream instances must have writable and readable properties of the correct types Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream writable starts in the writable state Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Identity TransformStream: can read from readable what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser sync TransformStream: can read from readable transformed version of what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser-doubler sync TransformStream: can read both chunks put into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser async TransformStream: can read from readable transformed version of what is put into writable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Uppercaser-doubler async TransformStream: can read both chunks put into the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable (when there are no queued writes) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable waits for transforms to finish before closing both Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable after sync enqueues and async done Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream: by default, closing the writable closes the readable after async enqueues and async done Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL Transform stream should call transformer methods as methods Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL methods should not not have .apply() or .call() called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream start, transform, and flush should be strictly ordered Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL it should be possible to call transform() synchronously Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL closing the writable should close the readable when there are no queued chunks, even with backpressure Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL enqueue() should throw after controller.terminate() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL enqueue() should throw after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() should do nothing the second time it is called Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL terminate() should do nothing after readable.cancel() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL start() should not be called twice Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL specifying a defined readableType should throw assert_throws: constructor should throw function "() => new TransformStream({ readableType: 'bytes' })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL specifying a defined writableType should throw assert_throws: constructor should throw function "() => new TransformStream({ writableType: 'bytes' })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL Subclassing TransformStream should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any-expected.txt
new file mode 100644
index 0000000..6f51247
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+FAIL testing "" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "" (length 0) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "z{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}q" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in1}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in1},}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1,}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{,in1}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{,{in1}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{,in1}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{," (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{,{,i,n,1,},}" (length 7) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in2}}{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{wrong}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{wron,g}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{quine}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{bogusPartial}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{bogusPartial}}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any.serviceworker-expected.txt
new file mode 100644
index 0000000..6f51247
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any.serviceworker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+FAIL testing "" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "" (length 0) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "z{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}q" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in1}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in1},}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1,}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{,in1}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{,{in1}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{,in1}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{," (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{,{,i,n,1,},}" (length 7) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in2}}{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{wrong}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{wron,g}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{quine}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{bogusPartial}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{bogusPartial}}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any.sharedworker-expected.txt
new file mode 100644
index 0000000..6f51247
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any.sharedworker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+FAIL testing "" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "" (length 0) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "z{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}q" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in1}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in1},}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1,}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{,in1}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{,{in1}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{,in1}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{," (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{,{,i,n,1,},}" (length 7) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in2}}{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{wrong}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{wron,g}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{quine}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{bogusPartial}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{bogusPartial}}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any.worker-expected.txt
new file mode 100644
index 0000000..6f51247
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/lipfuzz.any.worker-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+FAIL testing "" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "" (length 0) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "z{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}q" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in1}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in1},}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1,}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{,in1}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{,{in1}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{,in1}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{," (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{,{,i,n,1,},}" (length 7) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{in1}}{{in2}}{{in1}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{wrong}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{wron,g}}" (length 2) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{quine}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{bogusPartial}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL testing "{{bogusPartial}}}" (length 1) Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any-expected.txt
new file mode 100644
index 0000000..d76a151
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL TransformStream constructor should not call setters for highWaterMark or size Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream should use the original value of ReadableStream and WritableStream Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any.serviceworker-expected.txt
new file mode 100644
index 0000000..d76a151
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any.serviceworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL TransformStream constructor should not call setters for highWaterMark or size Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream should use the original value of ReadableStream and WritableStream Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any.sharedworker-expected.txt
new file mode 100644
index 0000000..d76a151
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any.sharedworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL TransformStream constructor should not call setters for highWaterMark or size Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream should use the original value of ReadableStream and WritableStream Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any.worker-expected.txt
new file mode 100644
index 0000000..d76a151
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/patched-global.any.worker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL TransformStream constructor should not call setters for highWaterMark or size Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL TransformStream should use the original value of ReadableStream and WritableStream Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any-expected.txt
new file mode 100644
index 0000000..5a2a25b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+PASS TransformStreamDefaultController should not be exported on the global object
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any.serviceworker-expected.txt
new file mode 100644
index 0000000..3a9ecca
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any.serviceworker-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL properties Failed to register a ServiceWorker: ServiceWorker script evaluation failed
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any.sharedworker-expected.txt
new file mode 100644
index 0000000..5a2a25b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any.sharedworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+PASS TransformStreamDefaultController should not be exported on the global object
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any.worker-expected.txt
new file mode 100644
index 0000000..5a2a25b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/properties.any.worker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+PASS TransformStreamDefaultController should not be exported on the global object
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any-expected.txt
index 0702fdb5..a20c3fd 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any-expected.txt
@@ -1,15 +1,14 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-PASS enqueue() inside size() should work
-PASS terminate() inside size() should work
-PASS error() inside size() should work
-PASS desiredSize inside size() should work
-PASS readable cancel() inside size() should work
-FAIL pipeTo() inside size() should work assert_array_equals: ws should contain two chunks lengths differ, expected 4 got 0
-PASS read() inside of size() should work
-PASS writer.write() inside size() should work
-PASS synchronous writer.write() inside size() should work
-PASS writer.close() inside size() should work
-PASS writer.abort() inside size() should work
+FAIL enqueue() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL terminate() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL error() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL desiredSize inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readable cancel() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL pipeTo() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL read() inside of size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.write() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL synchronous writer.write() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.close() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.abort() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.serviceworker-expected.txt
index 0702fdb5..a20c3fd 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.serviceworker-expected.txt
@@ -1,15 +1,14 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-PASS enqueue() inside size() should work
-PASS terminate() inside size() should work
-PASS error() inside size() should work
-PASS desiredSize inside size() should work
-PASS readable cancel() inside size() should work
-FAIL pipeTo() inside size() should work assert_array_equals: ws should contain two chunks lengths differ, expected 4 got 0
-PASS read() inside of size() should work
-PASS writer.write() inside size() should work
-PASS synchronous writer.write() inside size() should work
-PASS writer.close() inside size() should work
-PASS writer.abort() inside size() should work
+FAIL enqueue() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL terminate() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL error() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL desiredSize inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readable cancel() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL pipeTo() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL read() inside of size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.write() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL synchronous writer.write() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.close() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.abort() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.sharedworker-expected.txt
index 0702fdb5..a20c3fd 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.sharedworker-expected.txt
@@ -1,15 +1,14 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-PASS enqueue() inside size() should work
-PASS terminate() inside size() should work
-PASS error() inside size() should work
-PASS desiredSize inside size() should work
-PASS readable cancel() inside size() should work
-FAIL pipeTo() inside size() should work assert_array_equals: ws should contain two chunks lengths differ, expected 4 got 0
-PASS read() inside of size() should work
-PASS writer.write() inside size() should work
-PASS synchronous writer.write() inside size() should work
-PASS writer.close() inside size() should work
-PASS writer.abort() inside size() should work
+FAIL enqueue() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL terminate() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL error() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL desiredSize inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readable cancel() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL pipeTo() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL read() inside of size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.write() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL synchronous writer.write() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.close() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.abort() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.worker-expected.txt
index 0702fdb5..a20c3fd 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/reentrant-strategies.any.worker-expected.txt
@@ -1,15 +1,14 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-PASS enqueue() inside size() should work
-PASS terminate() inside size() should work
-PASS error() inside size() should work
-PASS desiredSize inside size() should work
-PASS readable cancel() inside size() should work
-FAIL pipeTo() inside size() should work assert_array_equals: ws should contain two chunks lengths differ, expected 4 got 0
-PASS read() inside of size() should work
-PASS writer.write() inside size() should work
-PASS synchronous writer.write() inside size() should work
-PASS writer.close() inside size() should work
-PASS writer.abort() inside size() should work
+FAIL enqueue() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL terminate() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL error() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL desiredSize inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readable cancel() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL pipeTo() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL read() inside of size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.write() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL synchronous writer.write() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.close() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writer.abort() inside size() should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any-expected.txt
new file mode 100644
index 0000000..e1c914b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+FAIL writableStrategy highWaterMark should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readableStrategy highWaterMark should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writable should have the correct size() function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL default writable strategy should be equivalent to { highWaterMark: 1 } Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL default readable strategy should be equivalent to { highWaterMark: 0 } Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a RangeError should be thrown for an invalid highWaterMark assert_throws: should throw RangeError for negative writableHighWaterMark function "() => new TransformStream(undefined, { highWaterMark: -1 })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL writableStrategy highWaterMark should be converted to a number Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readableStrategy highWaterMark should be converted to a number Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a bad readableStrategy size function should cause writer.write() to reject on an identity transform Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() catches the exception Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any.serviceworker-expected.txt
new file mode 100644
index 0000000..e1c914b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any.serviceworker-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+FAIL writableStrategy highWaterMark should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readableStrategy highWaterMark should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writable should have the correct size() function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL default writable strategy should be equivalent to { highWaterMark: 1 } Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL default readable strategy should be equivalent to { highWaterMark: 0 } Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a RangeError should be thrown for an invalid highWaterMark assert_throws: should throw RangeError for negative writableHighWaterMark function "() => new TransformStream(undefined, { highWaterMark: -1 })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL writableStrategy highWaterMark should be converted to a number Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readableStrategy highWaterMark should be converted to a number Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a bad readableStrategy size function should cause writer.write() to reject on an identity transform Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() catches the exception Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any.sharedworker-expected.txt
new file mode 100644
index 0000000..e1c914b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any.sharedworker-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+FAIL writableStrategy highWaterMark should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readableStrategy highWaterMark should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writable should have the correct size() function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL default writable strategy should be equivalent to { highWaterMark: 1 } Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL default readable strategy should be equivalent to { highWaterMark: 0 } Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a RangeError should be thrown for an invalid highWaterMark assert_throws: should throw RangeError for negative writableHighWaterMark function "() => new TransformStream(undefined, { highWaterMark: -1 })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL writableStrategy highWaterMark should be converted to a number Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readableStrategy highWaterMark should be converted to a number Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a bad readableStrategy size function should cause writer.write() to reject on an identity transform Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() catches the exception Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any.worker-expected.txt
new file mode 100644
index 0000000..e1c914b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/strategies.any.worker-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+FAIL writableStrategy highWaterMark should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readableStrategy highWaterMark should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL writable should have the correct size() function Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL default writable strategy should be equivalent to { highWaterMark: 1 } Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL default readable strategy should be equivalent to { highWaterMark: 0 } Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a RangeError should be thrown for an invalid highWaterMark assert_throws: should throw RangeError for negative writableHighWaterMark function "() => new TransformStream(undefined, { highWaterMark: -1 })" threw object "TypeError: Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled" ("TypeError") expected object "RangeError" ("RangeError")
+FAIL writableStrategy highWaterMark should be converted to a number Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL readableStrategy highWaterMark should be converted to a number Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a bad readableStrategy size function should cause writer.write() to reject on an identity transform Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() catches the exception Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any-expected.txt
index f11ad08..8d9bb29 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any-expected.txt
@@ -1,10 +1,9 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-FAIL controller.terminate() should error pipeTo() assert_false: pipeTo() should not have rejected yet expected false got true
-FAIL controller.terminate() should prevent remaining chunks from being processed assert_array_equals: transform() should have seen one chunk lengths differ, expected 2 got 0
-PASS controller.enqueue() should throw after controller.terminate()
-PASS controller.error() after controller.terminate() with queued chunk should error the readable
-PASS controller.error() after controller.terminate() without queued chunk should do nothing
-PASS controller.terminate() inside flush() should not prevent writer.close() from succeeding
+FAIL controller.terminate() should error pipeTo() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() should prevent remaining chunks from being processed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.enqueue() should throw after controller.terminate() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() after controller.terminate() with queued chunk should error the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() after controller.terminate() without queued chunk should do nothing Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() inside flush() should not prevent writer.close() from succeeding Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.serviceworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.serviceworker-expected.txt
index f11ad08..8d9bb29 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.serviceworker-expected.txt
@@ -1,10 +1,9 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-FAIL controller.terminate() should error pipeTo() assert_false: pipeTo() should not have rejected yet expected false got true
-FAIL controller.terminate() should prevent remaining chunks from being processed assert_array_equals: transform() should have seen one chunk lengths differ, expected 2 got 0
-PASS controller.enqueue() should throw after controller.terminate()
-PASS controller.error() after controller.terminate() with queued chunk should error the readable
-PASS controller.error() after controller.terminate() without queued chunk should do nothing
-PASS controller.terminate() inside flush() should not prevent writer.close() from succeeding
+FAIL controller.terminate() should error pipeTo() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() should prevent remaining chunks from being processed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.enqueue() should throw after controller.terminate() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() after controller.terminate() with queued chunk should error the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() after controller.terminate() without queued chunk should do nothing Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() inside flush() should not prevent writer.close() from succeeding Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.sharedworker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.sharedworker-expected.txt
index f11ad08..8d9bb29 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.sharedworker-expected.txt
@@ -1,10 +1,9 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-FAIL controller.terminate() should error pipeTo() assert_false: pipeTo() should not have rejected yet expected false got true
-FAIL controller.terminate() should prevent remaining chunks from being processed assert_array_equals: transform() should have seen one chunk lengths differ, expected 2 got 0
-PASS controller.enqueue() should throw after controller.terminate()
-PASS controller.error() after controller.terminate() with queued chunk should error the readable
-PASS controller.error() after controller.terminate() without queued chunk should do nothing
-PASS controller.terminate() inside flush() should not prevent writer.close() from succeeding
+FAIL controller.terminate() should error pipeTo() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() should prevent remaining chunks from being processed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.enqueue() should throw after controller.terminate() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() after controller.terminate() with queued chunk should error the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() after controller.terminate() without queued chunk should do nothing Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() inside flush() should not prevent writer.close() from succeeding Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.worker-expected.txt b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.worker-expected.txt
index f11ad08..8d9bb29 100644
--- a/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/external/wpt/streams/transform-streams/terminate.any.worker-expected.txt
@@ -1,10 +1,9 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Failed to execute 'pipeTo' on 'ReadableStream': pipeTo disabled because StreamsNative feature is enabled
-FAIL controller.terminate() should error pipeTo() assert_false: pipeTo() should not have rejected yet expected false got true
-FAIL controller.terminate() should prevent remaining chunks from being processed assert_array_equals: transform() should have seen one chunk lengths differ, expected 2 got 0
-PASS controller.enqueue() should throw after controller.terminate()
-PASS controller.error() after controller.terminate() with queued chunk should error the readable
-PASS controller.error() after controller.terminate() without queued chunk should do nothing
-PASS controller.terminate() inside flush() should not prevent writer.close() from succeeding
+FAIL controller.terminate() should error pipeTo() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() should prevent remaining chunks from being processed Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.enqueue() should throw after controller.terminate() Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() after controller.terminate() with queued chunk should error the readable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.error() after controller.terminate() without queued chunk should do nothing Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL controller.terminate() inside flush() should not prevent writer.close() from succeeding Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/transform-stream-enqueue-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/transform-stream-enqueue-expected.txt
new file mode 100644
index 0000000..067e208
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/transform-stream-enqueue-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL exception message for enqueue while closing should be correct assert_true: message should contain expected string expected true got false
+FAIL exception message for enqueue when errored should be correct assert_true: message should contain expected string expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/use-counters-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/use-counters-expected.txt
new file mode 100644
index 0000000..7569821
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/chromium/use-counters-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+PASS use of Response constructor should not be counted as using the ReadableStream constructor
+PASS use of ReadableStream constructor should be counted
+PASS use of WritableStream constructor should be counted
+FAIL use of TransformStream constructor should be counted Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/enabled/enabled-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/enabled/enabled-expected.txt
new file mode 100644
index 0000000..42defe0
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/enabled/enabled-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+PASS postMessage of a ReadableStream should work
+PASS postMessage of a WritableStream should work
+FAIL postMessage of a TransformStream should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/transform-stream-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/transform-stream-expected.txt
index d3bc518..e224f179 100644
--- a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/transform-stream-expected.txt
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/transform-stream-expected.txt
@@ -1,8 +1,8 @@
 This is a testharness.js-based test.
-FAIL window.postMessage should be able to transfer a TransformStream Cannot read property 'constructor' of null
-PASS a TransformStream with a locked writable should not be transferable
-PASS a TransformStream with a locked readable should not be transferable
-PASS a TransformStream with both sides locked should not be transferable
-FAIL piping through transferred transforms should work Cannot read property 'source' of null
+FAIL window.postMessage should be able to transfer a TransformStream Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a TransformStream with a locked writable should not be transferable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a TransformStream with a locked readable should not be transferable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL a TransformStream with both sides locked should not be transferable Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
+FAIL piping through transferred transforms should work Failed to construct 'TransformStream': TransformStream disabled because StreamsNative is enabled
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/window-expected.txt b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/window-expected.txt
new file mode 100644
index 0000000..8e6fa50
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/streams-native/http/tests/streams/transferable/window-expected.txt
@@ -0,0 +1,13 @@
+CONSOLE ERROR: line 23: Uncaught TypeError: Cannot read property 'start' of null
+CONSOLE ERROR: line 17: Uncaught (in promise) TypeError: Cannot read property 'constructor' of null
+CONSOLE ERROR: line 41: Uncaught (in promise) TypeError: Cannot read property 'addEventListener' of null
+CONSOLE ERROR: line 45: Uncaught (in promise) Error: assert_array_equals: there should be no ports in the event lengths differ, expected 0 got 1
+CONSOLE ERROR: line 5: Uncaught TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 is an untransferable 'null' value.
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = assert_array_equals: there should be no ports in the event lengths differ, expected 0 got 1
+FAIL window.postMessage should be able to transfer a ReadableStream assert_true: the original stream should be locked expected true got false
+FAIL port.postMessage should be able to transfer a ReadableStream assert_true: the original stream should be locked expected true got false
+FAIL the same ReadableStream posted multiple times should arrive together object null is not iterable (cannot read property Symbol(Symbol.iterator))
+FAIL transfer to and from an iframe should work assert_array_equals: there should be no ports in the event lengths differ, expected 0 got 1
+Harness: the test ran to completion.
+
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 8733cd56f..b487d97 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,9 +1,9 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 2.3.1-79
-Date: 20190301
-Revision: 4f37ab63de9705d7bf74ee75364747e41b7c06a1
+Version: 2.3.1-95
+Date: 20190315
+Revision: 8aaab78efcac81a05ec919be13792c98741ea1b5
 Security Critical: yes
 License: MIT
 License File: src/COPYING
diff --git a/third_party/protobuf/BUILD.gn b/third_party/protobuf/BUILD.gn
index 3024abd5..fafc2ef 100644
--- a/third_party/protobuf/BUILD.gn
+++ b/third_party/protobuf/BUILD.gn
@@ -222,6 +222,10 @@
     # The SQLite fuzzer's corpus generator needs protobuf_full and is not
     # included in Chrome.
     "//third_party/sqlite:sqlite3_lpm_corpus_gen",
+
+    # Some tests inside ChromeOS need reflection to parse golden files.
+    # Not included in production code.
+    "//chrome/test:usage_time_limit_unittests",
   ]
 
   sources = protobuf_lite_sources + [
@@ -695,7 +699,9 @@
 
 # Runtime dependency if the target needs the python scripts.
 group("py_proto_runtime") {
-  deps = [":py_proto"]
+  deps = [
+    ":py_proto",
+  ]
 
   # Targets that depend on this should depend on the copied data files.
   data = get_target_outputs(":copy_google")
diff --git a/tools/gdb/viewg.gdb b/tools/gdb/viewg.gdb
index 9b69581..c2fdd97 100644
--- a/tools/gdb/viewg.gdb
+++ b/tools/gdb/viewg.gdb
@@ -26,9 +26,9 @@
     set logging overwrite on
     set logging redirect on
     set logging on
-    printf "%s\n", view::PrintViewGraph(this).c_str()
+    printf "%s\n", views::PrintViewGraph(this).c_str()
     set logging off
     shell dot -Tsvg -o ~/state.svg ~/state.dot
     set pagination on
   end
-end
\ No newline at end of file
+end
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 2378ac5..d8bcbbc 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -205,6 +205,7 @@
       'Android Builder (dbg) Goma Latest Client': 'android_debug_static_bot_vrdata',
 
       'chromeos-amd64-generic-rel-goma-canary': 'cros_chrome_sdk',
+      'chromeos-amd64-generic-rel-goma-latest': 'cros_chrome_sdk',
       'chromeos-amd64-generic-rel-vm-tests': 'cros_chrome_sdk_headless_ozone_dcheck_always_on',
       'chromeos-kevin-rel-hw-tests': 'cros_chrome_sdk_headless_ozone',
       'chromeos-vm-code-coverage': 'cros_chrome_sdk_headless_ozone_coverage',
@@ -253,6 +254,7 @@
       'fuchsia-fyi-x64-rel': 'release_bot_fuchsia',
 
       'ios-device-goma-canary-clobber': 'ios',
+      'ios-device-goma-latest-clobber': 'ios',
 
       'ios-simulator': 'ios',
       'Jumbo Linux x64': 'jumbo_large_chunks_release_bot_minimal_symbols',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index b14c7931..d31ef6e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -15187,6 +15187,9 @@
 </enum>
 
 <enum name="EnterpriseDMTokenType">
+  <obsolete>
+    Deprecated 03/2019, since no code reports it anymore.
+  </obsolete>
   <summary>
     Result of DMToken operations as defined in
     components/policy/core/common/cloud/enterprise_metrics.h.
@@ -16096,6 +16099,9 @@
 </enum>
 
 <enum name="EnterprisePolicyType">
+  <obsolete>
+    Deprecated 03/2019, since no code reports it anymore.
+  </obsolete>
   <summary>
     Result of Policy operations as defined as MetricPolicy in
     components/policy/core/common/cloud/enterprise_metrics.h.
@@ -56501,6 +56507,10 @@
   <int value="8" label="Ambient badge in an Android Custom Tab"/>
   <int value="9" label="Ambient badge in a browser tab"/>
   <int value="10" label="Via ARC on Chrome OS"/>
+  <int value="11" label="Internal default-install on Chrome OS"/>
+  <int value="12" label="External default-install on Chrome OS"/>
+  <int value="13" label="Policy-install on Chrome OS"/>
+  <int value="14" label="System default app on Chrome OS"/>
 </enum>
 
 <enum name="WebappUninstallDialogAction">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 30d39622..40eb9822 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -28335,6 +28335,9 @@
 </histogram>
 
 <histogram name="Enterprise.DMToken" enum="EnterpriseDMTokenType">
+  <obsolete>
+    Deprecated 03/2019, since no code reports it anymore.
+  </obsolete>
   <owner>mnissler@chromium.org</owner>
   <summary>
     Events related to fetching, saving and loading DM server tokens. These are
@@ -28601,6 +28604,9 @@
 </histogram>
 
 <histogram name="Enterprise.Policy" enum="EnterprisePolicyType">
+  <obsolete>
+    Deprecated 03/2019, since no code reports it anymore.
+  </obsolete>
   <owner>mnissler@chromium.org</owner>
   <summary>
     Events related to fetching, saving and loading user policies, and also
diff --git a/tools/perf/cli_tools/update_wpr/update_wpr.py b/tools/perf/cli_tools/update_wpr/update_wpr.py
index ee8faaf..53d4cd7 100644
--- a/tools/perf/cli_tools/update_wpr/update_wpr.py
+++ b/tools/perf/cli_tools/update_wpr/update_wpr.py
@@ -160,7 +160,12 @@
     return self.device_id is None
 
   def _ExistingWpr(self):
-    """Returns a path to the current WPR archive for specified story."""
+    """Parses JSON story config to extract info about WPR archive.
+
+    Returns:
+      A 2-tuple with path to the current WPR archive for specified story and
+      whether it is used by other benchmarks too.
+    """
     config_file = os.path.join(DATA_DIR, 'system_health_%s.json' % (
         'desktop' if self._IsDesktop() else 'mobile'))
     with open(config_file) as f:
@@ -168,14 +173,17 @@
     archives = config['archives']
     archive = archives.get(self.story)
     if archive is None:
-      return None
+      return None, False
     archive = archive['DEFAULT']
-    return os.path.join(DATA_DIR, archive)
+    used_in_other_stories = any(
+        archive in config.values() for story, config in archives.iteritems()
+        if story != self.story)
+    return os.path.join(DATA_DIR, archive), used_in_other_stories
 
   def _DeleteExistingWpr(self):
     """Deletes current WPR archive."""
-    archive = self._ExistingWpr()
-    if archive is None:
+    archive, used_elsewhere = self._ExistingWpr()
+    if archive is None or used_elsewhere:
       return
     cli_helpers.Info('Deleting WPR: {archive}', archive=archive)
     if os.path.exists(archive):
@@ -369,7 +377,7 @@
 
   def UploadWpr(self):
     cli_helpers.Step('UPLOAD WPR: %s' % self.story)
-    archive = self._ExistingWpr()
+    archive, _ = self._ExistingWpr()
     if archive is None:
       cli_helpers.Error('NO WPR FOUND, use the "record" subcommand')
     _UploadArchiveToGoogleStorage(archive)
diff --git a/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py b/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py
index a875a38f..178d7343 100644
--- a/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py
+++ b/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py
@@ -255,6 +255,14 @@
       mock.call('.../data/dir/<archive>.sha1'),
     ])
 
+  @mock.patch('os.remove')
+  def testDoesNotDeleteReusedWpr(self, os_remove):
+    self._open.return_value.__enter__.return_value.read.return_value = (
+        '{"archives": {"<story>": {"DEFAULT": "<archive>"}, '
+        '"<other>": {"DEFAULT": "foo", "linux": "<arhive>"}}}')
+    self.wpr_updater._DeleteExistingWpr()
+    os_remove.assert_not_called()
+
   @mock.patch(WPR_UPDATER + 'WprUpdater._PrintRunInfo')
   @mock.patch(WPR_UPDATER + 'WprUpdater._DeleteExistingWpr')
   def testRecordWprDesktop(self, delete_existing_wpr, print_run_info):
@@ -286,7 +294,7 @@
     print_run_info.assert_called_once_with('<out-file>')
 
   @mock.patch(WPR_UPDATER + 'WprUpdater._ExistingWpr',
-              return_value='<archive>')
+              return_value=('<archive>', False))
   def testUploadWPR(self, existing_wpr):
     del existing_wpr  # Unused.
     self.wpr_updater.UploadWpr()
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py
index cb257400..b8eac16 100755
--- a/tools/perf/core/results_dashboard.py
+++ b/tools/perf/core/results_dashboard.py
@@ -15,9 +15,8 @@
 import os
 import subprocess
 import sys
-import traceback
 import time
-import tempfile
+import traceback
 import urllib
 import urllib2
 import zlib
@@ -139,7 +138,17 @@
                                     test_name, bot, buildername, buildnumber,
                                     project, buildbucket,
                                     revisions_dict, is_reference_build,
-                                    perf_dashboard_machine_group):
+                                    perf_dashboard_machine_group, output_dir,
+                                    max_bytes=0):
+  """Merges Histograms, adds Diagnostics, and batches the results.
+
+  Args:
+    histograms_file: input filename
+    output_dir: output directory
+    max_bytes: If non-zero, tries to produce files no larger than max_bytes.
+      (May generate a file that is larger than max_bytes if max_bytes is smaller
+      than a single Histogram.)
+  """
   add_diagnostics_args = []
   add_diagnostics_args.extend([
       '--benchmarks', test_name,
@@ -149,6 +158,9 @@
       '--is_reference_build', 'true' if is_reference_build else '',
   ])
 
+  if max_bytes:
+    add_diagnostics_args.extend(['--max_bytes', max_bytes])
+
   stdio_url = _MakeStdioUrl(test_name, buildername, buildnumber)
   if stdio_url:
     add_diagnostics_args.extend(['--log_urls_k', 'Buildbot stdio'])
@@ -172,21 +184,11 @@
       path_util.GetChromiumSrcDir(), 'third_party', 'catapult', 'tracing',
       'bin', 'add_reserved_diagnostics')
 
-  tf = tempfile.NamedTemporaryFile(delete=False)
-  tf.close()
-  temp_histogram_output_file = tf.name
-
+  # This script may write multiple files to output_dir.
+  output_path = os.path.join(output_dir, test_name + '.json')
   cmd = ([sys.executable, add_reserved_diagnostics_path] +
-         add_diagnostics_args + ['--output_path', temp_histogram_output_file])
-
-  try:
-    subprocess.check_call(cmd)
-    # TODO: Handle reference builds
-    with open(temp_histogram_output_file) as f:
-      hs = json.load(f)
-    return hs
-  finally:
-    os.remove(temp_histogram_output_file)
+         add_diagnostics_args + ['--output_path', output_path])
+  subprocess.check_call(cmd)
 
 
 def MakeListOfPoints(charts, bot, test_name, buildername,
diff --git a/tools/perf/core/upload_results_to_perf_dashboard.py b/tools/perf/core/upload_results_to_perf_dashboard.py
index 3afb2b3a..884dfab 100755
--- a/tools/perf/core/upload_results_to_perf_dashboard.py
+++ b/tools/perf/core/upload_results_to_perf_dashboard.py
@@ -10,8 +10,11 @@
 
 import json
 import optparse
+import os
 import re
+import shutil
 import sys
+import tempfile
 import time
 import urllib
 
@@ -59,6 +62,7 @@
       perf_dashboard_machine_group=options.perf_dashboard_machine_group)
   return dashboard_json
 
+
 def _GetDashboardHistogramData(options):
   revisions = {
       '--chromium_commit_positions': _GetMainRevision(options.got_revision_cp),
@@ -73,18 +77,34 @@
   is_reference_build = 'reference' in options.name
   stripped_test_name = options.name.replace('.reference', '')
 
-  begin_time = time.time()
-  hs = results_dashboard.MakeHistogramSetWithDiagnostics(
-      histograms_file=options.results_file, test_name=stripped_test_name,
-      bot=options.configuration_name, buildername=options.buildername,
-      buildnumber=options.buildnumber,
-      project=options.project, buildbucket=options.buildbucket,
-      revisions_dict=revisions, is_reference_build=is_reference_build,
-      perf_dashboard_machine_group=options.perf_dashboard_machine_group)
-  end_time = time.time()
-  print 'Duration of adding diagnostics for %s: %d seconds' % (
-      stripped_test_name, end_time - begin_time)
-  return hs
+  max_bytes = 1 << 20
+  output_dir = tempfile.mkdtemp()
+
+  try:
+    begin_time = time.time()
+    results_dashboard.MakeHistogramSetWithDiagnostics(
+        histograms_file=options.results_file, test_name=stripped_test_name,
+        bot=options.configuration_name, buildername=options.buildername,
+        buildnumber=options.buildnumber,
+        project=options.project, buildbucket=options.buildbucket,
+        revisions_dict=revisions, is_reference_build=is_reference_build,
+        perf_dashboard_machine_group=options.perf_dashboard_machine_group,
+        output_dir=output_dir,
+        max_bytes=max_bytes)
+    end_time = time.time()
+    print 'Duration of adding diagnostics for %s: %d seconds' % (
+        stripped_test_name, end_time - begin_time)
+
+    # Read all batch files from output_dir.
+    dashboard_jsons = []
+    for basename in os.listdir(output_dir):
+      with open(os.path.join(output_dir, basename)) as f:
+        dashboard_jsons.append(json.load(f))
+
+    return dashboard_jsons
+  finally:
+    shutil.rmtree(output_dir)
+
 
 def _CreateParser():
   # Parse options
@@ -127,14 +147,23 @@
 
   if not options.send_as_histograms:
     dashboard_json = _GetDashboardJson(options)
+    dashboard_jsons = []
+    if dashboard_json:
+      dashboard_jsons.append(dashboard_json)
   else:
-    dashboard_json = _GetDashboardHistogramData(options)
+    dashboard_jsons = _GetDashboardHistogramData(options)
+
+    # The HistogramSet might have been batched if it would be too large to
+    # upload together. It's safe to concatenate the batches in order to write
+    # output_json_file.
+    # TODO(crbug.com/918208): Use a script in catapult to merge dashboard_jsons.
+    dashboard_json = sum(dashboard_jsons, [])
 
   if options.output_json_file:
     json.dump(dashboard_json, options.output_json_file,
         indent=4, separators=(',', ': '))
 
-  if dashboard_json:
+  if dashboard_jsons:
     if options.output_json_dashboard_url:
       # Dump dashboard url to file.
       dashboard_url = GetDashboardUrl(options.name,
@@ -144,13 +173,14 @@
       with open(options.output_json_dashboard_url, 'w') as f:
         json.dump(dashboard_url if dashboard_url else '', f)
 
-    if not results_dashboard.SendResults(
-        dashboard_json,
-        options.name,
-        options.results_url,
-        send_as_histograms=options.send_as_histograms,
-        service_account_file=service_account_file):
-      return 1
+    for batch in dashboard_jsons:
+      if not results_dashboard.SendResults(
+          batch,
+          options.name,
+          options.results_url,
+          send_as_histograms=options.send_as_histograms,
+          service_account_file=service_account_file):
+        return 1
   else:
     # The upload didn't fail since there was no data to upload.
     print 'Warning: No perf dashboard JSON was produced.'
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py
index ab58f74..34957c0 100755
--- a/tools/perf/process_perf_results.py
+++ b/tools/perf/process_perf_results.py
@@ -274,7 +274,7 @@
 def process_perf_results(output_json, configuration_name,
                          service_account_file,
                          build_properties, task_output_dir,
-                         smoke_test_mode):
+                         smoke_test_mode, output_results_dir):
   """Process perf results.
 
   Consists of merging the json-test-format output, uploading the perf test
@@ -349,7 +349,7 @@
       return_code, benchmark_upload_result_map = _handle_perf_results(
           benchmark_enabled_map, benchmark_directory_map,
           configuration_name, build_properties, service_account_file,
-          extra_links)
+          extra_links, output_results_dir)
     except Exception:
       logging.exception('Error handling perf results jsons')
       return_code = 1
@@ -460,7 +460,8 @@
 
 def _handle_perf_results(
     benchmark_enabled_map, benchmark_directory_map, configuration_name,
-    build_properties, service_account_file, extra_links):
+    build_properties, service_account_file, extra_links,
+    output_results_dir):
   """
     Upload perf results to the perf dashboard.
 
@@ -475,73 +476,69 @@
         was successfully uploaded.
   """
   begin_time = time.time()
-  tmpfile_dir = tempfile.mkdtemp('outputresults')
+  # Upload all eligible benchmarks to the perf dashboard
+  results_dict = {}
+
+  invocations = []
+  for benchmark_name, directories in benchmark_directory_map.iteritems():
+    if not benchmark_enabled_map.get(benchmark_name, False):
+      continue
+    # Create a place to write the perf results that you will write out to
+    # logdog.
+    output_json_file = os.path.join(
+        output_results_dir, (str(uuid.uuid4()) + benchmark_name))
+    results_dict[benchmark_name] = output_json_file
+    invocations.append((
+        benchmark_name, directories, configuration_name,
+        build_properties, output_json_file, service_account_file))
+
+  # Kick off the uploads in multiple processes
+  pool = mp.Pool()
   try:
-    # Upload all eligible benchmarks to the perf dashboard
-    results_dict = {}
-
-    invocations = []
-    for benchmark_name, directories in benchmark_directory_map.iteritems():
-      if not benchmark_enabled_map.get(benchmark_name, False):
-        continue
-      # Create a place to write the perf results that you will write out to
-      # logdog.
-      output_json_file = os.path.join(
-          tmpfile_dir, (str(uuid.uuid4()) + benchmark_name))
-      results_dict[benchmark_name] = output_json_file
-      invocations.append((
-          benchmark_name, directories, configuration_name,
-          build_properties, output_json_file, service_account_file))
-
-    # Kick off the uploads in multiple processes
-    pool = mp.Pool()
-    try:
-      async_result = pool.map_async(
-          _upload_individual_benchmark, invocations)
-      results = async_result.get(timeout=2000)
-    except mp.TimeoutError:
-      logging.error('Failed uploading benchmarks to perf dashboard in parallel')
-      results = []
-      for benchmark_name in benchmark_directory_map:
-        results.append((benchmark_name, False))
-    finally:
-      pool.terminate()
-
-    # Keep a mapping of benchmarks to their upload results
-    benchmark_upload_result_map = {}
-    for r in results:
-      benchmark_upload_result_map[r[0]] = r[1]
-
-    logdog_dict = {}
-    upload_failures_counter = 0
-    logdog_stream = None
-    logdog_label = 'Results Dashboard'
-    for benchmark_name, output_file in results_dict.iteritems():
-      upload_succeed = benchmark_upload_result_map[benchmark_name]
-      if not upload_succeed:
-        upload_failures_counter += 1
-      is_reference = '.reference' in benchmark_name
-      _write_perf_data_to_logfile(
-        benchmark_name, output_file,
-        configuration_name, build_properties, logdog_dict,
-        is_reference, upload_failure=not upload_succeed)
-
-    logdog_file_name = _generate_unique_logdog_filename('Results_Dashboard_')
-    logdog_stream = logdog_helper.text(logdog_file_name,
-        json.dumps(dict(logdog_dict), sort_keys=True,
-                   indent=4, separators=(',', ': ')),
-        content_type=JSON_CONTENT_TYPE)
-    if upload_failures_counter > 0:
-      logdog_label += ('Upload Failure (%s benchmark upload failures)' %
-                       upload_failures_counter)
-    extra_links[logdog_label] = logdog_stream
-    end_time = time.time()
-    print_duration('Uploading results to perf dashboard', begin_time, end_time)
-    if upload_failures_counter > 0:
-      return 1, benchmark_upload_result_map
-    return 0, benchmark_upload_result_map
+    async_result = pool.map_async(
+        _upload_individual_benchmark, invocations)
+    results = async_result.get(timeout=2000)
+  except mp.TimeoutError:
+    logging.error('Failed uploading benchmarks to perf dashboard in parallel')
+    results = []
+    for benchmark_name in benchmark_directory_map:
+      results.append((benchmark_name, False))
   finally:
-    shutil.rmtree(tmpfile_dir)
+    pool.terminate()
+
+  # Keep a mapping of benchmarks to their upload results
+  benchmark_upload_result_map = {}
+  for r in results:
+    benchmark_upload_result_map[r[0]] = r[1]
+
+  logdog_dict = {}
+  upload_failures_counter = 0
+  logdog_stream = None
+  logdog_label = 'Results Dashboard'
+  for benchmark_name, output_file in results_dict.iteritems():
+    upload_succeed = benchmark_upload_result_map[benchmark_name]
+    if not upload_succeed:
+      upload_failures_counter += 1
+    is_reference = '.reference' in benchmark_name
+    _write_perf_data_to_logfile(
+      benchmark_name, output_file,
+      configuration_name, build_properties, logdog_dict,
+      is_reference, upload_failure=not upload_succeed)
+
+  logdog_file_name = _generate_unique_logdog_filename('Results_Dashboard_')
+  logdog_stream = logdog_helper.text(logdog_file_name,
+      json.dumps(dict(logdog_dict), sort_keys=True,
+                  indent=4, separators=(',', ': ')),
+      content_type=JSON_CONTENT_TYPE)
+  if upload_failures_counter > 0:
+    logdog_label += ('Upload Failure (%s benchmark upload failures)' %
+                      upload_failures_counter)
+  extra_links[logdog_label] = logdog_stream
+  end_time = time.time()
+  print_duration('Uploading results to perf dashboard', begin_time, end_time)
+  if upload_failures_counter > 0:
+    return 1, benchmark_upload_result_map
+  return 0, benchmark_upload_result_map
 
 
 def _write_perf_data_to_logfile(benchmark_name, output_file,
@@ -615,12 +612,16 @@
 
   args = parser.parse_args()
 
-  return_code, _ = process_perf_results(
-      args.output_json, args.configuration_name,
-      args.service_account_file,
-      args.build_properties, args.task_output_dir,
-      args.smoke_test_mode)
-  return return_code
+  output_results_dir = tempfile.mkdtemp('outputresults')
+  try:
+    return_code, _ = process_perf_results(
+        args.output_json, args.configuration_name,
+        args.service_account_file,
+        args.build_properties, args.task_output_dir,
+        args.smoke_test_mode, output_results_dir)
+    return return_code
+  finally:
+    shutil.rmtree(output_results_dir)
 
 
 if __name__ == '__main__':
diff --git a/tools/perf/process_perf_results_unittest.py b/tools/perf/process_perf_results_unittest.py
index 31a5e7f..f90d3bd 100755
--- a/tools/perf/process_perf_results_unittest.py
+++ b/tools/perf/process_perf_results_unittest.py
@@ -22,6 +22,9 @@
 import process_perf_results as ppr_module
 
 
+UUID_SIZE = 36
+
+
 class _FakeLogdogStream(object):
 
   def write(self, data):
@@ -116,12 +119,65 @@
                       "master:master.tryserver.chromium.perf",
                       "user_agent:cq"]}}"""
         })
+
+    output_results_dir = os.path.join(self.test_dir, 'outputresults')
+    os.mkdir(output_results_dir)
+
     return_code, benchmark_upload_result_map = ppr_module.process_perf_results(
         self.output_json, configuration_name='test-builder',
         service_account_file=self.service_account_file,
         build_properties=build_properties,
         task_output_dir=self.task_output_dir,
-        smoke_test_mode=False)
+        smoke_test_mode=False,
+        output_results_dir=output_results_dir)
+
+    # Output filenames are prefixed with a UUID. Strip it off.
+    output_results = {
+        filename[UUID_SIZE:]: os.stat(os.path.join(
+            output_results_dir, filename)).st_size
+        for filename in os.listdir(output_results_dir)}
+    self.assertEquals(32, len(output_results))
+
+    self.assertLess(10 << 10, output_results["power.desktop.reference"])
+    self.assertLess(10 << 10, output_results["blink_perf.image_decoder"])
+    self.assertLess(10 << 10, output_results["octane.reference"])
+    self.assertLess(10 << 10, output_results["power.desktop"])
+    self.assertLess(10 << 10, output_results["speedometer-future"])
+    self.assertLess(10 << 10, output_results["blink_perf.owp_storage"])
+    self.assertLess(10 << 10, output_results["memory.desktop"])
+    self.assertLess(10 << 10, output_results["wasm"])
+    self.assertLess(10 << 10, output_results[
+      "dummy_benchmark.histogram_benchmark_1"])
+    self.assertLess(10 << 10, output_results[
+      "dummy_benchmark.histogram_benchmark_1.reference"])
+    self.assertLess(10 << 10, output_results["wasm.reference"])
+    self.assertLess(10 << 10, output_results["speedometer"])
+    self.assertLess(10 << 10, output_results[
+      "memory.long_running_idle_gmail_tbmv2"])
+    self.assertLess(10 << 10, output_results["v8.runtime_stats.top_25"])
+    self.assertLess(1 << 10, output_results[
+      "dummy_benchmark.noisy_benchmark_1"])
+    self.assertLess(10 << 10, output_results["blink_perf.svg"])
+    self.assertLess(10 << 10, output_results[
+      "v8.runtime_stats.top_25.reference"])
+    self.assertLess(10 << 10, output_results["jetstream.reference"])
+    self.assertLess(10 << 10, output_results["jetstream"])
+    self.assertLess(10 << 10, output_results["speedometer2-future.reference"])
+    self.assertLess(10 << 10, output_results["blink_perf.svg.reference"])
+    self.assertLess(10 << 10, output_results[
+      "blink_perf.image_decoder.reference"])
+    self.assertLess(10 << 10, output_results["power.idle_platform.reference"])
+    self.assertLess(10 << 10, output_results["power.idle_platform"])
+    self.assertLess(1 << 10, output_results[
+      "dummy_benchmark.noisy_benchmark_1.reference"])
+    self.assertLess(10 << 10, output_results["speedometer-future.reference"])
+    self.assertLess(10 << 10, output_results[
+      "memory.long_running_idle_gmail_tbmv2.reference"])
+    self.assertLess(10 << 10, output_results["memory.desktop.reference"])
+    self.assertLess(10 << 10, output_results[
+      "blink_perf.owp_storage.reference"])
+    self.assertLess(10 << 10, output_results["octane"])
+    self.assertLess(10 << 10, output_results["speedometer.reference"])
 
     self.assertEquals(return_code, 1)
     self.assertEquals(benchmark_upload_result_map,
diff --git a/ui/android/java/res/values/color_palette.xml b/ui/android/java/res/values/color_palette.xml
index c1639897..4b7124a 100644
--- a/ui/android/java/res/values/color_palette.xml
+++ b/ui/android/java/res/values/color_palette.xml
@@ -16,6 +16,7 @@
     <color name="modern_grey_800_alpha_38" tools:ignore="UnusedResources">#613C4043</color>
     <color name="modern_grey_900">#202124</color>
 
+    <color name="modern_grey_900_with_white_alpha_6" tools:ignore="UnusedResources">#2D2E31</color>
     <color name="modern_grey_900_with_white_alpha_8" tools:ignore="UnusedResources">#313235</color>
 
     <color name="black_alpha_38">#61000000</color>
@@ -52,4 +53,16 @@
 
     <color name="default_green_light" tools:ignore="UnusedResources">@color/google_green_300</color>
     <color name="default_green_dark" tools:ignore="UnusedResources">@color/google_green_700</color>
+
+    <!-- Common background colors. -->
+    <color name="default_bg_color_light">@android:color/white</color>
+    <color name="default_bg_color_dark" tools:ignore="UnusedResources">
+        @color/modern_grey_900
+    </color>
+    <color name="default_bg_color_dark_elev_2" tools:ignore="UnusedResources">
+        @color/modern_grey_900_with_white_alpha_6
+    </color>
+    <color name="default_bg_color_dark_elev_3" tools:ignore="UnusedResources">
+        @color/modern_grey_900_with_white_alpha_8
+    </color>
 </resources>
\ No newline at end of file
diff --git a/ui/android/java/res/values/colors.xml b/ui/android/java/res/values/colors.xml
index fc5fd39..1d021bae 100644
--- a/ui/android/java/res/values/colors.xml
+++ b/ui/android/java/res/values/colors.xml
@@ -28,9 +28,24 @@
     <color name="hairline_stroke_color">@color/modern_grey_300</color>
 
     <!-- Common background and branding color. -->
-    <color name="modern_primary_color">@android:color/white</color>
+    <!-- TODO(huayinz): Change primary and secondary color to default_bg_color*. -->
+    <color name="modern_primary_color">@color/default_bg_color_light</color>
     <color name="modern_secondary_color">@color/modern_grey_100</color>
 
+    <!-- TODO(huayinz): Introduce a semantic bg reference for modern_grey_100. -->
+    <!-- Background colors that are used to show layers and their relative elevation. In light mode,
+         we use a combination of shadows and colors. In night mode, we use different colors to show
+         elevation. -->
+    <color name="default_bg_color_elev_0" tools:ignore="UnusedResources">
+        @color/modern_grey_100
+    </color>
+    <color name="default_bg_color_elev_2" tools:ignore="UnusedResources">
+        @color/default_bg_color_light
+    </color>
+    <color name="default_bg_color_elev_3" tools:ignore="UnusedResources">
+        @color/default_bg_color_light
+    </color>
+
     <color name="dropdown_divider_color">#E5E5E5</color>
     <color name="dropdown_dark_divider_color">#C0C0C0</color>
 </resources>
diff --git a/ui/android/java/res_night/OWNERS b/ui/android/java/res_night/OWNERS
new file mode 100644
index 0000000..b6cb286
--- /dev/null
+++ b/ui/android/java/res_night/OWNERS
@@ -0,0 +1,9 @@
+# This restriction is in place to avoid accidental addition to our top level
+# layout files, such as adding duplicated assets, or introducing new colors when
+# we don't want them.
+set noparent
+
+file://ui/android/java/res/OWNERS
+
+# COMPONENT: UI>Browser>Mobile
+# OS: Android
diff --git a/ui/android/java/res_night/values-night/colors.xml b/ui/android/java/res_night/values-night/colors.xml
index 374ba2d..1a9548f 100644
--- a/ui/android/java/res_night/values-night/colors.xml
+++ b/ui/android/java/res_night/values-night/colors.xml
@@ -17,6 +17,10 @@
     <color name="hairline_stroke_color">@color/white_alpha_10</color>
 
     <!-- Common background and branding color. -->
-    <color name="modern_primary_color">@color/modern_grey_900</color>
+    <color name="modern_primary_color">@color/default_bg_color_dark</color>
     <color name="modern_secondary_color">@color/modern_grey_800</color>
+    <color name="default_bg_color_elev_0">@color/default_bg_color_dark</color>
+    <color name="default_bg_color_elev_2">@color/default_bg_color_dark_elev_2</color>
+    <color name="default_bg_color_elev_3">@color/default_bg_color_dark_elev_3</color>
+
 </resources>
\ No newline at end of file
diff --git a/ui/aura/mus/input_method_mus.cc b/ui/aura/mus/input_method_mus.cc
index 1ff70a4..ad8fca7 100644
--- a/ui/aura/mus/input_method_mus.cc
+++ b/ui/aura/mus/input_method_mus.cc
@@ -272,7 +272,7 @@
 void InputMethodMus::UpdateTextInputType() {
   ui::TextInputType type = GetTextInputType();
   ui::mojom::TextInputStatePtr state = ui::mojom::TextInputState::New();
-  state->type = mojo::ConvertTo<ui::mojom::TextInputType>(type);
+  state->type = type;
   if (input_method_mus_delegate_) {
     if (type != ui::TEXT_INPUT_TYPE_NONE)
       input_method_mus_delegate_->SetImeVisibility(true, std::move(state));
diff --git a/ui/aura/test/ui_controls_factory_aurax11.cc b/ui/aura/test/ui_controls_factory_aurax11.cc
index 63d1998d..1b4db34 100644
--- a/ui/aura/test/ui_controls_factory_aurax11.cc
+++ b/ui/aura/test/ui_controls_factory_aurax11.cc
@@ -209,7 +209,8 @@
     }
     marker_event->xclient.message_type = MarkerEventAtom();
     PostEventToWindowTreeHost(*marker_event, host_);
-    ui::PlatformEventWaiter::Create(std::move(closure), base::Bind(&Matcher));
+    ui::PlatformEventWaiter::Create(std::move(closure),
+                                    base::BindRepeating(&Matcher));
   }
  private:
   void SetKeycodeAndSendThenMask(XEvent* xevent,
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 085ef60..258286c 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -927,6 +927,7 @@
       "ime/composition_text_unittest.cc",
       "ime/input_method_base_unittest.cc",
       "ime/input_method_chromeos_unittest.cc",
+      "ime/mojo/ime_struct_traits_unittest.cc",
       "ime/win/imm32_manager_unittest.cc",
       "ime/win/on_screen_keyboard_display_manager_unittest.cc",
       "ime/win/tsf_input_scope_unittest.cc",
@@ -986,7 +987,10 @@
   }
 
   if (build_ime) {
-    deps += [ "//ui/base/ime" ]
+    deps += [
+      "//ui/base/ime",
+      "//ui/base/ime/mojo:test_interfaces",
+    ]
   }
 
   if (is_ios) {
diff --git a/ui/base/ime/DEPS b/ui/base/ime/DEPS
index 12541f5e..ff8745b 100644
--- a/ui/base/ime/DEPS
+++ b/ui/base/ime/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+chromeos/system",
+  "+mojo/public",
   "+services/metrics/public/cpp",
 ]
diff --git a/ui/base/ime/input_method_win_base.cc b/ui/base/ime/input_method_win_base.cc
index 6b7c3be..bd7edb1 100644
--- a/ui/base/ime/input_method_win_base.cc
+++ b/ui/base/ime/input_method_win_base.cc
@@ -517,4 +517,48 @@
   return details;
 }
 
+void InputMethodWinBase::UpdateCompositionBoundsForEngine(
+    const TextInputClient* client) {
+  TextInputType text_input_type = GetTextInputType();
+  if (client == GetTextInputClient() &&
+      text_input_type != TEXT_INPUT_TYPE_NONE &&
+      text_input_type != TEXT_INPUT_TYPE_PASSWORD && GetEngine()) {
+    GetEngine()->SetCompositionBounds(GetCompositionBounds(client));
+  }
+}
+
+void InputMethodWinBase::ResetEngine() {
+  if (GetEngine())
+    GetEngine()->Reset();
+}
+
+void InputMethodWinBase::CancelCompositionForEngine() {
+  TextInputType text_input_type = GetTextInputType();
+  if (text_input_type != TEXT_INPUT_TYPE_NONE &&
+      text_input_type != TEXT_INPUT_TYPE_PASSWORD) {
+    InputMethodWinBase::ResetEngine();
+  }
+}
+
+void InputMethodWinBase::UpdateEngineFocusAndInputContext() {
+  if (!ui::IMEBridge::Get())  // IMEBridge could be null for tests.
+    return;
+
+  const TextInputType old_text_input_type =
+      ui::IMEBridge::Get()->GetCurrentInputContext().type;
+  ui::IMEEngineHandlerInterface::InputContext context(
+      GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
+      ui::TextInputClient::FOCUS_REASON_OTHER, GetClientShouldDoLearning());
+  ui::IMEBridge::Get()->SetCurrentInputContext(context);
+
+  // Update IME Engine state.
+  ui::IMEEngineHandlerInterface* engine = GetEngine();
+  if (engine) {
+    if (old_text_input_type != ui::TEXT_INPUT_TYPE_NONE)
+      engine->FocusOut();
+    if (GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
+      engine->FocusIn(context);
+  }
+}
+
 }  // namespace ui
diff --git a/ui/base/ime/input_method_win_base.h b/ui/base/ime/input_method_win_base.h
index 1745c866..f1f4950 100644
--- a/ui/base/ime/input_method_win_base.h
+++ b/ui/base/ime/input_method_win_base.h
@@ -60,6 +60,19 @@
       ui::KeyEvent* event,
       const std::vector<MSG>* char_msgs);
 
+  // Update composition bounds for Chromium IME extension.
+  void UpdateCompositionBoundsForEngine(const TextInputClient* client);
+
+  // Reset composition status for Chromium IME extension.
+  void ResetEngine();
+
+  // Cancel composition for Chromium IME extension.
+  void CancelCompositionForEngine();
+
+  // Update focus state for Chromium IME extension and update input context in
+  // ui::IMEBridge.
+  void UpdateEngineFocusAndInputContext();
+
   // The toplevel window handle.
   const HWND toplevel_window_handle_;
 
diff --git a/ui/base/ime/input_method_win_imm32.cc b/ui/base/ime/input_method_win_imm32.cc
index 723408b..48ebd26 100644
--- a/ui/base/ime/input_method_win_imm32.cc
+++ b/ui/base/ime/input_method_win_imm32.cc
@@ -100,14 +100,7 @@
   if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
     return;
   NotifyTextInputCaretBoundsChanged(client);
-  TextInputType text_input_type = GetTextInputType();
-  if (client == GetTextInputClient() &&
-      text_input_type != TEXT_INPUT_TYPE_NONE &&
-      text_input_type != TEXT_INPUT_TYPE_PASSWORD && GetEngine()) {
-    // |enabled_| == false could be faked, and the engine should rely on the
-    // real type from GetTextInputType().
-    GetEngine()->SetCompositionBounds(GetCompositionBounds(client));
-  }
+  InputMethodWinBase::UpdateCompositionBoundsForEngine(client);
   if (!enabled_)
     return;
 
@@ -135,11 +128,7 @@
   if (IsTextInputClientFocused(client)) {
     // |enabled_| == false could be faked, and the engine should rely on the
     // real type get from GetTextInputType().
-    TextInputType text_input_type = GetTextInputType();
-    if (text_input_type != TEXT_INPUT_TYPE_NONE &&
-        text_input_type != TEXT_INPUT_TYPE_PASSWORD && GetEngine()) {
-      GetEngine()->Reset();
-    }
+    InputMethodWinBase::CancelCompositionForEngine();
 
     if (enabled_)
       imm32_manager_.CancelIME(toplevel_window_handle_);
@@ -340,8 +329,7 @@
   if (!IsTextInputTypeNone() && GetTextInputClient()->HasCompositionText()) {
     GetTextInputClient()->ConfirmCompositionText();
 
-    if (GetEngine())
-      GetEngine()->Reset();
+    InputMethodWinBase::ResetEngine();
   }
 }
 
@@ -370,23 +358,7 @@
   tsf_inputscope::SetInputScopeForTsfUnawareWindow(
       window_handle, text_input_type, text_input_mode);
 
-  if (!ui::IMEBridge::Get())  // IMEBridge could be null for tests.
-    return;
-
-  const TextInputType old_text_input_type =
-      ui::IMEBridge::Get()->GetCurrentInputContext().type;
-  ui::IMEEngineHandlerInterface::InputContext context(
-      GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
-      ui::TextInputClient::FOCUS_REASON_OTHER, GetClientShouldDoLearning());
-  ui::IMEBridge::Get()->SetCurrentInputContext(context);
-
-  ui::IMEEngineHandlerInterface* engine = GetEngine();
-  if (engine) {
-    if (old_text_input_type != ui::TEXT_INPUT_TYPE_NONE)
-      engine->FocusOut();
-    if (GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
-      engine->FocusIn(context);
-  }
+  InputMethodWinBase::UpdateEngineFocusAndInputContext();
 }
 
 }  // namespace ui
diff --git a/ui/base/ime/input_method_win_tsf.cc b/ui/base/ime/input_method_win_tsf.cc
index 99394a0..f84b5e3 100644
--- a/ui/base/ime/input_method_win_tsf.cc
+++ b/ui/base/ime/input_method_win_tsf.cc
@@ -39,6 +39,11 @@
 InputMethodWinTSF::~InputMethodWinTSF() {}
 
 void InputMethodWinTSF::OnFocus() {
+  InputMethodBase::OnFocus();
+  if (!ui::TSFBridge::GetInstance()) {
+    // TSFBridge can be null for tests.
+    return;
+  }
   tsf_event_router_->SetManager(
       ui::TSFBridge::GetInstance()->GetThreadManager().Get());
   ui::TSFBridge::GetInstance()->SetInputMethodDelegate(
@@ -46,6 +51,11 @@
 }
 
 void InputMethodWinTSF::OnBlur() {
+  InputMethodBase::OnBlur();
+  if (!ui::TSFBridge::GetInstance()) {
+    // TSFBridge can be null for tests.
+    return;
+  }
   tsf_event_router_->SetManager(nullptr);
   ui::TSFBridge::GetInstance()->RemoveInputMethodDelegate();
 }
@@ -83,24 +93,38 @@
 
 void InputMethodWinTSF::OnTextInputTypeChanged(const TextInputClient* client) {
   InputMethodBase::OnTextInputTypeChanged(client);
-  if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
+  if (!ui::TSFBridge::GetInstance() || !IsTextInputClientFocused(client) ||
+      !IsWindowFocused(client)) {
     return;
+  }
   ui::TSFBridge::GetInstance()->CancelComposition();
   ui::TSFBridge::GetInstance()->OnTextInputTypeChanged(client);
+  InputMethodWinBase::UpdateEngineFocusAndInputContext();
 }
 
 void InputMethodWinTSF::OnCaretBoundsChanged(const TextInputClient* client) {
-  if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
+  if (!ui::TSFBridge::GetInstance() || !IsTextInputClientFocused(client) ||
+      !IsWindowFocused(client)) {
     return;
+  }
+  NotifyTextInputCaretBoundsChanged(client);
   ui::TSFBridge::GetInstance()->OnTextLayoutChanged();
+  InputMethodWinBase::UpdateCompositionBoundsForEngine(client);
 }
 
 void InputMethodWinTSF::CancelComposition(const TextInputClient* client) {
-  if (IsTextInputClientFocused(client) && IsWindowFocused(client))
+  if (ui::TSFBridge::GetInstance() && IsTextInputClientFocused(client) &&
+      IsWindowFocused(client)) {
     ui::TSFBridge::GetInstance()->CancelComposition();
+    InputMethodWinBase::CancelCompositionForEngine();
+  }
 }
 
 void InputMethodWinTSF::DetachTextInputClient(TextInputClient* client) {
+  if (!ui::TSFBridge::GetInstance()) {
+    // TSFBridge can be null for tests.
+    return;
+  }
   InputMethodWinBase::DetachTextInputClient(client);
   ui::TSFBridge::GetInstance()->RemoveFocusedClient(client);
 }
@@ -121,7 +145,8 @@
 void InputMethodWinTSF::OnDidChangeFocusedClient(
     TextInputClient* focused_before,
     TextInputClient* focused) {
-  if (IsWindowFocused(focused) && IsTextInputClientFocused(focused)) {
+  if (ui::TSFBridge::GetInstance() && IsWindowFocused(focused) &&
+      IsTextInputClientFocused(focused)) {
     ui::TSFBridge::GetInstance()->SetFocusedClient(toplevel_window_handle_,
                                                    focused);
 
@@ -138,8 +163,12 @@
 }
 
 void InputMethodWinTSF::ConfirmCompositionText() {
-  if (!IsTextInputTypeNone())
-    ui::TSFBridge::GetInstance()->ConfirmComposition();
+  if (!IsTextInputTypeNone()) {
+    if (GetTextInputClient()->HasCompositionText())
+      InputMethodWinBase::ResetEngine();
+    if (ui::TSFBridge::GetInstance())
+      ui::TSFBridge::GetInstance()->ConfirmComposition();
+  }
 }
 
 }  // namespace ui
diff --git a/ui/base/ime/mojo/BUILD.gn b/ui/base/ime/mojo/BUILD.gn
new file mode 100644
index 0000000..7443702
--- /dev/null
+++ b/ui/base/ime/mojo/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2019 The Chromium 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("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojo") {
+  sources = [
+    "ime_types.mojom",
+  ]
+}
+
+mojom("test_interfaces") {
+  sources = [
+    "ime_struct_traits_test.mojom",
+  ]
+
+  public_deps = [
+    ":mojo",
+  ]
+}
diff --git a/ui/base/ime/mojo/OWNERS b/ui/base/ime/mojo/OWNERS
new file mode 100644
index 0000000..e75daf74
--- /dev/null
+++ b/ui/base/ime/mojo/OWNERS
@@ -0,0 +1,8 @@
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/ui/base/ime/mojo/ime_struct_traits_test.mojom b/ui/base/ime/mojo/ime_struct_traits_test.mojom
new file mode 100644
index 0000000..f838693e0
--- /dev/null
+++ b/ui/base/ime/mojo/ime_struct_traits_test.mojom
@@ -0,0 +1,15 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module ui.mojom;
+
+import "ui/base/ime/mojo/ime_types.mojom";
+
+interface IMEStructTraitsTest {
+  [Sync]
+  EchoTextInputType(TextInputType in) => (TextInputType out);
+  [Sync]
+  EchoTextInputMode(TextInputMode in) => (TextInputMode out);
+};
+
diff --git a/ui/base/ime/mojo/ime_struct_traits_unittest.cc b/ui/base/ime/mojo/ime_struct_traits_unittest.cc
new file mode 100644
index 0000000..21ad47c5
--- /dev/null
+++ b/ui/base/ime/mojo/ime_struct_traits_unittest.cc
@@ -0,0 +1,96 @@
+// Copyright 2019 The Chromium 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/base/ime/mojo/ime_types_struct_traits.h"
+
+#include <utility>
+
+#include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/mojo/ime_struct_traits_test.mojom.h"
+
+namespace ui {
+
+namespace {
+
+class IMEStructTraitsTest : public testing::Test,
+                            public mojom::IMEStructTraitsTest {
+ public:
+  IMEStructTraitsTest() {}
+
+ protected:
+  mojom::IMEStructTraitsTestPtr GetTraitsTestProxy() {
+    mojom::IMEStructTraitsTestPtr proxy;
+    traits_test_bindings_.AddBinding(this, mojo::MakeRequest(&proxy));
+    return proxy;
+  }
+
+ private:
+  // mojom::IMEStructTraitsTest:
+  void EchoTextInputMode(ui::TextInputMode in,
+                         EchoTextInputModeCallback callback) override {
+    std::move(callback).Run(in);
+  }
+  void EchoTextInputType(ui::TextInputType in,
+                         EchoTextInputTypeCallback callback) override {
+    std::move(callback).Run(in);
+  }
+
+  base::MessageLoop loop_;  // A MessageLoop is needed for Mojo IPC to work.
+  mojo::BindingSet<mojom::IMEStructTraitsTest> traits_test_bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(IMEStructTraitsTest);
+};
+
+}  // namespace
+
+TEST_F(IMEStructTraitsTest, TextInputMode) {
+  const ui::TextInputMode kTextInputModes[] = {
+      ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_MODE_NONE,
+      ui::TEXT_INPUT_MODE_TEXT,    ui::TEXT_INPUT_MODE_TEL,
+      ui::TEXT_INPUT_MODE_URL,     ui::TEXT_INPUT_MODE_EMAIL,
+      ui::TEXT_INPUT_MODE_NUMERIC, ui::TEXT_INPUT_MODE_DECIMAL,
+      ui::TEXT_INPUT_MODE_SEARCH,
+  };
+
+  mojom::IMEStructTraitsTestPtr proxy = GetTraitsTestProxy();
+  for (size_t i = 0; i < base::size(kTextInputModes); i++) {
+    ui::TextInputMode mode_out;
+    ASSERT_TRUE(proxy->EchoTextInputMode(kTextInputModes[i], &mode_out));
+    EXPECT_EQ(kTextInputModes[i], mode_out);
+  }
+}
+
+TEST_F(IMEStructTraitsTest, TextInputType) {
+  const ui::TextInputType kTextInputTypes[] = {
+      ui::TEXT_INPUT_TYPE_NONE,
+      ui::TEXT_INPUT_TYPE_TEXT,
+      ui::TEXT_INPUT_TYPE_PASSWORD,
+      ui::TEXT_INPUT_TYPE_SEARCH,
+      ui::TEXT_INPUT_TYPE_EMAIL,
+      ui::TEXT_INPUT_TYPE_NUMBER,
+      ui::TEXT_INPUT_TYPE_TELEPHONE,
+      ui::TEXT_INPUT_TYPE_URL,
+      ui::TEXT_INPUT_TYPE_DATE,
+      ui::TEXT_INPUT_TYPE_DATE_TIME,
+      ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL,
+      ui::TEXT_INPUT_TYPE_MONTH,
+      ui::TEXT_INPUT_TYPE_TIME,
+      ui::TEXT_INPUT_TYPE_WEEK,
+      ui::TEXT_INPUT_TYPE_TEXT_AREA,
+      ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE,
+      ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD,
+  };
+
+  mojom::IMEStructTraitsTestPtr proxy = GetTraitsTestProxy();
+  for (size_t i = 0; i < base::size(kTextInputTypes); i++) {
+    ui::TextInputType type_out;
+    ASSERT_TRUE(proxy->EchoTextInputType(kTextInputTypes[i], &type_out));
+    EXPECT_EQ(kTextInputTypes[i], type_out);
+  }
+}
+
+}  // namespace ui
diff --git a/ui/base/ime/mojo/ime_types.mojom b/ui/base/ime/mojo/ime_types.mojom
new file mode 100644
index 0000000..d1356e3
--- /dev/null
+++ b/ui/base/ime/mojo/ime_types.mojom
@@ -0,0 +1,56 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module ui.mojom;
+
+// Text input type which is based on blink::WebTextInputType.
+enum TextInputType {
+  NONE,
+  TEXT,
+  PASSWORD,
+  SEARCH,
+  EMAIL,
+  NUMBER,
+  TELEPHONE,
+  URL,
+  DATE,
+  DATE_TIME,
+  DATE_TIME_LOCAL,
+  MONTH,
+  TIME,
+  WEEK,
+  TEXT_AREA,
+  CONTENT_EDITABLE,
+  DATE_TIME_FIELD,
+  MAX = DATE_TIME_FIELD,
+};
+
+// See comments for ui::TextInputMode for more details.
+enum TextInputMode {
+  kDefault,
+  kNone,
+  kText,
+  kTel,
+  kUrl,
+  kEmail,
+  kNumeric,
+  kDecimal,
+  kSearch,
+};
+
+// Text input flag which is based on blink::WebTextInputFlags.
+enum TextInputFlag {
+  NONE,
+  AUTOCOMPLETE_ON = 0x001,
+  AUTOCOMPLETE_OFF = 0x002,
+  AUTOCORRECT_ON = 0x004,
+  AUTOCORRECT_OFF = 0x008,
+  SPELLCHECK_ON = 0x010,
+  SPELLCHECK_OFF = 0x020,
+  AUTOCAPITALIZE_NONE = 0x040,
+  AUTOCAPITALIZE_CHARACTERS = 0x080,
+  AUTOCAPITALIZE_WORDS = 0x100,
+  AUTOCAPITALIZE_SENTENCES = 0x200,
+  ALL = 0x3FF,
+};
diff --git a/ui/base/ime/mojo/ime_types.typemap b/ui/base/ime/mojo/ime_types.typemap
new file mode 100644
index 0000000..57f6b1b
--- /dev/null
+++ b/ui/base/ime/mojo/ime_types.typemap
@@ -0,0 +1,21 @@
+# Copyright 2019 The Chromium 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 = "//ui/base/ime/mojo/ime_types.mojom"
+public_headers = [
+  "//ui/base/ime/text_input_mode.h",
+  "//ui/base/ime/text_input_type.h",
+]
+traits_headers = [ "//ui/base/ime/mojo/ime_types_struct_traits.h" ]
+sources = [
+  "//ui/base/ime/mojo/ime_types_struct_traits.cc",
+]
+public_deps = [
+  "//ui/base/ime:ime_types",
+]
+
+type_mappings = [
+  "ui.mojom.TextInputType=ui::TextInputType",
+  "ui.mojom.TextInputMode=ui::TextInputMode",
+]
diff --git a/ui/base/ime/mojo/ime_types_struct_traits.cc b/ui/base/ime/mojo/ime_types_struct_traits.cc
new file mode 100644
index 0000000..eb3df29
--- /dev/null
+++ b/ui/base/ime/mojo/ime_types_struct_traits.cc
@@ -0,0 +1,138 @@
+// Copyright 2019 The Chromium 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/base/ime/mojo/ime_types_struct_traits.h"
+
+namespace mojo {
+
+#define UI_TO_MOJO_TYPE_CASE(name) \
+  case ui::TEXT_INPUT_TYPE_##name: \
+    return ui::mojom::TextInputType::name
+
+// static
+ui::mojom::TextInputType
+EnumTraits<ui::mojom::TextInputType, ui::TextInputType>::ToMojom(
+    ui::TextInputType text_input_type) {
+  switch (text_input_type) {
+    UI_TO_MOJO_TYPE_CASE(NONE);
+    UI_TO_MOJO_TYPE_CASE(TEXT);
+    UI_TO_MOJO_TYPE_CASE(PASSWORD);
+    UI_TO_MOJO_TYPE_CASE(SEARCH);
+    UI_TO_MOJO_TYPE_CASE(EMAIL);
+    UI_TO_MOJO_TYPE_CASE(NUMBER);
+    UI_TO_MOJO_TYPE_CASE(TELEPHONE);
+    UI_TO_MOJO_TYPE_CASE(URL);
+    UI_TO_MOJO_TYPE_CASE(DATE);
+    UI_TO_MOJO_TYPE_CASE(DATE_TIME);
+    UI_TO_MOJO_TYPE_CASE(DATE_TIME_LOCAL);
+    UI_TO_MOJO_TYPE_CASE(MONTH);
+    UI_TO_MOJO_TYPE_CASE(TIME);
+    UI_TO_MOJO_TYPE_CASE(WEEK);
+    UI_TO_MOJO_TYPE_CASE(TEXT_AREA);
+    UI_TO_MOJO_TYPE_CASE(CONTENT_EDITABLE);
+    UI_TO_MOJO_TYPE_CASE(DATE_TIME_FIELD);
+  }
+  NOTREACHED();
+  return ui::mojom::TextInputType::NONE;
+}
+
+#undef UI_TO_MOJO_TYPE_CASE
+
+#define MOJO_TO_UI_TYPE_CASE(name)     \
+  case ui::mojom::TextInputType::name: \
+    *out = ui::TEXT_INPUT_TYPE_##name; \
+    return true;
+
+// static
+bool EnumTraits<ui::mojom::TextInputType, ui::TextInputType>::FromMojom(
+    ui::mojom::TextInputType input,
+    ui::TextInputType* out) {
+  switch (input) {
+    MOJO_TO_UI_TYPE_CASE(NONE);
+    MOJO_TO_UI_TYPE_CASE(TEXT);
+    MOJO_TO_UI_TYPE_CASE(PASSWORD);
+    MOJO_TO_UI_TYPE_CASE(SEARCH);
+    MOJO_TO_UI_TYPE_CASE(EMAIL);
+    MOJO_TO_UI_TYPE_CASE(NUMBER);
+    MOJO_TO_UI_TYPE_CASE(TELEPHONE);
+    MOJO_TO_UI_TYPE_CASE(URL);
+    MOJO_TO_UI_TYPE_CASE(DATE);
+    MOJO_TO_UI_TYPE_CASE(DATE_TIME);
+    MOJO_TO_UI_TYPE_CASE(DATE_TIME_LOCAL);
+    MOJO_TO_UI_TYPE_CASE(MONTH);
+    MOJO_TO_UI_TYPE_CASE(TIME);
+    MOJO_TO_UI_TYPE_CASE(WEEK);
+    MOJO_TO_UI_TYPE_CASE(TEXT_AREA);
+    MOJO_TO_UI_TYPE_CASE(CONTENT_EDITABLE);
+    MOJO_TO_UI_TYPE_CASE(DATE_TIME_FIELD);
+  }
+#undef MOJO_TO_UI_TYPE_CASE
+  return false;
+}
+
+// static
+ui::mojom::TextInputMode
+EnumTraits<ui::mojom::TextInputMode, ui::TextInputMode>::ToMojom(
+    ui::TextInputMode text_input_mode) {
+  switch (text_input_mode) {
+    case ui::TEXT_INPUT_MODE_DEFAULT:
+      return ui::mojom::TextInputMode::kDefault;
+    case ui::TEXT_INPUT_MODE_NONE:
+      return ui::mojom::TextInputMode::kNone;
+    case ui::TEXT_INPUT_MODE_TEXT:
+      return ui::mojom::TextInputMode::kText;
+    case ui::TEXT_INPUT_MODE_TEL:
+      return ui::mojom::TextInputMode::kTel;
+    case ui::TEXT_INPUT_MODE_URL:
+      return ui::mojom::TextInputMode::kUrl;
+    case ui::TEXT_INPUT_MODE_EMAIL:
+      return ui::mojom::TextInputMode::kEmail;
+    case ui::TEXT_INPUT_MODE_NUMERIC:
+      return ui::mojom::TextInputMode::kNumeric;
+    case ui::TEXT_INPUT_MODE_DECIMAL:
+      return ui::mojom::TextInputMode::kDecimal;
+    case ui::TEXT_INPUT_MODE_SEARCH:
+      return ui::mojom::TextInputMode::kSearch;
+  }
+  NOTREACHED();
+  return ui::mojom::TextInputMode::kDefault;
+}
+
+// static
+bool EnumTraits<ui::mojom::TextInputMode, ui::TextInputMode>::FromMojom(
+    ui::mojom::TextInputMode input,
+    ui::TextInputMode* out) {
+  switch (input) {
+    case ui::mojom::TextInputMode::kDefault:
+      *out = ui::TEXT_INPUT_MODE_DEFAULT;
+      return true;
+    case ui::mojom::TextInputMode::kNone:
+      *out = ui::TEXT_INPUT_MODE_NONE;
+      return true;
+    case ui::mojom::TextInputMode::kText:
+      *out = ui::TEXT_INPUT_MODE_TEXT;
+      return true;
+    case ui::mojom::TextInputMode::kTel:
+      *out = ui::TEXT_INPUT_MODE_TEL;
+      return true;
+    case ui::mojom::TextInputMode::kUrl:
+      *out = ui::TEXT_INPUT_MODE_URL;
+      return true;
+    case ui::mojom::TextInputMode::kEmail:
+      *out = ui::TEXT_INPUT_MODE_EMAIL;
+      return true;
+    case ui::mojom::TextInputMode::kNumeric:
+      *out = ui::TEXT_INPUT_MODE_NUMERIC;
+      return true;
+    case ui::mojom::TextInputMode::kDecimal:
+      *out = ui::TEXT_INPUT_MODE_DECIMAL;
+      return true;
+    case ui::mojom::TextInputMode::kSearch:
+      *out = ui::TEXT_INPUT_MODE_SEARCH;
+      return true;
+  }
+  return false;
+}
+
+}  // namespace mojo
diff --git a/ui/base/ime/mojo/ime_types_struct_traits.h b/ui/base/ime/mojo/ime_types_struct_traits.h
new file mode 100644
index 0000000..6af23bb
--- /dev/null
+++ b/ui/base/ime/mojo/ime_types_struct_traits.h
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_MOJO_IME_TYPES_STRUCT_TRAITS_H_
+#define UI_BASE_IME_MOJO_IME_TYPES_STRUCT_TRAITS_H_
+
+#include <vector>
+
+#include "ui/base/ime/mojo/ime_types.mojom.h"
+#include "ui/base/ime/text_input_mode.h"
+#include "ui/base/ime/text_input_type.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<ui::mojom::TextInputType, ui::TextInputType> {
+  static ui::mojom::TextInputType ToMojom(ui::TextInputType text_input_type);
+  static bool FromMojom(ui::mojom::TextInputType input, ui::TextInputType* out);
+};
+
+template <>
+struct EnumTraits<ui::mojom::TextInputMode, ui::TextInputMode> {
+  static ui::mojom::TextInputMode ToMojom(ui::TextInputMode text_input_mode);
+  static bool FromMojom(ui::mojom::TextInputMode input, ui::TextInputMode* out);
+};
+
+}  // namespace mojo
+
+#endif  // UI_BASE_IME_MOJO_IME_TYPES_STRUCT_TRAITS_H_
diff --git a/ui/base/ime/mojo/typemaps.gni b/ui/base/ime/mojo/typemaps.gni
new file mode 100644
index 0000000..a0526bf
--- /dev/null
+++ b/ui/base/ime/mojo/typemaps.gni
@@ -0,0 +1,5 @@
+# Copyright 2019 The Chromium 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 = [ "//ui/base/ime/mojo/ime_types.typemap" ]
diff --git a/ui/base/ime/win/tsf_text_store.cc b/ui/base/ime/win/tsf_text_store.cc
index a3ce5d1..3096d8db 100644
--- a/ui/base/ime/win/tsf_text_store.cc
+++ b/ui/base/ime/win/tsf_text_store.cc
@@ -595,7 +595,7 @@
   // If composition_string is empty and there is an existing composition going
   // on, we still need to call into blink to complete the composition.
   if (previous_composition_string_ != composition_string ||
-      (text_input_client_->HasCompositionText() &&
+      (has_composition_range_ && text_input_client_->HasCompositionText() &&
        composition_string.empty())) {
     previous_composition_string_ = composition_string;
 
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index 12e9cd4..28bb7c0 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -16,17 +16,6 @@
     "CalculateNativeWinOcclusion", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // OW_WIN
 
-// Enables the full screen handwriting virtual keyboard behavior.
-const base::Feature kEnableFullscreenHandwritingVirtualKeyboard = {
-    "enable-fullscreen-handwriting-virtual-keyboard",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kEnableStylusVirtualKeyboard = {
-    "enable-stylus-virtual-keyboard", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kEnableVirtualKeyboardUkm = {
-    "EnableVirtualKeyboardUkm", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables all upcoming UI features.
 const base::Feature kExperimentalUi{"ExperimentalUi",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h
index 4bf8738..92db88c4 100644
--- a/ui/base/ui_base_features.h
+++ b/ui/base/ui_base_features.h
@@ -13,12 +13,6 @@
 namespace features {
 
 // Keep sorted!
-COMPONENT_EXPORT(UI_BASE_FEATURES)
-extern const base::Feature kEnableFullscreenHandwritingVirtualKeyboard;
-COMPONENT_EXPORT(UI_BASE_FEATURES)
-extern const base::Feature kEnableStylusVirtualKeyboard;
-COMPONENT_EXPORT(UI_BASE_FEATURES)
-extern const base::Feature kEnableVirtualKeyboardUkm;
 COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kExperimentalUi;
 #if defined(OS_CHROMEOS)
 COMPONENT_EXPORT(UI_BASE_FEATURES)
diff --git a/ui/events/test/platform_event_waiter.cc b/ui/events/test/platform_event_waiter.cc
index 3169bcc..7f645df 100644
--- a/ui/events/test/platform_event_waiter.cc
+++ b/ui/events/test/platform_event_waiter.cc
@@ -4,6 +4,8 @@
 
 #include "ui/events/test/platform_event_waiter.h"
 
+#include <utility>
+
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -11,11 +13,10 @@
 
 namespace ui {
 
-PlatformEventWaiter::PlatformEventWaiter(
-    base::OnceClosure success_callback,
-    const PlatformEventMatcher& event_matcher)
+PlatformEventWaiter::PlatformEventWaiter(base::OnceClosure success_callback,
+                                         PlatformEventMatcher event_matcher)
     : success_callback_(std::move(success_callback)),
-      event_matcher_(event_matcher) {
+      event_matcher_(std::move(event_matcher)) {
   PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
 }
 
@@ -37,8 +38,9 @@
 // static
 PlatformEventWaiter* PlatformEventWaiter::Create(
     base::OnceClosure success_callback,
-    const PlatformEventMatcher& event_matcher) {
-  return new PlatformEventWaiter(std::move(success_callback), event_matcher);
+    PlatformEventMatcher event_matcher) {
+  return new PlatformEventWaiter(std::move(success_callback),
+                                 std::move(event_matcher));
 }
 
 }  // namespace ui
diff --git a/ui/events/test/platform_event_waiter.h b/ui/events/test/platform_event_waiter.h
index 9c3ed4c..c43c56c 100644
--- a/ui/events/test/platform_event_waiter.h
+++ b/ui/events/test/platform_event_waiter.h
@@ -13,14 +13,15 @@
 
 class PlatformEventWaiter : public PlatformEventObserver {
  public:
-  typedef base::Callback<bool(const PlatformEvent&)> PlatformEventMatcher;
+  using PlatformEventMatcher =
+      base::RepeatingCallback<bool(const PlatformEvent&)>;
 
   static PlatformEventWaiter* Create(base::OnceClosure success_callback,
-                                     const PlatformEventMatcher& event_matcher);
+                                     PlatformEventMatcher event_matcher);
 
  private:
   PlatformEventWaiter(base::OnceClosure success_callback,
-                      const PlatformEventMatcher& event_matcher);
+                      PlatformEventMatcher event_matcher);
   ~PlatformEventWaiter() override;
 
   // PlatformEventObserver:
diff --git a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
index 35bfb1a..2784ce4 100644
--- a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
@@ -212,10 +212,13 @@
   const paths = breadcrumbsPath.split('/').filter(path => path);
   const leaf = paths.pop();
 
-  // Expand all parents of the leaf element.
+  // Expand all parents of the leaf entry.
   let query = '#directory-tree';
   for (const parentLabel of paths) {
     query += ` [entry-label="${parentLabel}"]`;
+    // Wait for parent element to be displayed.
+    await remoteCall.waitForElement(appId, query);
+
     // Only expand if element isn't expanded yet.
     const elements = await remoteCall.callRemoteTestUtil(
         'queryAllElements', appId, [query + '[expanded]']);
@@ -225,12 +228,15 @@
     }
   }
 
-  // Navigate to leaf entry.
+  // Wait for the final entry to be displayed.
   query += ` [entry-label="${leaf}"]`;
+  await remoteCall.waitForElement(appId, query);
+
+  // Navigate to the final entry.
   chrome.test.assertTrue(
       !!await remoteCall.callRemoteTestUtil('fakeMouseClick', appId, [query]),
       'fakeMouseClick failed');
-  // Wait to navigation to leaf entry to finish.
+  // Wait to navigation to final entry to finish.
   await remoteCall.waitUntilCurrentDirectoryIsChanged(
       appId, (shortcutToPath || breadcrumbsPath));
 
@@ -844,6 +850,41 @@
 };
 
 /**
+ * Tests context menu for USB root with DCIM folder.
+ */
+testcase.dirContextMenuUsbDcim = async () => {
+  const usbMenus = [
+    ['#unmount', true],
+    ['#format', true],
+    ['#rename', false],
+    ['#share-with-linux', true],
+  ];
+  const dcimFolderMenus = [
+    ['#cut', true],
+    ['#copy', true],
+    ['#paste-into-folder', false],
+    ['#share-with-linux', true],
+    ['#rename', true],
+    ['#delete', true],
+    ['#new-folder', true],
+  ];
+
+  // Mount removable volumes.
+  await sendTestMessage({name: 'mountFakeUsbDcim'});
+
+  // Open Files app on local Downloads.
+  const appId =
+      await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.beautiful], []);
+
+  // Check the context menu for single partition USB.
+  await checkContextMenu(appId, '/fake-usb', usbMenus, true /* rootMenu */);
+
+  // Check the context menu for the DCIM folder inside USB.
+  await checkContextMenu(
+      appId, '/fake-usb/DCIM', dcimFolderMenus, false /* rootMenu */);
+};
+
+/**
  * Tests context menu for FSP root and a folder inside it.
  */
 testcase.dirContextMenuFsp = async () => {
diff --git a/ui/keyboard/keyboard_ukm_recorder.cc b/ui/keyboard/keyboard_ukm_recorder.cc
index 925557dd7..7deb27a 100644
--- a/ui/keyboard/keyboard_ukm_recorder.cc
+++ b/ui/keyboard/keyboard_ukm_recorder.cc
@@ -11,10 +11,8 @@
 
 void RecordUkmKeyboardShown(ukm::SourceId source,
                             const ui::TextInputType& input_type) {
-  if (source == ukm::kInvalidSourceId ||
-      !base::FeatureList::IsEnabled(features::kEnableVirtualKeyboardUkm)) {
+  if (source == ukm::kInvalidSourceId)
     return;
-  }
 
   ukm::builders::VirtualKeyboard_Open(source)
       .SetTextInputType(input_type)
diff --git a/ui/keyboard/keyboard_ukm_recorder_unittest.cc b/ui/keyboard/keyboard_ukm_recorder_unittest.cc
index 35c28be..b0bfea30 100644
--- a/ui/keyboard/keyboard_ukm_recorder_unittest.cc
+++ b/ui/keyboard/keyboard_ukm_recorder_unittest.cc
@@ -4,21 +4,16 @@
 
 #include "ui/keyboard/keyboard_ukm_recorder.h"
 
-#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/text_input_type.h"
-#include "ui/base/ui_base_features.h"
 
 namespace keyboard {
 
 TEST(KeyboardUkmRecorderTest, RecordUkmWithEmptySource) {
   base::test::ScopedTaskEnvironment env;
 
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kEnableVirtualKeyboardUkm);
-
   ukm::TestAutoSetUkmRecorder test_recorder;
   test_recorder.EnableRecording(false /* extensions */);
   EXPECT_EQ(0u, test_recorder.entries_count());
@@ -32,9 +27,6 @@
 TEST(KeyboardUkmRecorderTest, RecordUkmWithNavigationId) {
   base::test::ScopedTaskEnvironment env;
 
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kEnableVirtualKeyboardUkm);
-
   ukm::TestAutoSetUkmRecorder test_recorder;
   test_recorder.EnableRecording(false /* extensions */);
   ASSERT_EQ(0u, test_recorder.entries_count());
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index 71aff7a..fb259a60 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -1209,6 +1209,7 @@
     if (message_view_)
       message_view_->SizeToFit(kMessageViewWidth);
   }
+  content_row_->InvalidateLayout();
 }
 
 void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) {
@@ -1270,7 +1271,6 @@
   expanded_ = expanded;
 
   UpdateViewForExpandedState(expanded_);
-  content_row_->InvalidateLayout();
   PreferredSizeChanged();
 }
 
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h
index a36343d..3e8765b 100644
--- a/ui/message_center/views/notification_view_md.h
+++ b/ui/message_center/views/notification_view_md.h
@@ -209,24 +209,25 @@
 
  private:
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, CreateOrUpdateTest);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestIconSizing);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonsStateTest);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonCountTest);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, ExpandLongMessage);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, InlineSettings);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, NotificationWithoutIcon);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestAccentColor);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestActionButtonClick);
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestClick);
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestClickExpanded);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestActionButtonClick);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
+                           TestDeleteOnDisableNotification);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestDeleteOnToggleExpanded);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestIconSizing);
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestInlineReply);
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
                            TestInlineReplyRemovedByUpdate);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, ExpandLongMessage);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestAccentColor);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UseImageAsIcon);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, NotificationWithoutIcon);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, InlineSettings);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateAddingIcon);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonCountTest);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonsStateTest);
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateViewsOrderingTest);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestDeleteOnToggleExpanded);
-  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
-                           TestDeleteOnDisableNotification);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UseImageAsIcon);
 
   friend class NotificationViewMDTest;
 
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc
index dad0e37..d1f146c 100644
--- a/ui/message_center/views/notification_view_md_unittest.cc
+++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -1033,6 +1033,31 @@
   EXPECT_FALSE(notification_view()->right_content_->visible());
 }
 
+TEST_F(NotificationViewMDTest, UpdateAddingIcon) {
+  const int kNotificationIconSize = 30;
+
+  // Create a notification without an icon.
+  std::unique_ptr<Notification> notification = CreateSimpleNotification();
+  notification->set_icon(gfx::Image());
+  notification->set_image(gfx::Image());
+  UpdateNotificationViews(*notification);
+
+  // Capture the width of the left content without an icon.
+  const int left_content_width = notification_view()->left_content_->width();
+
+  // Update the notification, adding an icon.
+  notification->set_icon(
+      CreateTestImage(kNotificationIconSize, kNotificationIconSize));
+  UpdateNotificationViews(*notification);
+
+  // Notification should now have an icon.
+  EXPECT_TRUE(notification_view()->icon_view_->visible());
+  EXPECT_TRUE(notification_view()->right_content_->visible());
+
+  // There should be some space now to show the icon.
+  EXPECT_LT(notification_view()->left_content_->width(), left_content_width);
+}
+
 TEST_F(NotificationViewMDTest, InlineSettings) {
   std::unique_ptr<Notification> notification = CreateSimpleNotification();
   notification->set_type(NOTIFICATION_TYPE_SIMPLE);
diff --git a/ui/platform_window/mojo/BUILD.gn b/ui/platform_window/mojo/BUILD.gn
index 803e2e34..4a344c3 100644
--- a/ui/platform_window/mojo/BUILD.gn
+++ b/ui/platform_window/mojo/BUILD.gn
@@ -11,7 +11,7 @@
   output_name = "mojo_ime_lib"
 
   public_deps = [
-    "//ui/base/ime",
+    "//ui/base/ime:ime_types",
   ]
   deps = [
     ":interfaces",
@@ -32,4 +32,8 @@
   sources = [
     "text_input_state.mojom",
   ]
+
+  public_deps = [
+    "//ui/base/ime/mojo",
+  ]
 }
diff --git a/ui/platform_window/mojo/ime_type_converters.cc b/ui/platform_window/mojo/ime_type_converters.cc
index f4e438de..9435045 100644
--- a/ui/platform_window/mojo/ime_type_converters.cc
+++ b/ui/platform_window/mojo/ime_type_converters.cc
@@ -50,20 +50,6 @@
 TEXT_INPUT_FLAG_ASSERT(AUTOCAPITALIZE_SENTENCES);
 
 // static
-ui::mojom::TextInputType
-TypeConverter<ui::mojom::TextInputType, ui::TextInputType>::Convert(
-    const ui::TextInputType& input) {
-  return static_cast<ui::mojom::TextInputType>(input);
-}
-
-// static
-ui::TextInputType
-TypeConverter<ui::TextInputType, ui::mojom::TextInputType>::Convert(
-    const ui::mojom::TextInputType& input) {
-  return static_cast<ui::TextInputType>(input);
-}
-
-// static
 ui::TextInputState
 TypeConverter<ui::TextInputState, ui::mojom::TextInputStatePtr>::Convert(
     const ui::mojom::TextInputStatePtr& input) {
diff --git a/ui/platform_window/mojo/ime_type_converters.h b/ui/platform_window/mojo/ime_type_converters.h
index c970c9a..a55125d 100644
--- a/ui/platform_window/mojo/ime_type_converters.h
+++ b/ui/platform_window/mojo/ime_type_converters.h
@@ -14,18 +14,6 @@
 
 template <>
 struct MOJO_IME_EXPORT
-    TypeConverter<ui::mojom::TextInputType, ui::TextInputType> {
-  static ui::mojom::TextInputType Convert(const ui::TextInputType& input);
-};
-
-template <>
-struct MOJO_IME_EXPORT
-    TypeConverter<ui::TextInputType, ui::mojom::TextInputType> {
-  static ui::TextInputType Convert(const ui::mojom::TextInputType& input);
-};
-
-template <>
-struct MOJO_IME_EXPORT
     TypeConverter<ui::TextInputState, ui::mojom::TextInputStatePtr> {
   static ui::TextInputState Convert(const ui::mojom::TextInputStatePtr& input);
 };
diff --git a/ui/platform_window/mojo/text_input_state.mojom b/ui/platform_window/mojo/text_input_state.mojom
index 40f3318..21767a5 100644
--- a/ui/platform_window/mojo/text_input_state.mojom
+++ b/ui/platform_window/mojo/text_input_state.mojom
@@ -4,43 +4,7 @@
 
 module ui.mojom;
 
-// Text input type which is based on blink::WebTextInputType.
-enum TextInputType {
-  NONE,
-  TEXT,
-  PASSWORD,
-  SEARCH,
-  EMAIL,
-  NUMBER,
-  TELEPHONE,
-  URL,
-  DATE,
-  DATE_TIME,
-  DATE_TIME_LOCAL,
-  MONTH,
-  TIME,
-  WEEK,
-  TEXT_AREA,
-  CONTENT_EDITABLE,
-  DATE_TIME_FIELD,
-  MAX = DATE_TIME_FIELD,
-};
-
-// Text input flag which is based on blink::WebTextInputFlags.
-enum TextInputFlag {
-  NONE,
-  AUTOCOMPLETE_ON = 0x001,
-  AUTOCOMPLETE_OFF = 0x002,
-  AUTOCORRECT_ON = 0x004,
-  AUTOCORRECT_OFF = 0x008,
-  SPELLCHECK_ON = 0x010,
-  SPELLCHECK_OFF = 0x020,
-  AUTOCAPITALIZE_NONE = 0x040,
-  AUTOCAPITALIZE_CHARACTERS = 0x080,
-  AUTOCAPITALIZE_WORDS = 0x100,
-  AUTOCAPITALIZE_SENTENCES = 0x200,
-  ALL = 0x3FF,
-};
+import "ui/base/ime/mojo/ime_types.mojom";
 
 // Text input info which is based on blink::WebTextInputInfo.
 struct TextInputState {
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 7b59afbc..a09510e 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -787,6 +787,7 @@
       "AppKit.framework",
       "CoreGraphics.framework",
       "Foundation.framework",
+      "IOSurface.framework",
       "QuartzCore.framework",  # Required by bridged_native_widget.mm.
     ]
   }
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.h b/ui/views/cocoa/bridged_native_widget_host_impl.h
index 86b1588..9403ce4 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.h
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -426,6 +426,12 @@
   // Display link for getting vsync info for |display_|.
   scoped_refptr<ui::DisplayLinkMac> display_link_;
 
+  // Structure to avoid sending IOSurface mach ports over mojo.
+  // https://crbug.com/942213
+  class IOSurfaceToRemoteLayerInterceptor;
+  std::unique_ptr<IOSurfaceToRemoteLayerInterceptor>
+      io_surface_to_remote_layer_interceptor_;
+
   // The geometry of the window and its contents view, in screen coordinates.
   gfx::Rect window_bounds_in_screen_;
   gfx::Rect content_bounds_in_screen_;
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.mm b/ui/views/cocoa/bridged_native_widget_host_impl.mm
index 9b47a69..291c8bb 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.mm
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -9,7 +9,9 @@
 #include "base/mac/foundation_util.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
+#include "ui/base/cocoa/animation_utils.h"
 #include "ui/base/cocoa/remote_accessibility_api.h"
+#include "ui/base/cocoa/remote_layer_api.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/input_method_factory.h"
@@ -206,6 +208,60 @@
 
 }  // namespace
 
+// A gfx::CALayerParams may pass the content to be drawn across processes via
+// either an IOSurface (sent as mach port) or a CAContextID (which is an
+// integer). For historical reasons, software compositing uses IOSurfaces.
+// The mojo connection to the app shim process does not support sending mach
+// ports, which results in nothing being drawn when using software compositing.
+// To work around this issue, this structure creates a CALayer that uses the
+// IOSurface as its contents, and hosts this CALayer in a CAContext that is
+// the gfx::CALayerParams is then pointed to.
+// https://crbug.com/942213
+class BridgedNativeWidgetHostImpl::IOSurfaceToRemoteLayerInterceptor {
+ public:
+  IOSurfaceToRemoteLayerInterceptor() = default;
+  ~IOSurfaceToRemoteLayerInterceptor() = default;
+
+  void UpdateCALayerParams(gfx::CALayerParams* ca_layer_params) {
+    DCHECK(ca_layer_params->io_surface_mach_port);
+    base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
+        IOSurfaceLookupFromMachPort(ca_layer_params->io_surface_mach_port));
+
+    ScopedCAActionDisabler disabler;
+    // Lazily create |io_surface_layer_| and |ca_context_|.
+    if (!io_surface_layer_) {
+      io_surface_layer_.reset([[CALayer alloc] init]);
+      [io_surface_layer_ setContentsGravity:kCAGravityTopLeft];
+      [io_surface_layer_ setAnchorPoint:CGPointMake(0, 0)];
+    }
+    if (!ca_context_) {
+      CGSConnectionID connection_id = CGSMainConnectionID();
+      ca_context_.reset([[CAContext contextWithCGSConnection:connection_id
+                                                     options:@{}] retain]);
+      [ca_context_ setLayer:io_surface_layer_];
+    }
+
+    // Update |io_surface_layer_| to draw the contents of |ca_layer_params|.
+    id new_contents = static_cast<id>(io_surface.get());
+    [io_surface_layer_ setContents:new_contents];
+    gfx::Size bounds_dip = gfx::ConvertSizeToDIP(ca_layer_params->scale_factor,
+                                                 ca_layer_params->pixel_size);
+    [io_surface_layer_
+        setBounds:CGRectMake(0, 0, bounds_dip.width(), bounds_dip.height())];
+    if ([io_surface_layer_ contentsScale] != ca_layer_params->scale_factor)
+      [io_surface_layer_ setContentsScale:ca_layer_params->scale_factor];
+
+    // Change |ca_layer_params| to use |ca_context_| instead of an IOSurface.
+    ca_layer_params->ca_context_id = [ca_context_ contextId];
+    ca_layer_params->io_surface_mach_port.reset();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(IOSurfaceToRemoteLayerInterceptor);
+  base::scoped_nsobject<CAContext> ca_context_;
+  base::scoped_nsobject<CALayer> io_surface_layer_;
+};
+
 // static
 BridgedNativeWidgetHostImpl* BridgedNativeWidgetHostImpl::GetFromNativeWindow(
     gfx::NativeWindow native_window) {
@@ -1358,8 +1414,26 @@
 void BridgedNativeWidgetHostImpl::AcceleratedWidgetCALayerParamsUpdated() {
   const gfx::CALayerParams* ca_layer_params =
       compositor_->widget()->GetCALayerParams();
-  if (ca_layer_params)
-    bridge()->SetCALayerParams(*ca_layer_params);
+  if (ca_layer_params) {
+    // Replace IOSurface mach ports with CAContextIDs only when using the
+    // out-of-process bridge (to reduce risk, because this workaround is being
+    // merged to late-life-cycle release branches) and when an IOSurface
+    // mach port has been specified (in practice, when software compositing is
+    // enabled).
+    // https://crbug.com/942213
+    if (bridge_ptr_ && ca_layer_params->io_surface_mach_port) {
+      gfx::CALayerParams updated_ca_layer_params = *ca_layer_params;
+      if (!io_surface_to_remote_layer_interceptor_) {
+        io_surface_to_remote_layer_interceptor_ =
+            std::make_unique<IOSurfaceToRemoteLayerInterceptor>();
+      }
+      io_surface_to_remote_layer_interceptor_->UpdateCALayerParams(
+          &updated_ca_layer_params);
+      bridge_ptr_->SetCALayerParams(updated_ca_layer_params);
+    } else {
+      bridge()->SetCALayerParams(*ca_layer_params);
+    }
+  }
 
   // Take this opportunity to update the VSync parameters, if needed.
   if (display_link_) {
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index 99cbf309..3a78590 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -318,12 +318,18 @@
   DCHECK(item);
   submenu_->RemoveChildView(item);
 
-  // RemoveChildView() does not delete the item, which is a good thing
-  // in case a submenu is being displayed while items are being removed.
-  // Deletion will be done by ChildrenChanged() or at destruction.
   removed_items_.push_back(item);
 }
 
+void MenuItemView::RemoveAllMenuItems() {
+  DCHECK(submenu_);
+
+  for (int i = 0; i < submenu_->child_count(); ++i)
+    removed_items_.push_back(submenu_->child_at(i));
+
+  submenu_->RemoveAllChildViews(false);
+}
+
 MenuItemView* MenuItemView::AppendMenuItem(int item_id,
                                            const base::string16& label,
                                            Type type) {
diff --git a/ui/views/controls/menu/menu_item_view.h b/ui/views/controls/menu/menu_item_view.h
index 02309b2..6ef514d4 100644
--- a/ui/views/controls/menu/menu_item_view.h
+++ b/ui/views/controls/menu/menu_item_view.h
@@ -171,6 +171,10 @@
   // is deleted when ChildrenChanged() is invoked.
   void RemoveMenuItemAt(int index);
 
+  // Removes all items from the menu.  The removed MenuItemViews are deleted
+  // when ChildrenChanged() is invoked.
+  void RemoveAllMenuItems();
+
   // Appends an item to this menu.
   // item_id    The id of the item, used to identify it in delegate callbacks
   //            or (if delegate is NULL) to identify the command associated
diff --git a/ui/views/controls/menu/menu_model_adapter.cc b/ui/views/controls/menu/menu_model_adapter.cc
index 6fa4fcd..8b75a57 100644
--- a/ui/views/controls/menu/menu_model_adapter.cc
+++ b/ui/views/controls/menu/menu_model_adapter.cc
@@ -37,11 +37,8 @@
   DCHECK(menu);
 
   // Clear the menu.
-  if (menu->HasSubmenu()) {
-    const int subitem_count = menu->GetSubmenu()->child_count();
-    for (int i = 0; i < subitem_count; ++i)
-      menu->RemoveMenuItemAt(0);
-  }
+  if (menu->HasSubmenu())
+    menu->RemoveAllMenuItems();
 
   // Leave entries in the map if the menu is being shown.  This
   // allows the map to find the menu model of submenus being closed
diff --git a/ui/views/test/ui_controls_factory_desktop_aurax11.cc b/ui/views/test/ui_controls_factory_desktop_aurax11.cc
index 0180b30d..df718d54 100644
--- a/ui/views/test/ui_controls_factory_desktop_aurax11.cc
+++ b/ui/views/test/ui_controls_factory_desktop_aurax11.cc
@@ -237,7 +237,8 @@
     }
     marker_event->xclient.message_type = MarkerEventAtom();
     XSendEvent(x_display_, x_window_, x11::False, 0, marker_event);
-    ui::PlatformEventWaiter::Create(std::move(closure), base::Bind(&Matcher));
+    ui::PlatformEventWaiter::Create(std::move(closure),
+                                    base::BindRepeating(&Matcher));
   }
  private:
   aura::Window* RootWindowForPoint(const gfx::Point& point) {