diff --git a/.gn b/.gn
index ebe0f3a..20f2aad 100644
--- a/.gn
+++ b/.gn
@@ -29,22 +29,7 @@
   # also needs to be defined to src/ios/BUILD.gn (respectively removed from both
   # location when it is removed).
 
-  v8_extra_library_files = [
-    # Do *not* add more files to this list. V8 extra libraries is deprecated.
-    # TODO(902633): This list is be removed once streams are ported to C++.
-    # Dependencies used by the extra libraries. Putting them here causes them
-    # to be executed first during snapshot creation.
-    "//third_party/blink/renderer/core/streams/CommonOperations.js",
-    "//third_party/blink/renderer/core/streams/CommonStrings.js",
-    "//third_party/blink/renderer/core/streams/SimpleQueue.js",
-
-    # Extra libraries.
-    "//third_party/blink/renderer/core/streams/ByteLengthQueuingStrategy.js",
-    "//third_party/blink/renderer/core/streams/CountQueuingStrategy.js",
-    "//third_party/blink/renderer/core/streams/ReadableStream.js",
-    "//third_party/blink/renderer/core/streams/WritableStream.js",
-    "//third_party/blink/renderer/core/streams/TransformStream.js",
-  ]
+  v8_extra_library_files = []
   v8_experimental_extra_library_files = []
   v8_enable_gdbjit = false
   v8_imminent_deprecation_warnings = false
@@ -71,6 +56,7 @@
 # their includes checked for proper dependencies when you run either
 # "gn check" or "gn gen --check".
 check_targets = [
+  "//android_webview/*",
   "//apps/*",
   "//ash/*",
   "//base/*",
diff --git a/DEPS b/DEPS
index ce8c9b4..b93476c 100644
--- a/DEPS
+++ b/DEPS
@@ -167,11 +167,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': '674f77a24b6223604f582ee1f9dbaf8f8b973bd9',
+  'skia_revision': '1ebaa15a4c62453f5eeac71a5ba33e4dd6da566e',
   # 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': 'b3ced8d6a148ff54cf44cd9bcb61f9e3e65a3437',
+  'v8_revision': '23dacd6b32b6767f9bde088e80e70c054c825c22',
   # 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.
@@ -179,11 +179,11 @@
   # 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': '616a4dc0f2fbb2f24c9aa05d831b1d527bd6221b',
+  'angle_revision': 'f22f16d3c0a80ce7bbc4a8eeff81fde63aa6ad40',
   # 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': 'df782a7348d8818a138e6eea28bd5767241143bd',
+  'swiftshader_revision': '0cd9a67ce84f0083fef7aee7e0f3a0e5e59b8053',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -230,7 +230,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '16236fcfbe3194b31ba4fe7214fb3f78e5aa33c1',
+  'catapult_revision': '017b54db6bea7cae9c65896a4f4846209485212d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -302,7 +302,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': 'c15160f3ab08dcbb31adeac8490b394ed89a6d5b',
+  'dawn_revision': 'dc9f1e68069917f29d552d9cb0b7993fcb7c4059',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -862,7 +862,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '40b3bbb9073b04751ff33799ad163d785c24412c',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '98592f6c5dbe68b65645be7d0f0277757f0a09c7',
       'condition': 'checkout_linux',
   },
 
@@ -887,7 +887,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b9aca9494e40d24ee7383b237943dc7c8aa86ad8',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '5eac9d301390c5ff8afdaa95f46e68bb84e20575',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1521,7 +1521,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f0ba4163ae1474bf93d9ae3a9a119f21fab5596c',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@eb06828e0343cd99de93721890618db0490ab8cd',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/tools/system_webview_shell/BUILD.gn b/android_webview/tools/system_webview_shell/BUILD.gn
index fe78b4d..f21ba2a0 100644
--- a/android_webview/tools/system_webview_shell/BUILD.gn
+++ b/android_webview/tools/system_webview_shell/BUILD.gn
@@ -38,6 +38,7 @@
     ":system_webview_shell_apk_resources",
     "//base:base_java",
     "//third_party/android_deps:android_support_v7_appcompat_java",
+    "//third_party/guava:guava_android_java",
   ]
 }
 
diff --git a/android_webview/tools/system_webview_shell/apk/res/layout/activity_web_platform_tests.xml b/android_webview/tools/system_webview_shell/apk/res/layout/activity_web_platform_tests.xml
index 1b9654f..2116393 100644
--- a/android_webview/tools/system_webview_shell/apk/res/layout/activity_web_platform_tests.xml
+++ b/android_webview/tools/system_webview_shell/apk/res/layout/activity_web_platform_tests.xml
@@ -9,9 +9,10 @@
   <WebView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
-      android:id="@+id/webview"
+      android:id="@+id/rootWebView"
       android:layout_gravity="center_horizontal"
       android:layout_alignParentStart="true"
       android:layout_marginStart="0dp"
       />
+  <!-- All child layouts will be inserted here linearly. -->
 </RelativeLayout>
diff --git a/android_webview/tools/system_webview_shell/apk/res/layout/activity_web_platform_tests_child.xml b/android_webview/tools/system_webview_shell/apk/res/layout/activity_web_platform_tests_child.xml
index 8efb43b..033ecd52 100644
--- a/android_webview/tools/system_webview_shell/apk/res/layout/activity_web_platform_tests_child.xml
+++ b/android_webview/tools/system_webview_shell/apk/res/layout/activity_web_platform_tests_child.xml
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
-    tools:ignore="UselessParent"
     android:orientation="vertical"
     android:background="@android:color/black"
+    android:id="@+id/childLayout"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:id="@+id/childLayout">
+    android:layout_height="match_parent">
   <LinearLayout
       android:orientation="horizontal"
       android:layout_width="match_parent"
@@ -44,4 +44,4 @@
       android:layout_height="match_parent"
       android:id="@+id/childWebView"
       />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebPlatformTestsActivity.java b/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebPlatformTestsActivity.java
index 706b87a..699ed3b 100644
--- a/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebPlatformTestsActivity.java
+++ b/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebPlatformTestsActivity.java
@@ -20,6 +20,9 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
 
@@ -28,10 +31,8 @@
  *
  * This is currently implemented to support minimum viable implementation such that
  * multi-window and JavaScript are enabled by default.
- *
- * TODO(crbug.com/994939): It is currently implemented to support only a single child. Although not
- *                         explicitly stated, there may be some WPT tests that require more than one
- *                         children, which is not supported for now.
+ * Note: multi-window support in this shell is implemented, but due to a bug
+ *       in WebView (https://crbug.com/100272), it does not work properly unless a delay is given.
  */
 public class WebPlatformTestsActivity extends Activity {
     private static final String TAG = "WPTActivity";
@@ -43,55 +44,53 @@
     @VisibleForTesting
     public interface TestCallback {
         /** Called after child layout is added. */
-        void onChildLayoutAdded();
+        void onChildLayoutAdded(WebView webView);
         /** Called after child layout is removed. */
         void onChildLayoutRemoved();
     }
 
+    private BiMap<ViewGroup, WebView> mLayoutToWebViewBiMap = HashBiMap.create();
+
     private LayoutInflater mLayoutInflater;
     private RelativeLayout mRootLayout;
     private WebView mWebView;
-    private WebView mChildWebView;
-    private LinearLayout mChildLayout;
     private TestCallback mTestCallback;
 
     private class MultiWindowWebChromeClient extends WebChromeClient {
         @Override
         public boolean onCreateWindow(
-                WebView webView, boolean isDialog, boolean isUserGesture, Message resultMsg) {
+                WebView parentWebView, boolean isDialog, boolean isUserGesture, Message resultMsg) {
             if (DEBUG) Log.i(TAG, "onCreateWindow");
-            mChildLayout = createChildLayout();
-            mChildWebView = mChildLayout.findViewById(R.id.childWebView);
-            setUpWebSettings(mChildWebView.getSettings());
-            mChildWebView.setWebViewClient(new WebViewClient() {
+            WebView childWebView = createChildLayoutAndGetNewWebView(parentWebView);
+            WebSettings settings = childWebView.getSettings();
+            setUpWebSettings(settings);
+            childWebView.setWebViewClient(new WebViewClient() {
                 @Override
                 public void onPageFinished(WebView childWebView, String url) {
+                    if (DEBUG) Log.i(TAG, "onPageFinished");
                     // Once the view has loaded, display its title for debugging.
-                    TextView childTitleText = mChildLayout.findViewById(R.id.childTitleText);
+                    ViewGroup childLayout = mLayoutToWebViewBiMap.inverse().get(childWebView);
+                    TextView childTitleText = childLayout.findViewById(R.id.childTitleText);
                     childTitleText.setText(childWebView.getTitle());
                 }
             });
-            mChildWebView.setWebChromeClient(new WebChromeClient() {
-                @Override
-                public void onCloseWindow(WebView childWebView) {
-                    closeChild();
-                }
-            });
-            // Add the new WebView to the layout
-            mChildWebView.setLayoutParams(
-                    new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
-                            LinearLayout.LayoutParams.MATCH_PARENT));
+            childWebView.setWebChromeClient(new MultiWindowWebChromeClient());
             // Tell the transport about the new view
             WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
-            transport.setWebView(mChildWebView);
+            transport.setWebView(childWebView);
             resultMsg.sendToTarget();
-            if (mTestCallback != null) mTestCallback.onChildLayoutAdded();
+            if (mTestCallback != null) mTestCallback.onChildLayoutAdded(childWebView);
             return true;
         }
 
         @Override
         public void onCloseWindow(WebView webView) {
-            // Ignore window.close() on the test runner window.
+            ViewGroup childLayout = mLayoutToWebViewBiMap.inverse().get(webView);
+            if (childLayout == mRootLayout) {
+                Log.w(TAG, "Ignoring onCloseWindow() on the top-level webview.");
+            } else {
+                closeChild(childLayout);
+            }
         }
     }
 
@@ -115,7 +114,8 @@
         mLayoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         setContentView(R.layout.activity_web_platform_tests);
         mRootLayout = findViewById(R.id.rootLayout);
-        mWebView = findViewById(R.id.webview);
+        mWebView = mRootLayout.findViewById(R.id.rootWebView);
+        mLayoutToWebViewBiMap.put(mRootLayout, mWebView);
 
         String url = getUrlFromIntent();
         if (url == null) {
@@ -134,21 +134,23 @@
         super.onDestroy();
         removeAndDestroyWebView(mWebView);
         mWebView = null;
-        removeAndDestroyWebView(mChildWebView);
-        mChildWebView = null;
     }
 
-    private LinearLayout createChildLayout() {
+    private WebView createChildLayoutAndGetNewWebView(WebView parentWebView) {
+        // Add all the child layouts to the root layout such that we can remove
+        // a child layout without affecting any grand child layout.
+        final ViewGroup parentLayout = mRootLayout;
         // Provide parent such that MATCH_PARENT layout params can work. Ignore the return value
-        // which is mRootLayout.
-        mLayoutInflater.inflate(R.layout.activity_web_platform_tests_child, mRootLayout);
+        // which is parentLayout.
+        mLayoutInflater.inflate(R.layout.activity_web_platform_tests_child, parentLayout);
         // Choose what has just been added.
         LinearLayout childLayout =
-                (LinearLayout) mRootLayout.getChildAt(mRootLayout.getChildCount() - 1);
-
+                (LinearLayout) parentLayout.getChildAt(parentLayout.getChildCount() - 1);
         Button childCloseButton = childLayout.findViewById(R.id.childCloseButton);
-        childCloseButton.setOnClickListener((View v) -> { closeChild(); });
-        return childLayout;
+        childCloseButton.setOnClickListener((View v) -> { closeChild(childLayout); });
+        WebView childWebView = childLayout.findViewById(R.id.childWebView);
+        mLayoutToWebViewBiMap.put(childLayout, childWebView);
+        return childWebView;
     }
 
     private void setUpWebSettings(WebSettings settings) {
@@ -168,15 +170,13 @@
         mWebView.loadUrl(url);
     }
 
-    private void closeChild() {
+    private void closeChild(ViewGroup childLayout) {
         if (DEBUG) Log.i(TAG, "closeChild");
-        removeAndDestroyWebView(mChildWebView);
-        mChildWebView = null;
-
-        assert mChildLayout != null;
-        ViewGroup parent = (ViewGroup) mChildLayout.getParent();
-        parent.removeView(mChildLayout);
-        mChildLayout = null;
+        ViewGroup parent = (ViewGroup) childLayout.getParent();
+        if (parent != null) parent.removeView(childLayout);
+        WebView childWebView = mLayoutToWebViewBiMap.get(childLayout);
+        removeAndDestroyWebView(childWebView);
+        mLayoutToWebViewBiMap.remove(childLayout, childWebView);
         if (mTestCallback != null) mTestCallback.onChildLayoutRemoved();
     }
 
diff --git a/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebPlatformTestsActivityTest.java b/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebPlatformTestsActivityTest.java
index 52538e93..eb1a78080 100644
--- a/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebPlatformTestsActivityTest.java
+++ b/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebPlatformTestsActivityTest.java
@@ -6,6 +6,7 @@
 
 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 
+import android.os.Handler;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
@@ -20,30 +21,43 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.webview_shell.WebPlatformTestsActivity;
 
+import java.util.ArrayList;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Tests to ensure that system webview shell can handle WPT tests correctly.
  */
 @RunWith(BaseJUnit4ClassRunner.class)
 public class WebPlatformTestsActivityTest {
-    private static final String OPEN_TEST_WINDOW_SCRIPT =
+    private static final int CHILD_LAYOUT_ADDED = 1;
+    private static final int CHILD_LAYOUT_REMOVED = 2;
+
+    private static final long TEST_TIMEOUT_IN_SECONDS = scaleTimeout(3);
+    private static final long ON_CREATE_WINDOW_DELAY_MS = 100;
+
+    private static final String OPEN_CLOSE_TEST_WINDOW_SCRIPT =
             "<html><head><script>function ensure_test_window() {"
             + "  if (!this.test_window || this.test_window.location === null) {"
             + "    this.test_window = window.open('about:blank', 800, 600);"
-            // https://crbug.com/1002727
-            + "    setTimeout(function() { this.test_window.close(); }, 50);"
+            // Adding delay due to https://crbug.com/1002727
+            + "    setTimeout(function() { this.test_window.close(); }, "
+            + ON_CREATE_WINDOW_DELAY_MS + ");"
             + "  }"
             + "};"
             + "ensure_test_window();"
             + "</script></head><body>TestRunner Window</body></html>";
 
-    private static final int CHILD_LAYOUT_ADDED = 1;
-    private static final int CHILD_LAYOUT_REMOVED = 2;
-
-    private static final long TEST_TIMEOUT_IN_SECONDS = scaleTimeout(3);
+    private static final String MULTIPLE_OPEN_CLOSE_TEST_WINDOW_SCRIPT =
+            "<html><head><script>function ensure_test_window() {"
+            + "  if (!this.test_window || this.test_window.location === null) {"
+            + "    this.test_window = window.open('about:blank', 800, 600);"
+            + "  }"
+            + "};"
+            + "ensure_test_window();"
+            + "</script></head><body>TestRunner Window</body></html>";
 
     private WebPlatformTestsActivity mTestActivity;
 
@@ -58,13 +72,13 @@
 
     @Test
     @MediumTest
-    public void testOpenDestroyWindowFromTestRunner() throws Exception {
+    public void testOpenCloseWindow() throws Exception {
         final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mTestActivity.setTestCallback(new WebPlatformTestsActivity.TestCallback() {
                 @Override
-                public void onChildLayoutAdded() {
+                public void onChildLayoutAdded(WebView webView) {
                     queue.add(CHILD_LAYOUT_ADDED);
                 }
 
@@ -74,13 +88,77 @@
                 }
             });
             WebView webView = mTestActivity.getTestRunnerWebView();
-            webView.loadDataWithBaseURL(
-                    "https://some.domain.test/", OPEN_TEST_WINDOW_SCRIPT, "text/html", null, null);
+            webView.loadDataWithBaseURL("https://some.domain.test/", OPEN_CLOSE_TEST_WINDOW_SCRIPT,
+                    "text/html", null, null);
         });
-        Assert.assertEquals("Child window should be added.", Integer.valueOf(CHILD_LAYOUT_ADDED),
-                queue.poll(TEST_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS));
-        Assert.assertEquals("Child window should be removed.",
-                Integer.valueOf(CHILD_LAYOUT_REMOVED),
-                queue.poll(TEST_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS));
+        assertNextElementFromQueue("Child window should be added.", CHILD_LAYOUT_ADDED, queue);
+        assertNextElementFromQueue("Child window should be removed.", CHILD_LAYOUT_REMOVED, queue);
+    }
+
+    @Test
+    @MediumTest
+    public void testNestedOpensAndCloses() throws Exception {
+        final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
+        final int depthToTest = 3;
+        ArrayList<WebView> webViewList = new ArrayList<>();
+
+        // Open 'depthToTest' number of windows.
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mTestActivity.setTestCallback(new WebPlatformTestsActivity.TestCallback() {
+                private int mDepthCounter = 1; // one popup window is already opened by script.
+
+                @Override
+                public void onChildLayoutAdded(WebView webView) {
+                    // This logic should be moved to onPageFinished() once https://crbug.com/1002727
+                    // is fixed.
+                    if (mDepthCounter < depthToTest) {
+                        // Open another popup. Call evaluateJavascript later since loading may not
+                        // have completed. This delay is also needed in opening new popup window
+                        // due to https://crbug.com/1002727.
+                        new Handler().postDelayed(
+                                ()
+                                        -> webView.evaluateJavascript(
+                                                "window.open('about:blank', '_blank');", null),
+                                ON_CREATE_WINDOW_DELAY_MS);
+                        mDepthCounter++;
+                    }
+                    webViewList.add(webView);
+                    queue.add(CHILD_LAYOUT_ADDED);
+                }
+
+                @Override
+                public void onChildLayoutRemoved() {
+                    queue.add(CHILD_LAYOUT_REMOVED);
+                }
+            });
+            WebView webView = mTestActivity.getTestRunnerWebView();
+            webView.loadDataWithBaseURL("https://some.domain.test/",
+                    MULTIPLE_OPEN_CLOSE_TEST_WINDOW_SCRIPT, "text/html", null, null);
+        });
+        // Wait until the last creation has been finished.
+        for (int i = 0; i < depthToTest; ++i) {
+            assertNextElementFromQueue(
+                    i + "-th child window should be added.", CHILD_LAYOUT_ADDED, queue);
+        }
+        // Close the windows in reverse order.
+        for (int i = depthToTest - 1; i >= 0; --i) {
+            WebView webView = webViewList.get(i);
+            // Add a delay here due to https://crbug.com/1002727.
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+                new Handler().postDelayed(
+                        ()
+                                -> webView.evaluateJavascript("window.close();", null),
+                        ON_CREATE_WINDOW_DELAY_MS);
+            });
+            assertNextElementFromQueue(
+                    i + "-th child window should be removed.", CHILD_LAYOUT_REMOVED, queue);
+        }
+    }
+
+    private void assertNextElementFromQueue(String msg, int expected, BlockingQueue<Integer> queue)
+            throws Exception {
+        Integer element = queue.poll(TEST_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
+        if (element == null) throw new TimeoutException("Timeout while asserting: " + msg);
+        Assert.assertEquals(msg, Integer.valueOf(expected), element);
     }
 }
\ No newline at end of file
diff --git a/ash/shelf/shelf_container_view.cc b/ash/shelf/shelf_container_view.cc
index 5e03d01..a64ee93c 100644
--- a/ash/shelf/shelf_container_view.cc
+++ b/ash/shelf/shelf_container_view.cc
@@ -24,14 +24,7 @@
 }
 
 gfx::Size ShelfContainerView::CalculatePreferredSize() const {
-  const int width =
-      ShelfView::GetSizeOfAppIcons(shelf_view_->last_visible_index() -
-                                       shelf_view_->first_visible_index() + 1,
-                                   false);
-  const int height = ShelfConfig::Get()->button_size();
-  return shelf_view_->shelf()->IsHorizontalAlignment()
-             ? gfx::Size(width, height)
-             : gfx::Size(height, width);
+  return CalculateIdealSize();
 }
 
 void ShelfContainerView::ChildPreferredSizeChanged(views::View* child) {
@@ -39,7 +32,11 @@
 }
 
 void ShelfContainerView::Layout() {
-  shelf_view_->SetBoundsRect(gfx::Rect(shelf_view_->GetPreferredSize()));
+  // Should not use ShelfView::GetPreferredSize in replace of
+  // CalculateIdealSize. Because ShelfView::CalculatePreferredSize relies on the
+  // bounds of app icon. Meanwhile, the icon's bounds may be updated by
+  // animation.
+  shelf_view_->SetBoundsRect(gfx::Rect(CalculateIdealSize()));
 }
 
 const char* ShelfContainerView::GetClassName() const {
@@ -52,4 +49,15 @@
   shelf_view_->SetTransform(transform_matrix);
 }
 
+gfx::Size ShelfContainerView::CalculateIdealSize() const {
+  const int width =
+      ShelfView::GetSizeOfAppIcons(shelf_view_->last_visible_index() -
+                                       shelf_view_->first_visible_index() + 1,
+                                   false);
+  const int height = ShelfConfig::Get()->button_size();
+  return shelf_view_->shelf()->IsHorizontalAlignment()
+             ? gfx::Size(width, height)
+             : gfx::Size(height, width);
+}
+
 }  // namespace ash
diff --git a/ash/shelf/shelf_container_view.h b/ash/shelf/shelf_container_view.h
index 1eb6d7e..f83d355 100644
--- a/ash/shelf/shelf_container_view.h
+++ b/ash/shelf/shelf_container_view.h
@@ -35,6 +35,10 @@
   ShelfView* shelf_view_ = nullptr;
 
  private:
+  // Calculates the ideal size of |shelf_view_| to accommodate all of app icons
+  // without scrolling.
+  gfx::Size CalculateIdealSize() const;
+
   DISALLOW_COPY_AND_ASSIGN(ShelfContainerView);
 };
 
diff --git a/base/test/task_environment.cc b/base/test/task_environment.cc
index cc3021dc..99b1ebe 100644
--- a/base/test/task_environment.cc
+++ b/base/test/task_environment.cc
@@ -376,8 +376,16 @@
               ? nullptr
               : std::make_unique<RunLoop::ScopedRunTimeoutForTest>(
                     TestTimeouts::action_timeout(),
-                    MakeExpectedNotRunClosure(FROM_HERE,
-                                              "RunLoop::Run() timed out."))) {
+                    BindRepeating(
+                        [](sequence_manager::SequenceManager*
+                               sequence_manager) {
+                          ADD_FAILURE()
+                              << "RunLoop::Run() timed out with the following "
+                                 "pending task(s) in its TaskEnvironment's "
+                                 "main thread queue:\n"
+                              << sequence_manager->DescribeAllPendingTasks();
+                        },
+                        Unretained(sequence_manager_.get())))) {
   CHECK(!base::ThreadTaskRunnerHandle::IsSet());
   // If |subclass_creates_default_taskrunner| is true then initialization is
   // deferred until DeferredInitFromSubclass().
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 68144345..638a7a0 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -186,6 +186,7 @@
 class AudioInputDevice;
 class AudioOutputDevice;
 class BlockingUrlProtocol;
+class PaintCanvasVideoRenderer;
 }
 namespace memory_instrumentation {
 class OSMetrics;
@@ -471,6 +472,7 @@
   friend class content::SynchronousCompositorSyncCallBridge;
   friend class media::AudioInputDevice;
   friend class media::AudioOutputDevice;
+  friend class media::PaintCanvasVideoRenderer;
   friend class mojo::SyncCallRestrictions;
   friend class net::NetworkConfigWatcherMacThread;
   friend class viz::HostGpuMemoryBufferManager;
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py
index 9fbbf5e..ca91e24 100755
--- a/build/chromeos/test_runner.py
+++ b/build/chromeos/test_runner.py
@@ -450,7 +450,7 @@
       ])
 
     test_invocation = (
-        './%s --test-launcher-shard-index=%d '
+        'LD_LIBRARY_PATH=./ ./%s --test-launcher-shard-index=%d '
         '--test-launcher-total-shards=%d' % (
             self._test_exe, self._test_launcher_shard_index,
             self._test_launcher_total_shards)
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 540d35f..d2f4a60 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8900769199202486848
\ No newline at end of file
+8900743524103453968
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 0e31b93..bc98830 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8900771716210180352
\ No newline at end of file
+8900744692874110736
\ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index de3fe2e..452eedc 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=79
 MINOR=0
-BUILD=3930
+BUILD=3931
 PATCH=0
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
index a78bdc8..e7138c9 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
@@ -16,6 +16,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
+import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.OAuth2TokenService;
 import org.chromium.content_public.browser.WebContents;
@@ -268,7 +269,7 @@
             return;
         }
 
-        OAuth2TokenService.getAccessToken(
+        IdentityServicesProvider.getOAuth2TokenService().getAccessToken(
                 mAccount, AUTH_TOKEN_TYPE, new OAuth2TokenService.GetAccessTokenCallback() {
                     @Override
                     public void onGetTokenSuccess(String token) {
@@ -294,7 +295,7 @@
             return;
         }
 
-        OAuth2TokenService.invalidateAccessToken(accessToken);
+        IdentityServicesProvider.getOAuth2TokenService().invalidateAccessToken(accessToken);
     }
 
     /** Returns the e-mail address that corresponds to the access token or an empty string. */
@@ -316,8 +317,9 @@
 
         // According to API, location for CDMA networks is unreliable
         if (telephonyManager != null
-                && telephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA)
+                && telephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) {
             return telephonyManager.getNetworkCountryIso();
+        }
 
         return null;
     }
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/PasswordGenerationIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/PasswordGenerationIntegrationTest.java
index 6d32ac2..0dd5db1 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/PasswordGenerationIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/PasswordGenerationIntegrationTest.java
@@ -27,6 +27,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.IntegrationTest;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
@@ -107,6 +108,7 @@
 
     @Test
     @IntegrationTest
+    @DisabledTest(message = "crbug.com/1010344")
     public void testAutomaticGenerationUsePassword() throws InterruptedException, TimeoutException {
         waitForGenerationLabel();
         focusField(PASSWORD_NODE_ID);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerProperties.java
index 8d3fec1..91ce16c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerProperties.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerProperties.java
@@ -37,7 +37,10 @@
     public static final PropertyModel.WritableIntPropertyKey SHADOW_TOP_MARGIN =
             new PropertyModel.WritableIntPropertyKey();
 
+    public static final PropertyModel.WritableIntPropertyKey TOP_PADDING =
+            new PropertyModel.WritableIntPropertyKey();
+
     public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {IS_VISIBLE, IS_INCOGNITO,
             VISIBILITY_LISTENER, INITIAL_SCROLL_INDEX, ANIMATE_VISIBILITY_CHANGES,
-            TOP_CONTROLS_HEIGHT, BOTTOM_CONTROLS_HEIGHT, SHADOW_TOP_MARGIN};
+            TOP_CONTROLS_HEIGHT, BOTTOM_CONTROLS_HEIGHT, SHADOW_TOP_MARGIN, TOP_PADDING};
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinder.java
index 92ba9b6e..b4a9d634c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinder.java
@@ -11,6 +11,7 @@
 import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.IS_VISIBLE;
 import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.SHADOW_TOP_MARGIN;
 import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.TOP_CONTROLS_HEIGHT;
+import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.TOP_PADDING;
 import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.VISIBILITY_LISTENER;
 
 import android.support.v7.widget.LinearLayoutManager;
@@ -57,6 +58,9 @@
             view.requestLayout();
         } else if (SHADOW_TOP_MARGIN == propertyKey) {
             view.setShadowTopMargin(model.get(SHADOW_TOP_MARGIN));
+        } else if (TOP_PADDING == propertyKey) {
+            view.setPadding(view.getPaddingLeft(), model.get(TOP_PADDING), view.getPaddingRight(),
+                    view.getPaddingBottom());
         }
     }
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
index c871d4b..0baf407a 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
@@ -11,6 +11,7 @@
 import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.IS_VISIBLE;
 import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.SHADOW_TOP_MARGIN;
 import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.TOP_CONTROLS_HEIGHT;
+import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.TOP_PADDING;
 import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.VISIBILITY_LISTENER;
 
 import android.graphics.Bitmap;
@@ -248,7 +249,10 @@
 
         // Container view takes care of padding and margin in start surface.
         if (mode != TabListCoordinator.TabListMode.CAROUSEL) {
+            // TODO(crbug.com/1010310): Remove the start surface check when tasks-only start surface
+            //  can replace the omnibox check.
             int topControlsHeight = ReturnToChromeExperimentsUtil.shouldShowOmniboxOnTabSwitcher()
+                            && FeatureUtilities.isStartSurfaceEnabled()
                     ? 0
                     : fullscreenManager.getTopControlsHeight();
             mContainerViewModel.set(TOP_CONTROLS_HEIGHT, topControlsHeight);
@@ -258,9 +262,17 @@
             int toolbarHeight =
                     ContextUtils.getApplicationContext().getResources().getDimensionPixelSize(
                             R.dimen.toolbar_height_no_shadow);
-            mContainerViewModel.set(SHADOW_TOP_MARGIN,
-                    ReturnToChromeExperimentsUtil.shouldShowOmniboxOnTabSwitcher() ? 0
-                                                                                   : toolbarHeight);
+
+            if (ReturnToChromeExperimentsUtil.shouldShowOmniboxOnTabSwitcher()
+                    && !FeatureUtilities.isStartSurfaceEnabled()) {
+                // TODO(crbug.com/1010310): Remove this and the TOP_PADDING property once this can
+                //  be replaced by tasks-only start surface mode.
+                mContainerViewModel.set(TOP_PADDING, toolbarHeight);
+                mContainerViewModel.set(SHADOW_TOP_MARGIN, 2 * toolbarHeight);
+            } else {
+                mContainerViewModel.set(SHADOW_TOP_MARGIN,
+                        FeatureUtilities.isStartSurfaceEnabled() ? 0 : toolbarHeight);
+            }
         }
 
         mContainerView = containerView;
diff --git a/chrome/android/java/res/drawable/navigation_bubble_shadow.xml b/chrome/android/java/res/drawable-v19/navigation_bubble_shadow.xml
similarity index 100%
rename from chrome/android/java/res/drawable/navigation_bubble_shadow.xml
rename to chrome/android/java/res/drawable-v19/navigation_bubble_shadow.xml
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 64449fd..e9eb71d2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2208,7 +2208,7 @@
         if (keyCode == KeyEvent.KEYCODE_BACK && !isTablet()) {
             mHandler.removeCallbacks(mShowHistoryRunnable);
             mShowHistoryRunnable = null;
-            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M
+            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N
                     && event.getEventTime() - event.getDownTime()
                             >= ViewConfiguration.getLongPressTimeout()) {
                 return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
index 8a3e87c..9771609 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
@@ -59,7 +59,6 @@
     // his finger. Any delta smaller than (or equal to) than this are ignored.
     private static final float DELTA_IGNORE = 2.f;
 
-    private final NavigationSheetView mContentView;
     private final View mToolbarView;
     private final LayoutInflater mLayoutInflater;
     private final Supplier<BottomSheetController> mBottomSheetController;
@@ -97,6 +96,8 @@
         }
     }
 
+    private NavigationSheetView mContentView;
+
     private boolean mForward;
 
     private boolean mShowCloseIndicator;
@@ -119,8 +120,6 @@
         Context context = parent.getContext();
         mLayoutInflater = LayoutInflater.from(context);
         mToolbarView = mLayoutInflater.inflate(R.layout.navigation_sheet_toolbar, null);
-        mContentView =
-                (NavigationSheetView) mLayoutInflater.inflate(R.layout.navigation_sheet, null);
         mMediator = new NavigationSheetMediator(context, mModelList, (position, index) -> {
             mDelegate.navigateToIndex(index);
             close(false);
@@ -134,8 +133,6 @@
         mModelAdapter.registerType(NAVIGATION_LIST_ITEM_TYPE_ID, () -> {
             return mLayoutInflater.inflate(R.layout.navigation_popup_item, null);
         }, NavigationItemViewBinder::bind);
-        ListView listview = (ListView) mContentView.findViewById(R.id.navigation_entries);
-        listview.setAdapter(mModelAdapter);
         mOpenSheetRunnable = () -> {
             if (isHidden()) openSheet(false, true);
         };
@@ -154,9 +151,12 @@
 
     // Transition to either peeked or expanded state.
     private void openSheet(boolean fullyExpand, boolean animate) {
+        mContentView =
+                (NavigationSheetView) mLayoutInflater.inflate(R.layout.navigation_sheet, null);
+        ListView listview = (ListView) mContentView.findViewById(R.id.navigation_entries);
+        listview.setAdapter(mModelAdapter);
         NavigationHistory history = mDelegate.getHistory(mForward);
         mMediator.populateEntries(history);
-        mContentView.requestListViewLayout();
         mBottomSheetController.get().requestShowContent(this, true);
         mBottomSheetController.get().getBottomSheet().addObserver(mSheetObserver);
         mSheetTriggered = true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetView.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetView.java
index 083651a..2d3184f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetView.java
@@ -35,13 +35,6 @@
         return v == null ? 0 : -(v.getTop() - mListView.getPaddingTop());
     }
 
-    /**
-     * Request layout for the containing listview.
-     */
-    void requestListViewLayout() {
-        mListView.requestLayout();
-    }
-
     @Override
     public void onFinishInflate() {
         super.onFinishInflate();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java
index bbeae28..b63b264 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java
@@ -355,7 +355,7 @@
         if (isShowing) mActiveTab.exitFullscreenMode();
 
         // Also need to update browser control state after dismissal to refresh the constraints.
-        if (isShowing && mActiveTab.areRendererInputEventsIgnored()) {
+        if (isShowing && areRendererInputEventsIgnored()) {
             mChromeFullscreenManager.showAndroidControls(true);
         } else {
             TabBrowserControlsState.update(mActiveTab, BrowserControlsState.SHOWN,
@@ -363,6 +363,10 @@
         }
     }
 
+    private boolean areRendererInputEventsIgnored() {
+        return mActiveTab.getWebContents().getMainFrame().areInputEventsIgnored();
+    }
+
     /**
      * Helper method to run fade-in animation when the specified dialog view is shown.
      * @param dialogView The dialog view to be shown.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/InvalidationGcmUpstreamSender.java b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/InvalidationGcmUpstreamSender.java
index 22c81892..a0a2a010 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/InvalidationGcmUpstreamSender.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/InvalidationGcmUpstreamSender.java
@@ -22,6 +22,7 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.browser.init.ProcessInitializationHandler;
+import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.components.signin.ChromeSigninController;
 import org.chromium.components.signin.OAuth2TokenService;
 import org.chromium.components.sync.SyncConstants;
@@ -67,7 +68,8 @@
         }
 
         // Attempt to retrieve a token for the user.
-        OAuth2TokenService.getAccessToken(account, SyncConstants.CHROME_SYNC_OAUTH2_SCOPE,
+        IdentityServicesProvider.getOAuth2TokenService().getAccessToken(account,
+                SyncConstants.CHROME_SYNC_OAUTH2_SCOPE,
                 new OAuth2TokenService.GetAccessTokenCallback() {
                     @Override
                     public void onGetTokenSuccess(final String token) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 852eb093..7e30595 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -1876,14 +1876,6 @@
         return mIsRendererUnresponsive;
     }
 
-    /**
-     * @return Whether input events from the renderer are ignored on the browser side.
-     */
-    public boolean areRendererInputEventsIgnored() {
-        assert mNativeTabAndroid != 0;
-        return TabJni.get().areRendererInputEventsIgnored(mNativeTabAndroid, Tab.this);
-    }
-
     @NativeMethods
     interface Natives {
         void init(Tab caller);
@@ -1908,6 +1900,5 @@
         void createHistoricalTab(long nativeTabAndroid, Tab caller);
         void loadOriginalImage(long nativeTabAndroid, Tab caller);
         void attachDetachedTab(long nativeTabAndroid, Tab caller);
-        boolean areRendererInputEventsIgnored(long nativeTabAndroid, Tab caller);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java
index be898c2..1d26ac2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java
@@ -65,7 +65,8 @@
         return ChromeFeatureList.isInitialized()
                 && (FeatureUtilities.isGridTabSwitcherEnabled()
                         || FeatureUtilities.isTabGroupsAndroidEnabled())
-                && ChromeFeatureList.isEnabled(ChromeFeatureList.START_SURFACE_ANDROID);
+                && (ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_SWITCHER_ON_RETURN)
+                        || FeatureUtilities.isStartSurfaceEnabled());
     }
 
     /**
diff --git a/chrome/android/java/static_library_dex_reference_workarounds.flags b/chrome/android/java/static_library_dex_reference_workarounds.flags
index fc81e4d..04ad9c4f 100644
--- a/chrome/android/java/static_library_dex_reference_workarounds.flags
+++ b/chrome/android/java/static_library_dex_reference_workarounds.flags
@@ -9,6 +9,8 @@
 # This list of classes can be found by running
 # //build/android/gyp/validate_static_library_dex_references.py.
 
+-keep,allowobfuscation class android.support.design.widget.BaseTransientBottomBar$SnackbarBaseLayout { *; }
+-keep,allowobfuscation class android.support.design.widget.BaseTransientBottomBar$SnackbarBaseLayout$** { *; }
 -keep,allowobfuscation class android.support.design.widget.TabLayout { *; }
 -keep,allowobfuscation class android.support.design.widget.TabLayout$AdapterChangeListener { *; }
 -keep,allowobfuscation class android.support.v7.app.MediaRouteControllerDialog { *; }
@@ -31,15 +33,12 @@
 -keep,allowobfuscation class org.chromium.chrome.browser.firstrun.FirstRunPagerAdapter { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.init.ChromeBrowserInitializer$** { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.init.ProcessInitializationHandler$** { *; }
--keep,allowobfuscation class org.chromium.chrome.browser.init.ProcessInitializationHandler$** { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.media.ui.MediaImageCallback { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.media.ui.MediaImageManager { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.media.ui.MediaNotificationInfo$Builder { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.media.ui.MediaNotificationListener { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.media.ui.MediaSessionTabHelper { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.media.ui.MediaSessionTabHelper$** { *; }
--keep,allowobfuscation class org.chromium.chrome.browser.media.ui.MediaSessionTabHelper$** { *; }
--keep,allowobfuscation class org.chromium.chrome.browser.media.ui.MediaSessionTabHelper$** { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.payments.AndroidPaymentApp { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.payments.AndroidPaymentApp$** { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.payments.PaymentInstrument { *; }
@@ -54,5 +53,8 @@
 -keep,allowobfuscation class org.chromium.chrome.browser.preferences.privacy.ClearBrowsingDataTabsFragment$ClearBrowsingDataPagerAdapter { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.profiles.Profile { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.tab.Tab { *; }
+-keep,allowobfuscation class org.chromium.chrome.browser.usage_stats.NotificationSuspender$** { *; }
+-keep,allowobfuscation class org.chromium.chrome.browser.usage_stats.SuspensionTracker { *; }
+-keep,allowobfuscation class org.chromium.chrome.browser.usage_stats.UsageStatsService { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.util.IntentUtils { *; }
 -keep,allowobfuscation class org.chromium.chrome.browser.vr.ArImmersiveOverlay { *; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/background_sync/BackgroundSyncTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/background_sync/BackgroundSyncTest.java
index d8adf28..e70b830 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/background_sync/BackgroundSyncTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/background_sync/BackgroundSyncTest.java
@@ -37,6 +37,7 @@
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.TabTitleObserver;
+import org.chromium.chrome.test.util.browser.signin.SigninTestUtil;
 import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
 import org.chromium.components.background_task_scheduler.TaskInfo;
@@ -81,6 +82,10 @@
                 .when(mTaskScheduler)
                 .schedule(eq(ContextUtils.getApplicationContext()), any(TaskInfo.class));
 
+        // loadNativeLibraryAndInitBrowserProcess will access AccountManagerFacade, so it should
+        // be initialized beforehand.
+        SigninTestUtil.setUpAuthForTest();
+
         // This is necessary because our test devices don't have Google Play Services up to date,
         // and BackgroundSync requires that. Remove this once https://crbug.com/514449 has been
         // fixed.
@@ -102,6 +107,7 @@
     @After
     public void tearDown() {
         if (mTestServer != null) mTestServer.stopAndDestroyServer();
+        SigninTestUtil.tearDownAuthForTest();
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java
index 3e18af0..124142aa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java
@@ -7,15 +7,14 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import org.chromium.base.LocaleUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
 import org.chromium.components.payments.CurrencyFormatter;
-import org.chromium.content_public.browser.test.NativeLibraryTestRule;
 
 import java.util.Arrays;
 import java.util.List;
@@ -26,7 +25,7 @@
 @RunWith(BaseJUnit4ClassRunner.class)
 public class CurrencyFormatterTest {
     @Rule
-    public NativeLibraryTestRule mActivityTestRule = new NativeLibraryTestRule();
+    public ChromeBrowserTestRule mActivityTestRule = new ChromeBrowserTestRule();
 
     /**
      * Unicode non-breaking space.
@@ -34,11 +33,6 @@
     private static final String NBSP = "\u00A0";
     private static final String NarrowNBSP = "\u202F";
 
-    @Before
-    public void setUp() {
-        mActivityTestRule.loadNativeLibraryAndInitBrowserProcess();
-    }
-
     private static String longStringOfLength(int len) {
         StringBuilder currency = new StringBuilder();
         for (int i = 0; i < len; i++) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java
index 7df3cf8..80b12e6a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java
@@ -34,6 +34,7 @@
 
     @Rule
     public AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
+    private OAuth2TokenService mOAuth2TokenService;
 
     /**
      * Class handling GetAccessToken callbacks and providing a blocking {@link
@@ -72,6 +73,8 @@
     @Before
     public void setUp() {
         mContext = new AdvancedMockContext(InstrumentationRegistry.getTargetContext());
+        mOAuth2TokenService = new OAuth2TokenService(0 /*nativeOAuth2TokenServiceDelegate*/,
+                null /* AccountTrackerService */, AccountManagerFacade.get());
     }
 
     @After
@@ -95,7 +98,7 @@
         AccountHolder accountHolder1 = AccountHolder.builder(account1).build();
         mAccountManagerTestRule.addAccount(accountHolder1);
 
-        String[] sysAccounts = OAuth2TokenService.getSystemAccountNames();
+        String[] sysAccounts = mOAuth2TokenService.getSystemAccountNames();
         Assert.assertEquals("There should be one registered account", 1, sysAccounts.length);
         Assert.assertEquals("The account should be " + account1, account1.name, sysAccounts[0]);
 
@@ -114,7 +117,7 @@
         AccountHolder accountHolder2 = AccountHolder.builder(account2).build();
         mAccountManagerTestRule.addAccount(accountHolder2);
 
-        String[] sysAccounts = OAuth2TokenService.getSystemAccountNames();
+        String[] sysAccounts = mOAuth2TokenService.getSystemAccountNames();
         Assert.assertEquals("There should be one registered account", 2, sysAccounts.length);
         Assert.assertTrue("The list should contain " + account1,
                 Arrays.asList(sysAccounts).contains(account1.name));
@@ -155,7 +158,7 @@
         mAccountManagerTestRule.addAccount(accountHolder);
         GetAccessTokenCallbackForTest callback = new GetAccessTokenCallbackForTest();
         TestThreadUtils.runOnUiThreadBlocking(
-                () -> { OAuth2TokenService.getAccessToken(account, scope, callback); });
+                () -> { mOAuth2TokenService.getAccessToken(account, scope, callback); });
         Assert.assertEquals(expectedToken, callback.getToken());
     }
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ecf6813..56ceb04 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1567,6 +1567,10 @@
          desc="Message shown to the user to validate the download when the download content is classified as uncommon by safebrowsing. This variant is shown when the user is enrolled in the Advanced Protection program.">
         <ph name="FILE_NAME">$1<ex>bla.exe</ex></ph> was blocked by Advanced Protection.
       </message>
+      <message name="IDS_PROMPT_DEEP_SCANNING_DOWNLOAD"
+        desc="Message shown in the download shelf when a download is being scanned">
+        <ph name="FILE_NAME">$1<ex>bla.exe</ex></ph> is being scanned.
+      </message>
       <message name="IDS_BLOCK_REASON_UNCOMMON_DOWNLOAD"
          desc="Message shown to the user on chrome://downloads page to explain that this download is blocked because it is uncommon.">
         This file is not commonly downloaded and may be dangerous.
diff --git a/chrome/app/generated_resources_grd/IDS_PROMPT_DEEP_SCANNING_DOWNLOAD.png.sha1 b/chrome/app/generated_resources_grd/IDS_PROMPT_DEEP_SCANNING_DOWNLOAD.png.sha1
new file mode 100644
index 0000000..178a5239
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_PROMPT_DEEP_SCANNING_DOWNLOAD.png.sha1
@@ -0,0 +1 @@
+603c2c7e0bfe69f4e08fc921710c962bf1e0ad07
\ No newline at end of file
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index e146a29..aab5af5c 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -479,14 +479,6 @@
   }
 }
 
-bool TabAndroid::AreRendererInputEventsIgnored(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj) {
-  content::RenderProcessHost* render_process_host =
-      web_contents()->GetMainFrame()->GetProcess();
-  return render_process_host->IsBlocked();
-}
-
 scoped_refptr<content::DevToolsAgentHost> TabAndroid::GetDevToolsAgentHost() {
   return devtools_host_;
 }
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index e38f52e7..2cbbee6 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -181,11 +181,6 @@
 
   void AttachDetachedTab(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj);
-
-  bool AreRendererInputEventsIgnored(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-
  private:
   JavaObjectWeakGlobalRef weak_java_tab_;
 
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
index 42f7587e..99f42f7 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -372,6 +372,17 @@
   have_camera_image_ = true;
   mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New();
 
+  // Check if floor height estimate has changed. The estimate might eventually
+  // be provided by |arcore_| - for now, use hard-coded value.
+  if (floor_height_estimate_changed_) {
+    frame_data->stage_parameters_updated = true;
+    frame_data->stage_parameters = mojom::VRStageParameters::New();
+    frame_data->stage_parameters->standing_transform = gfx::Transform();
+    frame_data->stage_parameters->standing_transform.Translate3d(
+        0, floor_height_estimate_, 0);
+    floor_height_estimate_changed_ = false;
+  }
+
   frame_data->frame_id = webxr_->StartFrameAnimating();
   DVLOG(2) << __func__ << " frame=" << frame_data->frame_id;
 
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.h b/chrome/browser/android/vr/arcore_device/arcore_gl.h
index da95ffe3..bf120221 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.h
@@ -207,6 +207,12 @@
   mojom::VRDisplayInfoPtr display_info_;
   bool display_info_changed_ = false;
 
+  // True if floor height estimate should be passed to blink via XRFrameData
+  // returned by subsequent call to |GetFrameData()|.
+  bool floor_height_estimate_changed_ = true;
+  // Currently estimated floor height.
+  float floor_height_estimate_ = 1.2;
+
   std::vector<device::mojom::XRInputSourceStatePtr> input_states_;
   gfx::PointF screen_last_touch_;
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 56d982c..2aebea6 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -562,6 +562,10 @@
         <include name="IDR_SANDBOX_INTERNALS_HTML" file="resources\sandbox_internals\sandbox_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
         <include name="IDR_SANDBOX_INTERNALS_JS" file="resources\sandbox_internals\sandbox_internals.js" type="BINDATA" compress="gzip" />
       </if>
+      <if expr="is_win">
+        <include name="IDR_SANDBOX_INTERNALS_HTML" file="resources\sandbox_internals\sandbox_internals.html" preprocess="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
+        <include name="IDR_SANDBOX_INTERNALS_JS" file="resources\sandbox_internals\sandbox_internals_win.js" type="BINDATA" compress="gzip" />
+      </if>
       <include name="IDR_MEDIA_ENGAGEMENT_HTML" file="resources\media\media_engagement.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
       <include name="IDR_MEDIA_ENGAGEMENT_JS" file="resources\media\media_engagement.js" flattenhtml="true" type="BINDATA" compress="gzip" />
       <include name="IDR_MEDIA_ENGAGEMENT_SCORE_DETAILS_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\media_engagement_score_details.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 803887d..2629898 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2183,8 +2183,6 @@
     "extensions/file_manager/file_manager_private_api_functions.h",
     "extensions/file_manager/file_stream_md5_digester.cc",
     "extensions/file_manager/file_stream_md5_digester.h",
-    "extensions/file_manager/job_event_router.cc",
-    "extensions/file_manager/job_event_router.h",
     "extensions/file_manager/private_api_base.cc",
     "extensions/file_manager/private_api_base.h",
     "extensions/file_manager/private_api_dialog.cc",
@@ -2536,7 +2534,6 @@
     "extensions/file_manager/device_event_router_unittest.cc",
     "extensions/file_manager/drivefs_event_router_unittest.cc",
     "extensions/file_manager/event_router_unittest.cc",
-    "extensions/file_manager/job_event_router_unittest.cc",
     "extensions/gfx_utils_unittest.cc",
     "extensions/install_limiter_unittest.cc",
     "extensions/login_screen/login/login_api_unittest.cc",
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index fb2e37515a..98aa237 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -119,6 +119,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/task_manager/task_manager_interface.h"
+#include "chrome/browser/ui/ash/assistant/assistant_client.h"
 #include "chrome/browser/ui/ash/assistant/assistant_state_client.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #include "chrome/browser/ui/webui/chromeos/login/discover/discover_manager.h"
@@ -200,10 +201,6 @@
 #include "components/rlz/rlz_tracker.h"
 #endif
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-#include "chrome/browser/ui/ash/assistant/assistant_client.h"
-#endif
-
 namespace chromeos {
 
 namespace {
@@ -636,13 +633,11 @@
   // Requires UserManager.
   assistant_state_client_ = std::make_unique<AssistantStateClient>();
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
   // Assistant has to be initialized before
   // ChromeBrowserMainExtraPartsAsh::session_controller_client_ to avoid race of
   // SessionChanged event and assistant_client initialization. It must come
   // after AssistantStateClient.
   assistant_client_ = std::make_unique<AssistantClient>();
-#endif
 
   base::PostTaskAndReplyWithResult(
       FROM_HERE,
@@ -963,11 +958,9 @@
 
   arc_service_launcher_->Shutdown();
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
   // Assistant has to shut down before voice interaction controller client to
   // correctly remove the observer.
   assistant_client_.reset();
-#endif
 
   assistant_state_client_.reset();
 
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index 09191703..961badb 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -12,8 +12,8 @@
 #include "chrome/browser/chrome_browser_main_linux.h"
 #include "chrome/browser/chromeos/external_metrics.h"
 #include "chrome/browser/memory/memory_kills_monitor.h"
-#include "chromeos/assistant/buildflags.h"
 
+class AssistantClient;
 class AssistantStateClient;
 class ChromeKeyboardControllerClient;
 class SpokenFeedbackEventRewriterDelegate;
@@ -30,9 +30,6 @@
 class LockToSingleUserManager;
 }  // namespace policy
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-class AssistantClient;
-#endif
 
 namespace crostini {
 class CrostiniUnsupportedActionNotifier;
@@ -141,9 +138,7 @@
 
   std::unique_ptr<AssistantStateClient> assistant_state_client_;
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
   std::unique_ptr<AssistantClient> assistant_client_;
-#endif
 
   std::unique_ptr<LowDiskNotification> low_disk_notification_;
   std::unique_ptr<ArcKioskAppManager> arc_kiosk_app_manager_;
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
index 258f8ae2..44392a7 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -42,10 +42,7 @@
 #include "chromeos/login/login_state/login_state.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
-#include "components/drive/chromeos/file_system_interface.h"
 #include "components/drive/drive_pref_names.h"
-#include "components/drive/file_change.h"
-#include "components/drive/service/drive_service_interface.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
@@ -75,14 +72,6 @@
 // Frequency of sending onFileTransferUpdated.
 const int64_t kProgressEventFrequencyInMilliseconds = 1000;
 
-// Maximim size of detailed change info on directory change event. If the size
-// exceeds the maximum size, the detailed info is omitted and the force refresh
-// is kicked.
-const size_t kDirectoryChangeEventMaxDetailInfoSize = 1000;
-
-// This time(millisecond) is used for confirm following event exists.
-const int64_t kFileTransferEventDelayTimeInMilliseconds = 300;
-
 // Checks if the Recovery Tool is running. This is a temporary solution.
 // TODO(mtomasz): Replace with crbug.com/341902 solution.
 bool IsRecoveryToolRunning(Profile* profile) {
@@ -202,18 +191,6 @@
   return file_manager_private::COPY_PROGRESS_STATUS_TYPE_NONE;
 }
 
-file_manager_private::ChangeType ConvertChangeTypeFromDriveToApi(
-    drive::FileChange::ChangeType type) {
-  switch (type) {
-    case drive::FileChange::CHANGE_TYPE_ADD_OR_UPDATE:
-      return file_manager_private::CHANGE_TYPE_ADD_OR_UPDATE;
-    case drive::FileChange::CHANGE_TYPE_DELETE:
-      return file_manager_private::CHANGE_TYPE_DELETE;
-  }
-  NOTREACHED();
-  return file_manager_private::CHANGE_TYPE_ADD_OR_UPDATE;
-}
-
 std::string FileErrorToErrorName(base::File::Error error_code) {
   namespace js = extensions::api::file_manager_private;
   switch (error_code) {
@@ -362,43 +339,6 @@
   DISALLOW_COPY_AND_ASSIGN(DeviceEventRouterImpl);
 };
 
-class JobEventRouterImpl : public JobEventRouter {
- public:
-  explicit JobEventRouterImpl(Profile* profile)
-      : JobEventRouter(base::TimeDelta::FromMilliseconds(
-            kFileTransferEventDelayTimeInMilliseconds)),
-        profile_(profile) {}
-
- protected:
-  std::set<std::string> GetFileTransfersUpdateEventListenerExtensionIds()
-      override {
-    return GetEventListenerExtensionIds(
-        profile_, file_manager_private::OnFileTransfersUpdated::kEventName);
-  }
-
-  GURL ConvertDrivePathToFileSystemUrl(
-      const base::FilePath& file_path,
-      const std::string& extension_id) override {
-    return file_manager::util::ConvertDrivePathToFileSystemUrl(
-        profile_, file_path, extension_id);
-  }
-
-  void DispatchEventToExtension(
-      const std::string& extension_id,
-      extensions::events::HistogramValue histogram_value,
-      const std::string& event_name,
-      std::unique_ptr<base::ListValue> event_args) override {
-    ::file_manager::DispatchEventToExtension(profile_, extension_id,
-                                             histogram_value, event_name,
-                                             std::move(event_args));
-  }
-
- private:
-  Profile* const profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(JobEventRouterImpl);
-};
-
 class DriveFsEventRouterImpl : public DriveFsEventRouter {
  public:
   DriveFsEventRouterImpl(
@@ -465,7 +405,6 @@
     : pref_change_registrar_(std::make_unique<PrefChangeRegistrar>()),
       profile_(profile),
       device_event_router_(std::make_unique<DeviceEventRouterImpl>(profile)),
-      job_event_router_(std::make_unique<JobEventRouterImpl>(profile)),
       drivefs_event_router_(
           std::make_unique<DriveFsEventRouterImpl>(profile, &file_watchers_)),
       dispatch_directory_change_event_impl_(
@@ -509,14 +448,8 @@
       DriveIntegrationServiceFactory::FindForProfile(profile_);
   if (integration_service) {
     integration_service->RemoveObserver(this);
-    if (integration_service->GetDriveFsHost()) {
-      integration_service->GetDriveFsHost()->RemoveObserver(
-          drivefs_event_router_.get());
-    } else {
-      integration_service->file_system()->RemoveObserver(this);
-      integration_service->drive_service()->RemoveObserver(this);
-      integration_service->job_list()->RemoveObserver(job_event_router_.get());
-    }
+    integration_service->GetDriveFsHost()->RemoveObserver(
+        drivefs_event_router_.get());
   }
 
   VolumeManager* const volume_manager = VolumeManager::Get(profile_);
@@ -560,14 +493,8 @@
       DriveIntegrationServiceFactory::FindForProfile(profile_);
   if (integration_service) {
     integration_service->AddObserver(this);
-    if (integration_service->GetDriveFsHost()) {
-      integration_service->GetDriveFsHost()->AddObserver(
-          drivefs_event_router_.get());
-    } else {
-      integration_service->drive_service()->AddObserver(this);
-      integration_service->file_system()->AddObserver(this);
-      integration_service->job_list()->AddObserver(job_event_router_.get());
-    }
+    integration_service->GetDriveFsHost()->AddObserver(
+        drivefs_event_router_.get());
   }
 
   content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
@@ -613,34 +540,17 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!callback.is_null());
 
-  base::FilePath watch_path = local_path;
-  bool is_on_drive = drive::util::IsUnderDriveMountPoint(watch_path);
-  // Tweak watch path for remote sources - we need to drop leading /special
-  // directory from there in order to be able to pair these events with
-  // their change notifications.
-  if (is_on_drive)
-    watch_path = drive::util::ExtractDrivePath(watch_path);
-
-  auto iter = file_watchers_.find(watch_path);
+  auto iter = file_watchers_.find(local_path);
   if (iter == file_watchers_.end()) {
     std::unique_ptr<FileWatcher> watcher(new FileWatcher(virtual_path));
     watcher->AddExtension(extension_id);
+    watcher->WatchLocalFile(
+        local_path,
+        base::Bind(&EventRouter::HandleFileWatchNotification,
+                   weak_factory_.GetWeakPtr()),
+        std::move(callback));
 
-    if (is_on_drive) {
-      // For Drive, file watching is done via OnDirectoryChanged().
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(std::move(callback), true));
-    } else {
-      // For local files, start watching using FileWatcher.
-      watcher->WatchLocalFile(
-          watch_path,
-          base::Bind(&EventRouter::HandleFileWatchNotification,
-                     weak_factory_.GetWeakPtr(),
-                     static_cast<drive::FileChange*>(nullptr)),
-          std::move(callback));
-    }
-
-    file_watchers_[watch_path] = std::move(watcher);
+    file_watchers_[local_path] = std::move(watcher);
   } else {
     iter->second->AddExtension(extension_id);
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -652,17 +562,10 @@
                                   const std::string& extension_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  base::FilePath watch_path = local_path;
-  // Tweak watch path for remote sources - we need to drop leading /special
-  // directory from there in order to be able to pair these events with
-  // their change notifications.
-  if (drive::util::IsUnderDriveMountPoint(watch_path)) {
-    watch_path = drive::util::ExtractDrivePath(watch_path);
-  }
-  auto iter = file_watchers_.find(watch_path);
+  auto iter = file_watchers_.find(local_path);
   if (iter == file_watchers_.end())
     return;
-  // Remove the watcher if |watch_path| is no longer watched by any extensions.
+  // Remove the watcher if |local_path| is no longer watched by any extensions.
   iter->second->RemoveExtension(extension_id);
   if (iter->second->GetExtensionIds().empty())
     file_watchers_.erase(iter);
@@ -738,7 +641,7 @@
   std::vector<std::string> extension_ids;
   extension_ids.push_back(extension_id);
 
-  DispatchDirectoryChangeEvent(file_system_url.virtual_path(), nullptr,
+  DispatchDirectoryChangeEvent(file_system_url.virtual_path(),
                                false /* error */, extension_ids);
 }
 
@@ -767,122 +670,7 @@
       file_manager_private::OnPreferencesChanged::Create());
 }
 
-void EventRouter::OnDirectoryChanged(const base::FilePath& drive_path) {
-  HandleFileWatchNotification(nullptr, drive_path, false);
-}
-
-void EventRouter::OnFileChanged(const drive::FileChange& changed_files) {
-  // In this method, we convert changed_files to a map which can be handled by
-  // HandleFileWatchNotification.
-  //
-  // e.g.
-  // /a/b DIRECTORY:DELETE
-  //
-  // map[/a] = /a/b DIRECTORY:DELETE
-  // map[/a/b] = /a/b DIRECTORY:DELETE
-  //
-  // We used the key of map to match the watched directories of file watchers.
-  typedef std::map<base::FilePath, drive::FileChange> FileChangeMap;
-  typedef drive::FileChange::ChangeList::List FileChangeList;
-
-  FileChangeMap map;
-  const drive::FileChange::Map& changed_file_map = changed_files.map();
-  for (auto const& file_change_key_value : changed_file_map) {
-    // Check whether the FileChangeList contains directory deletion.
-    bool contains_directory_deletion = false;
-    const FileChangeList list = file_change_key_value.second.list();
-    for (drive::FileChange::Change const& change : list) {
-      if (change.IsDirectory() && change.IsDelete()) {
-        contains_directory_deletion = true;
-        break;
-      }
-    }
-
-    const base::FilePath& path = file_change_key_value.first;
-    map[path.DirName()].Update(path, file_change_key_value.second);
-
-    // For deletion of a directory, onFileChanged gets different changed_files.
-    // We solve the difference here.
-    //
-    // /a/b is watched, and /a is deleted from Drive (e.g. from Web).
-    // 1. /a/b DELETE:DIRECTORY
-    // 2. /a DELETE:DIRECTORY
-    //
-    // /a/b is watched, and /a is deleted from the Files app.
-    // 1. /a DELETE:DIRECTORY
-    if (contains_directory_deletion) {
-      // Expand the deleted directory path with watched paths.
-      for (auto file_watchers_it = file_watchers_.lower_bound(path);
-           file_watchers_it != file_watchers_.end(); ++file_watchers_it) {
-        if (path == file_watchers_it->first ||
-            path.IsParent(file_watchers_it->first)) {
-          map[file_watchers_it->first].Update(
-              file_watchers_it->first,
-              drive::FileChange::FileType::FILE_TYPE_DIRECTORY,
-              drive::FileChange::ChangeType::CHANGE_TYPE_DELETE);
-        }
-      }
-    }
-  }
-
-  for (auto const& file_change_key_value : map) {
-    HandleFileWatchNotification(&(file_change_key_value.second),
-                                file_change_key_value.first, false);
-  }
-}
-
-void EventRouter::OnDriveSyncError(drive::file_system::DriveSyncErrorType type,
-                                   const base::FilePath& drive_path) {
-  file_manager_private::DriveSyncErrorEvent event;
-  switch (type) {
-    case drive::file_system::DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION:
-      event.type =
-          file_manager_private::DRIVE_SYNC_ERROR_TYPE_DELETE_WITHOUT_PERMISSION;
-      break;
-    case drive::file_system::DRIVE_SYNC_ERROR_SERVICE_UNAVAILABLE:
-      event.type =
-          file_manager_private::DRIVE_SYNC_ERROR_TYPE_SERVICE_UNAVAILABLE;
-      break;
-    case drive::file_system::DRIVE_SYNC_ERROR_NO_SERVER_SPACE:
-      event.type = file_manager_private::DRIVE_SYNC_ERROR_TYPE_NO_SERVER_SPACE;
-      break;
-    case drive::file_system::DRIVE_SYNC_ERROR_MISC:
-      event.type =
-          file_manager_private::DRIVE_SYNC_ERROR_TYPE_MISC;
-      break;
-  }
-  event.file_url = util::ConvertDrivePathToFileSystemUrl(
-      profile_, drive_path, kFileManagerAppId).spec();
-  BroadcastEvent(profile_,
-                 extensions::events::FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
-                 file_manager_private::OnDriveSyncError::kEventName,
-                 file_manager_private::OnDriveSyncError::Create(event));
-}
-
-void EventRouter::OnRefreshTokenInvalid() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  // Raise a DriveConnectionStatusChanged event to notify the status offline.
-  BroadcastEvent(
-      profile_, extensions::events::
-                    FILE_MANAGER_PRIVATE_ON_DRIVE_CONNECTION_STATUS_CHANGED,
-      file_manager_private::OnDriveConnectionStatusChanged::kEventName,
-      file_manager_private::OnDriveConnectionStatusChanged::Create());
-}
-
-void EventRouter::OnReadyToSendRequests() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  // Raise a DriveConnectionStatusChanged event to notify the status online.
-  BroadcastEvent(
-      profile_, extensions::events::
-                    FILE_MANAGER_PRIVATE_ON_DRIVE_CONNECTION_STATUS_CHANGED,
-      file_manager_private::OnDriveConnectionStatusChanged::kEventName,
-      file_manager_private::OnDriveConnectionStatusChanged::Create());
-}
-
-void EventRouter::HandleFileWatchNotification(const drive::FileChange* list,
-                                              const base::FilePath& local_path,
+void EventRouter::HandleFileWatchNotification(const base::FilePath& local_path,
                                               bool got_error) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -891,38 +679,24 @@
     return;
   }
 
-  if (list && list->size() > kDirectoryChangeEventMaxDetailInfoSize) {
-    // Removes the detailed information, if the list size is more than
-    // kDirectoryChangeEventMaxDetailInfoSize, since passing large list
-    // and processing it may cause more itme.
-    // This will be invoked full-refresh in the Files app.
-    list = nullptr;
-  }
-
   DispatchDirectoryChangeEvent(iter->second->virtual_path(),
-                               list,
                                got_error,
                                iter->second->GetExtensionIds());
 }
 
 void EventRouter::DispatchDirectoryChangeEvent(
     const base::FilePath& virtual_path,
-    const drive::FileChange* list,
     bool got_error,
     const std::vector<std::string>& extension_ids) {
-  dispatch_directory_change_event_impl_.Run(virtual_path, list, got_error,
+  dispatch_directory_change_event_impl_.Run(virtual_path, got_error,
                                             extension_ids);
 }
 
 void EventRouter::DispatchDirectoryChangeEventImpl(
     const base::FilePath& virtual_path,
-    const drive::FileChange* list,
     bool got_error,
     const std::vector<std::string>& extension_ids) {
   DCHECK(profile_);
-  std::unique_ptr<drive::FileChange> changes;
-  if (list)
-    changes = std::make_unique<drive::FileChange>(*list);  // Copy
 
   for (size_t i = 0; i < extension_ids.size(); ++i) {
     std::string* extension_id = new std::string(extension_ids[i]);
@@ -937,13 +711,11 @@
         profile_, *extension_id, file_definition,
         base::BindOnce(
             &EventRouter::DispatchDirectoryChangeEventWithEntryDefinition,
-            weak_factory_.GetWeakPtr(), std::move(changes),
-            base::Owned(extension_id), got_error));
+            weak_factory_.GetWeakPtr(), base::Owned(extension_id), got_error));
   }
 }
 
 void EventRouter::DispatchDirectoryChangeEventWithEntryDefinition(
-    std::unique_ptr<drive::FileChange> list,
     const std::string* extension_id,
     bool watcher_error,
     const EntryDefinition& entry_definition) {
@@ -960,35 +732,6 @@
       ? file_manager_private::FILE_WATCH_EVENT_TYPE_ERROR
       : file_manager_private::FILE_WATCH_EVENT_TYPE_CHANGED;
 
-  // Detailed information is available.
-  if (list) {
-    event.changed_files =
-        std::make_unique<std::vector<file_manager_private::FileChange>>();
-
-    if (list->map().empty())
-      return;
-
-    for (drive::FileChange::Map::const_iterator it = list->map().begin();
-         it != list->map().end();
-         it++) {
-      file_manager_private::FileChange change_list;
-
-      GURL url = util::ConvertDrivePathToFileSystemUrl(
-          profile_, it->first, *extension_id);
-      change_list.url = url.spec();
-
-      for (drive::FileChange::ChangeList::List::const_iterator change =
-               it->second.list().begin();
-           change != it->second.list().end();
-           change++) {
-        change_list.changes.push_back(
-            ConvertChangeTypeFromDriveToApi(change->change()));
-      }
-
-      event.changed_files->push_back(std::move(change_list));
-    }
-  }
-
   event.entry.additional_properties.SetString(
       "fileSystemName", entry_definition.file_system_name);
   event.entry.additional_properties.SetString(
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h
index ed2aa70..625e7fd 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.h
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -18,7 +18,6 @@
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/chromeos/extensions/file_manager/device_event_router.h"
 #include "chrome/browser/chromeos/extensions/file_manager/drivefs_event_router.h"
-#include "chrome/browser/chromeos/extensions/file_manager/job_event_router.h"
 #include "chrome/browser/chromeos/file_manager/file_watcher.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
@@ -29,9 +28,6 @@
 #include "chromeos/settings/timezone_settings.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/intent_helper/arc_intent_helper_observer.h"
-#include "components/drive/chromeos/file_system_observer.h"
-#include "components/drive/chromeos/sync_client.h"
-#include "components/drive/service/drive_service_interface.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 #include "storage/browser/fileapi/file_system_operation.h"
@@ -41,10 +37,6 @@
 
 using file_manager::util::EntryDefinition;
 
-namespace drive {
-class FileChange;
-}
-
 namespace file_manager {
 
 // Monitors changes in disk mounts, network connection state and preferences
@@ -53,15 +45,12 @@
     : public KeyedService,
       public network::NetworkConnectionTracker::NetworkConnectionObserver,
       public chromeos::system::TimezoneSettings::Observer,
-      public drive::FileSystemObserver,
-      public drive::DriveServiceObserver,
       public VolumeManagerObserver,
       public arc::ArcIntentHelperObserver,
       public drive::DriveIntegrationServiceObserver,
       public guest_os::GuestOsSharePath::Observer {
  public:
   typedef base::Callback<void(const base::FilePath& virtual_path,
-                              const drive::FileChange* list,
                               bool got_error,
                               const std::vector<std::string>& extension_ids)>
       DispatchDirectoryChangeEventImplCallback;
@@ -121,16 +110,6 @@
   // chromeos::system::TimezoneSettings::Observer overrides.
   void TimezoneChanged(const icu::TimeZone& timezone) override;
 
-  // drive::DriveServiceObserver overrides.
-  void OnRefreshTokenInvalid() override;
-  void OnReadyToSendRequests() override;
-
-  // drive::FileSystemObserver overrides.
-  void OnDirectoryChanged(const base::FilePath& drive_path) override;
-  void OnFileChanged(const drive::FileChange& changed_files) override;
-  void OnDriveSyncError(drive::file_system::DriveSyncErrorType type,
-                        const base::FilePath& drive_path) override;
-
   // VolumeManagerObserver overrides.
   void OnDiskAdded(const chromeos::disks::Disk& disk, bool mounting) override;
   void OnDiskRemoved(const chromeos::disks::Disk& disk) override;
@@ -168,28 +147,23 @@
   void OnFileManagerPrefsChanged();
 
   // Process file watch notifications.
-  void HandleFileWatchNotification(const drive::FileChange* list,
-                                   const base::FilePath& path,
-                                   bool got_error);
+  void HandleFileWatchNotification(const base::FilePath& path, bool got_error);
 
   // Sends directory change event.
   void DispatchDirectoryChangeEvent(
       const base::FilePath& path,
-      const drive::FileChange* list,
       bool got_error,
       const std::vector<std::string>& extension_ids);
 
   // Default implementation of DispatchDirectoryChangeEvent.
   void DispatchDirectoryChangeEventImpl(
       const base::FilePath& path,
-      const drive::FileChange* list,
       bool got_error,
       const std::vector<std::string>& extension_ids);
 
   // Sends directory change event, after converting the file definition to entry
   // definition.
   void DispatchDirectoryChangeEventWithEntryDefinition(
-      std::unique_ptr<drive::FileChange> list,
       const std::string* extension_id,
       bool watcher_error,
       const EntryDefinition& entry_definition);
@@ -223,7 +197,6 @@
   Profile* profile_;
 
   std::unique_ptr<DeviceEventRouter> device_event_router_;
-  std::unique_ptr<JobEventRouter> job_event_router_;
   std::unique_ptr<DriveFsEventRouter> drivefs_event_router_;
 
   DispatchDirectoryChangeEventImplCallback
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
index 7c38500..963a373 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -146,17 +146,6 @@
                               "exfat",
                               ""}};
 
-void DispatchDirectoryChangeEventImpl(
-    int* counter,
-    const base::FilePath& virtual_path,
-    const drive::FileChange* list,
-    bool got_error,
-    const std::vector<std::string>& extension_ids) {
-  ++(*counter);
-}
-
-void AddFileWatchCallback(bool success) {}
-
 void AddLocalFileSystem(Profile* profile, base::FilePath root) {
   const char kLocalMountPointName[] = "local";
   const char kTestFileContent[] = "The five boxing wizards jumped quickly";
@@ -461,81 +450,6 @@
   EXPECT_EQ("fileManagerPrivate", warning.key);
 }
 
-IN_PROC_BROWSER_TEST_F(FileManagerPrivateApiTest, OnFileChanged) {
-  // In drive volume, deletion of a directory is notified via OnFileChanged.
-  // Local changes directly come to HandleFileWatchNotification from
-  // FileWatcher.
-  typedef drive::FileChange FileChange;
-  typedef drive::FileChange::FileType FileType;
-  typedef drive::FileChange::ChangeType ChangeType;
-
-  int counter = 0;
-  event_router_->SetDispatchDirectoryChangeEventImplForTesting(
-      base::Bind(&DispatchDirectoryChangeEventImpl, &counter));
-
-  // /a/b/c and /a/d/e are being watched.
-  event_router_->AddFileWatch(
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs/root/a/b/c")),
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs-virtual/root/a/b/c")),
-      "extension_1", base::Bind(&AddFileWatchCallback));
-
-  event_router_->AddFileWatch(
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs/root/a/d/e")),
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs-hash/root/a/d/e")),
-      "extension_2", base::Bind(&AddFileWatchCallback));
-
-  event_router_->AddFileWatch(
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs/root/aaa")),
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs-hash/root/aaa")),
-      "extension_3", base::Bind(&AddFileWatchCallback));
-
-  // event_router->addFileWatch create some tasks which are performed on
-  // ThreadPool. Wait until they are done.
-  base::ThreadPoolInstance::Get()->FlushForTesting();
-  // We also wait the UI thread here, since some tasks which are performed
-  // above message loop back results to the UI thread.
-  base::RunLoop().RunUntilIdle();
-
-  // When /a is deleted (1 and 2 is notified).
-  FileChange first_change;
-  first_change.Update(
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs/root/a")),
-      FileType::FILE_TYPE_DIRECTORY, ChangeType::CHANGE_TYPE_DELETE);
-  event_router_->OnFileChanged(first_change);
-  EXPECT_EQ(2, counter);
-
-  // When /a/b/c is deleted (1 is notified).
-  FileChange second_change;
-  second_change.Update(
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs/root/a/b/c")),
-      FileType::FILE_TYPE_DIRECTORY, ChangeType::CHANGE_TYPE_DELETE);
-  event_router_->OnFileChanged(second_change);
-  EXPECT_EQ(3, counter);
-
-  // When /z/y is deleted (Not notified).
-  FileChange third_change;
-  third_change.Update(
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs/root/z/y")),
-      FileType::FILE_TYPE_DIRECTORY, ChangeType::CHANGE_TYPE_DELETE);
-  event_router_->OnFileChanged(third_change);
-  EXPECT_EQ(3, counter);
-
-  // Remove file watchers.
-  event_router_->RemoveFileWatch(
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs/root/a/b/c")),
-      "extension_1");
-  event_router_->RemoveFileWatch(
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs/root/a/d/e")),
-      "extension_2");
-  event_router_->RemoveFileWatch(
-      base::FilePath(FILE_PATH_LITERAL("/no-existing-fs/root/aaa")),
-      "extension_3");
-
-  // event_router->addFileWatch create some tasks which are performed on
-  // ThreadPool. Wait until they are done.
-  base::ThreadPoolInstance::Get()->FlushForTesting();
-}
-
 IN_PROC_BROWSER_TEST_F(FileManagerPrivateApiTest, ContentChecksum) {
   AddLocalFileSystem(browser()->profile(), temp_dir_.GetPath());
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/job_event_router.cc b/chrome/browser/chromeos/extensions/file_manager/job_event_router.cc
deleted file mode 100644
index 131e499..0000000
--- a/chrome/browser/chromeos/extensions/file_manager/job_event_router.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/extensions/file_manager/job_event_router.h"
-
-#include <cmath>
-#include <memory>
-
-#include "base/bind.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/chromeos/file_manager/app_id.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/drive/file_system_core_util.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-namespace file_manager_private = extensions::api::file_manager_private;
-
-namespace file_manager {
-
-JobEventRouter::JobEventRouter(const base::TimeDelta& event_delay)
-    : event_delay_(event_delay), num_completed_bytes_(0), num_total_bytes_(0) {}
-
-JobEventRouter::~JobEventRouter() = default;
-
-void JobEventRouter::OnJobAdded(const drive::JobInfo& job_info) {
-  OnJobUpdated(job_info);
-}
-
-void JobEventRouter::OnJobUpdated(const drive::JobInfo& job_info) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!drive::IsActiveFileTransferJobInfo(job_info))
-    return;
-
-  // Add new job info.
-  UpdateBytes(job_info);
-  drive_jobs_[job_info.job_id] = std::make_unique<drive::JobInfo>(job_info);
-
-  ScheduleDriveFileTransferEvent(
-      job_info, file_manager_private::TRANSFER_STATE_IN_PROGRESS,
-      false /* immediate */);
-}
-
-void JobEventRouter::OnJobDone(const drive::JobInfo& job_info,
-                               drive::FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!drive::IsActiveFileTransferJobInfo(job_info))
-    return;
-
-  const file_manager_private::TransferState state =
-      error == drive::FILE_ERROR_OK
-          ? file_manager_private::TRANSFER_STATE_COMPLETED
-          : file_manager_private::TRANSFER_STATE_FAILED;
-
-  drive::JobInfo completed_job = job_info;
-  completed_job.num_completed_bytes = completed_job.num_total_bytes;
-  UpdateBytes(completed_job);
-
-  ScheduleDriveFileTransferEvent(job_info, state, true /* immediate */);
-
-  // Forget about the job.
-  drive_jobs_.erase(job_info.job_id);
-  if (drive_jobs_.empty()) {
-    num_completed_bytes_ = 0L;
-    num_total_bytes_ = 0L;
-  }
-}
-
-void JobEventRouter::UpdateBytes(const drive::JobInfo& job_info) {
-  int64_t last_completed_bytes = 0;
-  int64_t last_total_bytes = 0;
-  if (drive_jobs_.count(job_info.job_id)) {
-    last_completed_bytes = drive_jobs_[job_info.job_id]->num_completed_bytes;
-    last_total_bytes = drive_jobs_[job_info.job_id]->num_total_bytes;
-  }
-  num_completed_bytes_ += job_info.num_completed_bytes - last_completed_bytes;
-  num_total_bytes_ += job_info.num_total_bytes - last_total_bytes;
-}
-
-void JobEventRouter::ScheduleDriveFileTransferEvent(
-    const drive::JobInfo& job_info,
-    file_manager_private::TransferState state,
-    bool immediate) {
-  const bool no_pending_task = !pending_job_info_;
-
-  pending_job_info_ = std::make_unique<drive::JobInfo>(job_info);
-  pending_state_ = state;
-
-  if (immediate) {
-    SendDriveFileTransferEvent();
-  } else if (no_pending_task) {
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&JobEventRouter::SendDriveFileTransferEvent,
-                       weak_factory_.GetWeakPtr()),
-        event_delay_);
-  }
-}
-
-void JobEventRouter::SendDriveFileTransferEvent() {
-  if (!pending_job_info_)
-    return;
-
-  const std::set<std::string>& extension_ids =
-      GetFileTransfersUpdateEventListenerExtensionIds();
-
-  for (const auto extension_id : extension_ids) {
-    DispatchFileTransfersUpdateEventToExtension(
-        extension_id, *pending_job_info_, pending_state_, drive_jobs_.size(),
-        num_completed_bytes_, num_total_bytes_);
-  }
-
-  pending_job_info_.reset();
-}
-
-void JobEventRouter::DispatchFileTransfersUpdateEventToExtension(
-    const std::string& extension_id,
-    const drive::JobInfo& job_info,
-    const file_manager_private::TransferState& state,
-    const int64_t num_total_jobs,
-    const int64_t num_completed_bytes,
-    const int64_t num_total_bytes) {
-  file_manager_private::FileTransferStatus status;
-
-  const GURL url =
-      ConvertDrivePathToFileSystemUrl(job_info.file_path, extension_id);
-  status.file_url = url.spec();
-  status.transfer_state = state;
-  // JavaScript does not have 64-bit integers. Instead we use double, which
-  // is in IEEE 754 formant and accurate up to 52-bits in JS, and in practice
-  // in C++. Larger values are rounded.
-  status.num_total_jobs = num_total_jobs;
-  status.processed = num_completed_bytes;
-  status.total = num_total_bytes;
-  status.hide_when_zero_jobs = false;
-
-  DispatchEventToExtension(
-      extension_id,
-      extensions::events::FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
-      file_manager_private::OnFileTransfersUpdated::kEventName,
-      file_manager_private::OnFileTransfersUpdated::Create(status));
-}
-
-}  // namespace file_manager
diff --git a/chrome/browser/chromeos/extensions/file_manager/job_event_router.h b/chrome/browser/chromeos/extensions/file_manager/job_event_router.h
deleted file mode 100644
index 58fef1b7..0000000
--- a/chrome/browser/chromeos/extensions/file_manager/job_event_router.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_JOB_EVENT_ROUTER_H_
-#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_JOB_EVENT_ROUTER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "chrome/common/extensions/api/file_manager_private.h"
-#include "components/drive/job_list.h"
-#include "extensions/browser/extension_event_histogram_value.h"
-#include "url/gurl.h"
-
-namespace file_manager {
-
-// Files app's event router handling job related events.
-class JobEventRouter : public drive::JobListObserver {
- public:
-  explicit JobEventRouter(const base::TimeDelta& event_delay);
-  ~JobEventRouter() override;
-
-  // drive::JobListObserver overrides.
-  void OnJobAdded(const drive::JobInfo& job_info) override;
-  void OnJobUpdated(const drive::JobInfo& job_info) override;
-  void OnJobDone(const drive::JobInfo& job_info,
-                 drive::FileError error) override;
-
- protected:
-  // Helper method for getting set of listener extension ids.
-  virtual std::set<std::string>
-  GetFileTransfersUpdateEventListenerExtensionIds() = 0;
-
-  // Helper method for converting drive path to file system url.
-  virtual GURL ConvertDrivePathToFileSystemUrl(
-      const base::FilePath& file_path,
-      const std::string& extension_id) = 0;
-
-  // Helper method for dispatching an event to an extension.
-  virtual void DispatchEventToExtension(
-      const std::string& extension_id,
-      extensions::events::HistogramValue histogram_value,
-      const std::string& event_name,
-      std::unique_ptr<base::ListValue> event_args) = 0;
-
- private:
-  // Request sending transfer event with |job_info| and |state|.
-  // If |immediate| is true, the event will be dispatched synchronously.
-  // Otherwise, the event is throttled, or may be skipped.
-  void ScheduleDriveFileTransferEvent(
-      const drive::JobInfo& job_info,
-      extensions::api::file_manager_private::TransferState state,
-      bool immediate);
-
-  // Send transfer event requested by ScheduleDriveFileTransferEvent at last.
-  void SendDriveFileTransferEvent();
-
-  // Update |num_completed_bytes_| and |num_total_bytes_| depends on |job|.
-  void UpdateBytes(const drive::JobInfo& job_info);
-
-  // Dispatches FileTransfersUpdate event to an extension.
-  void DispatchFileTransfersUpdateEventToExtension(
-      const std::string& extension_id,
-      const drive::JobInfo& job_info,
-      const extensions::api::file_manager_private::TransferState& state,
-      const int64_t num_total_jobs,
-      const int64_t num_completed_bytes,
-      const int64_t num_total_bytes);
-
-  // Delay time before sending progress events.
-  base::TimeDelta event_delay_;
-
-  // Set of job that are in the job schedular.
-  std::map<drive::JobID, std::unique_ptr<drive::JobInfo>> drive_jobs_;
-
-  // Job info of pending event. |ScheduleDriveFileTransferEvent| registers
-  // timeout callback to dispatch this.
-  std::unique_ptr<drive::JobInfo> pending_job_info_;
-
-  // Transfer state of pending event.
-  extensions::api::file_manager_private::TransferState pending_state_;
-
-  // Computed bytes of tasks that have been processed. Once it completes all
-  // tasks, it clears the variable.
-  int64_t num_completed_bytes_;
-
-  // Total bytes of tasks that have been processed. Once it completes all tasks,
-  // it clears the variable.
-  int64_t num_total_bytes_;
-
-  // Thread checker.
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<JobEventRouter> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(JobEventRouter);
-};
-
-}  // namespace file_manager
-
-#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_JOB_EVENT_ROUTER_H_
diff --git a/chrome/browser/chromeos/extensions/file_manager/job_event_router_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/job_event_router_unittest.cc
deleted file mode 100644
index 2c3cfb4..0000000
--- a/chrome/browser/chromeos/extensions/file_manager/job_event_router_unittest.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/extensions/file_manager/job_event_router.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace file_manager {
-namespace {
-
-class JobEventRouterImpl : public JobEventRouter {
- public:
-  JobEventRouterImpl() : JobEventRouter(base::TimeDelta::FromMilliseconds(0)) {
-    listener_extension_ids_.insert("extension_a");
-  }
-  std::vector<std::unique_ptr<base::DictionaryValue>> events;
-
-  void SetListenerExtensionIds(std::set<std::string> extension_ids) {
-    listener_extension_ids_ = extension_ids;
-  }
-
- protected:
-  std::set<std::string> GetFileTransfersUpdateEventListenerExtensionIds()
-      override {
-    return listener_extension_ids_;
-  }
-
-  GURL ConvertDrivePathToFileSystemUrl(
-      const base::FilePath& file_path,
-      const std::string& extension_id) override {
-    std::string url;
-    url.append("filesystem:chrome-extension://");
-    url.append(extension_id);
-    url.append(file_path.value());
-    return GURL(url);
-  }
-
-  void DispatchEventToExtension(
-      const std::string& extension_id,
-      extensions::events::HistogramValue histogram_value,
-      const std::string& event_name,
-      std::unique_ptr<base::ListValue> event_args) override {
-    const base::DictionaryValue* event;
-    event_args->GetDictionary(0, &event);
-    events.push_back(base::WrapUnique(event->DeepCopy()));
-  }
-
- private:
-  std::set<std::string> listener_extension_ids_;
-
-  DISALLOW_COPY_AND_ASSIGN(JobEventRouterImpl);
-};
-
-class JobEventRouterTest : public testing::Test {
- protected:
-  void SetUp() override {
-    job_event_router = std::make_unique<JobEventRouterImpl>();
-  }
-
-  drive::JobInfo CreateJobInfo(drive::JobID id,
-                               int64_t num_completed_bytes,
-                               int64_t num_total_bytes,
-                               const base::FilePath& file_path) {
-    drive::JobInfo job(drive::TYPE_DOWNLOAD_FILE);
-    job.job_id = id;
-    job.num_total_bytes = num_total_bytes;
-    job.num_completed_bytes = num_completed_bytes;
-    job.file_path = file_path;
-    return job;
-  }
-
-  std::string GetEventString(size_t index, const std::string& name) {
-    std::string value;
-    job_event_router->events[index]->GetString(name, &value);
-    return value;
-  }
-
-  double GetEventDouble(size_t index, const std::string& name) {
-    double value = NAN;
-    job_event_router->events[index]->GetDouble(name, &value);
-    return value;
-  }
-
-  std::unique_ptr<JobEventRouterImpl> job_event_router;
-
- private:
-  base::test::SingleThreadTaskEnvironment task_environment_;
-};
-
-TEST_F(JobEventRouterTest, Basic) {
-  // Add a job.
-  job_event_router->OnJobAdded(
-      CreateJobInfo(0, 0, 100, base::FilePath("/test/a")));
-  // Event should be throttled.
-  ASSERT_EQ(0u, job_event_router->events.size());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_EQ(1u, job_event_router->events.size());
-  EXPECT_EQ("in_progress", GetEventString(0, "transferState"));
-  EXPECT_EQ(0.0f, GetEventDouble(0, "processed"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "total"));
-  job_event_router->events.clear();
-
-  // Job is updated.
-  job_event_router->OnJobUpdated(
-      CreateJobInfo(0, 50, 100, base::FilePath("/test/a")));
-  job_event_router->OnJobUpdated(
-      CreateJobInfo(0, 100, 100, base::FilePath("/test/a")));
-  // Event should be throttled.
-  ASSERT_EQ(0u, job_event_router->events.size());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_EQ(1u, job_event_router->events.size());
-  EXPECT_EQ("in_progress", GetEventString(0, "transferState"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "processed"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "total"));
-  job_event_router->events.clear();
-
-  // Complete first job.
-  job_event_router->OnJobDone(
-      CreateJobInfo(0, 100, 100, base::FilePath("/test/a")),
-      drive::FILE_ERROR_OK);
-  // Complete event should not be throttled.
-  ASSERT_EQ(1u, job_event_router->events.size());
-  EXPECT_EQ("completed", GetEventString(0, "transferState"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "processed"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "total"));
-  job_event_router->events.clear();
-}
-
-TEST_F(JobEventRouterTest, CompleteWithInvalidCompletedBytes) {
-  job_event_router->OnJobDone(
-      CreateJobInfo(0, 50, 100, base::FilePath("/test/a")),
-      drive::FILE_ERROR_OK);
-  ASSERT_EQ(1u, job_event_router->events.size());
-  EXPECT_EQ("completed", GetEventString(0, "transferState"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "processed"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "total"));
-}
-
-TEST_F(JobEventRouterTest, AnotherJobAddedBeforeComplete) {
-  job_event_router->OnJobAdded(
-      CreateJobInfo(0, 0, 100, base::FilePath("/test/a")));
-  job_event_router->OnJobUpdated(
-      CreateJobInfo(0, 50, 100, base::FilePath("/test/a")));
-  job_event_router->OnJobAdded(
-      CreateJobInfo(1, 0, 100, base::FilePath("/test/b")));
-
-  // Event should be throttled.
-  ASSERT_EQ(0u, job_event_router->events.size());
-  base::RunLoop().RunUntilIdle();
-  ASSERT_EQ(1u, job_event_router->events.size());
-  EXPECT_EQ("in_progress", GetEventString(0, "transferState"));
-  EXPECT_EQ(50.0f, GetEventDouble(0, "processed"));
-  EXPECT_EQ(200.0f, GetEventDouble(0, "total"));
-  job_event_router->events.clear();
-
-  job_event_router->OnJobDone(
-      CreateJobInfo(0, 100, 100, base::FilePath("/test/a")),
-      drive::FILE_ERROR_OK);
-  job_event_router->OnJobDone(
-      CreateJobInfo(1, 100, 100, base::FilePath("/test/b")),
-      drive::FILE_ERROR_OK);
-  // Complete event should not be throttled.
-  ASSERT_EQ(2u, job_event_router->events.size());
-  EXPECT_EQ("completed", GetEventString(0, "transferState"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "processed"));
-  EXPECT_EQ(200.0f, GetEventDouble(0, "total"));
-  EXPECT_EQ("completed", GetEventString(1, "transferState"));
-  EXPECT_EQ(200.0f, GetEventDouble(1, "processed"));
-  EXPECT_EQ(200.0f, GetEventDouble(1, "total"));
-}
-
-TEST_F(JobEventRouterTest, AnotherJobAddedAfterComplete) {
-  job_event_router->OnJobAdded(
-      CreateJobInfo(0, 0, 100, base::FilePath("/test/a")));
-  job_event_router->OnJobUpdated(
-      CreateJobInfo(0, 50, 100, base::FilePath("/test/a")));
-  job_event_router->OnJobDone(
-      CreateJobInfo(0, 100, 100, base::FilePath("/test/a")),
-      drive::FILE_ERROR_OK);
-  job_event_router->OnJobAdded(
-      CreateJobInfo(1, 0, 100, base::FilePath("/test/b")));
-  job_event_router->OnJobDone(
-      CreateJobInfo(1, 100, 100, base::FilePath("/test/b")),
-      drive::FILE_ERROR_OK);
-
-  // Complete event should not be throttled.
-  ASSERT_EQ(2u, job_event_router->events.size());
-  EXPECT_EQ("completed", GetEventString(0, "transferState"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "processed"));
-  // Total byte shold be reset when all tasks complete.
-  EXPECT_EQ(100.0f, GetEventDouble(0, "total"));
-  EXPECT_EQ("completed", GetEventString(1, "transferState"));
-  EXPECT_EQ(100.0f, GetEventDouble(1, "processed"));
-  EXPECT_EQ(100.0f, GetEventDouble(1, "total"));
-}
-
-TEST_F(JobEventRouterTest, UpdateTotalSizeAfterAdded) {
-  job_event_router->OnJobAdded(
-      CreateJobInfo(0, 0, 0, base::FilePath("/test/a")));
-  base::RunLoop().RunUntilIdle();
-  job_event_router->OnJobUpdated(
-      CreateJobInfo(0, 0, 100, base::FilePath("/test/a")));
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_EQ(2u, job_event_router->events.size());
-
-  EXPECT_EQ("in_progress", GetEventString(0, "transferState"));
-  EXPECT_EQ(0.0f, GetEventDouble(0, "processed"));
-  EXPECT_EQ(0.0f, GetEventDouble(0, "total"));
-
-  EXPECT_EQ("in_progress", GetEventString(1, "transferState"));
-  EXPECT_EQ(0.0f, GetEventDouble(1, "processed"));
-  EXPECT_EQ(100.0f, GetEventDouble(1, "total"));
-}
-
-TEST_F(JobEventRouterTest, MultipleListenerExtensions) {
-  std::set<std::string> extension_ids;
-  extension_ids.insert("extension_a");
-  extension_ids.insert("extension_b");
-  job_event_router->SetListenerExtensionIds(extension_ids);
-
-  // Add a job.
-  job_event_router->OnJobAdded(
-      CreateJobInfo(0, 0, 100, base::FilePath("/test/a")));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_EQ(2u, job_event_router->events.size());
-
-  // Check event for extension_a.
-  EXPECT_EQ("in_progress", GetEventString(0, "transferState"));
-  EXPECT_EQ(0.0f, GetEventDouble(0, "processed"));
-  EXPECT_EQ(100.0f, GetEventDouble(0, "total"));
-  EXPECT_EQ("filesystem:chrome-extension://extension_a/test/a",
-            GetEventString(0, "fileUrl"));
-
-  // Check event for extension_b.
-  EXPECT_EQ("in_progress", GetEventString(1, "transferState"));
-  EXPECT_EQ(0.0f, GetEventDouble(1, "processed"));
-  EXPECT_EQ(100.0f, GetEventDouble(1, "total"));
-  EXPECT_EQ("filesystem:chrome-extension://extension_b/test/a",
-            GetEventString(1, "fileUrl"));
-}
-
-}  // namespace
-}  // namespace file_manager
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 4253a45..804e0bc2f 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -237,6 +237,7 @@
         TestCase("fileDisplayMtp"),
         TestCase("fileDisplayUsb"),
         TestCase("fileDisplayUsbPartition"),
+        TestCase("fileDisplayUsbPartitionSort"),
         TestCase("fileDisplayPartitionFileTable"),
         TestCase("fileSearch"),
         TestCase("fileDisplayWithoutDownloadsVolume").DontMountVolumes(),
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 533c0df..b7d1587b 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -2000,6 +2000,35 @@
     return;
   }
 
+  if (name == "mountUsbWithMultiplePartitionTypes") {
+    // Create a device path to mimic a realistic device path.
+    constexpr char kDevicePath[] =
+        "sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2/1-2.2:1.0/host0/"
+        "target0:0:0/0:0:0:0";
+    const base::FilePath device_path(kDevicePath);
+
+    // Create partition volumes with the same device path.
+    partition_1_ = std::make_unique<RemovableTestVolume>(
+        "partition-1", VOLUME_TYPE_REMOVABLE_DISK_PARTITION,
+        chromeos::DEVICE_TYPE_USB, device_path, "Drive Label", "ntfs");
+    partition_2_ = std::make_unique<RemovableTestVolume>(
+        "partition-2", VOLUME_TYPE_REMOVABLE_DISK_PARTITION,
+        chromeos::DEVICE_TYPE_USB, device_path, "Drive Label", "ext4");
+    partition_3_ = std::make_unique<RemovableTestVolume>(
+        "partition-3", VOLUME_TYPE_REMOVABLE_DISK_PARTITION,
+        chromeos::DEVICE_TYPE_USB, device_path, "Drive Label", "vfat");
+
+    // Create fake entries on partitions.
+    ASSERT_TRUE(partition_1_->PrepareTestEntries(profile()));
+    ASSERT_TRUE(partition_2_->PrepareTestEntries(profile()));
+    ASSERT_TRUE(partition_3_->PrepareTestEntries(profile()));
+
+    ASSERT_TRUE(partition_1_->Mount(profile()));
+    ASSERT_TRUE(partition_2_->Mount(profile()));
+    ASSERT_TRUE(partition_3_->Mount(profile()));
+    return;
+  }
+
   if (name == "unmountPartitions") {
     DCHECK(partition_1_);
     DCHECK(partition_2_);
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
index 5b33288..c8112228 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
@@ -158,6 +158,7 @@
   std::unique_ptr<FakeTestVolume> mtp_volume_;
   std::unique_ptr<RemovableTestVolume> partition_1_;
   std::unique_ptr<RemovableTestVolume> partition_2_;
+  std::unique_ptr<RemovableTestVolume> partition_3_;
   std::unique_ptr<DocumentsProviderTestVolume> documents_provider_volume_;
   std::unique_ptr<MediaViewTestVolume> media_view_images_;
   std::unique_ptr<MediaViewTestVolume> media_view_videos_;
diff --git a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.cc b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.cc
index f7d3538..a0f041dd 100644
--- a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.cc
+++ b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h"
-#include "chromeos/assistant/buildflags.h"
 #include "chromeos/constants/chromeos_features.h"
 
 namespace chromeos {
@@ -44,7 +43,6 @@
     return;
   }
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
   if (::assistant::IsAssistantAllowedForProfile(
           ProfileManager::GetActiveUserProfile()) ==
           ash::mojom::AssistantAllowedState::ALLOWED &&
@@ -52,7 +50,6 @@
     view_->Show();
     return;
   }
-#endif
   exit_callback_.Run();
 }
 
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
index d76cb61..d532f69 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/chromeos/printing/history/print_job_info_proto_conversions.h"
 #include "chrome/browser/printing/print_job.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -343,9 +344,20 @@
                       const printing::proto::PrintSettings& settings) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-    auto printer =
-        CupsPrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinter(
-            printer_name);
+    auto profile = ProfileManager::GetPrimaryUserProfile();
+    if (!profile) {
+      LOG(WARNING) << "Cannot find printer without a valid profile.";
+      return false;
+    }
+
+    auto manager = CupsPrintersManagerFactory::GetForBrowserContext(profile);
+    if (!manager) {
+      LOG(WARNING)
+          << "CupsPrintersManager could not be found for the current profile.";
+      return false;
+    }
+
+    auto printer = manager->GetPrinter(printer_name);
     if (!printer) {
       LOG(WARNING)
           << "Printer was removed while job was in progress.  It cannot "
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 51493d96..8277212 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -1202,17 +1202,15 @@
     DCHECK_NE(danger_type,
               download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT);
 
-    if (danger_type != download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
-      if (ShouldBlockFile(danger_type, item)) {
-        item->OnContentCheckCompleted(
-            // Specifying a dangerous type here would take precendence over the
-            // blocking of the file.
-            download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
-            download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED);
-      } else {
-        item->OnContentCheckCompleted(danger_type,
-                                      download::DOWNLOAD_INTERRUPT_REASON_NONE);
-      }
+    if (ShouldBlockFile(danger_type, item)) {
+      item->OnContentCheckCompleted(
+          // Specifying a dangerous type here would take precedence over the
+          // blocking of the file.
+          download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+          download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED);
+    } else {
+      item->OnContentCheckCompleted(danger_type,
+                                    download::DOWNLOAD_INTERRUPT_REASON_NONE);
     }
   }
 
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
index f176c13c..03bd783 100644
--- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -1082,7 +1082,7 @@
 
   void CheckClientDownload(
       DownloadItem* download_item,
-      safe_browsing::CheckDownloadCallback callback) override {
+      safe_browsing::CheckDownloadRepeatingCallback callback) override {
     std::move(callback).Run(MockCheckClientDownload());
   }
   MOCK_METHOD0(MockCheckClientDownload, safe_browsing::DownloadCheckResult());
@@ -1345,23 +1345,17 @@
         .SetDangerLevel(kParameters.initial_danger_level);
   }
 
-  if (kParameters.expected_danger_type !=
-      download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS) {
-    if (kParameters.blocked) {
-      EXPECT_CALL(*download_item,
-                  OnContentCheckCompleted(
-                      // Specifying a dangerous type here would take precendence
-                      // over the blocking of the file.
-                      download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
-                      download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED));
-    } else {
-      EXPECT_CALL(
-          *download_item,
-          OnContentCheckCompleted(kParameters.expected_danger_type,
-                                  download::DOWNLOAD_INTERRUPT_REASON_NONE));
-    }
+  if (kParameters.blocked) {
+    EXPECT_CALL(*download_item,
+                OnContentCheckCompleted(
+                    // Specifying a dangerous type here would take precedence
+                    // over the blocking of the file.
+                    download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+                    download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED));
   } else {
-    EXPECT_CALL(*download_item, OnContentCheckCompleted(_, _)).Times(0);
+    EXPECT_CALL(*download_item, OnContentCheckCompleted(
+                                    kParameters.expected_danger_type,
+                                    download::DOWNLOAD_INTERRUPT_REASON_NONE));
   }
 
   pref_service()->SetInteger(
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index fd04b3e..5f4dd49 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -1170,7 +1170,7 @@
 
   void CheckClientDownload(
       DownloadItem* download_item,
-      safe_browsing::CheckDownloadCallback callback) override {
+      safe_browsing::CheckDownloadRepeatingCallback callback) override {
     std::move(callback).Run(safe_browsing::DownloadCheckResult::UNCOMMON);
   }
 };
@@ -3219,7 +3219,6 @@
 
 // This test ensures that the Referer header is properly sanitized when
 // Save Image As is chosen from the context menu.
-// TODO(crbug.com/1005586): Re-enable this test.
 IN_PROC_BROWSER_TEST_P(DownloadReferrerPolicyTest,
                        DISABLED_SaveImageAsReferrerPolicy) {
   embedded_test_server()->RegisterRequestHandler(
@@ -3300,10 +3299,8 @@
 
 // This test ensures that a cross-domain download correctly sets the referrer
 // according to the referrer policy.
-//
-// Disabled because flaky. See https://crbug.com/1009022.
 IN_PROC_BROWSER_TEST_P(DownloadReferrerPolicyTest,
-                       DISABLED_DownloadCrossDomainReferrerPolicy) {
+                       DownloadCrossDomainReferrerPolicy) {
   embedded_test_server()->RegisterRequestHandler(
       base::Bind(&ServerRedirectRequestHandler));
   embedded_test_server()->RegisterRequestHandler(
@@ -4172,7 +4169,7 @@
 
   DownloadItem* download = downloads[0];
   EXPECT_FALSE(download->IsDangerous());
-  EXPECT_EQ(download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
+  EXPECT_EQ(download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
             download->GetDangerType());
 
   download->Cancel(true);
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
index 5c6fb196..c75ebb8 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
@@ -534,9 +534,8 @@
   TestShowAction(ActionInfo::TYPE_BROWSER);
 }
 
-// crbug.com/1010061: disabled due to flakiness.
 IN_PROC_BROWSER_TEST_P(ParameterizedShowActionDeclarativeContentApiTest,
-                       DISABLED_ActionInManifest) {
+                       ActionInManifest) {
   TestShowAction(ActionInfo::TYPE_ACTION);
 }
 
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
index 3d041fe8..c0eed2de 100644
--- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
@@ -30,6 +30,7 @@
 #include "extensions/common/manifest.h"
 #include "extensions/common/switches.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/origin.h"
 
 using content::DesktopMediaID;
 using extensions::api::desktop_capture::ChooseDesktopMedia::Results::Options;
@@ -176,8 +177,9 @@
     // http://crbug.com/304341
     content::RenderFrameHost* const main_frame = web_contents->GetMainFrame();
     result = content::DesktopStreamsRegistry::GetInstance()->RegisterStream(
-        main_frame->GetProcess()->GetID(), main_frame->GetRoutingID(), origin,
-        source, extension()->name(), content::kRegistryStreamTypeDesktop);
+        main_frame->GetProcess()->GetID(), main_frame->GetRoutingID(),
+        url::Origin::Create(origin), source, extension()->name(),
+        content::kRegistryStreamTypeDesktop);
   }
 
   Options options;
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
index a761a4ef..82a0c89 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
@@ -20,6 +20,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/common/extension.h"
+#include "url/origin.h"
 
 using content::BrowserThread;
 using extensions::tab_capture::TabCaptureState;
@@ -56,18 +57,10 @@
   ~LiveRequest() override {}
 
   // Accessors.
-  const std::string& extension_id() const {
-    return extension_id_;
-  }
-  bool is_anonymous() const {
-    return is_anonymous_;
-  }
-  TabCaptureState capture_state() const {
-    return capture_state_;
-  }
-  bool is_verified() const {
-    return is_verified_;
-  }
+  const std::string& extension_id() const { return extension_id_; }
+  bool is_anonymous() const { return is_anonymous_; }
+  TabCaptureState capture_state() const { return capture_state_; }
+  bool is_verified() const { return is_verified_; }
 
   void SetIsVerified() {
     DCHECK(!is_verified_);
@@ -77,7 +70,7 @@
   bool WasTargettingRenderFrameID(int render_process_id,
                                   int render_frame_id) const {
     return render_process_id_ == render_process_id &&
-        render_frame_id_ == render_frame_id;
+           render_frame_id_ == render_frame_id;
   }
 
   void UpdateCaptureState(TabCaptureState next_capture_state) {
@@ -220,17 +213,17 @@
   content::RenderFrameHost* const main_frame = caller_contents->GetMainFrame();
   if (main_frame) {
     device_id = content::DesktopStreamsRegistry::GetInstance()->RegisterStream(
-        main_frame->GetProcess()->GetID(), main_frame->GetRoutingID(), origin,
-        source, extension_name, content::kRegistryStreamTypeTab);
+        main_frame->GetProcess()->GetID(), main_frame->GetRoutingID(),
+        url::Origin::Create(origin), source, extension_name,
+        content::kRegistryStreamTypeTab);
   }
 
   return device_id;
 }
 
-bool TabCaptureRegistry::VerifyRequest(
-    int render_process_id,
-    int render_frame_id,
-    const std::string& extension_id) {
+bool TabCaptureRegistry::VerifyRequest(int render_process_id,
+                                       int render_frame_id,
+                                       const std::string& extension_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   LiveRequest* const request = FindRequest(render_process_id, render_frame_id);
@@ -261,7 +254,7 @@
   LiveRequest* request =
       FindRequest(target_render_process_id, target_render_frame_id);
   if (!request) {
-      return;  // Stale or invalid request update.
+    return;  // Stale or invalid request update.
   }
 
   TabCaptureState next_state = tab_capture::TAB_CAPTURE_STATE_NONE;
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 91191139..c62565180 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -1468,8 +1468,7 @@
 
 // Test that the webRequest events are dispatched for the WebSocket handshake
 // requests.
-// crbug.com/1010061: disabled due to flakiness.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, DISABLED_WebSocketRequest) {
+IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebSocketRequest) {
   ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(StartWebSocketServer(net::GetWebSocketTestDataDirectory()));
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_websocket.html"))
diff --git a/chrome/browser/media/cast_mirroring_service_host.cc b/chrome/browser/media/cast_mirroring_service_host.cc
index 298b0f2..d529636 100644
--- a/chrome/browser/media/cast_mirroring_service_host.cc
+++ b/chrome/browser/media/cast_mirroring_service_host.cc
@@ -39,6 +39,7 @@
 #include "services/viz/public/mojom/gpu.mojom.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
+#include "url/origin.h"
 
 using content::BrowserThread;
 
@@ -144,7 +145,7 @@
             desktop_stream_id,
             initiator_contents->GetMainFrame()->GetProcess()->GetID(),
             initiator_contents->GetMainFrame()->GetRoutingID(),
-            initiator_contents->GetVisibleURL().GetOrigin(),
+            url::Origin::Create(initiator_contents->GetVisibleURL()),
             &original_extension_name, content::kRegistryStreamTypeDesktop);
     mojo::MakeSelfOwnedReceiver(
         std::make_unique<CastMirroringServiceHost>(media_id),
diff --git a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
index 430f515..7e52d84f 100644
--- a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
+++ b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
@@ -49,6 +49,7 @@
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "url/origin.h"
 
 #if defined(OS_CHROMEOS)
 #include "ash/shell.h"
@@ -343,7 +344,7 @@
         content::DesktopStreamsRegistry::GetInstance()->RequestMediaForStreamId(
             request.requested_video_device_id,
             main_frame->GetProcess()->GetID(), main_frame->GetRoutingID(),
-            request.security_origin, nullptr,
+            url::Origin::Create(request.security_origin), nullptr,
             content::kRegistryStreamTypeDesktop);
   }
 
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 19cc287f..494caccc 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -134,15 +134,10 @@
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/printing/printer_metrics_provider.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/metrics/assistant_service_metrics_provider.h"
 #include "chrome/browser/metrics/chromeos_metrics_provider.h"
 #include "chrome/browser/signin/signin_status_metrics_provider_chromeos.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.h"
-#include "chromeos/assistant/buildflags.h"
-
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-#include "chrome/browser/metrics/assistant_service_metrics_provider.h"
-#endif
-
 #endif
 
 #if defined(OS_WIN)
@@ -736,6 +731,9 @@
   // Using WrapUnique to access a private constructor.
   metrics_service_->RegisterMetricsProvider(
       base::WrapUnique(new app_list::AppListLaunchMetricsProvider()));
+
+  metrics_service_->RegisterMetricsProvider(
+      std::make_unique<AssistantServiceMetricsProvider>());
 #endif  // defined(OS_CHROMEOS)
 
 #if !defined(OS_CHROMEOS)
@@ -766,13 +764,6 @@
   metrics_service_->RegisterMetricsProvider(
       std::make_unique<PowerMetricsProvider>());
 #endif
-
-#if defined(OS_CHROMEOS)
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-  metrics_service_->RegisterMetricsProvider(
-      std::make_unique<AssistantServiceMetricsProvider>());
-#endif  // BUILDFLAG(ENABLE_CROS_ASSISTANT)
-#endif  // defined(OS_CHROMEOS)
 }
 
 void ChromeMetricsServiceClient::RegisterUKMProviders() {
diff --git a/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc b/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc
index 154a004..4dcc1d7 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc
@@ -32,7 +32,6 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#include "chromeos/assistant/buildflags.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/login/login_state/login_state.h"
 #endif
@@ -179,12 +178,10 @@
 #endif  // BUILDFLAG(ENABLE_PLUGINS)
 
 #if defined(OS_CHROMEOS)
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-  expected_providers++;  // AssistantServiceMetricsProvider.
-#endif                   // BUILDFLAG(ENABLE_CROS_ASSISTANT)
+  // AssistantServiceMetricsProvider,
   // ChromeOSMetricsProvider, SigninStatusMetricsProviderChromeOS,
   // PrinterMetricsProvider, and HashedLoggingMetricsProvider.
-  expected_providers += 4;
+  expected_providers += 5;
 #endif  // defined(OS_CHROMEOS)
 
 #if !defined(OS_CHROMEOS)
diff --git a/chrome/browser/policy/chrome_browser_policy_connector_unittest.cc b/chrome/browser/policy/chrome_browser_policy_connector_unittest.cc
index 118b275..7ef145b 100644
--- a/chrome/browser/policy/chrome_browser_policy_connector_unittest.cc
+++ b/chrome/browser/policy/chrome_browser_policy_connector_unittest.cc
@@ -30,6 +30,7 @@
           nullptr);
   provider.UpdateChromePolicy(map);
   EXPECT_TRUE(connector.HasMachineLevelPolicies());
+  BrowserPolicyConnectorBase::SetPolicyProviderForTesting(nullptr);
 }
 #endif  // !defined(OS_CHROMEOS)
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index d1c60be..bafc4d06 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -301,12 +301,12 @@
 #include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector_chromeos.h"
-#include "chromeos/assistant/buildflags.h"
 #include "chromeos/audio/audio_devices_pref_handler_impl.h"
 #include "chromeos/components/account_manager/account_manager.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/network/fast_transition_observer.h"
 #include "chromeos/network/proxy/proxy_config_handler.h"
+#include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
 #include "chromeos/services/multidevice_setup/multidevice_setup_service.h"
 #include "chromeos/timezone/timezone_resolver.h"
 #include "components/arc/arc_prefs.h"
@@ -315,11 +315,6 @@
 #include "components/onc/onc_pref_names.h"
 #include "components/quirks/quirks_manager.h"
 #include "extensions/browser/api/lock_screen_data/lock_screen_item_storage.h"
-
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-#include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
-#endif
-
 #else
 #include "chrome/browser/extensions/default_apps.h"
 #endif
@@ -915,6 +910,7 @@
   arc::prefs::RegisterProfilePrefs(registry);
   certificate_manager::CertificatesHandler::RegisterProfilePrefs(registry);
   chromeos::AccountManager::RegisterPrefs(registry);
+  chromeos::assistant::prefs::RegisterProfilePrefsForBrowser(registry);
   chromeos::CupsPrintersManager::RegisterProfilePrefs(registry);
   chromeos::first_run::RegisterProfilePrefs(registry);
   chromeos::file_system_provider::RegisterProfilePrefs(registry);
@@ -944,11 +940,6 @@
   policy::AppInstallEventLogManagerWrapper::RegisterProfilePrefs(registry);
   policy::StatusCollector::RegisterProfilePrefs(registry);
   ::onc::RegisterProfilePrefs(registry);
-
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-  chromeos::assistant::prefs::RegisterProfilePrefsForBrowser(registry);
-#endif
-
 #endif
 
 #if defined(OS_CHROMEOS) && BUILDFLAG(ENABLE_APP_LIST)
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
index ccb221b..557b569 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
@@ -392,26 +392,22 @@
 // This test class enables ResourceLoadingHints with OptimizationHints.
 // First parameter is true if the test should be run with a webpage that
 // preloads resources in the HTML head using link-rel preload.
-// Second parameter is true if the blink feature
-// kSendPreviewsLoadingHintsBeforeCommit should be enabled.
-// Third parameter is true if the OptimizationGuideKeyedService feature is
+// Second parameter is true if the OptimizationGuideKeyedService feature is
 // enabled.
 // All tests should pass in the same way for all cases.
 class ResourceLoadingHintsBrowserTest
-    : public ::testing::WithParamInterface<std::tuple<bool, bool, bool>>,
+    : public ::testing::WithParamInterface<std::tuple<bool, bool>>,
       public ResourceLoadingNoFeaturesBrowserTest {
  public:
   ResourceLoadingHintsBrowserTest()
       : use_preload_resources_webpage_(std::get<0>(GetParam())),
-        use_render_frame_observer_(std::get<1>(GetParam())),
-        use_optimization_guide_keyed_service_(std::get<2>(GetParam())) {}
+        use_optimization_guide_keyed_service_(std::get<1>(GetParam())) {}
 
   ~ResourceLoadingHintsBrowserTest() override = default;
 
   void SetUp() override {
     // Enabling NoScript should have no effect since resource loading takes
     // priority over NoScript.
-    if (!use_render_frame_observer_) {
       scoped_feature_list_.InitWithFeatures(
           {previews::features::kPreviews, previews::features::kNoScriptPreviews,
            optimization_guide::features::kOptimizationHints,
@@ -419,16 +415,6 @@
            data_reduction_proxy::features::
                kDataReductionProxyEnabledWithNetworkService},
           {});
-    } else {
-      scoped_feature_list_.InitWithFeatures(
-          {blink::features::kSendPreviewsLoadingHintsBeforeCommit,
-           previews::features::kPreviews, previews::features::kNoScriptPreviews,
-           optimization_guide::features::kOptimizationHints,
-           previews::features::kResourceLoadingHints,
-           data_reduction_proxy::features::
-               kDataReductionProxyEnabledWithNetworkService},
-          {});
-    }
 
     if (use_optimization_guide_keyed_service_) {
       ogks_feature_list_.InitWithFeatures(
@@ -457,19 +443,12 @@
     return ResourceLoadingNoFeaturesBrowserTest::https_url_iframe();
   }
 
-  bool use_preload_resources_webpage() const {
-    return use_preload_resources_webpage_;
-  }
-
-  bool use_render_frame_observer() const { return use_render_frame_observer_; }
-
  protected:
   base::test::ScopedFeatureList scoped_feature_list_;
   base::test::ScopedFeatureList ogks_feature_list_;
 
  private:
   const bool use_preload_resources_webpage_;
-  const bool use_render_frame_observer_;
   const bool use_optimization_guide_keyed_service_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourceLoadingHintsBrowserTest);
@@ -477,13 +456,10 @@
 
 // First parameter is true if the test should be run with a webpage that
 // preloads resources in the HTML head using link-rel preload. Second parameter
-// is true if the blink feature kSendPreviewsLoadingHintsBeforeCommit
-// should be enabled. Third parameter is true if the
-// OptimizationGuideKeyedService feature is enabled.
+// is true if the OptimizationGuideKeyedService feature is enabled.
 INSTANTIATE_TEST_SUITE_P(,
                          ResourceLoadingHintsBrowserTest,
                          ::testing::Combine(::testing::Bool(),
-                                            ::testing::Bool(),
                                             ::testing::Bool()));
 
 // Previews InfoBar (which these tests triggers) does not work on Mac.
@@ -498,9 +474,6 @@
 IN_PROC_BROWSER_TEST_P(
     ResourceLoadingHintsBrowserTest,
     DISABLE_ON_WIN_MAC_CHROMESOS(ResourceLoadingHintsHttpsWhitelisted)) {
-  if (use_preload_resources_webpage() && !use_render_frame_observer())
-    return;
-
   GURL url = https_url();
 
   // Whitelist resource loading hints for https_hint_setup_url()'s' host.
@@ -684,9 +657,6 @@
 IN_PROC_BROWSER_TEST_P(
     ResourceLoadingHintsBrowserTest,
     DISABLE_ON_WIN_MAC_CHROMESOS(ExperimentalHints_ExperimentIsEnabled)) {
-  if (use_preload_resources_webpage() && !use_render_frame_observer())
-    return;
-
   base::test::ScopedFeatureList scoped_list;
   scoped_list.InitAndEnableFeatureWithParameters(
       optimization_guide::features::kOptimizationHintsExperiments,
@@ -729,9 +699,6 @@
 IN_PROC_BROWSER_TEST_P(
     ResourceLoadingHintsBrowserTest,
     DISABLE_ON_WIN_MAC_CHROMESOS(MixExperimentalHints_ExperimentIsEnabled)) {
-  if (use_preload_resources_webpage() && !use_render_frame_observer())
-    return;
-
   base::test::ScopedFeatureList scoped_list;
   scoped_list.InitAndEnableFeatureWithParameters(
       optimization_guide::features::kOptimizationHintsExperiments,
@@ -810,8 +777,6 @@
 IN_PROC_BROWSER_TEST_P(
     ResourceLoadingHintsBrowserTest,
     DISABLE_ON_WIN_MAC_CHROMESOS(SameOriginDifferentPattern)) {
-  if (use_preload_resources_webpage() && !use_render_frame_observer())
-    return;
   // Whitelist resource loading hints for https_url()'s' host and pattern.
   SetDefaultOnlyResourceLoadingHintsWithPagePattern(https_hint_setup_url(),
                                                     https_url().path());
@@ -872,8 +837,6 @@
 IN_PROC_BROWSER_TEST_P(
     ResourceLoadingHintsBrowserTest,
     DISABLE_ON_WIN_MAC_CHROMESOS(MixExperimentalHints_ExperimentIsNotEnabled)) {
-  if (use_preload_resources_webpage() && !use_render_frame_observer())
-    return;
   base::test::ScopedFeatureList scoped_list;
   scoped_list.InitAndEnableFeatureWithParameters(
       optimization_guide::features::kOptimizationHintsExperiments,
@@ -909,8 +872,6 @@
     ResourceLoadingHintsBrowserTest,
     DISABLE_ON_WIN_MAC_CHROMESOS(
         ResourceLoadingHintsHttpsWhitelistedRedirectToHttps)) {
-  if (use_preload_resources_webpage() && !use_render_frame_observer())
-    return;
   GURL url = redirect_url();
 
   // Whitelist resource loading hints for https_hint_setup_url()'s' host.
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
index 9049ffa..ccfb7d0 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
@@ -49,13 +49,6 @@
     content::NavigationHandle* navigation_handle) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
-  // When kSendPreviewsLoadingHintsBeforeCommit is disabled, resource
-  // loading hints are sent in DidFinishNavigation.
-  if (!base::FeatureList::IsEnabled(
-          blink::features::kSendPreviewsLoadingHintsBeforeCommit)) {
-    return;
-  }
-
   if (!navigation_handle->IsInMainFrame() ||
       navigation_handle->IsSameDocument() || navigation_handle->IsErrorPage()) {
     return;
@@ -75,15 +68,6 @@
   }
 
   ReportRedirects(navigation_handle);
-
-  // When kSendPreviewsLoadingHintsBeforeCommit is enabled, resource
-  // loading hints are sent in ReadyToCommitNavigation.
-  if (base::FeatureList::IsEnabled(
-          blink::features::kSendPreviewsLoadingHintsBeforeCommit)) {
-    return;
-  }
-
-  SendResourceLoadingHints(navigation_handle);
 }
 
 void ResourceLoadingHintsWebContentsObserver::SendResourceLoadingHints(
@@ -112,13 +96,6 @@
   mojo::Remote<blink::mojom::PreviewsResourceLoadingHintsReceiver>
       hints_receiver;
 
-  if (!base::FeatureList::IsEnabled(
-          blink::features::kSendPreviewsLoadingHintsBeforeCommit)) {
-    // Hints should be sent only after the renderer frame has committed.
-    DCHECK(navigation_handle->HasCommitted());
-    web_contents()->GetMainFrame()->GetRemoteInterfaces()->GetInterface(
-        hints_receiver.BindNewPipeAndPassReceiver());
-  }
   blink::mojom::PreviewsResourceLoadingHintsPtr hints_ptr =
       blink::mojom::PreviewsResourceLoadingHints::New();
 
@@ -142,14 +119,9 @@
   for (const std::string& hint : hints)
     hints_ptr->subresources_to_block.push_back(hint);
 
-  if (!base::FeatureList::IsEnabled(
-          blink::features::kSendPreviewsLoadingHintsBeforeCommit)) {
-    hints_receiver->SetResourceLoadingHints(std::move(hints_ptr));
-  } else {
     auto hints_receiver_associated =
         GetResourceLoadingHintsReceiver(navigation_handle);
     hints_receiver_associated->SetResourceLoadingHints(std::move(hints_ptr));
-  }
 }
 
 const std::vector<std::string> ResourceLoadingHintsWebContentsObserver::
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 306a056d..36a9356b9 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -39,6 +39,9 @@
         "welcome:closure_compile",
       ]
     }
+    if (is_win) {
+      deps += [ "sandbox_internals:closure_compile" ]
+    }
     if (is_chromeos) {
       deps += [ "chromeos:closure_compile" ]
     }
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
index 913648a..bee9b77a 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
@@ -96,8 +96,8 @@
    * @private
    */
   this.modes_ = new cca.views.camera.Modes(
-      photoPreferrer, videoPreferrer, this.restart.bind(this), doSavePhoto,
-      createVideoSaver, doSaveVideo);
+      this.defaultMode, photoPreferrer, videoPreferrer, this.restart.bind(this),
+      doSavePhoto, createVideoSaver, doSaveVideo);
 
   /**
    * @type {?string}
@@ -165,6 +165,16 @@
     return this.locked_ || chrome.app.window.current().isMinimized() ||
         cca.state.get('suspend');
   },
+  get defaultMode() {
+    switch (window.intent && window.intent.mode) {
+      case cca.intent.Mode.PHOTO:
+        return cca.views.camera.Mode.PHOTO;
+      case cca.intent.Mode.VIDEO:
+        return cca.views.camera.Mode.VIDEO;
+      default:
+        return cca.views.camera.Mode.PHOTO;
+    }
+  },
 };
 
 /**
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
index 20c02f8..43693e5 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
@@ -71,7 +71,19 @@
  */
 
 /**
+ * Capture modes.
+ * @enum {string}
+ */
+cca.views.camera.Mode = {
+  PHOTO: 'photo-mode',
+  VIDEO: 'video-mode',
+  SQUARE: 'square-mode',
+  PORTRAIT: 'portrait-mode',
+};
+
+/**
  * Mode controller managing capture sequence of different camera mode.
+ * @param {!cca.views.camera.Mode} defaultMode Default mode to be switched to.
  * @param {cca.device.PhotoResolPreferrer} photoResolPreferrer
  * @param {cca.device.VideoConstraintsPreferrer} videoPreferrer
  * @param {!DoSwitchMode} doSwitchMode
@@ -81,7 +93,7 @@
  * @constructor
  */
 cca.views.camera.Modes = function(
-    photoResolPreferrer, videoPreferrer, doSwitchMode, doSavePhoto,
+    defaultMode, photoResolPreferrer, videoPreferrer, doSwitchMode, doSavePhoto,
     createVideoSaver, doSaveVideo) {
   /**
    * @type {!DoSwitchMode}
@@ -91,7 +103,7 @@
 
   /**
    * Capture controller of current camera mode.
-   * @type {cca.views.camera.Mode}
+   * @type {cca.views.camera.ModeBase}
    */
   this.current = null;
 
@@ -188,12 +200,12 @@
   });
 
   // Set default mode when app started.
-  this.updateModeUI_('photo-mode');
+  this.updateModeUI_(defaultMode);
 };
 
 /**
  * Updates state of mode related UI to the target mode.
- * @param {string} mode Mode to be toggled.
+ * @param {!cca.views.camera.Mode} mode Mode to be toggled.
  */
 cca.views.camera.Modes.prototype.updateModeUI_ = function(mode) {
   Object.keys(this.allModes_).forEach((m) => cca.state.set(m, m == mode));
@@ -411,7 +423,7 @@
  *     height.
  * @constructor
  */
-cca.views.camera.Mode = function(stream, captureResolution) {
+cca.views.camera.ModeBase = function(stream, captureResolution) {
   /**
    * Stream of current mode.
    * @type {?Promise}
@@ -439,7 +451,7 @@
  * Initiates video/photo capture operation.
  * @return {?Promise} Promise for ongoing capture operation.
  */
-cca.views.camera.Mode.prototype.startCapture = function() {
+cca.views.camera.ModeBase.prototype.startCapture = function() {
   if (!this.capture_) {
     this.capture_ = this.start_().finally(() => this.capture_ = null);
   }
@@ -451,7 +463,7 @@
  * @async
  * @return {Promise} Promise for ongoing capture operation.
  */
-cca.views.camera.Mode.prototype.stopCapture = async function() {
+cca.views.camera.ModeBase.prototype.stopCapture = async function() {
   this.stop_();
   return await this.capture_;
 };
@@ -460,26 +472,27 @@
  * Adds an observer to save image metadata.
  * @return {!Promise} Promise for the operation.
  */
-cca.views.camera.Mode.prototype.addMetadataObserver = async function() {};
+cca.views.camera.ModeBase.prototype.addMetadataObserver = async function() {};
 
 /**
  * Remove the observer that saves metadata.
  * @return {!Promise} Promise for the operation.
  */
-cca.views.camera.Mode.prototype.removeMetadataObserver = async function() {};
+cca.views.camera.ModeBase.prototype.removeMetadataObserver =
+    async function() {};
 
 /**
  * Initiates video/photo capture operation under this mode.
  * @async
  * @protected
  */
-cca.views.camera.Mode.prototype.start_ = async function() {};
+cca.views.camera.ModeBase.prototype.start_ = async function() {};
 
 /**
  * Stops the ongoing capture operation under this mode.
  * @protected
  */
-cca.views.camera.Mode.prototype.stop_ = function() {};
+cca.views.camera.ModeBase.prototype.stop_ = function() {};
 
 /**
  * Video mode capture controller.
@@ -489,7 +502,7 @@
  * @constructor
  */
 cca.views.camera.Video = function(stream, createVideoSaver, doSaveVideo) {
-  cca.views.camera.Mode.call(this, stream, null);
+  cca.views.camera.ModeBase.call(this, stream, null);
 
   /**
    * @type {!CreateVideoSaver}
@@ -529,7 +542,7 @@
 };
 
 cca.views.camera.Video.prototype = {
-  __proto__: cca.views.camera.Mode.prototype,
+  __proto__: cca.views.camera.ModeBase.prototype,
 };
 
 /**
@@ -637,7 +650,7 @@
  * @constructor
  */
 cca.views.camera.Photo = function(stream, doSavePhoto, captureResolution) {
-  cca.views.camera.Mode.call(this, stream, captureResolution);
+  cca.views.camera.ModeBase.call(this, stream, captureResolution);
 
   /**
    * Callback for saving picture.
@@ -669,7 +682,7 @@
 };
 
 cca.views.camera.Photo.prototype = {
-  __proto__: cca.views.camera.Mode.prototype,
+  __proto__: cca.views.camera.ModeBase.prototype,
 };
 
 /**
diff --git a/chrome/browser/resources/chromeos/camera/src/views/main.html b/chrome/browser/resources/chromeos/camera/src/views/main.html
index 33664d4..fc78682 100644
--- a/chrome/browser/resources/chromeos/camera/src/views/main.html
+++ b/chrome/browser/resources/chromeos/camera/src/views/main.html
@@ -12,6 +12,7 @@
     <script src="../js/browser_proxy/browser_proxy.js"></script>
     <script src="../js/google-analytics-bundle.js"></script>
     <script src="../js/metrics.js"></script>
+    <script src="../js/intent.js"></script>
     <script src="../js/util.js"></script>
     <script src="../js/resolution_event_broker.js"></script>
     <script src="../js/toast.js"></script>
diff --git a/chrome/browser/resources/sandbox_internals/BUILD.gn b/chrome/browser/resources/sandbox_internals/BUILD.gn
new file mode 100644
index 0000000..63c7e16
--- /dev/null
+++ b/chrome/browser/resources/sandbox_internals/BUILD.gn
@@ -0,0 +1,20 @@
+# 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("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+  if (is_win) {
+    deps = [
+      ":sandbox_internals_win",
+    ]
+  }
+}
+
+js_library("sandbox_internals_win") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:util",
+  ]
+}
diff --git a/chrome/browser/resources/sandbox_internals/OWNERS b/chrome/browser/resources/sandbox_internals/OWNERS
new file mode 100644
index 0000000..058ee25c
--- /dev/null
+++ b/chrome/browser/resources/sandbox_internals/OWNERS
@@ -0,0 +1,3 @@
+file://sandbox/OWNERS
+# COMPONENT: Internals>Sandbox
+# TEAM: security-dev@chromium.org
diff --git a/chrome/browser/resources/sandbox_internals/sandbox_internals.html b/chrome/browser/resources/sandbox_internals/sandbox_internals.html
index 7f4816b..c5c269f 100644
--- a/chrome/browser/resources/sandbox_internals/sandbox_internals.html
+++ b/chrome/browser/resources/sandbox_internals/sandbox_internals.html
@@ -30,10 +30,13 @@
       }
     </style>
     <script src="chrome://resources/js/cr.js"></script>
-    <if expr="not is_android">
+<if expr="is_linux">
     <script src="chrome://resources/js/load_time_data.js"></script>
     <script src="chrome://sandbox/strings.js"></script>
-    </if>
+</if>
+<if expr="is_win">
+    <script src="chrome://resources/js/promise_resolver.js"></script>
+</if>
     <script src="chrome://resources/js/util.js"></script>
     <script src="sandbox_internals.js"></script>
   </head>
@@ -42,7 +45,9 @@
 
     <table id="sandbox-status">
     </table>
-
     <p id="evaluation"></p>
+<if expr="is_win">
+    <pre id="raw-info"></pre>
+</if>
   </body>
 </html>
diff --git a/chrome/browser/resources/sandbox_internals/sandbox_internals_win.js b/chrome/browser/resources/sandbox_internals/sandbox_internals_win.js
new file mode 100644
index 0000000..100b04e
--- /dev/null
+++ b/chrome/browser/resources/sandbox_internals/sandbox_internals_win.js
@@ -0,0 +1,108 @@
+// 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.
+
+/**
+ * @typedef {{
+ *   processId: number,
+ *   processType: string,
+ *   name: string,
+ *   metricsName: string
+ * }}
+ */
+let BrowserHostProcess;
+
+/**
+ * @typedef {{
+ *   processId: number
+ * }}
+ */
+let RendererHostProcess;
+
+/**
+ * This may have additional fields displayed in the JSON output.
+ * See //sandbox/win/src/sandbox_constants.cc for keys in policy.
+ * @typedef {{
+ *   processIds: !Array<number>,
+ *   lockdownLevel: string,
+ *   desiredIntegrityLevel: string,
+ *   platformMitigations: string
+ * }}
+ */
+let PolicyDiagnostic;
+
+/**
+ * @typedef {{
+ *   browser: !Array<!BrowserHostProcess>,
+ *   renderer: !Array<!RendererHostProcess>,
+ *   policies: !Array<!PolicyDiagnostic>
+ * }}
+ */
+let SandboxDiagnostics;
+
+/**
+ * Adds a row to the sandbox-status table.
+ * @param {!Array<string>} args
+ */
+function addRow(args) {
+  const row = document.createElement('tr');
+  for (const text of args) {
+    const col = row.appendChild(document.createElement('td'));
+    col.textContent = text;
+  }
+  $('sandbox-status').appendChild(row);
+}
+
+/**
+ * Adds policy information for a process to the sandbox-status table.
+ * @param {number} pid
+ * @param {string} type
+ * @param {string} name
+ * @param {PolicyDiagnostic} policy
+ */
+function addRowForProcess(pid, type, name, policy) {
+  if (policy) {
+    addRow([
+      pid, type, name, policy.lockdownLevel, policy.desiredIntegrityLevel,
+      policy.platformMitigations
+    ]);
+  } else {
+    addRow([pid, type, name, 'Not Sandboxed', '', '']);
+  }
+}
+
+/** @param {!SandboxDiagnostics} results */
+function onGetSandboxDiagnostics(results) {
+  // Make it easy to look up policies.
+  /** @type {!Map<number,!PolicyDiagnostic>} */
+  const policies = new Map();
+  for (const policy of results.policies) {
+    // At present only one process per TargetPolicy object.
+    const pid = policy.processIds[0];
+    policies.set(pid, policy);
+  }
+
+  // Titles.
+  addRow(['Process', 'Type', 'Name', 'Sandbox', 'Intregity', 'Mitigations']);
+
+  // Browser Processes.
+  for (const process of results.browser) {
+    const pid = process.processId;
+    const name = process.name || process.metricsName;
+    addRowForProcess(pid, process.processType, name, policies.get(pid));
+  }
+
+  // Renderer Processes.
+  for (const process of results.renderer) {
+    const pid = process.processId;
+    addRowForProcess(pid, 'Renderer', '', policies.get(pid));
+  }
+
+  // Raw Diagnostics.
+  $('raw-info').textContent =
+      'policies: ' + JSON.stringify(results.policies, null, 2);
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+  cr.sendWithPromise('requestSandboxDiagnostics').then(onGetSandboxDiagnostics);
+});
diff --git a/chrome/browser/resources/tab_strip/tab.html b/chrome/browser/resources/tab_strip/tab.html
index 0e23e27a..e86a82a4 100644
--- a/chrome/browser/resources/tab_strip/tab.html
+++ b/chrome/browser/resources/tab_strip/tab.html
@@ -3,6 +3,7 @@
     --tabstrip-tab-height: 216px;
     --tabstrip-tab-width: 288px;
     --tabstrip-tab-title-height: 40px;
+    --tabstrip-tab-transition-duration: 250ms;
 
     cursor: pointer;
     height: var(--tabstrip-tab-height);
@@ -13,7 +14,7 @@
   #dragImage {
     background: var(--tabstrip-tab-background-color);
     border-radius: var(--tabstrip-card-border-radius);
-    box-shadow: 0 0 0 1px currentColor;
+    box-shadow: 0 0 0 1px var(--tabstrip-tab-separator-color);
     color: var(--tabstrip-tab-text-color);
     display: flex;
     flex-direction: column;
@@ -29,7 +30,7 @@
 
   #title {
     align-items: center;
-    border-block-end: 1px solid currentColor;
+    border-block-end: 1px solid var(--tabstrip-tab-separator-color);
     box-sizing: border-box;
     display: flex;
     height: var(--tabstrip-tab-title-height);
@@ -43,12 +44,14 @@
     height: 100%;
     margin-inline-end: 8px;
     margin-inline-start: 12px;
+    overflow: hidden;
     position: relative;
     width: var(--favicon-size);
   }
 
   #loading,
-  #favicon {
+  #favicon,
+  #crashedIcon {
     height: var(--favicon-size);
     left: 50%;
     position: absolute;
@@ -67,7 +70,16 @@
 
   #favicon {
     background-size: contain;
-    transition: border-radius 250ms;
+    transition: border-radius var(--tabstrip-tab-transition-duration);
+  }
+
+  #crashedIcon {
+    -webkit-mask:
+        url(chrome://theme/IDR_CRASH_SAD_FAVICON@2x)
+        center/contain no-repeat;
+    background-color: currentColor;
+    opacity: 0;
+    transform: translate(-50%, 100%);
   }
 
   :host([loading]) #loading,
@@ -82,6 +94,24 @@
     width: calc(var(--favicon-size) - 6px);
   }
 
+  :host([crashed]) #favicon {
+    opacity: 0;
+    transform: translate(-50%, 100%);
+    transition:
+        opacity var(--tabstrip-tab-transition-duration),
+        transform var(--tabstrip-tab-transition-duration);
+  }
+
+  :host([crashed]) #crashedIcon {
+    opacity: 1;
+    transform: translate(-50%, -50%);
+    transition:
+        opacity var(--tabstrip-tab-transition-duration),
+        transform var(--tabstrip-tab-transition-duration);
+    /* Wait until transition for #favicon finishes. */
+    transition-delay: var(--tabstrip-tab-transition-duration);
+  }
+
   #titleText {
     font-size: 100%;
     font-weight: normal;
@@ -178,6 +208,7 @@
     <div id="faviconContainer">
       <div id="loading"></div>
       <div id="favicon"></div>
+      <div id="crashedIcon"></div>
     </div>
     <h2 id="titleText"></h2>
     <button id="close">
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.cc
index 0e57121..187ddfc6 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.cc
@@ -131,6 +131,20 @@
   std::move(callback).Run(result_, data_);
 }
 
+bool DlpTriggeredRulesOK(
+    const ::safe_browsing::DlpDeepScanningVerdict& verdict) {
+  if (verdict.status() != DlpDeepScanningVerdict::SUCCESS)
+    return false;
+
+  for (int i = 0; i < verdict.triggered_rules_size(); ++i) {
+    if (verdict.triggered_rules(i).action() ==
+        DlpDeepScanningVerdict::TriggeredRule::BLOCK) {
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace
 
 // A BinaryUploadService::Request implementation that gets the data to scan
@@ -352,7 +366,7 @@
 
   text_request_complete_ = true;
   bool text_complies = (result == BinaryUploadService::Result::SUCCESS &&
-                        response.dlp_scan_verdict().triggered_rules().empty());
+                        DlpTriggeredRulesOK(response.dlp_scan_verdict()));
   std::fill(result_.text_results.begin(), result_.text_results.end(),
             text_complies);
   MaybeCompleteScanRequest();
@@ -372,7 +386,7 @@
       web_contents_->GetLastCommittedURL(), path.AsUTF8Unsafe(), sha256_[index],
       result, response);
 
-  bool dlp_ok = response.dlp_scan_verdict().triggered_rules().empty();
+  bool dlp_ok = DlpTriggeredRulesOK(response.dlp_scan_verdict());
   bool malware_ok = response.malware_scan_verdict().verdict() !=
                         MalwareDeepScanningVerdict::UWS &&
                     response.malware_scan_verdict().verdict() !=
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate_unittest.cc
index 67ebf82..5d7dff9 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate_unittest.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h"
 
-#include <set>
+#include <map>
 #include <vector>
 
 #include "base/bind.h"
@@ -242,8 +242,9 @@
     return web_contents_.get();
   }
 
-  void PathFailsDeepScan(base::FilePath path) {
-    failures_.insert(std::move(path));
+  void PathFailsDeepScan(base::FilePath path,
+                         DeepScanningClientResponse response) {
+    failures_.insert({std::move(path), std::move(response)});
   }
 
  private:
@@ -262,16 +263,20 @@
         kDmToken));
   }
 
-  bool StatusCallback(const base::FilePath& path) {
+  DeepScanningClientResponse StatusCallback(const base::FilePath& path) {
     // The path succeeds if it is not in the |failures_| maps.
-    return failures_.find(path) == failures_.end();
+    auto it = failures_.find(path);
+    return it != failures_.end()
+               ? it->second
+               : FakeDeepScanningDialogDelegate::SuccessfulResponse();
   }
 
   base::RunLoop run_loop_;
   std::unique_ptr<content::WebContents> web_contents_;
 
   // Paths in this map will be consider to have failed deep scan checks.
-  std::set<base::FilePath> failures_;
+  // The actual failure response is given for each path.
+  std::map<base::FilePath, DeepScanningClientResponse> failures_;
 };
 
 TEST_F(DeepScanningDialogDelegateAuditOnlyTest, Empty) {
@@ -440,8 +445,26 @@
 
   data.text.emplace_back(base::UTF8ToUTF16("foo"));
   data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo"));
+  data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_malware_1"));
+  data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_malware_2"));
+  data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_dlp_status"));
+  data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_dlp_rule"));
 
-  PathFailsDeepScan(data.paths[0]);
+  // Mark some files with failed scans.
+  PathFailsDeepScan(data.paths[1],
+                    FakeDeepScanningDialogDelegate::MalwareResponse(
+                        MalwareDeepScanningVerdict::UWS));
+  PathFailsDeepScan(data.paths[2],
+                    FakeDeepScanningDialogDelegate::MalwareResponse(
+                        MalwareDeepScanningVerdict::MALWARE));
+  PathFailsDeepScan(data.paths[3],
+                    FakeDeepScanningDialogDelegate::DlpResponse(
+                        DlpDeepScanningVerdict::FAILURE, "",
+                        DlpDeepScanningVerdict::TriggeredRule::REPORT_ONLY));
+  PathFailsDeepScan(data.paths[4],
+                    FakeDeepScanningDialogDelegate::DlpResponse(
+                        DlpDeepScanningVerdict::SUCCESS, "rule",
+                        DlpDeepScanningVerdict::TriggeredRule::BLOCK));
 
   bool called = false;
   DeepScanningDialogDelegate::ShowForWebContents(
@@ -450,11 +473,15 @@
           [](bool* called, const DeepScanningDialogDelegate::Data& data,
              const DeepScanningDialogDelegate::Result& result) {
             EXPECT_EQ(1u, data.text.size());
-            EXPECT_EQ(1u, data.paths.size());
+            EXPECT_EQ(5u, data.paths.size());
             ASSERT_EQ(1u, result.text_results.size());
-            ASSERT_EQ(1u, result.paths_results.size());
+            ASSERT_EQ(5u, result.paths_results.size());
             EXPECT_TRUE(result.text_results[0]);
-            EXPECT_FALSE(result.paths_results[0]);
+            EXPECT_TRUE(result.paths_results[0]);
+            EXPECT_FALSE(result.paths_results[1]);
+            EXPECT_FALSE(result.paths_results[2]);
+            EXPECT_FALSE(result.paths_results[3]);
+            EXPECT_FALSE(result.paths_results[4]);
             *called = true;
           },
           &called));
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.cc b/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.cc
index 9336a8f..4fcd4ad0 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.cc
@@ -42,19 +42,53 @@
   return ret;
 }
 
+// static
+DeepScanningClientResponse
+FakeDeepScanningDialogDelegate::SuccessfulResponse() {
+  DeepScanningClientResponse response;
+  response.mutable_dlp_scan_verdict()->set_status(
+      DlpDeepScanningVerdict::SUCCESS);
+  response.mutable_malware_scan_verdict()->set_verdict(
+      MalwareDeepScanningVerdict::CLEAN);
+  return response;
+}
+
+// static
+DeepScanningClientResponse FakeDeepScanningDialogDelegate::MalwareResponse(
+    MalwareDeepScanningVerdict::Verdict verdict) {
+  DeepScanningClientResponse response;
+  response.mutable_dlp_scan_verdict()->set_status(
+      DlpDeepScanningVerdict::SUCCESS);
+  response.mutable_malware_scan_verdict()->set_verdict(verdict);
+  return response;
+}
+
+// static
+DeepScanningClientResponse FakeDeepScanningDialogDelegate::DlpResponse(
+    DlpDeepScanningVerdict::Status status,
+    const std::string& rule_name,
+    DlpDeepScanningVerdict::TriggeredRule::Action action) {
+  DeepScanningClientResponse response;
+  response.mutable_dlp_scan_verdict()->set_status(status);
+  response.mutable_malware_scan_verdict()->set_verdict(
+      MalwareDeepScanningVerdict::CLEAN);
+
+  if (!rule_name.empty()) {
+    DlpDeepScanningVerdict::TriggeredRule* rule =
+        response.mutable_dlp_scan_verdict()->add_triggered_rules();
+    rule->set_rule_name(rule_name);
+    rule->set_action(action);
+  }
+
+  return response;
+}
+
 void FakeDeepScanningDialogDelegate::Response(
     base::FilePath path,
     std::unique_ptr<BinaryUploadService::Request> request) {
-  DeepScanningClientResponse response;
-  bool status = status_callback_.is_null() ? false : status_callback_.Run(path);
-  if (!status) {
-    // If the scan should fail, mark both the DLP and malware as failed.
-    // for DLP, just add a rule to the triggered list., does not matter what
-    // the rule is.  For malware, just set the verdict to MALWARE.
-    response.mutable_dlp_scan_verdict()->mutable_triggered_rules()->Add();
-    response.mutable_malware_scan_verdict()->set_verdict(
-        MalwareDeepScanningVerdict::MALWARE);
-  }
+  DeepScanningClientResponse response = status_callback_.is_null()
+                                            ? DeepScanningClientResponse()
+                                            : status_callback_.Run(path);
 
   if (path.empty()) {
     StringRequestCallback(BinaryUploadService::Result::SUCCESS, response);
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.h b/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.h
index 4e0b2ad..30041568 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.h
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h"
 #include "chrome/browser/safe_browsing/download_protection/binary_upload_service.h"
+#include "components/safe_browsing/proto/webprotect.pb.h"
 
 namespace content {
 class WebContents;
@@ -23,9 +24,12 @@
 class FakeDeepScanningDialogDelegate : public DeepScanningDialogDelegate {
  public:
   // Callback that determines the scan status of the file specified.  To
-  // simulate a file that passes a scan, return true, otherwise return false.
-  // If an empty path is given, this represents the non-file based text data.
-  using StatusCallback = base::RepeatingCallback<bool(const base::FilePath&)>;
+  // simulate a file that passes a scan return a successful response, such
+  // as the value returned by SuccessfulResponse().  To simulate a file that
+  // does not pass a scan return a failed response, such as the value returned
+  // by MalwareResponse() or DlpResponse().
+  using StatusCallback = base::RepeatingCallback<DeepScanningClientResponse(
+      const base::FilePath&)>;
 
   FakeDeepScanningDialogDelegate(base::RepeatingClosure delete_closure,
                                  StatusCallback status_callback,
@@ -46,6 +50,19 @@
       Data data,
       CompletionCallback callback);
 
+  // Returns a deep scanning response that represents a successful scan.
+  static DeepScanningClientResponse SuccessfulResponse();
+
+  // Returns a deep scanning response with a specific malware verdict,
+  static DeepScanningClientResponse MalwareResponse(
+      MalwareDeepScanningVerdict::Verdict verdict);
+
+  // Returns a deep scanning response with a specific DLP verdict,
+  static DeepScanningClientResponse DlpResponse(
+      DlpDeepScanningVerdict::Status status,
+      const std::string& rule_name,
+      DlpDeepScanningVerdict::TriggeredRule::Action action);
+
  private:
   // Simulates a response from the binary upload service.  the |path| argument
   // is used to call |status_callback_| to determine if the path should succeed
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
index 99470455..0f5b01c 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
@@ -19,6 +19,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
+#include "chrome/browser/safe_browsing/download_protection/binary_upload_service.h"
+#include "chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h"
 #include "chrome/browser/safe_browsing/download_protection/download_feedback_service.h"
 #include "chrome/browser/safe_browsing/download_protection/download_item_request.h"
 #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
@@ -58,6 +60,32 @@
   }
 }
 
+void DeepScanningClientResponseToDownloadCheckResult(
+    const DeepScanningClientResponse& response,
+    DownloadCheckResult* download_result,
+    DownloadCheckResultReason* download_reason) {
+  if (response.has_malware_scan_verdict() &&
+      response.malware_scan_verdict().verdict() ==
+          MalwareDeepScanningVerdict::MALWARE) {
+    *download_result = DownloadCheckResult::DANGEROUS;
+    *download_reason = DownloadCheckResultReason::REASON_DOWNLOAD_DANGEROUS;
+    return;
+  }
+
+  if (response.has_malware_scan_verdict() &&
+      response.malware_scan_verdict().verdict() ==
+          MalwareDeepScanningVerdict::UWS) {
+    *download_result = DownloadCheckResult::POTENTIALLY_UNWANTED;
+    *download_reason =
+        DownloadCheckResultReason::REASON_DOWNLOAD_POTENTIALLY_UNWANTED;
+    return;
+  }
+
+  // TODO(drubery): Handle DLP violations here as well.
+  *download_result = DownloadCheckResult::SAFE;
+  *download_reason = DownloadCheckResultReason::REASON_DOWNLOAD_SAFE;
+}
+
 }  // namespace
 
 void MaybeReportDownloadDeepScanningVerdict(
@@ -101,7 +129,7 @@
 
 CheckClientDownloadRequest::CheckClientDownloadRequest(
     download::DownloadItem* item,
-    CheckDownloadCallback callback,
+    CheckDownloadRepeatingCallback callback,
     DownloadProtectionService* service,
     scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
     scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor)
@@ -111,11 +139,12 @@
           item->GetFullPath(),
           {item->GetTabUrl(), item->GetTabReferrerUrl()},
           content::DownloadItemUtils::GetBrowserContext(item),
-          std::move(callback),
+          callback,
           service,
           std::move(database_manager),
           std::move(binary_feature_extractor)),
-      item_(item) {
+      item_(item),
+      callback_(callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   item_->AddObserver(this);
   DVLOG(2) << "Starting SafeBrowsing download check for: "
@@ -248,44 +277,60 @@
       result, upload_requested, item_, request_data, response_body);
 }
 
+bool CheckClientDownloadRequest::ShouldReturnAsynchronousVerdict(
+    DownloadCheckResultReason reason) {
+  if (!ShouldUploadForDlpScan() && !ShouldUploadForMalwareScan(reason))
+    return false;
+
+  Profile* profile = Profile::FromBrowserContext(GetBrowserContext());
+  if (!profile)
+    return false;
+
+  return ShouldDelayVerdicts();
+}
+
+bool CheckClientDownloadRequest::ShouldDelayVerdicts() {
+  int delay_delivery = g_browser_process->local_state()->GetInteger(
+      prefs::kDelayDeliveryUntilVerdict);
+  return (delay_delivery == DELAY_DOWNLOADS ||
+          delay_delivery == DELAY_UPLOADS_AND_DOWNLOADS);
+}
+
 void CheckClientDownloadRequest::MaybeUploadBinary(
     DownloadCheckResultReason reason) {
   bool upload_for_dlp = ShouldUploadForDlpScan();
   bool upload_for_malware = ShouldUploadForMalwareScan(reason);
-  if (upload_for_dlp || upload_for_malware) {
-    Profile* profile = Profile::FromBrowserContext(GetBrowserContext());
-    if (!profile)
-      return;
+  if (!upload_for_dlp && !upload_for_malware)
+    return;
 
-    const std::string& raw_digest_sha256 = item_->GetHash();
-    auto request = std::make_unique<DownloadItemRequest>(
-        item_, base::BindOnce(&MaybeReportDownloadDeepScanningVerdict, profile,
-                              item_->GetURL(),
-                              item_->GetTargetFilePath().AsUTF8Unsafe(),
-                              base::HexEncode(raw_digest_sha256.data(),
-                                              raw_digest_sha256.size())));
+  Profile* profile = Profile::FromBrowserContext(GetBrowserContext());
+  if (!profile)
+    return;
 
-    if (upload_for_dlp) {
-      DlpDeepScanningClientRequest dlp_request;
-      dlp_request.set_content_source(
-          DlpDeepScanningClientRequest::FILE_DOWNLOAD);
-      request->set_request_dlp_scan(std::move(dlp_request));
-    }
+  auto request = std::make_unique<DownloadItemRequest>(
+      item_, ShouldDelayVerdicts(),
+      base::BindOnce(&CheckClientDownloadRequest::OnDeepScanningComplete,
+                     weakptr_factory_.GetWeakPtr()));
 
-    if (upload_for_malware) {
-      MalwareDeepScanningClientRequest malware_request;
-      malware_request.set_population(
-          MalwareDeepScanningClientRequest::POPULATION_ENTERPRISE);
-      malware_request.set_download_token(
-          DownloadProtectionService::GetDownloadPingToken(item_));
-      request->set_request_malware_scan(std::move(malware_request));
-    }
-
-    request->set_dm_token(
-        policy::BrowserDMTokenStorage::Get()->RetrieveDMToken());
-
-    service()->UploadForDeepScanning(profile, std::move(request));
+  if (upload_for_dlp) {
+    DlpDeepScanningClientRequest dlp_request;
+    dlp_request.set_content_source(DlpDeepScanningClientRequest::FILE_DOWNLOAD);
+    request->set_request_dlp_scan(std::move(dlp_request));
   }
+
+  if (upload_for_malware) {
+    MalwareDeepScanningClientRequest malware_request;
+    malware_request.set_population(
+        MalwareDeepScanningClientRequest::POPULATION_ENTERPRISE);
+    malware_request.set_download_token(
+        DownloadProtectionService::GetDownloadPingToken(item_));
+    request->set_request_malware_scan(std::move(malware_request));
+  }
+
+  request->set_dm_token(
+      policy::BrowserDMTokenStorage::Get()->RetrieveDMToken());
+
+  service()->UploadForDeepScanning(profile, std::move(request));
 }
 
 void CheckClientDownloadRequest::NotifyRequestFinished(
@@ -365,4 +410,36 @@
   return true;
 }
 
+void CheckClientDownloadRequest::OnDeepScanningComplete(
+    BinaryUploadService::Result result,
+    DeepScanningClientResponse response) {
+  Profile* profile = Profile::FromBrowserContext(GetBrowserContext());
+  if (profile) {
+    std::string raw_digest_sha256 = item_->GetHash();
+    MaybeReportDownloadDeepScanningVerdict(
+        profile, item_->GetURL(), item_->GetTargetFilePath().AsUTF8Unsafe(),
+        base::HexEncode(raw_digest_sha256.data(), raw_digest_sha256.size()),
+        result, response);
+  }
+
+  if (!ShouldDelayVerdicts())
+    return;
+
+  DownloadCheckResult download_result = DownloadCheckResult::SAFE;
+  DownloadCheckResultReason download_reason =
+      DownloadCheckResultReason::REASON_DOWNLOAD_SAFE;
+
+  // Fails open in case of error.
+  if (result == BinaryUploadService::Result::SUCCESS) {
+    DeepScanningClientResponseToDownloadCheckResult(response, &download_result,
+                                                    &download_reason);
+  }
+
+  // If we're not delaying verdicts, we already ran |callback_| with the final
+  // result in FinishRequest.
+  callback_.Run(download_result);
+  NotifyRequestFinished(download_result, download_reason);
+  service()->RequestFinished(this);
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.h b/chrome/browser/safe_browsing/download_protection/check_client_download_request.h
index d1472b0..33d1747 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.h
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.h
@@ -16,7 +16,9 @@
 #include "build/build_config.h"
 #include "chrome/browser/safe_browsing/download_protection/binary_upload_service.h"
 #include "chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h"
+#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
 #include "components/download/public/common/download_item.h"
+#include "components/safe_browsing/proto/webprotect.pb.h"
 #include "content/public/browser/browser_thread.h"
 #include "url/gurl.h"
 
@@ -29,7 +31,7 @@
  public:
   CheckClientDownloadRequest(
       download::DownloadItem* item,
-      CheckDownloadCallback callback,
+      CheckDownloadRepeatingCallback callback,
       DownloadProtectionService* service,
       scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
       scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor);
@@ -56,25 +58,50 @@
                                   bool upload_requested,
                                   const std::string& request_data,
                                   const std::string& response_body) override;
+
+  // Returns true if the CheckClientDownloadRequest should return the
+  // ASYNC_SCANNING result while it does deep scanning.
+  bool ShouldReturnAsynchronousVerdict(
+      DownloadCheckResultReason reason) override;
+
+  // Uploads the binary for deep scanning if the reason and policies indicate
+  // it should be.
   void MaybeUploadBinary(DownloadCheckResultReason reason) override;
+
+  // Called when this request is completed.
   void NotifyRequestFinished(DownloadCheckResult result,
                              DownloadCheckResultReason reason) override;
 
+  // Returns true when the file should be uploaded for a DLP compliance scan.
+  // This consults the CheckContentCompliance enterprise policy.
   bool ShouldUploadForDlpScan();
+
+  // Returns true when the file should be uploaded for a malware scan. This
+  // consults the SendFilesForMalwareCheck enterprise policy.
   bool ShouldUploadForMalwareScan(DownloadCheckResultReason reason);
 
+  // Returns true when the downloads UX should prevent access to the file until
+  // the deep scanning verdict has been received. This consults the
+  // DelayDeliveryUntilVerdict enterprise policy.
+  bool ShouldDelayVerdicts();
+
+  // Called when deep scanning is complete. Where appropriate, it updates the
+  // download UX, and sends a real time report about the download.
+  void OnDeepScanningComplete(BinaryUploadService::Result result,
+                              DeepScanningClientResponse response);
+
   // The DownloadItem we are checking. Will be NULL if the request has been
   // canceled. Must be accessed only on UI thread.
   download::DownloadItem* item_;
+  CheckDownloadRepeatingCallback callback_;
 
   base::WeakPtrFactory<CheckClientDownloadRequest> weakptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(CheckClientDownloadRequest);
 };
 
-// Function that can be called from BinaryUploadService::Callback to report
-// verdicts.  Only successful results are reported, assuming that reporting
-// is turned on by enterprise policy.
+// Helper function to examine a DeepScanningClientResponse and report the
+// appropriate events to the enterprise admin.
 void MaybeReportDownloadDeepScanningVerdict(
     Profile* profile,
     const GURL& url,
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
index b35e2824..5e38253 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h"
 
 #include "base/bind.h"
+#include "base/cancelable_callback.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
@@ -16,6 +17,7 @@
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
 #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
+#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
 #include "chrome/browser/safe_browsing/download_protection/ppapi_download_request.h"
 #include "chrome/common/safe_browsing/file_type_policies.h"
 #include "components/prefs/pref_service.h"
@@ -24,6 +26,7 @@
 #include "components/safe_browsing/web_ui/safe_browsing_ui.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/cpp/simple_url_loader.h"
@@ -206,10 +209,15 @@
 
   MaybeUploadBinary(reason);
 
-  std::move(callback_).Run(result);
-  NotifyRequestFinished(result, reason);
-  service()->RequestFinished(this);
-  // DownloadProtectionService::RequestFinished may delete us.
+  if (ShouldReturnAsynchronousVerdict(reason)) {
+    std::move(callback_).Run(DownloadCheckResult::ASYNC_SCANNING);
+    timeout_closure_.Cancel();
+  } else {
+    std::move(callback_).Run(result);
+    NotifyRequestFinished(result, reason);
+    service()->RequestFinished(this);
+    // DownloadProtectionService::RequestFinished may delete us.
+  }
 }
 
 bool CheckClientDownloadRequestBase::ShouldSampleWhitelistedDownload() {
@@ -377,13 +385,13 @@
 void CheckClientDownloadRequestBase::StartTimeout() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   timeout_start_time_ = base::TimeTicks::Now();
-  base::PostDelayedTask(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&CheckClientDownloadRequestBase::FinishRequest,
-                     GetWeakPtr(), DownloadCheckResult::UNKNOWN,
-                     REASON_REQUEST_CANCELED),
-      base::TimeDelta::FromMilliseconds(
-          service_->download_request_timeout_ms()));
+  timeout_closure_.Reset(base::BindOnce(
+      &CheckClientDownloadRequestBase::FinishRequest, GetWeakPtr(),
+      DownloadCheckResult::UNKNOWN, REASON_REQUEST_CANCELED));
+  base::PostDelayedTask(FROM_HERE, {BrowserThread::UI},
+                        timeout_closure_.callback(),
+                        base::TimeDelta::FromMilliseconds(
+                            service_->download_request_timeout_ms()));
 }
 
 void CheckClientDownloadRequestBase::OnCertificateWhitelistCheckDone(
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h
index 1fdd1a9..d563971 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h
@@ -13,6 +13,7 @@
 
 #include "base/callback.h"
 #include "base/callback_list.h"
+#include "base/cancelable_callback.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
@@ -126,6 +127,11 @@
                                           const std::string& request_data,
                                           const std::string& response_body) = 0;
 
+  // Called when finishing the request, to determine whether asynchronous
+  // scanning is pending.
+  virtual bool ShouldReturnAsynchronousVerdict(
+      DownloadCheckResultReason reason) = 0;
+
   // Called after receiving, or failing to receive a response from the server.
   virtual void MaybeUploadBinary(DownloadCheckResultReason reason) = 0;
 
@@ -146,6 +152,11 @@
 
   CheckDownloadCallback callback_;
 
+  // A cancelable closure used to track the timeout. If we decide to upload the
+  // file for deep scanning, we want to cancel the timeout so it doesn't trigger
+  // in the middle of scanning.
+  base::CancelableOnceClosure timeout_closure_;
+
   std::unique_ptr<network::SimpleURLLoader> loader_;
   std::string client_download_request_data_;
 
diff --git a/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.cc b/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.cc
index 95d8bef..833a8db 100644
--- a/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.cc
@@ -150,6 +150,11 @@
   // TODO(https://crbug.com/996797): Integrate with DownloadFeedbackService.
 }
 
+bool CheckNativeFileSystemWriteRequest::ShouldReturnAsynchronousVerdict(
+    DownloadCheckResultReason reason) {
+  return false;
+}
+
 void CheckNativeFileSystemWriteRequest::MaybeUploadBinary(
     DownloadCheckResultReason reason) {}
 
diff --git a/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.h b/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.h
index 7f02521..54eed13 100644
--- a/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.h
+++ b/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.h
@@ -48,6 +48,8 @@
                                   bool upload_requested,
                                   const std::string& request_data,
                                   const std::string& response_body) override;
+  bool ShouldReturnAsynchronousVerdict(
+      DownloadCheckResultReason reason) override;
   void MaybeUploadBinary(DownloadCheckResultReason reason) override;
   void NotifyRequestFinished(DownloadCheckResult result,
                              DownloadCheckResultReason reason) override;
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request.cc b/chrome/browser/safe_browsing/download_protection/download_item_request.cc
index 1ccca42..831dca14 100644
--- a/chrome/browser/safe_browsing/download_protection/download_item_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_item_request.cc
@@ -6,6 +6,7 @@
 
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/safe_browsing/download_protection/binary_upload_service.h"
 #include "components/download/public/common/download_item.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -40,11 +41,10 @@
 }  // namespace
 
 DownloadItemRequest::DownloadItemRequest(download::DownloadItem* item,
+                                         bool read_immediately,
                                          BinaryUploadService::Callback callback)
-    : Request(std::move(callback)),
-      item_(item),
-      weakptr_factory_(this) {
-  item_->AddObserver(this);
+    : Request(std::move(callback)), item_(item), weakptr_factory_(this) {
+  read_immediately ? ReadFile() : item_->AddObserver(this);
 }
 
 DownloadItemRequest::~DownloadItemRequest() {
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request.h b/chrome/browser/safe_browsing/download_protection/download_item_request.h
index 095c65de..5b725f6 100644
--- a/chrome/browser/safe_browsing/download_protection/download_item_request.h
+++ b/chrome/browser/safe_browsing/download_protection/download_item_request.h
@@ -17,7 +17,13 @@
 class DownloadItemRequest : public BinaryUploadService::Request,
                             download::DownloadItem::Observer {
  public:
+  // Create a DownloadItemRequest for the given |item|. If |read_immediately| is
+  // true, try to read the file contents right away. Otherwise, wait until the
+  // file has been renamed to its final path. If the caller expects |item| to be
+  // renamed imminently, it's recommended to set |read_immediately| to false,
+  // to avoid race conditions while reading the file.
   DownloadItemRequest(download::DownloadItem* item,
+                      bool read_immediately,
                       BinaryUploadService::Callback callback);
   ~DownloadItemRequest() override;
 
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc
index a156871..400f3e3 100644
--- a/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc
@@ -19,7 +19,9 @@
 
 class DownloadItemRequestTest : public ::testing::Test {
  public:
-  DownloadItemRequestTest() : item_(), request_(&item_, base::DoNothing()) {}
+  DownloadItemRequestTest()
+      : item_(),
+        request_(&item_, /*read_immediately=*/false, base::DoNothing()) {}
 
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
index 7f7a1e04..0f485b6 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -168,7 +168,7 @@
 
 void DownloadProtectionService::CheckClientDownload(
     download::DownloadItem* item,
-    CheckDownloadCallback callback) {
+    CheckDownloadRepeatingCallback callback) {
   if (item->GetDangerType() ==
       download::DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY) {
     std::move(callback).Run(DownloadCheckResult::WHITELISTED_BY_POLICY);
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.h b/chrome/browser/safe_browsing/download_protection/download_protection_service.h
index 4329e62..eb968b4 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.h
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.h
@@ -81,7 +81,7 @@
   // invoked on the UI thread.  This method must be called once the download
   // is finished and written to disk.
   virtual void CheckClientDownload(download::DownloadItem* item,
-                                   CheckDownloadCallback callback);
+                                   CheckDownloadRepeatingCallback callback);
 
   // Checks whether any of the URLs in the redirect chain of the
   // download match the SafeBrowsing bad binary URL list.  The result is
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_util.h b/chrome/browser/safe_browsing/download_protection/download_protection_util.h
index 8571f727..97c872e0 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_util.h
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_util.h
@@ -88,6 +88,13 @@
 // Callback type which is invoked once the download request is done.
 typedef base::OnceCallback<void(DownloadCheckResult)> CheckDownloadCallback;
 
+// Callback type which is invoked once the download request is done. This is
+// used in cases where asynchronous scanning is allowed, so the callback is
+// triggered multiple times (once when asynchronous scanning begins, once when
+// the final result is ready).
+typedef base::RepeatingCallback<void(DownloadCheckResult)>
+    CheckDownloadRepeatingCallback;
+
 // A type of callback run on the main thread when a ClientDownloadRequest has
 // been formed for a download, or when one has not been formed for a supported
 // download.
diff --git a/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc b/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
index 639e25a..8eddbf28 100644
--- a/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
+++ b/chrome/browser/site_isolation/chrome_site_per_process_browsertest.cc
@@ -1617,9 +1617,8 @@
 
 // Tests that a cross-site iframe runs its beforeunload handler when closing a
 // tab.  See https://crbug.com/853021.
-// crbug.com/1010061: disabled due to flakiness.
 IN_PROC_BROWSER_TEST_F(ChromeSitePerProcessTest,
-                       DISABLED_TabCloseWithCrossSiteBeforeUnloadIframe) {
+                       TabCloseWithCrossSiteBeforeUnloadIframe) {
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
   content::WebContents* first_web_contents =
       tab_strip_model->GetActiveWebContents();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index b039cfc7..08271819 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -613,13 +613,20 @@
     ]
   }
 
-  if (is_android || is_linux) {
+  if (is_win || is_android || is_linux) {
     sources += [
       "webui/sandbox_internals_ui.cc",
       "webui/sandbox_internals_ui.h",
     ]
   }
 
+  if (is_win) {
+    sources += [
+      "webui/sandbox/sandbox_handler.cc",
+      "webui/sandbox/sandbox_handler.h",
+    ]
+  }
+
   if (is_android) {
     sources += [
       "android/android_about_app_info.cc",
@@ -3722,7 +3729,7 @@
     }
   }
 
-  if (enable_cros_assistant) {
+  if (is_chromeos) {
     deps += [
       "//ash/public/cpp",
       "//chromeos/services/assistant:lib",
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc
index fca4ffc..b5afb81c 100644
--- a/chrome/browser/ui/page_info/page_info.cc
+++ b/chrome/browser/ui/page_info/page_info.cc
@@ -63,6 +63,7 @@
 #include "components/safe_browsing/buildflags.h"
 #include "components/safe_browsing/password_protection/metrics_util.h"
 #include "components/safe_browsing/proto/csd.pb.h"
+#include "components/security_state/core/features.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/ssl_errors/error_info.h"
 #include "components/strings/grit/components_chromium_strings.h"
@@ -826,6 +827,13 @@
           subject_name));
     }
 
+    if (base::FeatureList::IsEnabled(
+            security_state::features::kLegacyTLSWarnings) &&
+        visible_security_state.connection_used_legacy_tls &&
+        !visible_security_state.is_legacy_tls_control_site) {
+      site_connection_status_ = SITE_CONNECTION_STATUS_LEGACY_TLS;
+    }
+
     ReportAnyInsecureContent(visible_security_state, &site_connection_status_,
                              &site_connection_details_);
   }
diff --git a/chrome/browser/ui/page_info/page_info.h b/chrome/browser/ui/page_info/page_info.h
index e793442..1b8dc0d 100644
--- a/chrome/browser/ui/page_info/page_info.h
+++ b/chrome/browser/ui/page_info/page_info.h
@@ -65,6 +65,7 @@
     SITE_CONNECTION_STATUS_UNENCRYPTED,      // Connection is not encrypted.
     SITE_CONNECTION_STATUS_ENCRYPTED_ERROR,  // Connection error occurred.
     SITE_CONNECTION_STATUS_INTERNAL_PAGE,    // Internal site.
+    SITE_CONNECTION_STATUS_LEGACY_TLS,  // Connection used a legacy TLS version.
   };
 
   // Validation status of a website's identity.
diff --git a/chrome/browser/ui/page_info/page_info_ui.cc b/chrome/browser/ui/page_info/page_info_ui.cc
index 419d083b..cad3cc0 100644
--- a/chrome/browser/ui/page_info/page_info_ui.cc
+++ b/chrome/browser/ui/page_info/page_info_ui.cc
@@ -325,6 +325,10 @@
           return CreateSecurityDescription(SecuritySummaryColor::RED,
                                            IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY,
                                            IDS_PAGE_INFO_MIXED_CONTENT_DETAILS);
+        case PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS:
+          return CreateSecurityDescription(SecuritySummaryColor::RED,
+                                           IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY,
+                                           IDS_PAGE_INFO_LEGACY_TLS_DETAILS);
         default:
           return CreateSecurityDescription(SecuritySummaryColor::GREEN,
                                            IDS_PAGE_INFO_SECURE_SUMMARY,
@@ -506,6 +510,7 @@
       break;
     case PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE:
     case PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION:
+    case PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS:
       resource_id = IDR_PAGEINFO_WARNING_MINOR;
       break;
     case PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED:
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc
index e4854f2..f21c66f 100644
--- a/chrome/browser/ui/page_info/page_info_unittest.cc
+++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -32,6 +32,7 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/infobars/core/infobar.h"
 #include "components/safe_browsing/buildflags.h"
+#include "components/security_state/core/features.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/ssl_host_state_delegate.h"
 #include "content/public/browser/ssl_status.h"
@@ -842,6 +843,63 @@
 }
 
 #if !defined(OS_ANDROID)
+// Tests that the site connection status is correctly set for Legacy TLS sites
+// when the kLegacyTLSWarnings feature is enabled.
+TEST_F(PageInfoTest, LegacyTLS) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      security_state::features::kLegacyTLSWarnings);
+
+  security_level_ = security_state::WARNING;
+  visible_security_state_.url = GURL("https://scheme-is-cryptographic.test");
+  visible_security_state_.certificate = cert();
+  visible_security_state_.cert_status = 0;
+  int status = 0;
+  status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1);
+  status = SetSSLVersion(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256);
+  visible_security_state_.connection_status = status;
+  visible_security_state_.connection_info_initialized = true;
+  visible_security_state_.connection_used_legacy_tls = true;
+  visible_security_state_.is_legacy_tls_control_site = false;
+
+  SetDefaultUIExpectations(mock_ui());
+
+  EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS,
+            page_info()->site_connection_status());
+  EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_CERT,
+            page_info()->site_identity_status());
+}
+
+// Tests that the site connection status is not set to LEGACY_TLS when a site
+// using legacy TLS is marked as a control site in the visible security state,
+// when the kLegacyTLSWarnings feature is enabled.
+TEST_F(PageInfoTest, LegacyTLSControlSite) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      security_state::features::kLegacyTLSWarnings);
+
+  security_level_ = security_state::SECURE;
+  visible_security_state_.url = GURL("https://scheme-is-cryptographic.test");
+  visible_security_state_.certificate = cert();
+  visible_security_state_.cert_status = 0;
+  int status = 0;
+  status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1);
+  status = SetSSLVersion(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256);
+  visible_security_state_.connection_status = status;
+  visible_security_state_.connection_info_initialized = true;
+  visible_security_state_.connection_used_legacy_tls = true;
+  visible_security_state_.is_legacy_tls_control_site = true;
+
+  SetDefaultUIExpectations(mock_ui());
+
+  EXPECT_EQ(PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED,
+            page_info()->site_connection_status());
+  EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_CERT,
+            page_info()->site_identity_status());
+}
+#endif
+
+#if !defined(OS_ANDROID)
 TEST_F(PageInfoTest, NoInfoBar) {
   SetDefaultUIExpectations(mock_ui());
   EXPECT_EQ(0u, infobar_service()->infobar_count());
diff --git a/chrome/browser/ui/tab_contents/chrome_web_contents_view_handle_drop_unittest.cc b/chrome/browser/ui/tab_contents/chrome_web_contents_view_handle_drop_unittest.cc
index 9f2c8fda..b398140 100644
--- a/chrome/browser/ui/tab_contents/chrome_web_contents_view_handle_drop_unittest.cc
+++ b/chrome/browser/ui/tab_contents/chrome_web_contents_view_handle_drop_unittest.cc
@@ -47,15 +47,22 @@
 
     run_loop_.reset(new base::RunLoop());
 
+    using FakeDelegate = safe_browsing::FakeDeepScanningDialogDelegate;
+    using Verdict = safe_browsing::DlpDeepScanningVerdict;
+    auto callback = base::Bind(
+        [](bool scan_succeeds, const base::FilePath&) {
+          return scan_succeeds ? FakeDelegate::SuccessfulResponse()
+                               : FakeDelegate::DlpResponse(
+                                     Verdict::FAILURE, std::string(),
+                                     Verdict::TriggeredRule::REPORT_ONLY);
+        },
+        scan_succeeds);
+
     safe_browsing::DeepScanningDialogDelegate::SetDMTokenForTesting("dm_token");
     safe_browsing::DeepScanningDialogDelegate::SetFactoryForTesting(
         base::BindRepeating(
             &safe_browsing::FakeDeepScanningDialogDelegate::Create,
-            run_loop_->QuitClosure(),
-            base::Bind([](bool scan_succeeds,
-                          const base::FilePath&) { return scan_succeeds; },
-                       scan_succeeds),
-            "dm_token"));
+            run_loop_->QuitClosure(), callback, "dm_token"));
   }
 
   // Common code for running the test cases.
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index fc74c86..303cbae 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -288,73 +288,21 @@
     return;
   }
 
-  if (IsShowingWarningDialog() != model_->IsDangerous()) {
-    ToggleWarningDialog();
+  bool is_danger_type_async_scanning =
+      (model_->GetDangerType() ==
+       download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING);
+  if (model_->IsDangerous() && !IsShowingWarningDialog()) {
+    TransitionToWarningDialog();
+  } else if (is_danger_type_async_scanning && !IsShowingDeepScanning()) {
+    TransitionToDeepScanningDialog();
   } else {
-    status_label_->SetText(GetStatusText());
-    status_label_->GetViewAccessibility().OverrideIsIgnored(
-        status_label_->GetText().empty());
-    file_name_label_->SetY(GetYForFilenameText());
-    switch (model_->GetState()) {
-      case DownloadItem::IN_PROGRESS:
-        // No need to send accessible alert for "paused", as the button ends
-        // up being refocused in the actual use case, and the name of the
-        // button reports that the download has been paused.
-        // Reset the status counter so that user receives immediate feedback
-        // once the download is resumed.
-        if (!model_->IsPaused())
-          UpdateAccessibleAlert(GetInProgressAccessibleAlertText(), false);
-        model_->IsPaused() ? StopDownloadProgress() : StartDownloadProgress();
-        LoadIconIfItemPathChanged();
-        break;
-      case DownloadItem::INTERRUPTED:
-        model_->GetFileNameToReportUser().LossyDisplayName();
-        UpdateAccessibleAlert(
-            l10n_util::GetStringFUTF16(
-                IDS_DOWNLOAD_FAILED_ACCESSIBLE_ALERT,
-                model_->GetFileNameToReportUser().LossyDisplayName()),
-            true);
-        StopDownloadProgress();
-        complete_animation_ = std::make_unique<gfx::SlideAnimation>(this);
-        complete_animation_->SetSlideDuration(
-            base::TimeDelta::FromMilliseconds(2500));
-        complete_animation_->SetTweenType(gfx::Tween::LINEAR);
-        complete_animation_->Show();
-        LoadIcon();
-        break;
-      case DownloadItem::COMPLETE:
-        UpdateAccessibleAlert(
-            l10n_util::GetStringFUTF16(
-                IDS_DOWNLOAD_COMPLETE_ACCESSIBLE_ALERT,
-                model_->GetFileNameToReportUser().LossyDisplayName()),
-            true);
-        if (model_->ShouldRemoveFromShelfWhenComplete()) {
-          shelf_->RemoveDownloadView(this);  // This will delete us!
-          return;
-        }
-        StopDownloadProgress();
-        complete_animation_ = std::make_unique<gfx::SlideAnimation>(this);
-        complete_animation_->SetSlideDuration(
-            base::TimeDelta::FromMilliseconds(2500));
-        complete_animation_->SetTweenType(gfx::Tween::LINEAR);
-        complete_animation_->Show();
-        LoadIcon();
-        break;
-      case DownloadItem::CANCELLED:
-        UpdateAccessibleAlert(
-            l10n_util::GetStringFUTF16(
-                IDS_DOWNLOAD_CANCELLED_ACCESSIBLE_ALERT,
-                model_->GetFileNameToReportUser().LossyDisplayName()),
-            true);
-        StopDownloadProgress();
-        if (complete_animation_)
-          complete_animation_->Stop();
-        LoadIcon();
-        break;
-      default:
-        NOTREACHED();
-    }
-    SchedulePaint();
+    TransitionToNormalMode();
+  }
+
+  if (model_->GetState() == DownloadItem::COMPLETE &&
+      model_->ShouldRemoveFromShelfWhenComplete()) {
+    shelf_->RemoveDownloadView(this);  // This will delete us!
+    return;
   }
 
   base::string16 new_tip = model_->GetTooltipText(font_list_, kTooltipMaxWidth);
@@ -366,6 +314,75 @@
   UpdateAccessibleName();
 }
 
+void DownloadItemView::TransitionToNormalMode() {
+  if (IsShowingDeepScanning())
+    ClearDeepScanningDialog();
+  if (IsShowingWarningDialog())
+    ClearWarningDialog();
+
+  status_label_->SetText(GetStatusText());
+  status_label_->GetViewAccessibility().OverrideIsIgnored(
+      status_label_->GetText().empty());
+  file_name_label_->SetY(GetYForFilenameText());
+  switch (model_->GetState()) {
+    case DownloadItem::IN_PROGRESS:
+      // No need to send accessible alert for "paused", as the button ends
+      // up being refocused in the actual use case, and the name of the
+      // button reports that the download has been paused.
+      // Reset the status counter so that user receives immediate feedback
+      // once the download is resumed.
+      if (!model_->IsPaused())
+        UpdateAccessibleAlert(GetInProgressAccessibleAlertText(), false);
+      model_->IsPaused() ? StopDownloadProgress() : StartDownloadProgress();
+      LoadIconIfItemPathChanged();
+      break;
+    case DownloadItem::INTERRUPTED:
+      model_->GetFileNameToReportUser().LossyDisplayName();
+      UpdateAccessibleAlert(
+          l10n_util::GetStringFUTF16(
+              IDS_DOWNLOAD_FAILED_ACCESSIBLE_ALERT,
+              model_->GetFileNameToReportUser().LossyDisplayName()),
+          true);
+      StopDownloadProgress();
+      complete_animation_ = std::make_unique<gfx::SlideAnimation>(this);
+      complete_animation_->SetSlideDuration(
+          base::TimeDelta::FromMilliseconds(2500));
+      complete_animation_->SetTweenType(gfx::Tween::LINEAR);
+      complete_animation_->Show();
+      LoadIcon();
+      break;
+    case DownloadItem::COMPLETE:
+      UpdateAccessibleAlert(
+          l10n_util::GetStringFUTF16(
+              IDS_DOWNLOAD_COMPLETE_ACCESSIBLE_ALERT,
+              model_->GetFileNameToReportUser().LossyDisplayName()),
+          true);
+      StopDownloadProgress();
+      complete_animation_ = std::make_unique<gfx::SlideAnimation>(this);
+      complete_animation_->SetSlideDuration(
+          base::TimeDelta::FromMilliseconds(2500));
+      complete_animation_->SetTweenType(gfx::Tween::LINEAR);
+      complete_animation_->Show();
+      LoadIcon();
+      break;
+    case DownloadItem::CANCELLED:
+      UpdateAccessibleAlert(
+          l10n_util::GetStringFUTF16(
+              IDS_DOWNLOAD_CANCELLED_ACCESSIBLE_ALERT,
+              model_->GetFileNameToReportUser().LossyDisplayName()),
+          true);
+      StopDownloadProgress();
+      if (complete_animation_)
+        complete_animation_->Stop();
+      LoadIcon();
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  SchedulePaint();
+}
+
 void DownloadItemView::OnDownloadDestroyed() {
   shelf_->RemoveDownloadView(this);  // This will delete us!
 }
@@ -418,6 +435,10 @@
       child_origin.Offset(button_size.width() + kSaveDiscardButtonPadding, 0);
     }
     discard_button_->SetBoundsRect(gfx::Rect(child_origin, button_size));
+  } else if (IsShowingDeepScanning()) {
+    gfx::Point child_origin(kStartPadding + kWarningIconSize + kStartPadding,
+                            (height() - deep_scanning_label_->height()) / 2);
+    deep_scanning_label_->SetPosition(child_origin);
   } else {
     int mirrored_x = GetMirroredXWithWidthInView(
         kStartPadding + DownloadShelf::kProgressIndicatorSize +
@@ -636,7 +657,7 @@
 }
 
 void DownloadItemView::DrawIcon(gfx::Canvas* canvas) {
-  if (IsShowingWarningDialog()) {
+  if (IsShowingWarningDialog() || IsShowingDeepScanning()) {
     int icon_x = base::i18n::IsRTL()
                      ? width() - kWarningIconSize - kStartPadding
                      : kStartPadding;
@@ -828,12 +849,26 @@
   ConfigureInkDrop();
 }
 
-void DownloadItemView::ToggleWarningDialog() {
-  if (model_->IsDangerous())
-    ShowWarningDialog();
-  else
+void DownloadItemView::TransitionToWarningDialog() {
+  if (IsShowingDeepScanning())
+    ClearDeepScanningDialog();
+
+  ShowWarningDialog();
+
+  // We need to load the icon now that the download has the real path.
+  LoadIcon();
+
+  // Force the shelf to layout again as our size has changed.
+  shelf_->Layout();
+  shelf_->SchedulePaint();
+}
+
+void DownloadItemView::TransitionToDeepScanningDialog() {
+  if (IsShowingWarningDialog())
     ClearWarningDialog();
 
+  ShowDeepScanningDialog();
+
   // We need to load the icon now that the download has the real path.
   LoadIcon();
 
@@ -843,8 +878,6 @@
 }
 
 void DownloadItemView::ClearWarningDialog() {
-  DCHECK_EQ(model_->GetDangerType(),
-            download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED);
   DCHECK(IsShowingWarningDialog());
 
   SetMode(NORMAL_MODE);
@@ -930,8 +963,13 @@
           GetNativeTheme()->GetSystemColor(
               ui::NativeTheme::kColorId_AlertSeverityHigh));
 
-    case download::DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED:
     case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING:
+      return gfx::CreateVectorIcon(
+          vector_icons::kErrorIcon, kErrorIconSize,
+          GetNativeTheme()->GetSystemColor(
+              ui::NativeTheme::kColorId_AlertSeverityMedium));
+
+    case download::DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED:
     case download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
     case download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
     case download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
@@ -943,6 +981,43 @@
   return gfx::ImageSkia();
 }
 
+void DownloadItemView::ShowDeepScanningDialog() {
+  DCHECK_EQ(mode_, NORMAL_MODE);
+  SetMode(DEEP_SCANNING_MODE);
+
+  base::string16 elided_filename =
+      gfx::ElideFilename(model_->GetFileNameToReportUser(), font_list_,
+                         kTextWidth, gfx::Typesetter::BROWSER);
+  base::string16 deep_scanning_text = l10n_util::GetStringFUTF16(
+      IDS_PROMPT_DEEP_SCANNING_DOWNLOAD, elided_filename);
+  auto deep_scanning_label = std::make_unique<views::Label>(deep_scanning_text);
+  deep_scanning_label->SetMultiLine(true);
+  deep_scanning_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  deep_scanning_label->SetAutoColorReadabilityEnabled(false);
+  deep_scanning_label_ = AddChildView(std::move(deep_scanning_label));
+  deep_scanning_label_->SetSize(AdjustTextAndGetSize(deep_scanning_label_));
+
+  open_button_->SetEnabled(false);
+  file_name_label_->SetVisible(false);
+  status_label_->SetVisible(false);
+}
+
+void DownloadItemView::ClearDeepScanningDialog() {
+  DCHECK(IsShowingDeepScanning());
+
+  SetMode(NORMAL_MODE);
+  dropdown_state_ = NORMAL;
+
+  delete deep_scanning_label_;
+  deep_scanning_label_ = nullptr;
+
+  LoadIcon();
+
+  open_button_->SetEnabled(true);
+  file_name_label_->SetVisible(true);
+  status_label_->SetVisible(true);
+}
+
 gfx::Size DownloadItemView::GetButtonSize() const {
   DCHECK(discard_button_ && (mode_ == MALICIOUS_MODE || save_button_));
   gfx::Size size = discard_button_->GetPreferredSize();
diff --git a/chrome/browser/ui/views/download/download_item_view.h b/chrome/browser/ui/views/download/download_item_view.h
index 966bc705..27fa340 100644
--- a/chrome/browser/ui/views/download/download_item_view.h
+++ b/chrome/browser/ui/views/download/download_item_view.h
@@ -129,9 +129,11 @@
   enum State { NORMAL = 0, HOT, PUSHED };
 
   enum Mode {
-    NORMAL_MODE = 0,  // Showing download item.
-    DANGEROUS_MODE,   // Displaying the dangerous download warning.
-    MALICIOUS_MODE    // Displaying the malicious download warning.
+    NORMAL_MODE = 0,    // Showing download item.
+    DANGEROUS_MODE,     // Displaying the dangerous download warning.
+    MALICIOUS_MODE,     // Displaying the malicious download warning.
+    DEEP_SCANNING_MODE  // Displaying information about in progress deep
+                        // scanning.
   };
 
   static constexpr int kTextWidth = 140;
@@ -210,8 +212,14 @@
     return mode_ == DANGEROUS_MODE || mode_ == MALICIOUS_MODE;
   }
 
-  // Clears or shows the warning dialog as per the state of |model_|.
-  void ToggleWarningDialog();
+  // Whether we are in the deep scanning mode.
+  bool IsShowingDeepScanning() const { return mode_ == DEEP_SCANNING_MODE; }
+
+  // Starts showing the normal mode dialog, clearing the existing dialog.
+  void TransitionToNormalMode();
+
+  // Starts showing the warning dialog, clearing the existing dialog.
+  void TransitionToWarningDialog();
 
   // Reverts from dangerous mode to normal download mode.
   void ClearWarningDialog();
@@ -220,6 +228,15 @@
   // warning.
   void ShowWarningDialog();
 
+  // Starts showing the deep scanning dialog, clearing the existing dialog.
+  void TransitionToDeepScanningDialog();
+
+  // Reverts from deep scanning mode to normal download mode.
+  void ClearDeepScanningDialog();
+
+  // Starts displaying the deep scanning warning.
+  void ShowDeepScanningDialog();
+
   // Returns the current warning icon (should only be called when the view is
   // actually showing a warning).
   gfx::ImageSkia GetWarningIcon();
@@ -393,6 +410,9 @@
   // and reload the icon.
   base::FilePath last_download_item_path_;
 
+  // Deep scanning mode label.
+  views::Label* deep_scanning_label_;
+
   // Method factory used to delay reenabling of the item when opening the
   // downloaded file.
   base::WeakPtrFactory<DownloadItemView> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index cde5b37..0894f371 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -214,7 +214,7 @@
 #include "chrome/browser/ui/webui/discards/discards_ui.h"
 #endif
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)
 #include "chrome/browser/ui/webui/sandbox_internals_ui.h"
 #endif
 
@@ -689,7 +689,7 @@
     return &NewWebUI<CastUI>;
   }
 #endif
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)
   if (url.host_piece() == chrome::kChromeUISandboxHost) {
     return &NewWebUI<SandboxInternalsUI>;
   }
diff --git a/chrome/browser/ui/webui/sandbox/sandbox_handler.cc b/chrome/browser/ui/webui/sandbox/sandbox_handler.cc
new file mode 100644
index 0000000..a4f1c53
--- /dev/null
+++ b/chrome/browser/ui/webui/sandbox/sandbox_handler.cc
@@ -0,0 +1,134 @@
+// 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/webui/sandbox/sandbox_handler.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/task/post_task.h"
+#include "base/values.h"
+#include "content/public/browser/browser_child_process_host_iterator.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_data.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/common/process_type.h"
+#include "services/service_manager/sandbox/win/sandbox_win.h"
+
+using content::BrowserChildProcessHostIterator;
+using content::ChildProcessData;
+using content::RenderProcessHost;
+
+namespace sandbox_handler {
+namespace {
+base::Value FetchBrowserChildProcesses() {
+  // The |BrowserChildProcessHostIterator| must only be used on the IO thread.
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  base::Value browser_processes(base::Value::Type::LIST);
+
+  for (BrowserChildProcessHostIterator itr; !itr.Done(); ++itr) {
+    const ChildProcessData& process_data = itr.GetData();
+    // Only add processes that have already started, i.e. with valid handles.
+    if (!process_data.GetProcess().IsValid())
+      continue;
+    base::Value proc(base::Value::Type::DICTIONARY);
+    proc.SetPath("processId", base::Value(base::strict_cast<double>(
+                                  process_data.GetProcess().Pid())));
+    proc.SetPath("processType",
+                 base::Value(content::GetProcessTypeNameInEnglish(
+                     process_data.process_type)));
+    proc.SetPath("name", base::Value(process_data.name));
+    proc.SetPath("metricsName", base::Value(process_data.metrics_name));
+    browser_processes.GetList().push_back(std::move(proc));
+  }
+
+  return browser_processes;
+}
+
+base::Value FetchRenderHostProcesses() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  base::Value renderer_processes(base::Value::Type::LIST);
+
+  for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
+       !it.IsAtEnd(); it.Advance()) {
+    RenderProcessHost* host = it.GetCurrentValue();
+    // Skip processes that might not have started yet.
+    if (!host->GetProcess().IsValid())
+      continue;
+
+    base::Value proc(base::Value::Type::DICTIONARY);
+    proc.SetPath(
+        "processId",
+        base::Value(base::strict_cast<double>(host->GetProcess().Pid())));
+    renderer_processes.GetList().push_back(std::move(proc));
+  }
+
+  return renderer_processes;
+}
+
+}  // namespace
+
+SandboxHandler::SandboxHandler() = default;
+SandboxHandler::~SandboxHandler() = default;
+
+void SandboxHandler::RegisterMessages() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  web_ui()->RegisterMessageCallback(
+      "requestSandboxDiagnostics",
+      base::BindRepeating(&SandboxHandler::HandleRequestSandboxDiagnostics,
+                          base::Unretained(this)));
+}
+
+void SandboxHandler::HandleRequestSandboxDiagnostics(
+    const base::ListValue* args) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  CHECK_EQ(1U, args->GetList().size());
+  sandbox_diagnostics_callback_id_ = args->GetList()[0].Clone();
+
+  AllowJavascript();
+
+  base::PostTaskAndReplyWithResult(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::Bind(&FetchBrowserChildProcesses),
+      base::Bind(&SandboxHandler::FetchBrowserChildProcessesCompleted,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SandboxHandler::FetchBrowserChildProcessesCompleted(
+    base::Value browser_processes) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  browser_processes_ = std::move(browser_processes);
+
+  service_manager::SandboxWin::GetPolicyDiagnostics(
+      base::Bind(&SandboxHandler::FetchSandboxDiagnosticsCompleted,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+// This runs nested inside SandboxWin so we get out quickly.
+void SandboxHandler::FetchSandboxDiagnosticsCompleted(
+    base::Value sandbox_policies) {
+  sandbox_policies_ = std::move(sandbox_policies);
+  base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+                 base::BindOnce(&SandboxHandler::GetRendererProcessesAndFinish,
+                                weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SandboxHandler::GetRendererProcessesAndFinish() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  auto renderer_processes = FetchRenderHostProcesses();
+  base::Value results(base::Value::Type::DICTIONARY);
+  results.SetPath("browser", std::move(browser_processes_));
+  results.SetPath("policies", std::move(sandbox_policies_));
+  results.SetPath("renderer", std::move(renderer_processes));
+  ResolveJavascriptCallback(sandbox_diagnostics_callback_id_,
+                            std::move(results));
+}
+
+}  // namespace sandbox_handler
diff --git a/chrome/browser/ui/webui/sandbox/sandbox_handler.h b/chrome/browser/ui/webui/sandbox/sandbox_handler.h
new file mode 100644
index 0000000..822044f
--- /dev/null
+++ b/chrome/browser/ui/webui/sandbox/sandbox_handler.h
@@ -0,0 +1,52 @@
+// 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_WEBUI_SANDBOX_SANDBOX_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SANDBOX_SANDBOX_HANDLER_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace base {
+class Value;
+class ListValue;
+}  // namespace base
+
+namespace sandbox_handler {
+// This class takes care of sending the list of processes and their sandboxing
+// status to the chrome://sandbox WebUI page when it is requested.
+class SandboxHandler : public content::WebUIMessageHandler {
+ public:
+  SandboxHandler();
+  ~SandboxHandler() override;
+
+ private:
+  // content::WebUIMessageHandler:
+  void RegisterMessages() override;
+
+  // Callback for the "requestSandboxDiagnostics" message.
+  void HandleRequestSandboxDiagnostics(const base::ListValue* args);
+
+  void OnSandboxDataFetched(base::Value results);
+
+  void FetchBrowserChildProcessesCompleted(base::Value browser_processes);
+  void FetchSandboxDiagnosticsCompleted(base::Value sandbox_policies);
+  void GetRendererProcessesAndFinish();
+
+  // The ID of the callback that will get invoked with the sandbox list.
+  base::Value sandbox_diagnostics_callback_id_;
+  base::Value browser_processes_;
+  base::Value sandbox_policies_;
+
+  // Always keep this the last member of this class to make sure it's the
+  // first thing to be destructed.
+  base::WeakPtrFactory<SandboxHandler> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(SandboxHandler);
+};
+
+}  // namespace sandbox_handler
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SANDBOX_SANDBOX_HANDLER_H_
diff --git a/chrome/browser/ui/webui/sandbox_internals_ui.cc b/chrome/browser/ui/webui/sandbox_internals_ui.cc
index 18b4832..81eb48d 100644
--- a/chrome/browser/ui/webui/sandbox_internals_ui.cc
+++ b/chrome/browser/ui/webui/sandbox_internals_ui.cc
@@ -15,6 +15,10 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/ui/webui/sandbox/sandbox_handler.h"
+#endif
+
 #if defined(OS_ANDROID)
 #include "chrome/common/sandbox_status_extension_android.mojom.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -79,6 +83,10 @@
 
 SandboxInternalsUI::SandboxInternalsUI(content::WebUI* web_ui)
     : content::WebUIController(web_ui) {
+#if defined(OS_WIN)
+  web_ui->AddMessageHandler(
+      std::make_unique<sandbox_handler::SandboxHandler>());
+#endif
   Profile* profile = Profile::FromWebUI(web_ui);
   content::WebUIDataSource::Add(profile, CreateDataSource());
 }
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
index 87be8b1..ed45098c 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
@@ -98,6 +98,10 @@
     colors.SetString("--tabstrip-tab-text-color",
                      color_utils::SkColorToRgbaString(
                          tp.GetColor(ThemeProperties::COLOR_TAB_TEXT)));
+    colors.SetString("--tabstrip-tab-separator-color",
+                     color_utils::SkColorToRgbaString(SkColorSetA(
+                         tp.GetColor(ThemeProperties::COLOR_TAB_TEXT),
+                         /* 16% opacity */ 0.16 * 255)));
 
     ResolveJavascriptCallback(callback_id, colors);
   }
diff --git a/chrome/browser/ui/webui/test_data_source.cc b/chrome/browser/ui/webui/test_data_source.cc
index 7a7790a3..1fbe673 100644
--- a/chrome/browser/ui/webui/test_data_source.cc
+++ b/chrome/browser/ui/webui/test_data_source.cc
@@ -25,6 +25,19 @@
 const char kModuleQuery[] = "module=";
 }  // namespace
 
+TestDataSource::TestDataSource(std::string root) {
+  base::FilePath test_data;
+  CHECK(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data));
+  src_root_ = test_data.AppendASCII(root).NormalizePathSeparators();
+  DCHECK(test_data.IsParent(src_root_));
+
+  base::FilePath exe_dir;
+  base::PathService::Get(base::DIR_EXE, &exe_dir);
+  gen_root_ = exe_dir.AppendASCII("gen/chrome/test/data/" + root)
+                  .NormalizePathSeparators();
+  DCHECK(exe_dir.IsParent(gen_root_));
+}
+
 std::string TestDataSource::GetSource() {
   return "test";
 }
@@ -83,22 +96,6 @@
 void TestDataSource::ReadFile(
     const std::string& path,
     const content::URLDataSource::GotDataCallback& callback) {
-  if (src_root_.empty()) {
-    base::FilePath test_data;
-    CHECK(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data));
-    src_root_ = test_data.Append(FILE_PATH_LITERAL("webui"));
-  }
-
-  if (gen_root_.empty()) {
-    std::string gen_path = "gen/chrome/test/data/webui/";
-#if defined(OS_WIN)
-    base::ReplaceChars(gen_path, "//", "\\", &gen_path);
-#endif
-    base::FilePath exe_dir;
-    base::PathService::Get(base::DIR_EXE, &exe_dir);
-    gen_root_ = exe_dir.AppendASCII(gen_path);
-  }
-
   std::string content;
 
   GURL url = GetURLForPath(path);
diff --git a/chrome/browser/ui/webui/test_data_source.h b/chrome/browser/ui/webui/test_data_source.h
index 86816587..e4c6ea6 100644
--- a/chrome/browser/ui/webui/test_data_source.h
+++ b/chrome/browser/ui/webui/test_data_source.h
@@ -12,10 +12,10 @@
 #include "content/public/browser/url_data_source.h"
 #include "url/gurl.h"
 
-// Serves files at chrome://test/ from //src/chrome/test/data/webui.
+// Serves files at chrome://test/ from //src/chrome/test/data/<root>.
 class TestDataSource : public content::URLDataSource {
  public:
-  TestDataSource() = default;
+  explicit TestDataSource(std::string root);
   ~TestDataSource() override = default;
 
  private:
diff --git a/chrome/browser/vr/webxr_vr_input_browser_test.cc b/chrome/browser/vr/webxr_vr_input_browser_test.cc
index f81cbf4..a67509b 100644
--- a/chrome/browser/vr/webxr_vr_input_browser_test.cc
+++ b/chrome/browser/vr/webxr_vr_input_browser_test.cc
@@ -258,13 +258,9 @@
   std::move(callback).Run();
 }
 
-// TODO(crbug.com/986637) - Enable for OpenXR
 // Ensure that when an input source's handedness changes, an input source change
 // event is fired and a new input source is created.
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTest,
-                                    WebXrVrWmrBrowserTest,
-                                    WebXrVrBrowserTestBase,
-                                    TestInputHandednessChange) {
+WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestInputHandednessChange) {
   WebXrControllerInputMock my_mock;
   unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
 
@@ -301,16 +297,12 @@
   t->EndTest();
 }
 
-// TODO(crbug.com/986637) - Enable for OpenXR
 // Test that inputsourceschange events contain only the expected added/removed
 // input sources when a mock controller is connected/disconnected.
 // Also validates that if an input source changes substantially we get an event
 // containing both the removal of the old one and the additon of the new one,
 // rather than two events.
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTest,
-                                    WebXrVrWmrBrowserTest,
-                                    WebXrVrBrowserTestBase,
-                                    TestInputSourcesChange) {
+WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestInputSourcesChange) {
   WebXrControllerInputMock my_mock;
 
   // TODO(crbug.com/963676): Figure out if the race is a product or test bug.
@@ -359,10 +351,11 @@
                                  WebXrVrBrowserTestBase::kPollTimeoutShort);
   t->RunJavaScriptOrFail("updateCachedInputSource(0)");
 
-  // At least currently, there is no way for WMR to have insufficient buttons
-  // for a gamepad as long as a controller is connected, so skip this part on
-  // WMR since it'll always fail
-  if (t->GetRuntimeType() != XrBrowserTestBase::RuntimeType::RUNTIME_WMR) {
+  // At least currently, there is no way for WMR/OpenXR to have insufficient
+  // buttons for a gamepad as long as a controller is connected, so skip this
+  // part on WMR/OpenXR since it'll always fail
+  if (t->GetRuntimeType() != XrBrowserTestBase::RuntimeType::RUNTIME_WMR &&
+      t->GetRuntimeType() != XrBrowserTestBase::RuntimeType::RUNTIME_OPENXR) {
     my_mock.UpdateControllerSupport(controller_index, insufficient_axis_types,
                                     insufficient_buttons);
 
@@ -380,9 +373,9 @@
 
 // Ensure that when an input source's profiles array changes, an input source
 // change event is fired and a new input source is created.
-// OpenVR-only since WMR only supports one kind of gamepad, so it's not possible
-// to update the connected gamepad functionality to force the profiles array to
-// change.
+// OpenVR-only since WMR/OpenXR only supports one kind of gamepad, so it's not
+// possible to update the connected gamepad functionality to force the profiles
+// array to change.
 IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestInputProfilesChange) {
   WebXrControllerInputMock my_mock;
   unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
@@ -422,8 +415,8 @@
 // Ensure that changes to a gamepad object respect that it is the same object
 // and that if whether or not an input source has a gamepad changes that the
 // input source change event is fired and a new input source is created.
-// OpenVR-only since WMR doesn't support the notion of an incomplete gamepad
-// except if using voice input.
+// OpenVR-only since WMR/OpenXR doesn't support the notion of an incomplete
+// gamepad except if using voice input.
 IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestInputGamepadSameObject) {
   WebXrControllerInputMock my_mock;
 
@@ -493,8 +486,8 @@
 
 // Ensure that if the controller lacks enough data to be considered a Gamepad
 // that the input source that it is associated with does not have a Gamepad.
-// OpenVR-only because WMR does not currently support the notion of incomplete
-// gamepads other than voice input.
+// OpenVR-only because WMR/OpenXR does not currently support the notion of
+// incomplete gamepads other than voice input.
 IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestGamepadIncompleteData) {
   WebXrControllerInputMock my_mock;
 
@@ -514,14 +507,10 @@
   EndTest();
 }
 
-// TODO(crbug.com/986637) - Enable for OpenXR
 // Ensure that if a Gamepad has the minimum required number of axes/buttons to
 // be considered an xr-standard Gamepad, that it is exposed as such, and that
 // we can check the state of it's priamry axes/button.
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTest,
-                                    WebXrVrWmrBrowserTest,
-                                    WebXrVrBrowserTestBase,
-                                    TestGamepadMinimumData) {
+WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestGamepadMinimumData) {
   WebXrControllerInputMock my_mock;
 
   unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
@@ -532,11 +521,13 @@
 
   VerifyInputCounts(t, 1, 1);
 
-  // We only actually connect the data for the one button, but WMR expects
-  // the WMR controller (which has all of the required and optional buttons)
-  // and so adds dummy/placeholder buttons regardless of what data we send up.
+  // We only actually connect the data for the one button, but WMR/OpenXR
+  // expects the WMR/OpenXR  controller (which has all of the required and
+  // optional buttons) and so adds dummy/placeholder buttons regardless of what
+  // data we send up.
   std::string button_count = "1";
-  if (t->GetRuntimeType() == XrBrowserTestBase::RuntimeType::RUNTIME_WMR)
+  if (t->GetRuntimeType() == XrBrowserTestBase::RuntimeType::RUNTIME_WMR ||
+      t->GetRuntimeType() == XrBrowserTestBase::RuntimeType::RUNTIME_OPENXR)
     button_count = "4";
 
   t->PollJavaScriptBooleanOrFail("isButtonCountEqualTo(" + button_count + ")",
@@ -563,22 +554,27 @@
              XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR) {
     VerifyInputSourceProfilesArray(
         t, {"test-value-test-value", "generic-trigger"});
+  } else if (t->GetRuntimeType() ==
+             XrBrowserTestBase::RuntimeType::RUNTIME_OPENXR) {
+    // OpenXR will still report having squeeze, menu, touchpad, and thumbstick
+    // because it only supports that type of controller and fills in default
+    // values if those inputs don't exist.
+    VerifyInputSourceProfilesArray(
+        t, {"windows-mixed-reality",
+            "generic-trigger-squeeze-touchpad-thumbstick"});
   }
 
   t->RunJavaScriptOrFail("done()");
   t->EndTest();
 }
 
-// TODO(crbug.com/986637) - Enable for OpenXR
 // Make sure the input gets plumbed to the correct gamepad, including when
 // button presses are interleaved.
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTest,
-                                    WebXrVrWmrBrowserTest,
-                                    WebXrVrBrowserTestBase,
-                                    TestMultipleGamepads) {
+WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestMultipleGamepads) {
   WebXrControllerInputMock my_mock;
 
-  unsigned int controller_index1 = my_mock.CreateAndConnectMinimalGamepad();
+  unsigned int controller_index1 = my_mock.CreateAndConnectMinimalGamepad(
+      device::ControllerRole::kControllerRoleLeft);
   unsigned int controller_index2 = my_mock.CreateAndConnectMinimalGamepad();
 
   t->LoadUrlAndAwaitInitialization(
@@ -587,11 +583,13 @@
 
   VerifyInputCounts(t, 2, 2);
 
-  // We only actually connect the data for the one button, but WMR expects
-  // the WMR controller (which has all of the required and optional buttons)
-  // and so adds dummy/placeholder buttons regardless of what data we send up.
+  // We only actually connect the data for the one button, but WMR/OpenXR
+  // expects the WMR/OpenXR controller (which has all of the required and
+  // optional buttons) and so adds dummy/placeholder buttons regardless of what
+  // data we send up.
   std::string button_count = "1";
-  if (t->GetRuntimeType() == XrBrowserTestBase::RuntimeType::RUNTIME_WMR)
+  if (t->GetRuntimeType() == XrBrowserTestBase::RuntimeType::RUNTIME_WMR ||
+      t->GetRuntimeType() == XrBrowserTestBase::RuntimeType::RUNTIME_OPENXR)
     button_count = "4";
 
   // Make sure both gamepads have the expected button count and mapping.
@@ -639,20 +637,24 @@
              XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR) {
     VerifyInputSourceProfilesArray(
         t, {"test-value-test-value", "generic-trigger"});
+  } else if (t->GetRuntimeType() ==
+             XrBrowserTestBase::RuntimeType::RUNTIME_OPENXR) {
+    // OpenXR will still report having squeeze, menu, touchpad, and thumbstick
+    // because it only supports that type of controller and fills in default
+    // values if those inputs don't exist.
+    VerifyInputSourceProfilesArray(
+        t, {"windows-mixed-reality",
+            "generic-trigger-squeeze-touchpad-thumbstick"});
   }
 
   t->RunJavaScriptOrFail("done()");
   t->EndTest();
 }
 
-// TODO(crbug.com/986637) - Enable for OpenXR
 // Ensure that if a Gamepad has all of the required and optional buttons as
 // specified by the xr-standard mapping, that those buttons are plumbed up
 // in their required places.
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTest,
-                                    WebXrVrWmrBrowserTest,
-                                    WebXrVrBrowserTestBase,
-                                    TestGamepadCompleteData) {
+WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestGamepadCompleteData) {
   WebXrControllerInputMock my_mock;
 
   // Create a controller that supports all reserved buttons.
@@ -745,6 +747,14 @@
     VerifyInputSourceProfilesArray(
         t, {"test-value-test-value",
             "generic-trigger-squeeze-touchpad-thumbstick"});
+  } else if (t->GetRuntimeType() ==
+             XrBrowserTestBase::RuntimeType::RUNTIME_OPENXR) {
+    // OpenXR will still report having squeeze, menu, touchpad, and thumbstick
+    // because it only supports that type of controller and fills in default
+    // values if those inputs don't exist.
+    VerifyInputSourceProfilesArray(
+        t, {"windows-mixed-reality",
+            "generic-trigger-squeeze-touchpad-thumbstick"});
   }
 
   t->RunJavaScriptOrFail("done()");
@@ -756,7 +766,7 @@
 // the secondary axes button is reserved by the system, but we still get valid
 // data for the axes, there may be other controllers where this is the case).
 // Because this is specifically a bug in the OpenVR runtime/with configurable
-// controllers, not testing WMR.
+// controllers, not testing WMR/OpenXR.
 IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestInputAxesWithNoButton) {
   WebXrControllerInputMock my_mock;
 
@@ -811,8 +821,8 @@
 // Ensure that if a Gamepad has all required buttons, an extra button not
 // mapped in the xr-standard specification, and is missing reserved buttons
 // from the XR Standard specification, that the extra button does not appear
-// in either of the reserved button slots. OpenVR-only since WMR only supports
-// one controller type.
+// in either of the reserved button slots. OpenVR-only since WMR/OpenXR only
+// supports one controller type.
 IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestGamepadReservedData) {
   WebXrControllerInputMock my_mock;
 
@@ -869,9 +879,9 @@
 // Ensure that if a gamepad has a grip, but not any extra buttons or a secondary
 // axis, that no trailing placeholder button is added.  This is a slight
 // variation on TestGamepadMinimalData, but won't re-test whether or not buttons
-// get sent up.  Note that since WMR always builds the WMR controller which
-// supports all required and optional buttons specified by the xr-standard
-// mapping, this test is OpenVR-only.
+// get sent up.  Note that since WMR/OpenXR always builds the WMR/OpenXR
+// controller which supports all required and optional buttons specified by the
+// xr-standard mapping, this test is OpenVR-only.
 IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestGamepadOptionalData) {
   WebXrControllerInputMock my_mock;
 
@@ -909,16 +919,13 @@
   EndTest();
 }
 
-// TODO(crbug.com/986637) - Enable for OpenXR
 // Test that controller input is registered via WebXR's input method. This uses
 // multiple controllers to make sure the input is going to the correct one.
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTest,
-                                    WebXrVrWmrBrowserTest,
-                                    WebXrVrBrowserTestBase,
-                                    TestMultipleControllerInputRegistered) {
+WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestMultipleControllerInputRegistered) {
   WebXrControllerInputMock my_mock;
 
-  unsigned int controller_index1 = my_mock.CreateAndConnectMinimalGamepad();
+  unsigned int controller_index1 = my_mock.CreateAndConnectMinimalGamepad(
+      device::ControllerRole::kControllerRoleLeft);
   unsigned int controller_index2 = my_mock.CreateAndConnectMinimalGamepad();
 
   // Load the test page and enter presentation.
@@ -963,14 +970,10 @@
   EndTest();
 }
 
-// TODO(crbug.com/986637) - Enable for OpenXR
 // Test that controller input is registered via WebXR's input method.
 // Equivalent to
 // WebXrVrInputTest#testControllerClicksRegisteredOnDaydream_WebXr.
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTest,
-                                    WebXrVrWmrBrowserTest,
-                                    WebXrVrBrowserTestBase,
-                                    TestControllerInputRegistered) {
+WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestControllerInputRegistered) {
   WebXrControllerInputMock my_mock;
 
   unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
@@ -1068,13 +1071,9 @@
   return array_string;
 }
 
-// TODO(crbug.com/986637) - Enable for OpenXR
 // Test that changes in controller position are properly plumbed through to
 // WebXR.
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTest,
-                                    WebXrVrWmrBrowserTest,
-                                    WebXrVrBrowserTestBase,
-                                    TestControllerPositionTracking) {
+WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestControllerPositionTracking) {
   WebXrControllerInputMock my_mock;
 
   auto controller_data = my_mock.CreateValidController(
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 25b4ee1..774f1c0 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -39,9 +39,9 @@
     "web_app_constants.h",
     "web_app_data_retriever.cc",
     "web_app_data_retriever.h",
-    "web_app_file_extension_registration.cc",
-    "web_app_file_extension_registration.h",
-    "web_app_file_extension_registration_win.cc",
+    "web_app_file_handler_registration.cc",
+    "web_app_file_handler_registration.h",
+    "web_app_file_handler_registration_win.cc",
     "web_app_helpers.cc",
     "web_app_helpers.h",
     "web_app_icon_generator.cc",
diff --git a/chrome/browser/web_applications/components/file_handler_manager.cc b/chrome/browser/web_applications/components/file_handler_manager.cc
index 44a8c4e..99bccfe5 100644
--- a/chrome/browser/web_applications/components/file_handler_manager.cc
+++ b/chrome/browser/web_applications/components/file_handler_manager.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/web_applications/components/file_handler_manager.h"
 
 #include "base/feature_list.h"
-#include "chrome/browser/web_applications/components/web_app_file_extension_registration.h"
+#include "chrome/browser/web_applications/components/web_app_file_handler_registration.h"
 #include "third_party/blink/public/common/features.h"
 
 namespace web_app {
@@ -31,8 +31,10 @@
     return;
   std::set<std::string> file_extensions =
       GetFileExtensionsFromFileHandlers(*file_handlers);
+  std::set<std::string> mime_types =
+      GetMimeTypesFromFileHandlers(*file_handlers);
   RegisterFileHandlersForWebApp(installed_app_id, app_name, *profile_,
-                                file_extensions);
+                                file_extensions, mime_types);
 }
 
 void FileHandlerManager::OnWebAppUninstalled(const AppId& installed_app_id) {
@@ -63,4 +65,14 @@
   return file_extensions;
 }
 
+std::set<std::string> GetMimeTypesFromFileHandlers(
+    const std::vector<apps::FileHandlerInfo>& file_handlers) {
+  std::set<std::string> mime_types;
+  for (const auto& file_handler : file_handlers) {
+    for (const auto& mime_type : file_handler.types)
+      mime_types.insert(mime_type);
+  }
+  return mime_types;
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/components/file_handler_manager.h b/chrome/browser/web_applications/components/file_handler_manager.h
index d43e01a..efebe740 100644
--- a/chrome/browser/web_applications/components/file_handler_manager.h
+++ b/chrome/browser/web_applications/components/file_handler_manager.h
@@ -56,6 +56,10 @@
 std::set<std::string> GetFileExtensionsFromFileHandlers(
     const std::vector<apps::FileHandlerInfo>& file_handlers);
 
+// Compute the set of mime types specified in |file_handlers|.
+std::set<std::string> GetMimeTypesFromFileHandlers(
+    const std::vector<apps::FileHandlerInfo>& file_handlers);
+
 }  // namespace web_app
 
 #endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_FILE_HANDLER_MANAGER_H_
diff --git a/chrome/browser/web_applications/components/file_handler_manager_unittest.cc b/chrome/browser/web_applications/components/file_handler_manager_unittest.cc
index ee368406..8abeacdd 100644
--- a/chrome/browser/web_applications/components/file_handler_manager_unittest.cc
+++ b/chrome/browser/web_applications/components/file_handler_manager_unittest.cc
@@ -32,4 +32,23 @@
   }
 }
 
+TEST(FileHandlerUtilsTest, GetMimeTypesFromFileHandlers) {
+  // Construct FileHandlerInfo vector with multiple mime types.
+  const std::vector<std::string> test_mime_types = {
+      "text/plain", "image/png", "application/vnd.my-app.file"};
+  apps::FileHandlerInfo fhi1;
+  apps::FileHandlerInfo fhi2;
+  fhi1.types.insert(test_mime_types[0]);
+  fhi1.types.insert(test_mime_types[1]);
+  fhi2.types.insert(test_mime_types[2]);
+  std::vector<apps::FileHandlerInfo> file_handlers = {fhi1, fhi2};
+  std::set<std::string> mime_types =
+      GetMimeTypesFromFileHandlers(file_handlers);
+
+  EXPECT_EQ(mime_types.size(), test_mime_types.size());
+  for (const auto& test_mime_type : test_mime_types) {
+    EXPECT_TRUE(mime_types.find(test_mime_type) != mime_types.end());
+  }
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_file_extension_registration.cc b/chrome/browser/web_applications/components/web_app_file_handler_registration.cc
similarity index 68%
rename from chrome/browser/web_applications/components/web_app_file_extension_registration.cc
rename to chrome/browser/web_applications/components/web_app_file_handler_registration.cc
index fb8ba32..4374e29c 100644
--- a/chrome/browser/web_applications/components/web_app_file_extension_registration.cc
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/web_applications/components/web_app_file_extension_registration.h"
+#include "chrome/browser/web_applications/components/web_app_file_handler_registration.h"
 
 #include "base/logging.h"
 #include "build/build_config.h"
@@ -14,11 +14,11 @@
   return false;
 }
 
-void RegisterFileHandlersForWebApp(
-    const AppId& app_id,
-    const std::string& app_name,
-    const Profile& profile,
-    const std::set<std::string>& file_extensions) {
+void RegisterFileHandlersForWebApp(const AppId& app_id,
+                                   const std::string& app_name,
+                                   const Profile& profile,
+                                   const std::set<std::string>& file_extensions,
+                                   const std::set<std::string>& mime_types) {
   DCHECK(OsSupportsWebAppFileHandling());
   // Stub function for OS's that don't support Web App file handling yet.
 }
diff --git a/chrome/browser/web_applications/components/web_app_file_extension_registration.h b/chrome/browser/web_applications/components/web_app_file_handler_registration.h
similarity index 67%
rename from chrome/browser/web_applications/components/web_app_file_extension_registration.h
rename to chrome/browser/web_applications/components/web_app_file_handler_registration.h
index 0854b37..6534375 100644
--- a/chrome/browser/web_applications/components/web_app_file_extension_registration.h
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_FILE_EXTENSION_REGISTRATION_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_FILE_EXTENSION_REGISTRATION_H_
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_FILE_HANDLER_REGISTRATION_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_FILE_HANDLER_REGISTRATION_H_
 
 #include <set>
 #include <string>
@@ -18,13 +18,13 @@
 bool OsSupportsWebAppFileHandling();
 
 // Do OS-specific registration to handle opening files with the specified
-// |file_extensions| with the PWA with the specified |app_id|.
+// |file_extensions| and |mime_types| with the PWA with the specified |app_id|.
 // This may also involve creating a shim app to launch Chrome from.
-void RegisterFileHandlersForWebApp(
-    const AppId& app_id,
-    const std::string& app_name,
-    const Profile& profile,
-    const std::set<std::string>& file_extensions);
+void RegisterFileHandlersForWebApp(const AppId& app_id,
+                                   const std::string& app_name,
+                                   const Profile& profile,
+                                   const std::set<std::string>& file_extensions,
+                                   const std::set<std::string>& mime_types);
 
 // Undo the file extensions registration for the PWA with specified |app_id|.
 // If a shim app was required, also removes the shim app.
@@ -33,4 +33,4 @@
 
 }  // namespace web_app
 
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_FILE_EXTENSION_REGISTRATION_H_
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_FILE_HANDLER_REGISTRATION_H_
diff --git a/chrome/browser/web_applications/components/web_app_file_extension_registration_win.cc b/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc
similarity index 64%
rename from chrome/browser/web_applications/components/web_app_file_extension_registration_win.cc
rename to chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc
index 90001b7..7f3fb278 100644
--- a/chrome/browser/web_applications/components/web_app_file_extension_registration_win.cc
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration_win.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/web_applications/components/web_app_file_extension_registration.h"
+#include "chrome/browser/web_applications/components/web_app_file_handler_registration.h"
 
 #include "chrome/browser/profiles/profile.h"
 
@@ -12,11 +12,11 @@
   return true;
 }
 
-void RegisterFileHandlersForWebApp(
-    const AppId& app_id,
-    const std::string& app_name,
-    const Profile& profile,
-    const std::set<std::string>& file_extensions) {
+void RegisterFileHandlersForWebApp(const AppId& app_id,
+                                   const std::string& app_name,
+                                   const Profile& profile,
+                                   const std::set<std::string>& file_extensions,
+                                   const std::set<std::string>& mime_types) {
   // TODO(davidbienvenu): Setup shim app and windows registry for this |app_id|.
 }
 
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 099b83f..43b1d0d5 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -322,7 +322,7 @@
 const char kChromeUILinuxProxyConfigHost[] = "linux-proxy-config";
 #endif
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)
 const char kChromeUISandboxHost[] = "sandbox";
 #endif
 
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index a68a213..215d9387 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -281,7 +281,7 @@
 extern const char kChromeUILinuxProxyConfigHost[];
 #endif
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)
 extern const char kChromeUISandboxHost[];
 #endif
 
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index f986c18c..5ca9875 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -581,9 +581,7 @@
         render_frame, subresource_filter_ruleset_dealer_.get(),
         std::move(ad_resource_tracker));
   }
-  if (base::FeatureList::IsEnabled(
-          blink::features::kSendPreviewsLoadingHintsBeforeCommit) &&
-      render_frame->IsMainFrame()) {
+  if (render_frame->IsMainFrame()) {
     new previews::ResourceLoadingHintsAgent(
         render_frame_observer->associated_interfaces(), render_frame);
   }
diff --git a/chrome/services/app_service/DEPS b/chrome/services/app_service/DEPS
index 13b1d4a0..5f276bc5 100644
--- a/chrome/services/app_service/DEPS
+++ b/chrome/services/app_service/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
+  "+components/services/app_service/public/cpp",
   "+services/preferences/public",
 ]
diff --git a/chrome/services/app_service/public/cpp/BUILD.gn b/chrome/services/app_service/public/cpp/BUILD.gn
index 21ea92bfa..52dfe5d 100644
--- a/chrome/services/app_service/public/cpp/BUILD.gn
+++ b/chrome/services/app_service/public/cpp/BUILD.gn
@@ -52,6 +52,7 @@
   deps = [
     "//base",
     "//chrome/services/app_service/public/mojom",
+    "//components/services/app_service/public/cpp:intent_util",
   ]
 }
 
diff --git a/chrome/services/app_service/public/cpp/intent_filter_util.cc b/chrome/services/app_service/public/cpp/intent_filter_util.cc
index b1d9cb75..fc60a0a 100644
--- a/chrome/services/app_service/public/cpp/intent_filter_util.cc
+++ b/chrome/services/app_service/public/cpp/intent_filter_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/services/app_service/public/cpp/intent_filter_util.h b/chrome/services/app_service/public/cpp/intent_filter_util.h
index 3d9d071..2c966bc0 100644
--- a/chrome/services/app_service/public/cpp/intent_filter_util.h
+++ b/chrome/services/app_service/public/cpp/intent_filter_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// 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.
 
diff --git a/chrome/services/app_service/public/cpp/intent_util.cc b/chrome/services/app_service/public/cpp/intent_util.cc
index 2a9da46..3b6b749 100644
--- a/chrome/services/app_service/public/cpp/intent_util.cc
+++ b/chrome/services/app_service/public/cpp/intent_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -6,6 +6,7 @@
 
 #include "base/optional.h"
 #include "base/strings/string_util.h"
+#include "components/services/app_service/public/cpp/intent_util.h"
 
 namespace {
 
@@ -47,8 +48,7 @@
       return base::StartsWith(value, condition_value->value,
                               base::CompareCase::INSENSITIVE_ASCII);
     case apps::mojom::PatternMatchType::kGlob:
-      // TODO(crbug.com/853604): Implement glob pattern match.
-      return false;
+      return MatchGlob(value, condition_value->value);
   }
 }
 
diff --git a/chrome/services/app_service/public/cpp/intent_util.h b/chrome/services/app_service/public/cpp/intent_util.h
index 1df81d9..7be0a0ef 100644
--- a/chrome/services/app_service/public/cpp/intent_util.h
+++ b/chrome/services/app_service/public/cpp/intent_util.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// 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_INTENT_UTIL_H_
 #define CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_
 
-// Utility functions for App Service intent.
+// Utility functions for App Service intent handling.
 
 #include <string>
 
diff --git a/chrome/services/app_service/public/cpp/intent_util_unittest.cc b/chrome/services/app_service/public/cpp/intent_util_unittest.cc
index c224c435..3e124b9 100644
--- a/chrome/services/app_service/public/cpp/intent_util_unittest.cc
+++ b/chrome/services/app_service/public/cpp/intent_util_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -87,4 +87,63 @@
   EXPECT_TRUE(apps_util::ConditionValueMatches("/ABC", condition_value));
   EXPECT_FALSE(apps_util::ConditionValueMatches("/d", condition_value));
 }
-// TODO(crbug.com/853604): Test glob pattern match when implemented.
+
+TEST_F(IntentUtilTest, GlobMatchType) {
+  auto condition_value_star = apps_util::MakeConditionValue(
+      "/a*b", apps::mojom::PatternMatchType::kGlob);
+  EXPECT_TRUE(apps_util::ConditionValueMatches("/b", condition_value_star));
+  EXPECT_TRUE(apps_util::ConditionValueMatches("/ab", condition_value_star));
+  EXPECT_TRUE(apps_util::ConditionValueMatches("/aab", condition_value_star));
+  EXPECT_TRUE(
+      apps_util::ConditionValueMatches("/aaaaaab", condition_value_star));
+  EXPECT_FALSE(apps_util::ConditionValueMatches("/aabb", condition_value_star));
+  EXPECT_FALSE(apps_util::ConditionValueMatches("/aabc", condition_value_star));
+  EXPECT_FALSE(apps_util::ConditionValueMatches("/bb", condition_value_star));
+
+  auto condition_value_dot = apps_util::MakeConditionValue(
+      "/a.b", apps::mojom::PatternMatchType::kGlob);
+  EXPECT_TRUE(apps_util::ConditionValueMatches("/aab", condition_value_dot));
+  EXPECT_TRUE(apps_util::ConditionValueMatches("/acb", condition_value_dot));
+  EXPECT_FALSE(apps_util::ConditionValueMatches("/ab", condition_value_dot));
+  EXPECT_FALSE(apps_util::ConditionValueMatches("/abd", condition_value_dot));
+  EXPECT_FALSE(apps_util::ConditionValueMatches("/abbd", condition_value_dot));
+
+  auto condition_value_dot_and_star = apps_util::MakeConditionValue(
+      "/a.*b", apps::mojom::PatternMatchType::kGlob);
+  EXPECT_TRUE(
+      apps_util::ConditionValueMatches("/aab", condition_value_dot_and_star));
+  EXPECT_TRUE(apps_util::ConditionValueMatches("/aadsfadslkjb",
+                                               condition_value_dot_and_star));
+  EXPECT_TRUE(
+      apps_util::ConditionValueMatches("/ab", condition_value_dot_and_star));
+
+  // This arguably should be true, however the algorithm is transcribed from the
+  // upstream Android codebase, which behaves like this.
+  EXPECT_FALSE(apps_util::ConditionValueMatches("/abasdfab",
+                                                condition_value_dot_and_star));
+  EXPECT_FALSE(apps_util::ConditionValueMatches("/abasdfad",
+                                                condition_value_dot_and_star));
+  EXPECT_FALSE(apps_util::ConditionValueMatches("/bbasdfab",
+                                                condition_value_dot_and_star));
+  EXPECT_FALSE(
+      apps_util::ConditionValueMatches("/a", condition_value_dot_and_star));
+  EXPECT_FALSE(
+      apps_util::ConditionValueMatches("/b", condition_value_dot_and_star));
+
+  auto condition_value_escape_dot = apps_util::MakeConditionValue(
+      "/a\\.b", apps::mojom::PatternMatchType::kGlob);
+  EXPECT_TRUE(
+      apps_util::ConditionValueMatches("/a.b", condition_value_escape_dot));
+
+  // This arguably should be false, however the transcribed is carried from the
+  // upstream Android codebase, which behaves like this.
+  EXPECT_TRUE(
+      apps_util::ConditionValueMatches("/acb", condition_value_escape_dot));
+
+  auto condition_value_escape_star = apps_util::MakeConditionValue(
+      "/a\\*b", apps::mojom::PatternMatchType::kGlob);
+  EXPECT_TRUE(
+      apps_util::ConditionValueMatches("/a*b", condition_value_escape_star));
+  EXPECT_FALSE(
+      apps_util::ConditionValueMatches("/acb", condition_value_escape_star));
+}
diff --git a/chrome/services/util_win/public/mojom/util_win_mojom_traits.cc b/chrome/services/util_win/public/mojom/util_win_mojom_traits.cc
index 68c5439..00224bcd 100644
--- a/chrome/services/util_win/public/mojom/util_win_mojom_traits.cc
+++ b/chrome/services/util_win/public/mojom/util_win_mojom_traits.cc
@@ -131,7 +131,7 @@
 const base::string16& StructTraits<
     chrome::mojom::InspectionResultDataView,
     ModuleInspectionResult>::version(const ModuleInspectionResult& input) {
-  return input.basename;
+  return input.version;
 }
 // static
 chrome::mojom::CertificateType
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 02c066f..76f6649 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -14,7 +14,6 @@
 import("//chrome/browser/media/router/features.gni")
 import("//chrome/chrome_repack_locales.gni")
 import("//chrome/common/features.gni")
-import("//chromeos/assistant/assistant.gni")
 import("//components/feature_engagement/features.gni")
 import("//components/feed/features.gni")
 import("//components/gwp_asan/buildflags/buildflags.gni")
@@ -2276,6 +2275,7 @@
         "../browser/signin/chromeos_mirror_account_consistency_browsertest.cc",
         "../browser/ui/app_list/arc/arc_usb_host_permission_browsertest.cc",
         "../browser/ui/ash/accelerator_commands_browsertest.cc",
+        "../browser/ui/ash/assistant/assistant_context_browsertest.cc",
         "../browser/ui/ash/chrome_new_window_client_browsertest.cc",
         "../browser/ui/ash/chrome_screenshot_grabber_browsertest.cc",
         "../browser/ui/ash/keyboard/keyboard_controller_browsertest.cc",
@@ -2333,10 +2333,6 @@
         "base/interactive_test_utils_aura.h",
         "base/interactive_test_utils_views.cc",
       ]
-      if (enable_cros_assistant) {
-        sources +=
-            [ "../browser/ui/ash/assistant/assistant_context_browsertest.cc" ]
-      }
       sources -= [
         "../../apps/load_and_launch_browsertest.cc",
         "../browser/policy/policy_startup_browsertest.cc",
diff --git a/chrome/test/base/test_chrome_web_ui_controller_factory.cc b/chrome/test/base/test_chrome_web_ui_controller_factory.cc
index c87472d..71df79a 100644
--- a/chrome/test/base/test_chrome_web_ui_controller_factory.cc
+++ b/chrome/test/base/test_chrome_web_ui_controller_factory.cc
@@ -65,7 +65,8 @@
                      web_ui, webui_url);
   // Add an empty callback since managed-footnote always sends this message.
   web_ui->RegisterMessageCallback("observeManagedUI", base::DoNothing());
-  content::URLDataSource::Add(profile, std::make_unique<TestDataSource>());
+  content::URLDataSource::Add(profile,
+                              std::make_unique<TestDataSource>("webui"));
   return controller;
 }
 
diff --git a/chrome/test/data/pdf/test_util.js b/chrome/test/data/pdf/test_util.js
index 3baa481..24a30f18 100644
--- a/chrome/test/data/pdf/test_util.js
+++ b/chrome/test/data/pdf/test_util.js
@@ -116,23 +116,6 @@
   };
 }
 
-function animationFrame() {
-  return new Promise(resolve => requestAnimationFrame(resolve));
-}
-
-function contentElement() {
-  return document.elementFromPoint(innerWidth / 2, innerHeight / 2);
-}
-
-async function testAsync(f) {
-  try {
-    await f();
-    chrome.test.succeed();
-  } catch (e) {
-    chrome.test.fail(e);
-  }
-}
-
 /**
  * @return {!HTMLElement} An element containing a dom-repeat of bookmarks, for
  *     testing the bookmarks outside of the toolbar.
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index 7d38e22..5e867c2 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -394,13 +394,7 @@
   }
 };
 
-// This test is flaky on Mac10.9 Tests (dbg). See https://crbug.com/771099.
-GEN('#if defined(OS_MACOSX)');
-GEN('#define MAYBE_Filtering DISABLED_Filtering');
-GEN('#else');
-GEN('#define MAYBE_Filtering Filtering');
-GEN('#endif');
-TEST_F('CrExtensionsItemListTest', 'MAYBE_Filtering', function() {
+TEST_F('CrExtensionsItemListTest', 'Filtering', function() {
   this.runMochaTest(extension_item_list_tests.TestNames.Filtering);
 });
 
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index 1d004b2..87f0ca2 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -699,11 +699,6 @@
 var OSSettingsPeoplePageAccountManagerTest =
     class extends OSSettingsBrowserTest {
   /** @override */
-  get featureList() {
-    return {enabled: ['chromeos::features::kAccountManager']};
-  }
-
-  /** @override */
   get browsePreload() {
     return super.browsePreload + 'people_page/account_manager.html';
   }
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 4cc02d6e..0afeddd 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -588,8 +588,7 @@
 
   /** @override */
   featureList: {
-    enabled: ['chromeos::features::kAccountManager'],
-    disabled: ['chromeos::features::kSplitSettings']
+    disabled: ['chromeos::features::kSplitSettings'],
   },
 
   /** @override */
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 8a62e4c..bf06a5b92 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -388,6 +388,8 @@
       "webview/webview_grpc_service.h",
       "webview/webview_layout_manager.cc",
       "webview/webview_layout_manager.h",
+      "webview/webview_navigation_throttle.cc",
+      "webview/webview_navigation_throttle.h",
       "webview/webview_window_manager.cc",
       "webview/webview_window_manager.h",
     ]
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 344e534..fbca0e4 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -137,6 +137,10 @@
 #include "chromecast/external_mojo/broker_service/broker_service.h"
 #endif
 
+#if BUILDFLAG(ENABLE_CAST_WAYLAND_SERVER)
+#include "chromecast/browser/webview/webview_controller.h"
+#endif  // BUILDFLAG(ENABLE_CAST_WAYLAND_SERVER)
+
 namespace chromecast {
 namespace shell {
 
@@ -946,6 +950,13 @@
             handle, general_audience_browsing_service_.get()));
   }
 
+#if BUILDFLAG(ENABLE_CAST_WAYLAND_SERVER)
+  auto webview_throttle = WebviewController::MaybeGetNavigationThrottle(handle);
+  if (webview_throttle) {
+    throttles.push_back(std::move(webview_throttle));
+  }
+#endif  // BUILDFLAG(ENABLE_CAST_WAYLAND_SERVER)
+
   return throttles;
 }
 
diff --git a/chromecast/browser/webview/proto/webview.proto b/chromecast/browser/webview/proto/webview.proto
index 0bac50d3..1304f849 100644
--- a/chromecast/browser/webview/proto/webview.proto
+++ b/chromecast/browser/webview/proto/webview.proto
@@ -169,6 +169,14 @@
   bool require_user_gesture = 1;
 }
 
+message NavigationRequestEvent {
+  string url = 1;
+}
+
+enum NavigationDecision {
+  PREVENT = 0;
+  NAVIGATE = 1;
+}
 message WebviewRequest {
   // Unique identifier for the request. For requests that will have a response,
   // the response id will match the request id.
@@ -209,6 +217,8 @@
     GetTitleRequest get_title = 16;
     // No response.
     SetAutoMediaPlaybackPolicyRequest set_auto_media_playback_policy = 17;
+    // Response to a navigation request.
+    NavigationDecision navigation_decision = 19;
   }
 }
 
@@ -225,6 +235,8 @@
     CanGoBackResponse can_go_back = 5;
     CanGoForwardResponse can_go_forward = 6;
     GetTitleResponse get_title = 7;
+    // Triggered by web navigation events inside the webview.
+    NavigationRequestEvent navigation_event = 9;
   }
 }
 
diff --git a/chromecast/browser/webview/webview_controller.cc b/chromecast/browser/webview/webview_controller.cc
index 8d2880cb..d8814fd 100644
--- a/chromecast/browser/webview/webview_controller.cc
+++ b/chromecast/browser/webview/webview_controller.cc
@@ -10,8 +10,10 @@
 #include "chromecast/browser/cast_web_contents_impl.h"
 #include "chromecast/browser/webview/proto/webview.pb.h"
 #include "chromecast/browser/webview/webview_layout_manager.h"
+#include "chromecast/browser/webview/webview_navigation_throttle.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browsing_data_remover.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/web_preferences.h"
@@ -21,11 +23,32 @@
 
 namespace chromecast {
 
+namespace {
+
+const void* kWebviewResponseUserDataKey = &kWebviewResponseUserDataKey;
+
+class WebviewUserData : public base::SupportsUserData::Data {
+ public:
+  explicit WebviewUserData(WebviewController* controller);
+  ~WebviewUserData() override;
+
+  std::unique_ptr<Data> Clone() override;
+
+  WebviewController* controller() const { return controller_; }
+
+ private:
+  WebviewController* controller_;
+};
+
+}  // namespace
+
 WebviewController::WebviewController(content::BrowserContext* browser_context,
                                      Client* client)
     : client_(client) {
   content::WebContents::CreateParams create_params(browser_context, nullptr);
   contents_ = content::WebContents::Create(create_params);
+  contents_->SetUserData(kWebviewResponseUserDataKey,
+                         std::make_unique<WebviewUserData>(this));
   CastWebContents::InitParams cast_contents_init;
   cast_contents_init.is_root_window = true;
   cast_contents_init.enabled_for_dev = CAST_IS_DEBUG_BUILD();
@@ -44,6 +67,20 @@
 
 WebviewController::~WebviewController() {}
 
+std::unique_ptr<content::NavigationThrottle>
+WebviewController::MaybeGetNavigationThrottle(
+    content::NavigationHandle* handle) {
+  auto* web_contents = handle->GetWebContents();
+  auto* webview_user_data = static_cast<WebviewUserData*>(
+      web_contents->GetUserData(kWebviewResponseUserDataKey));
+  if (webview_user_data &&
+      webview_user_data->controller()->has_navigation_delegate_) {
+    return std::make_unique<WebviewNavigationThrottle>(
+        handle, webview_user_data->controller());
+  }
+  return nullptr;
+}
+
 void WebviewController::ProcessRequest(const webview::WebviewRequest& request) {
   switch (request.type_case()) {
     case webview::WebviewRequest::kInput:
@@ -142,13 +179,29 @@
         client_->OnError("set_auto_media_playback_policy() not supplied");
       }
       break;
-
+    case webview::WebviewRequest::kNavigationDecision:
+      if (current_navigation_throttle_) {
+        current_navigation_throttle_->ProcessNavigationDecision(
+            request.navigation_decision());
+        current_navigation_throttle_ = nullptr;
+      }
+      break;
     default:
       client_->OnError("Unknown request code");
       break;
   }
 }
 
+void WebviewController::SendNavigationEvent(WebviewNavigationThrottle* throttle,
+                                            const GURL& gurl) {
+  DCHECK(!current_navigation_throttle_);
+  std::unique_ptr<webview::WebviewResponse> response =
+      std::make_unique<webview::WebviewResponse>();
+  response->mutable_navigation_event()->set_url(gurl.spec());
+  current_navigation_throttle_ = throttle;
+  client_->EnqueueSend(std::move(response));
+}
+
 void WebviewController::ClosePage() {
   cast_web_contents_->ClosePage();
 }
@@ -308,7 +361,7 @@
   prefs.javascript_enabled = request.javascript_enabled();
   contents_->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
 
-  // TODO(dnicoara): Add support for |has_navigation_delegate|.
+  has_navigation_delegate_ = request.has_navigation_delegate();
 
   // Given that cast_shell enables devtools unconditionally there isn't
   // anything that needs to be done for |request.debugging_enabled()|. Though,
@@ -388,4 +441,13 @@
   }
 }
 
+WebviewUserData::WebviewUserData(WebviewController* controller)
+    : controller_(controller) {}
+
+WebviewUserData::~WebviewUserData() = default;
+
+std::unique_ptr<base::SupportsUserData::Data> WebviewUserData::Clone() {
+  return std::make_unique<WebviewUserData>(controller_);
+}
+
 }  // namespace chromecast
diff --git a/chromecast/browser/webview/webview_controller.h b/chromecast/browser/webview/webview_controller.h
index 8ba32d86..f321dc1 100644
--- a/chromecast/browser/webview/webview_controller.h
+++ b/chromecast/browser/webview/webview_controller.h
@@ -8,8 +8,10 @@
 #include <memory>
 #include <string>
 
+#include "base/supports_user_data.h"
 #include "chromecast/browser/cast_web_contents.h"
 #include "chromecast/browser/webview/proto/webview.pb.h"
+#include "url/gurl.h"
 
 namespace aura {
 class Window;
@@ -22,10 +24,14 @@
 namespace content {
 class BrowserContext;
 class WebContents;
+class NavigationHandle;
+class NavigationThrottle;
 }  // namespace content
 
 namespace chromecast {
 
+class WebviewNavigationThrottle;
+
 // This owns a WebContents and CastWebContents and processes proto commands
 // to allow the web contents to be controlled and embedded.
 class WebviewController : public CastWebContents::Delegate,
@@ -41,6 +47,11 @@
   WebviewController(content::BrowserContext* browser_context, Client* client);
   ~WebviewController() override;
 
+  // Returns a navigation throttle for the current navigation request, if one is
+  // necessary.
+  static std::unique_ptr<content::NavigationThrottle>
+  MaybeGetNavigationThrottle(content::NavigationHandle* handle);
+
   // Cause the controller to be destroyed after giving the webpage a chance to
   // run unload events. This unsets the client so no more messages will be
   // sent.
@@ -54,6 +65,9 @@
   // Attach this web contents to an aura window as a child.
   void AttachTo(aura::Window* window, int window_id);
 
+  void SendNavigationEvent(WebviewNavigationThrottle* throttle,
+                           const GURL& url);
+
  private:
   webview::AsyncPageEvent_State current_state();
 
@@ -90,6 +104,16 @@
   std::unique_ptr<CastWebContents> cast_web_contents_;
   bool stopped_ = false;
 
+  bool has_navigation_delegate_ = false;
+
+  // The navigation throttle for the current navigation event, if any.
+  // Is set only:
+  //    When has_navigation_delegate is true, and
+  //    A NavigationEvent call is currently in process.
+  // Cleared immediately after the NavigationDecision has been processed.
+  WebviewNavigationThrottle* current_navigation_throttle_ =
+      nullptr;  // Not owned.
+
   base::WeakPtrFactory<WebviewController> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WebviewController);
diff --git a/chromecast/browser/webview/webview_navigation_throttle.cc b/chromecast/browser/webview/webview_navigation_throttle.cc
new file mode 100644
index 0000000..2130754
--- /dev/null
+++ b/chromecast/browser/webview/webview_navigation_throttle.cc
@@ -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.
+
+#include "chromecast/browser/webview/webview_navigation_throttle.h"
+
+#include "base/bind.h"
+#include "chromecast/browser/webview/proto/webview.pb.h"
+#include "chromecast/browser/webview/webview_controller.h"
+#include "content/public/browser/navigation_handle.h"
+
+namespace chromecast {
+
+WebviewNavigationThrottle::WebviewNavigationThrottle(
+    content::NavigationHandle* handle,
+    WebviewController* controller)
+    : NavigationThrottle(handle),
+      url_(handle->GetURL()),
+      controller_(controller) {}
+
+WebviewNavigationThrottle::~WebviewNavigationThrottle() = default;
+
+content::NavigationThrottle::ThrottleCheckResult
+WebviewNavigationThrottle::WillStartRequest() {
+  controller_->SendNavigationEvent(this, url_);
+
+  return content::NavigationThrottle::DEFER;
+}
+
+void WebviewNavigationThrottle::ProcessNavigationDecision(
+    webview::NavigationDecision decision) {
+  if (decision != webview::PREVENT) {
+    this->Resume();
+    return;
+  }
+  this->CancelDeferredNavigation(content::NavigationThrottle::CANCEL);
+}
+
+const char* WebviewNavigationThrottle::GetNameForLogging() {
+  return "WebviewNavigationThrottle";
+}
+
+}  // namespace chromecast
diff --git a/chromecast/browser/webview/webview_navigation_throttle.h b/chromecast/browser/webview/webview_navigation_throttle.h
new file mode 100644
index 0000000..8961381
--- /dev/null
+++ b/chromecast/browser/webview/webview_navigation_throttle.h
@@ -0,0 +1,45 @@
+// 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 CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_NAVIGATION_THROTTLE_H_
+#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_NAVIGATION_THROTTLE_H_
+
+#include "base/macros.h"
+#include "base/sequenced_task_runner.h"
+#include "chromecast/browser/webview/proto/webview.grpc.pb.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "url/gurl.h"
+
+namespace chromecast {
+
+class WebviewController;
+
+// A NavigationDelegate that defers navigation events until a NavigationDecision
+// is returned over RPC.
+class WebviewNavigationThrottle : public content::NavigationThrottle {
+ public:
+  WebviewNavigationThrottle(content::NavigationHandle* handle,
+                            WebviewController* controller);
+
+  ~WebviewNavigationThrottle() override;
+
+  ThrottleCheckResult WillStartRequest() override;
+  const char* GetNameForLogging() override;
+
+ protected:
+  friend class WebviewController;
+  void ProcessNavigationDecision(webview::NavigationDecision decision);
+
+ private:
+  scoped_refptr<base::SequencedTaskRunner> response_task_runner_;
+
+  const GURL url_;
+  WebviewController* controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebviewNavigationThrottle);
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_NAVIGATION_THROTTLE_H_
diff --git a/chromecast/media/audio/cma_audio_output_stream.cc b/chromecast/media/audio/cma_audio_output_stream.cc
index d99252b..946da50 100644
--- a/chromecast/media/audio/cma_audio_output_stream.cc
+++ b/chromecast/media/audio/cma_audio_output_stream.cc
@@ -190,6 +190,7 @@
     cma_backend_->Stop();
   }
   push_in_progress_ = false;
+  source_callback_ = nullptr;
   cma_backend_state_ = CmaBackendState::kPendingClose;
 
   cma_backend_task_runner_.reset();
@@ -279,12 +280,13 @@
   DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
   DCHECK_NE(status, CmaBackend::BufferStatus::kBufferPending);
 
-  DCHECK(push_in_progress_);
   push_in_progress_ = false;
 
   if (!source_callback_ || encountered_error_)
     return;
 
+  DCHECK_EQ(cma_backend_state_, CmaBackendState::kStarted);
+
   if (status != CmaBackend::BufferStatus::kBufferSuccess) {
     source_callback_->OnError();
     return;
diff --git a/chromeos/assistant/BUILD.gn b/chromeos/assistant/BUILD.gn
index 0b20141..23b590e 100644
--- a/chromeos/assistant/BUILD.gn
+++ b/chromeos/assistant/BUILD.gn
@@ -8,8 +8,5 @@
 buildflag_header("buildflags") {
   header = "buildflags.h"
 
-  flags = [
-    "ENABLE_CROS_ASSISTANT=$enable_cros_assistant",
-    "ENABLE_CROS_LIBASSISTANT=$enable_cros_libassistant",
-  ]
+  flags = [ "ENABLE_CROS_LIBASSISTANT=$enable_cros_libassistant" ]
 }
diff --git a/chromeos/assistant/assistant.gni b/chromeos/assistant/assistant.gni
index 21b216f..e145d0b 100644
--- a/chromeos/assistant/assistant.gni
+++ b/chromeos/assistant/assistant.gni
@@ -1,13 +1,6 @@
 import("//build/config/chrome_build.gni")
 
 declare_args() {
-  # Enable assistant features. Assistant related code is compiled only when
-  # true. The default assistant implementation is a stub.
-  enable_cros_assistant = is_chromeos
-}
-
-declare_args() {
-  # Enable assistant implementation based on libassistant. This requires
-  # enable_cros_assistant also enabled.
-  enable_cros_libassistant = enable_cros_assistant && is_chrome_branded
+  # Enable assistant implementation based on libassistant.
+  enable_cros_libassistant = is_chromeos && is_chrome_branded
 }
diff --git a/chromeos/dbus/shill/fake_shill_ipconfig_client.cc b/chromeos/dbus/shill/fake_shill_ipconfig_client.cc
index fdd86d0f..319b284 100644
--- a/chromeos/dbus/shill/fake_shill_ipconfig_client.cc
+++ b/chromeos/dbus/shill/fake_shill_ipconfig_client.cc
@@ -35,9 +35,6 @@
     const dbus::ObjectPath& ipconfig_path,
     ShillPropertyChangedObserver* observer) {}
 
-void FakeShillIPConfigClient::Refresh(const dbus::ObjectPath& ipconfig_path,
-                                      VoidDBusMethodCallback callback) {}
-
 void FakeShillIPConfigClient::GetProperties(
     const dbus::ObjectPath& ipconfig_path,
     const DictionaryValueCallback& callback) {
diff --git a/chromeos/dbus/shill/fake_shill_ipconfig_client.h b/chromeos/dbus/shill/fake_shill_ipconfig_client.h
index 1ffc610e..eeac643 100644
--- a/chromeos/dbus/shill/fake_shill_ipconfig_client.h
+++ b/chromeos/dbus/shill/fake_shill_ipconfig_client.h
@@ -28,8 +28,6 @@
   void RemovePropertyChangedObserver(
       const dbus::ObjectPath& ipconfig_path,
       ShillPropertyChangedObserver* observer) override;
-  void Refresh(const dbus::ObjectPath& ipconfig_path,
-               VoidDBusMethodCallback callback) override;
   void GetProperties(const dbus::ObjectPath& ipconfig_path,
                      const DictionaryValueCallback& callback) override;
   void SetProperty(const dbus::ObjectPath& ipconfig_path,
diff --git a/chromeos/dbus/shill/shill_ipconfig_client.cc b/chromeos/dbus/shill/shill_ipconfig_client.cc
index 0070297..0c5c648 100644
--- a/chromeos/dbus/shill/shill_ipconfig_client.cc
+++ b/chromeos/dbus/shill/shill_ipconfig_client.cc
@@ -45,8 +45,6 @@
       ShillPropertyChangedObserver* observer) override {
     GetHelper(ipconfig_path)->RemovePropertyChangedObserver(observer);
   }
-  void Refresh(const dbus::ObjectPath& ipconfig_path,
-               VoidDBusMethodCallback callback) override;
   void GetProperties(const dbus::ObjectPath& ipconfig_path,
                      const DictionaryValueCallback& callback) override;
   void SetProperty(const dbus::ObjectPath& ipconfig_path,
@@ -94,13 +92,6 @@
   GetHelper(ipconfig_path)->CallDictionaryValueMethod(&method_call, callback);
 }
 
-void ShillIPConfigClientImpl::Refresh(const dbus::ObjectPath& ipconfig_path,
-                                      VoidDBusMethodCallback callback) {
-  dbus::MethodCall method_call(shill::kFlimflamIPConfigInterface,
-                               shill::kRefreshFunction);
-  GetHelper(ipconfig_path)->CallVoidMethod(&method_call, std::move(callback));
-}
-
 void ShillIPConfigClientImpl::SetProperty(const dbus::ObjectPath& ipconfig_path,
                                           const std::string& name,
                                           const base::Value& value,
diff --git a/chromeos/dbus/shill/shill_ipconfig_client.h b/chromeos/dbus/shill/shill_ipconfig_client.h
index 2dd805b..fd18e21 100644
--- a/chromeos/dbus/shill/shill_ipconfig_client.h
+++ b/chromeos/dbus/shill/shill_ipconfig_client.h
@@ -70,11 +70,6 @@
       const dbus::ObjectPath& ipconfig_path,
       ShillPropertyChangedObserver* observer) = 0;
 
-  // Refreshes the active IP configuration after service property changes and
-  // renews the DHCP lease, if any.
-  virtual void Refresh(const dbus::ObjectPath& ipconfig_path,
-                       VoidDBusMethodCallback callback) = 0;
-
   // Calls GetProperties method.
   // |callback| is called after the method call succeeds.
   virtual void GetProperties(const dbus::ObjectPath& ipconfig_path,
diff --git a/chromeos/network/fake_network_device_handler.cc b/chromeos/network/fake_network_device_handler.cc
index 29811f3..ef58ab7 100644
--- a/chromeos/network/fake_network_device_handler.cc
+++ b/chromeos/network/fake_network_device_handler.cc
@@ -22,11 +22,6 @@
     const base::Closure& callback,
     const network_handler::ErrorCallback& error_callback) {}
 
-void FakeNetworkDeviceHandler::RequestRefreshIPConfigs(
-    const std::string& device_path,
-    const base::Closure& callback,
-    const network_handler::ErrorCallback& error_callback) {}
-
 void FakeNetworkDeviceHandler::RegisterCellularNetwork(
     const std::string& device_path,
     const std::string& network_id,
diff --git a/chromeos/network/fake_network_device_handler.h b/chromeos/network/fake_network_device_handler.h
index 362fe06..8df99bc1 100644
--- a/chromeos/network/fake_network_device_handler.h
+++ b/chromeos/network/fake_network_device_handler.h
@@ -36,11 +36,6 @@
       const base::Closure& callback,
       const network_handler::ErrorCallback& error_callback) override;
 
-  void RequestRefreshIPConfigs(
-      const std::string& device_path,
-      const base::Closure& callback,
-      const network_handler::ErrorCallback& error_callback) override;
-
   void RegisterCellularNetwork(
       const std::string& device_path,
       const std::string& network_id,
diff --git a/chromeos/network/mock_network_device_handler.h b/chromeos/network/mock_network_device_handler.h
index 9689a09a..83140ee 100644
--- a/chromeos/network/mock_network_device_handler.h
+++ b/chromeos/network/mock_network_device_handler.h
@@ -38,11 +38,6 @@
                     const base::Closure& callback,
                     const network_handler::ErrorCallback& error_callback));
 
-  MOCK_METHOD3(RequestRefreshIPConfigs,
-               void(const std::string& device_path,
-                    const base::Closure& callback,
-                    const network_handler::ErrorCallback& error_callback));
-
   MOCK_METHOD4(RegisterCellularNetwork,
                void(const std::string& device_path,
                     const std::string& network_id,
diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc
index 99cd01fd..01e52b7 100644
--- a/chromeos/network/network_configuration_handler.cc
+++ b/chromeos/network/network_configuration_handler.cc
@@ -300,11 +300,6 @@
                  base::Passed(&properties_copy), callback),
       base::Bind(&NetworkConfigurationHandler::SetPropertiesErrorCallback,
                  weak_ptr_factory_.GetWeakPtr(), service_path, error_callback));
-
-  // If we set the StaticIPConfig property, request an IP config refresh
-  // after calling SetProperties.
-  if (properties_to_set->HasKey(shill::kStaticIPConfigProperty))
-    RequestRefreshIPConfigs(service_path);
 }
 
 void NetworkConfigurationHandler::ClearShillProperties(
@@ -660,19 +655,6 @@
   network_state_handler_->RequestUpdateForNetwork(service_path);
 }
 
-void NetworkConfigurationHandler::RequestRefreshIPConfigs(
-    const std::string& service_path) {
-  if (!network_device_handler_)
-    return;
-  const NetworkState* network_state =
-      network_state_handler_->GetNetworkState(service_path);
-  if (!network_state || network_state->device_path().empty())
-    return;
-  network_device_handler_->RequestRefreshIPConfigs(
-      network_state->device_path(), base::DoNothing(),
-      network_handler::ErrorCallback());
-}
-
 // static
 NetworkConfigurationHandler* NetworkConfigurationHandler::InitializeForTest(
     NetworkStateHandler* network_state_handler,
diff --git a/chromeos/network/network_configuration_handler.h b/chromeos/network/network_configuration_handler.h
index 6fd2561..5363a2f 100644
--- a/chromeos/network/network_configuration_handler.h
+++ b/chromeos/network/network_configuration_handler.h
@@ -207,9 +207,6 @@
       const std::string& dbus_error_name,
       const std::string& dbus_error_message);
 
-  // Signals the device handler to request an IP config refresh.
-  void RequestRefreshIPConfigs(const std::string& service_path);
-
   // Removes network configuration for |service_path| from the profile specified
   // by |profile_path|. If |profile_path| is not set, the network is removed
   // from all the profiles that include it.
diff --git a/chromeos/network/network_device_handler.h b/chromeos/network/network_device_handler.h
index fd7b31b4..8cdcefe0 100644
--- a/chromeos/network/network_device_handler.h
+++ b/chromeos/network/network_device_handler.h
@@ -72,14 +72,6 @@
       const base::Closure& callback,
       const network_handler::ErrorCallback& error_callback) = 0;
 
-  // Requests a refresh of the IP configuration for the device specified by
-  // |device_path| if it exists. This will apply any newly configured
-  // properties and renew the DHCP lease.
-  virtual void RequestRefreshIPConfigs(
-      const std::string& device_path,
-      const base::Closure& callback,
-      const network_handler::ErrorCallback& error_callback) = 0;
-
   // Tells the device specified by |device_path| to register to the cellular
   // network with id |network_id|. If |network_id| is empty then registration
   // will proceed in automatic mode, which will cause the modem to register
diff --git a/chromeos/network/network_device_handler_impl.cc b/chromeos/network/network_device_handler_impl.cc
index 3d87a2e..b58bcb2 100644
--- a/chromeos/network/network_device_handler_impl.cc
+++ b/chromeos/network/network_device_handler_impl.cc
@@ -71,44 +71,6 @@
       shill_error_name, shill_error_message);
 }
 
-void IPConfigRefreshCallback(const std::string& ipconfig_path, bool result) {
-  if (!result) {
-    NET_LOG(ERROR) << "IPConfigs.Refresh Failed: " << ipconfig_path;
-  } else {
-    NET_LOG(EVENT) << "IPConfigs.Refresh Succeeded: " << ipconfig_path;
-  }
-}
-
-void RefreshIPConfigsCallback(
-    const base::Closure& callback,
-    const network_handler::ErrorCallback& error_callback,
-    const std::string& device_path,
-    const base::DictionaryValue& properties) {
-  const base::ListValue* ip_configs;
-  if (!properties.GetListWithoutPathExpansion(shill::kIPConfigsProperty,
-                                              &ip_configs)) {
-    network_handler::ShillErrorCallbackFunction(
-        "RequestRefreshIPConfigs Failed", device_path, error_callback,
-        std::string("Missing ") + shill::kIPConfigsProperty, "");
-    return;
-  }
-
-  for (size_t i = 0; i < ip_configs->GetSize(); i++) {
-    std::string ipconfig_path;
-    if (!ip_configs->GetString(i, &ipconfig_path))
-      continue;
-    ShillIPConfigClient::Get()->Refresh(
-        dbus::ObjectPath(ipconfig_path),
-        base::BindOnce(&IPConfigRefreshCallback, ipconfig_path));
-  }
-  // It is safe to invoke |callback| here instead of waiting for the
-  // IPConfig.Refresh callbacks to complete because the Refresh DBus calls will
-  // be executed in order and thus before any further DBus requests that
-  // |callback| may issue.
-  if (!callback.is_null())
-    callback.Run();
-}
-
 void SetDevicePropertyInternal(
     const std::string& device_path,
     const std::string& property_name,
@@ -299,16 +261,6 @@
                             error_callback);
 }
 
-void NetworkDeviceHandlerImpl::RequestRefreshIPConfigs(
-    const std::string& device_path,
-    const base::Closure& callback,
-    const network_handler::ErrorCallback& error_callback) {
-  GetDeviceProperties(
-      device_path,
-      base::Bind(&RefreshIPConfigsCallback, callback, error_callback),
-      error_callback);
-}
-
 void NetworkDeviceHandlerImpl::RegisterCellularNetwork(
     const std::string& device_path,
     const std::string& network_id,
diff --git a/chromeos/network/network_device_handler_impl.h b/chromeos/network/network_device_handler_impl.h
index 465ad4e..0270817 100644
--- a/chromeos/network/network_device_handler_impl.h
+++ b/chromeos/network/network_device_handler_impl.h
@@ -42,11 +42,6 @@
       const base::Closure& callback,
       const network_handler::ErrorCallback& error_callback) override;
 
-  void RequestRefreshIPConfigs(
-      const std::string& device_path,
-      const base::Closure& callback,
-      const network_handler::ErrorCallback& error_callback) override;
-
   void RegisterCellularNetwork(
       const std::string& device_path,
       const std::string& network_id,
diff --git a/chromeos/network/network_device_handler_unittest.cc b/chromeos/network/network_device_handler_unittest.cc
index 52da2df..39474245 100644
--- a/chromeos/network/network_device_handler_unittest.cc
+++ b/chromeos/network/network_device_handler_unittest.cc
@@ -465,15 +465,6 @@
   EXPECT_EQ(NetworkDeviceHandler::kErrorDeviceMissing, result_);
 }
 
-TEST_F(NetworkDeviceHandlerTest, RequestRefreshIPConfigs) {
-  network_device_handler_->RequestRefreshIPConfigs(
-      kDefaultWifiDevicePath, success_callback_, error_callback_);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(kResultSuccess, result_);
-  // TODO(stevenjb): Add test interface to ShillIPConfigClient and test
-  // refresh calls.
-}
-
 TEST_F(NetworkDeviceHandlerTest, RequirePin) {
   // Test that the success callback gets called.
   network_device_handler_->RequirePin(kDefaultCellularDevicePath, true,
diff --git a/chromeos/services/BUILD.gn b/chromeos/services/BUILD.gn
index 9ac4968..28bf7d8 100644
--- a/chromeos/services/BUILD.gn
+++ b/chromeos/services/BUILD.gn
@@ -18,6 +18,7 @@
 source_set("unit_tests") {
   testonly = true
   deps = [
+    "//chromeos/services/assistant:tests",
     "//chromeos/services/cellular_setup:unit_tests",
     "//chromeos/services/cros_healthd/public/cpp:unit_tests",
     "//chromeos/services/device_sync:unit_tests",
@@ -28,8 +29,4 @@
     "//chromeos/services/network_config:unit_tests",
     "//chromeos/services/secure_channel:unit_tests",
   ]
-
-  if (enable_cros_assistant) {
-    deps += [ "//chromeos/services/assistant:tests" ]
-  }
 }
diff --git a/chromeos/services/assistant/BUILD.gn b/chromeos/services/assistant/BUILD.gn
index a3212361..e8f3afa6 100644
--- a/chromeos/services/assistant/BUILD.gn
+++ b/chromeos/services/assistant/BUILD.gn
@@ -5,7 +5,6 @@
 import("//chromeos/assistant/assistant.gni")
 
 assert(is_chromeos)
-assert(enable_cros_assistant)
 
 component("lib") {
   output_name = "assistant_service"
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index 63568d5..e0055c9 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -106,6 +106,11 @@
     "//components/guest_os",
     "//components/onc",
     "//components/prefs",
+
+    # TODO(crbug.com/853604): After fully migrating the intent picker to query
+    # directly from App Service, we will deprecated the match functionality
+    # in intent_filter and this dependency will be removed.
+    "//components/services/app_service/public/cpp:intent_util",
     "//components/session_manager/core",
     "//components/timers",
     "//components/url_formatter",
diff --git a/components/arc/ime/DEPS b/components/arc/ime/DEPS
index ab2c42a0..2b080107 100644
--- a/components/arc/ime/DEPS
+++ b/components/arc/ime/DEPS
@@ -7,4 +7,5 @@
   "+ui/gfx/geometry",
 # Revisit this dependency when crbug.com/890403 is resovled.
   "+ui/views",
+  "+ui/wm",
 ]
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc
index 5db6d52..3dd4c9c 100644
--- a/components/arc/ime/arc_ime_service.cc
+++ b/components/arc/ime/arc_ime_service.cc
@@ -26,6 +26,7 @@
 #include "ui/gfx/range/range.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/non_client_view.h"
+#include "ui/wm/core/ime_util_chromeos.h"
 
 namespace arc {
 
@@ -496,6 +497,17 @@
   return true;
 }
 
+void ArcImeService::EnsureCaretNotInRect(const gfx::Rect& rect_in_screen) {
+  if (focused_arc_window_ == nullptr)
+    return;
+  aura::Window* top_level_window = focused_arc_window_->GetToplevelWindow();
+  // If the window is not a notification, the window move is handled by
+  // Android.
+  if (top_level_window->type() != aura::client::WINDOW_TYPE_POPUP)
+    return;
+  wm::EnsureWindowNotInRect(top_level_window, rect_in_screen);
+}
+
 ui::TextInputMode ArcImeService::GetTextInputMode() const {
   return ui::TEXT_INPUT_MODE_DEFAULT;
 }
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h
index 9b68a96..8b59b60 100644
--- a/components/arc/ime/arc_ime_service.h
+++ b/components/arc/ime/arc_ime_service.h
@@ -122,6 +122,7 @@
   bool GetEditableSelectionRange(gfx::Range* range) const override;
   bool GetTextFromRange(const gfx::Range& range,
                         base::string16* text) const override;
+  void EnsureCaretNotInRect(const gfx::Rect& rect) override;
 
   // Overridden from ui::TextInputClient (with default implementation):
   // TODO(kinaba): Support each of these methods to the extent possible in
@@ -141,7 +142,6 @@
   bool ChangeTextDirectionAndLayoutAlignment(
       base::i18n::TextDirection direction) override;
   void ExtendSelectionAndDelete(size_t before, size_t after) override;
-  void EnsureCaretNotInRect(const gfx::Rect& rect) override {}
   bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override;
   void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override {
   }
diff --git a/components/arc/intent_helper/DEPS b/components/arc/intent_helper/DEPS
index f64439e4..01b231f 100644
--- a/components/arc/intent_helper/DEPS
+++ b/components/arc/intent_helper/DEPS
@@ -5,6 +5,7 @@
   "+ash/shell.h",
   "+ash/shell_delegate.h",
   "+components/google/core",
+  "+components/services/app_service/public/cpp",
   "+components/url_formatter",
   "+content/public/common/service_manager_connection.h",
   "+services/service_manager/public/cpp/connector.h",
diff --git a/components/arc/intent_helper/intent_filter.cc b/components/arc/intent_helper/intent_filter.cc
index fd15d61..51d713d 100644
--- a/components/arc/intent_helper/intent_filter.cc
+++ b/components/arc/intent_helper/intent_filter.cc
@@ -9,6 +9,7 @@
 #include "base/compiler_specific.h"
 #include "base/strings/string_util.h"
 #include "components/arc/mojom/intent_helper.mojom.h"
+#include "components/services/app_service/public/cpp/intent_util.h"
 #include "url/gurl.h"
 
 namespace arc {
@@ -148,92 +149,10 @@
       return base::StartsWith(str, pattern_,
                               base::CompareCase::INSENSITIVE_ASCII);
     case mojom::PatternType::PATTERN_SIMPLE_GLOB:
-      return MatchGlob(str);
+      return apps_util::MatchGlob(str, pattern_);
   }
 
   return false;
 }
 
-// Transcribed from android's PatternMatcher#matchPattern.
-bool IntentFilter::PatternMatcher::MatchGlob(const std::string& str) const {
-#define GET_CHAR(s, i) ((UNLIKELY(i >= s.length())) ? '\0' : s[i])
-
-  const size_t NP = pattern_.length();
-  const size_t NS = str.length();
-  if (NP == 0) {
-    return NS == 0;
-  }
-  size_t ip = 0, is = 0;
-  char nextChar = GET_CHAR(pattern_, 0);
-  while (ip < NP && is < NS) {
-    char c = nextChar;
-    ++ip;
-    nextChar = GET_CHAR(pattern_, ip);
-    const bool escaped = (c == '\\');
-    if (escaped) {
-      c = nextChar;
-      ++ip;
-      nextChar = GET_CHAR(pattern_, ip);
-    }
-    if (nextChar == '*') {
-      if (!escaped && c == '.') {
-        if (ip >= (NP - 1)) {
-          // At the end with a pattern match
-          return true;
-        }
-        ++ip;
-        nextChar = GET_CHAR(pattern_, ip);
-        // Consume everything until the next char in the pattern is found.
-        if (nextChar == '\\') {
-          ++ip;
-          nextChar = GET_CHAR(pattern_, ip);
-        }
-        do {
-          if (GET_CHAR(str, is) == nextChar) {
-            break;
-          }
-          ++is;
-        } while (is < NS);
-        if (is == NS) {
-          // Next char in the pattern didn't exist in the match.
-          return false;
-        }
-        ++ip;
-        nextChar = GET_CHAR(pattern_, ip);
-        ++is;
-      } else {
-        // Consume only characters matching the one before '*'.
-        do {
-          if (GET_CHAR(str, is) != c) {
-            break;
-          }
-          ++is;
-        } while (is < NS);
-        ++ip;
-        nextChar = GET_CHAR(pattern_, ip);
-      }
-    } else {
-      if (c != '.' && GET_CHAR(str, is) != c)
-        return false;
-      ++is;
-    }
-  }
-
-  if (ip >= NP && is >= NS) {
-    // Reached the end of both strings
-    return true;
-  }
-
-  // One last check: we may have finished the match string, but still have a
-  // '.*' at the end of the pattern, which is still a match.
-  if (ip == NP - 2 && GET_CHAR(pattern_, ip) == '.' &&
-      GET_CHAR(pattern_, ip + 1) == '*') {
-    return true;
-  }
-
-  return false;
-
-#undef GET_CHAR
-}
-
 }  // namespace arc
diff --git a/components/arc/intent_helper/intent_filter.h b/components/arc/intent_helper/intent_filter.h
index 49f3d77..db457d0 100644
--- a/components/arc/intent_helper/intent_filter.h
+++ b/components/arc/intent_helper/intent_filter.h
@@ -61,8 +61,6 @@
     mojom::PatternType match_type() const { return match_type_; }
 
    private:
-    bool MatchGlob(const std::string& match) const;
-
     std::string pattern_;
     mojom::PatternType match_type_;
 
diff --git a/components/ntp_snippets/remote/remote_suggestions_database.cc b/components/ntp_snippets/remote/remote_suggestions_database.cc
index b61121a0..52696e4 100644
--- a/components/ntp_snippets/remote/remote_suggestions_database.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_database.cc
@@ -95,6 +95,11 @@
 }
 
 void RemoteSuggestionsDatabase::SaveSnippet(const RemoteSuggestion& snippet) {
+  if (IsErrorState()) {
+    DVLOG(0) << "Attempted save snippet but db is in an error state, aborting";
+    return;
+  }
+
   std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
   // OnDatabaseLoaded relies on the detail that the primary snippet id goes
   // first in the protocol representation.
@@ -105,6 +110,11 @@
 
 void RemoteSuggestionsDatabase::SaveSnippets(
     const RemoteSuggestion::PtrVector& snippets) {
+  if (IsErrorState()) {
+    DVLOG(0) << "Attempted save snippets but db is in an error state, aborting";
+    return;
+  }
+
   std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
   for (const std::unique_ptr<RemoteSuggestion>& snippet : snippets) {
     // OnDatabaseLoaded relies on the detail that the primary snippet id goes
@@ -121,7 +131,11 @@
 
 void RemoteSuggestionsDatabase::DeleteSnippets(
     std::unique_ptr<std::vector<std::string>> snippet_ids) {
-  DCHECK(IsInitialized());
+  if (IsErrorState()) {
+    DVLOG(0)
+        << "Attempted delete snippets but db is in an error state, aborting";
+    return;
+  }
 
   std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
   database_->UpdateEntries(
@@ -141,7 +155,10 @@
 
 void RemoteSuggestionsDatabase::SaveImage(const std::string& snippet_id,
                                           const std::string& image_data) {
-  DCHECK(IsInitialized());
+  if (IsErrorState()) {
+    DVLOG(0) << "Attempted save image but db is in an error state, aborting";
+    return;
+  }
 
   SnippetImageProto image_proto;
   image_proto.set_data(image_data);
@@ -162,7 +179,10 @@
 
 void RemoteSuggestionsDatabase::DeleteImages(
     std::unique_ptr<std::vector<std::string>> snippet_ids) {
-  DCHECK(IsInitialized());
+  if (IsErrorState()) {
+    DVLOG(0) << "Attempted delete images but db is in an error state, aborting";
+    return;
+  }
   image_database_->UpdateEntries(
       std::make_unique<ImageKeyEntryVector>(), std::move(snippet_ids),
       base::BindOnce(&RemoteSuggestionsDatabase::OnImageDatabaseSaved,
@@ -171,7 +191,10 @@
 
 void RemoteSuggestionsDatabase::GarbageCollectImages(
     std::unique_ptr<std::set<std::string>> alive_snippet_ids) {
-  DCHECK(image_database_initialized_);
+  if (IsErrorState()) {
+    DVLOG(0) << "Attempted gc but db is in an error state, aborting";
+    return;
+  }
   image_database_->LoadKeys(base::BindOnce(
       &RemoteSuggestionsDatabase::DeleteUnreferencedImages,
       weak_ptr_factory_.GetWeakPtr(), std::move(alive_snippet_ids)));
diff --git a/components/ntp_snippets/remote/remote_suggestions_database_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_database_unittest.cc
index ddd82600..dedb1e0 100644
--- a/components/ntp_snippets/remote/remote_suggestions_database_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_database_unittest.cc
@@ -80,8 +80,16 @@
                                                       std::move(image_db));
   }
 
+  void ForceDBError() { db_->OnDatabaseError(); }
+
   FakeDB<SnippetProto>* suggestion_db() { return suggestion_db_; }
+  std::map<std::string, SnippetProto>& suggestion_db_storage() {
+    return suggestion_db_storage_;
+  }
   FakeDB<SnippetImageProto>* image_db() { return image_db_; }
+  std::map<std::string, SnippetImageProto>& image_db_storage() {
+    return image_db_storage_;
+  }
 
   RemoteSuggestionsDatabase* db() { return db_.get(); }
 
@@ -431,4 +439,28 @@
   image_db()->GetCallback(true);
 }
 
+TEST_F(RemoteSuggestionsDatabaseTest, TryOperationsAfterError) {
+  CreateDatabase();
+  suggestion_db()->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
+  image_db()->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
+  ASSERT_TRUE(db()->IsInitialized());
+
+  ForceDBError();
+  ASSERT_TRUE(db()->IsErrorState());
+
+  std::unique_ptr<RemoteSuggestion> snippet = CreateTestSuggestion();
+  std::string image_data("pretty image");
+
+  db()->SaveSnippet(*snippet);
+  db()->SaveImage(snippet->id(), image_data);
+  ASSERT_TRUE(suggestion_db_storage().empty());
+  ASSERT_TRUE(image_db_storage().empty());
+
+  db()->DeleteImage("foo");
+  db()->GarbageCollectImages(
+      std::make_unique<std::set<std::string>>(std::set<std::string>({"foo"})));
+
+  SUCCEED() << "This test passes if it doesn't crash";
+}
+
 }  // namespace ntp_snippets
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 3951a32..6bbed3b 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -396,6 +396,7 @@
     "in_memory_url_index_types_unittest.cc",
     "in_memory_url_index_unittest.cc",
     "keyword_provider_unittest.cc",
+    "local_history_zero_suggest_provider_unittest.cc",
     "location_bar_model_impl_unittest.cc",
     "omnibox_controller_unittest.cc",
     "omnibox_edit_model_unittest.cc",
@@ -434,6 +435,7 @@
     "//components/prefs:test_support",
     "//components/search",
     "//components/search_engines",
+    "//components/search_engines:test_support",
     "//components/sessions",
     "//components/signin/public/identity_manager:test_support",
     "//components/strings",
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider.cc b/components/omnibox/browser/local_history_zero_suggest_provider.cc
index 4ab879c..dcbaf7f 100644
--- a/components/omnibox/browser/local_history_zero_suggest_provider.cc
+++ b/components/omnibox/browser/local_history_zero_suggest_provider.cc
@@ -36,10 +36,6 @@
 // Default relevance for the LocalHistoryZeroSuggestProvider query suggestions.
 const int kLocalHistoryZeroSuggestRelevance = 500;
 
-// ZeroSuggestVariant field trial param value for the local history query
-// suggestions.
-const char kZeroSuggestLocalVariant[] = "Local";
-
 // ProviderHistoryDBTask wraps two non-null callbacks into a HistoryDBTask to
 // passed to HistoryService::ScheduleDBTask. |request_callback| gets invoked on
 // the history backend thread when the on-disk history database becomes
@@ -116,6 +112,10 @@
 }  // namespace
 
 // static
+const char LocalHistoryZeroSuggestProvider::kZeroSuggestLocalVariant[] =
+    "Local";
+
+// static
 LocalHistoryZeroSuggestProvider* LocalHistoryZeroSuggestProvider::Create(
     AutocompleteProviderClient* client,
     AutocompleteProviderListener* listener) {
@@ -127,8 +127,8 @@
   TRACE_EVENT0("omnibox", "LocalHistoryZeroSuggestProvider::Start");
 
   history_task_tracker_.TryCancel(history_db_task_id_);
+  done_ = true;
   matches_.clear();
-  Stop(true, false);
 
   // Allow local history query suggestions only when the user is unauthenticated
   // and is not in an off-the-record context.
@@ -176,6 +176,7 @@
         google_search_url, max_matches_, url_db);
     OnQueryURLDatabaseComplete(input, std::move(url_matches));
   } else {
+    done_ = false;
     history_db_task_id_ = history_service->ScheduleDBTask(
         FROM_HERE,
         std::make_unique<ProviderHistoryDBTask>(
@@ -230,6 +231,8 @@
                      weak_ptr_factory_.GetWeakPtr(), match.contents),
       &history_task_tracker_);
 
+  // Prevent the deleted suggestion from being resuggested until the
+  // corresponding URLs are asynchronously deleted.
   deleted_suggestions_set_.insert(match.contents);
 }
 
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider.h b/components/omnibox/browser/local_history_zero_suggest_provider.h
index 82a7808..75de3875 100644
--- a/components/omnibox/browser/local_history_zero_suggest_provider.h
+++ b/components/omnibox/browser/local_history_zero_suggest_provider.h
@@ -23,6 +23,11 @@
 // history when Google is the default search engine.
 class LocalHistoryZeroSuggestProvider : public AutocompleteProvider {
  public:
+  // ZeroSuggestVariant field trial param value for the local history query
+  // suggestions.
+  // Public for testing.
+  static const char kZeroSuggestLocalVariant[];
+
   // Creates and returns an instance of this provider.
   static LocalHistoryZeroSuggestProvider* Create(
       AutocompleteProviderClient* client,
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc b/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc
new file mode 100644
index 0000000..13e736bb
--- /dev/null
+++ b/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc
@@ -0,0 +1,341 @@
+// 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 "components/omnibox/browser/local_history_zero_suggest_provider.h"
+
+#include <memory>
+
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/url_database.h"
+#include "components/history/core/test/history_service_test_util.h"
+#include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/autocomplete_provider_listener.h"
+#include "components/omnibox/browser/autocomplete_result.h"
+#include "components/omnibox/browser/fake_autocomplete_provider_client.h"
+#include "components/omnibox/browser/in_memory_url_index_test_util.h"
+#include "components/omnibox/common/omnibox_features.h"
+#include "components/search_engines/search_engines_test_util.h"
+#include "components/search_engines/template_url.h"
+#include "components/search_engines/template_url_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+
+namespace {
+
+// Used to populate the URLDatabase.
+struct TestURLData {
+  const TemplateURL* search_provider;
+  std::string search_terms;
+  std::string other_query_params;
+  int age_in_days;
+  std::string title = "";
+  int visit_count = 1;
+  int typed_count = 1;
+  bool hidden = false;
+};
+
+// Used to validate expected autocomplete matches.
+struct TestMatchData {
+  std::string content;
+  int relevance;
+  bool allowed_to_be_default_match = false;
+};
+
+}  // namespace
+
+class LocalHistoryZeroSuggestProviderTest
+    : public testing::Test,
+      public AutocompleteProviderListener {
+ public:
+  LocalHistoryZeroSuggestProviderTest()
+      : client_(std::make_unique<FakeAutocompleteProviderClient>()),
+        provider_(base::WrapRefCounted(
+            LocalHistoryZeroSuggestProvider::Create(client_.get(), this))) {
+    SetZeroSuggestVariant(
+        metrics::OmniboxEventProto::NTP_REALBOX,
+        LocalHistoryZeroSuggestProvider::kZeroSuggestLocalVariant);
+  }
+  ~LocalHistoryZeroSuggestProviderTest() override {}
+
+ protected:
+  // testing::Test
+  void SetUp() override {
+    // Verify that Google is the default search provider.
+    ASSERT_EQ(SEARCH_ENGINE_GOOGLE,
+              default_search_provider()->GetEngineType(
+                  client_->GetTemplateURLService()->search_terms_data()));
+  }
+  void TearDown() override { task_environment_.RunUntilIdle(); }
+
+  // AutocompleteProviderListener
+  void OnProviderUpdate(bool updated_matches) override;
+
+  // Configures the ZeroSuggestVariant field trial param with the given value
+  // for the given context.
+  void SetZeroSuggestVariant(PageClassification page_classification,
+                             std::string zero_suggest_variant_value);
+
+  // Fills the URLDatabase with search URLs using the provided information.
+  void LoadURLs(std::vector<TestURLData> url_data_list);
+
+  // Waits for history::HistoryService's async operations.
+  void WaitForHistoryService();
+
+  // Creates an input using the provided information and queries the provider.
+  void StartProviderAndWaitUntilDone(const std::string& text,
+                                     bool from_omnibox_focus,
+                                     PageClassification page_classification);
+
+  // Verifies that provider matches are as expected.
+  void ExpectMatches(std::vector<TestMatchData> match_data_list);
+
+  const TemplateURL* default_search_provider() {
+    return client_->GetTemplateURLService()->GetDefaultSearchProvider();
+  }
+
+  base::test::TaskEnvironment task_environment_;
+  // Used to spin the message loop until |provider_| is done with its async ops.
+  std::unique_ptr<base::RunLoop> provider_run_loop_;
+  std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
+  std::unique_ptr<FakeAutocompleteProviderClient> client_;
+  scoped_refptr<LocalHistoryZeroSuggestProvider> provider_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LocalHistoryZeroSuggestProviderTest);
+};
+
+void LocalHistoryZeroSuggestProviderTest::SetZeroSuggestVariant(
+    PageClassification page_classification,
+    std::string zero_suggest_variant_value) {
+  scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list_->InitAndEnableFeatureWithParameters(
+      omnibox::kOnFocusSuggestions,
+      {{std::string(OmniboxFieldTrial::kZeroSuggestVariantRule) + ":" +
+            base::NumberToString(static_cast<int>(page_classification)) + ":*",
+        zero_suggest_variant_value}});
+}
+
+void LocalHistoryZeroSuggestProviderTest::LoadURLs(
+    std::vector<TestURLData> url_data_list) {
+  const Time now = Time::Now();
+  history::URLRows rows;
+  for (const auto& entry : url_data_list) {
+    TemplateURLRef::SearchTermsArgs search_terms_args(
+        base::UTF8ToUTF16(entry.search_terms));
+    const auto& search_terms_data =
+        client_->GetTemplateURLService()->search_terms_data();
+    std::string search_url =
+        entry.search_provider->url_ref().ReplaceSearchTerms(search_terms_args,
+                                                            search_terms_data);
+    history::URLRow row(GURL{search_url});
+    row.set_title(base::UTF8ToUTF16(entry.title));
+    row.set_visit_count(entry.visit_count);
+    row.set_typed_count(entry.typed_count);
+    row.set_last_visit(now - TimeDelta::FromDays(entry.age_in_days));
+    row.set_hidden(entry.hidden);
+    rows.push_back(row);
+  }
+  client_->GetHistoryService()->AddPagesWithDetails(rows,
+                                                    history::SOURCE_BROWSED);
+  WaitForHistoryService();
+}
+
+void LocalHistoryZeroSuggestProviderTest::WaitForHistoryService() {
+  history::BlockUntilHistoryProcessesPendingRequests(
+      client_->GetHistoryService());
+
+  // MemoryURLIndex schedules tasks to rebuild its index on the history thread.
+  // Block here to make sure they are complete.
+  BlockUntilInMemoryURLIndexIsRefreshed(client_->GetInMemoryURLIndex());
+}
+
+void LocalHistoryZeroSuggestProviderTest::StartProviderAndWaitUntilDone(
+    const std::string& text = "",
+    bool from_omnibox_focus = true,
+    PageClassification page_classification =
+        metrics::OmniboxEventProto::NTP_REALBOX) {
+  AutocompleteInput input(base::ASCIIToUTF16(text), page_classification,
+                          TestSchemeClassifier());
+  input.set_from_omnibox_focus(from_omnibox_focus);
+  provider_->Start(input, false);
+  if (!provider_->done()) {
+    provider_run_loop_ = std::make_unique<base::RunLoop>();
+    // Quits in OnProviderUpdate when the provider is done.
+    provider_run_loop_->Run();
+  }
+}
+
+void LocalHistoryZeroSuggestProviderTest::OnProviderUpdate(
+    bool updated_matches) {
+  if (provider_->done() && provider_run_loop_)
+    provider_run_loop_->Quit();
+}
+
+void LocalHistoryZeroSuggestProviderTest::ExpectMatches(
+    std::vector<TestMatchData> match_data_list) {
+  ASSERT_EQ(match_data_list.size(), provider_->matches().size());
+  size_t index = 0;
+  for (const auto& expected : match_data_list) {
+    const auto& match = provider_->matches()[index];
+    EXPECT_EQ(expected.relevance, match.relevance);
+    EXPECT_EQ(base::UTF8ToUTF16(expected.content), match.contents);
+    EXPECT_EQ(expected.allowed_to_be_default_match,
+              match.allowed_to_be_default_match);
+    index++;
+  }
+}
+
+// Tests that suggestions are returned only if when input is empty and focused.
+TEST_F(LocalHistoryZeroSuggestProviderTest, Input) {
+  LoadURLs({
+      {default_search_provider(), "hello world", "&foo=bar", 1},
+  });
+
+  StartProviderAndWaitUntilDone(/*text=*/"blah");
+  ExpectMatches({});
+
+  StartProviderAndWaitUntilDone(/*text=*/"", /*from_omnibox_focus=*/false);
+  ExpectMatches({});
+
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({{"hello world", 500}});
+}
+
+// Tests that suggestions are returned only if ZeroSuggestVariant is configured
+// to return local history suggestions in the NTP.
+TEST_F(LocalHistoryZeroSuggestProviderTest, ZeroSuggestVariant) {
+  LoadURLs({
+      {default_search_provider(), "hello world", "&foo=bar", 1},
+  });
+
+  SetZeroSuggestVariant(
+      metrics::OmniboxEventProto::OTHER,
+      LocalHistoryZeroSuggestProvider::kZeroSuggestLocalVariant);
+  StartProviderAndWaitUntilDone(
+      /*text=*/"", /*from_omnibox_focus=*/true,
+      /*page_classification=*/metrics::OmniboxEventProto::OTHER);
+  ExpectMatches({});
+
+  SetZeroSuggestVariant(metrics::OmniboxEventProto::NTP_REALBOX,
+                        /*zero_suggest_variant_value=*/"blah");
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({});
+
+  SetZeroSuggestVariant(
+      metrics::OmniboxEventProto::NTP_REALBOX,
+      LocalHistoryZeroSuggestProvider::kZeroSuggestLocalVariant);
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({{"hello world", 500}});
+
+  SetZeroSuggestVariant(
+      metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS,
+      LocalHistoryZeroSuggestProvider::kZeroSuggestLocalVariant);
+  StartProviderAndWaitUntilDone(
+      /*text=*/"", /*from_omnibox_focus=*/true,
+      /*page_classification=*/
+      metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS);
+  ExpectMatches({{"hello world", 500}});
+}
+
+// Tests that search terms are extracted from the default search provider's
+// search history only and only when Google is the default search provider.
+TEST_F(LocalHistoryZeroSuggestProviderTest, DefaultSearchProvider) {
+  auto* template_url_service = client_->GetTemplateURLService();
+  auto* other_search_provider = template_url_service->Add(
+      std::make_unique<TemplateURL>(*GenerateDummyTemplateURLData("other")));
+  LoadURLs({
+      {default_search_provider(), "hello world", "&foo=bar", 1},
+      {default_search_provider(), "", "&foo=bar", 1},
+      {other_search_provider, "does not matter", "&foo=bar", 1},
+  });
+
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({{"hello world", 500}});
+
+  template_url_service->SetUserSelectedDefaultSearchProvider(
+      other_search_provider);
+  // Verify that Google is not the default search provider.
+  ASSERT_NE(SEARCH_ENGINE_GOOGLE,
+            default_search_provider()->GetEngineType(
+                template_url_service->search_terms_data()));
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({});
+}
+
+// Tests that search terms are extracted with the correct encoding, whitespaces
+// are collapsed, search terms are lowercased and duplicated, and empty searches
+// are ignored.
+TEST_F(LocalHistoryZeroSuggestProviderTest, SearchTerms) {
+  LoadURLs({
+      {default_search_provider(), "hello world", "&foo=bar", 1},
+      {default_search_provider(), "hello   world", "&foo=bar", 1},
+      {default_search_provider(), "hello   world", "&foo=bar", 1},
+      {default_search_provider(), "hello world", "&foo=bar", 1},
+      {default_search_provider(), "HELLO WORLD", "&foo=bar", 1},
+      {default_search_provider(), "   ", "&foo=bar", 1},
+      {default_search_provider(), "سلام دنیا", "&foo=bar", 2},
+  });
+
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({{"hello world", 500}, {"سلام دنیا", 499}});
+}
+
+// Tests that the suggestions are ordered by recency.
+TEST_F(LocalHistoryZeroSuggestProviderTest, Suggestions_Recency) {
+  LoadURLs({
+      {default_search_provider(), "less recent search", "&foo=bar", 2},
+      {default_search_provider(), "more recent search", "&foo=bar", 1},
+  });
+
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({{"more recent search", 500}, {"less recent search", 499}});
+}
+
+// Tests that suggestions are created from fresh search histories only.
+TEST_F(LocalHistoryZeroSuggestProviderTest, Suggestions_Freshness) {
+  int fresh = (Time::Now() - history::AutocompleteAgeThreshold()).InDays() - 1;
+  int stale = (Time::Now() - history::AutocompleteAgeThreshold()).InDays() + 1;
+  LoadURLs({
+      {default_search_provider(), "stale search", "&foo=bar", stale},
+      {default_search_provider(), "fresh search", "&foo=bar", fresh},
+  });
+
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({{"fresh search", 500}});
+}
+
+// Tests that all the search URLs that would produce a given suggestion get
+// deleted when the autocomplete match is deleted.
+TEST_F(LocalHistoryZeroSuggestProviderTest, Delete) {
+  LoadURLs({
+      {default_search_provider(), "hello   world", "&foo=bar&aqs=1", 1},
+      {default_search_provider(), "HELLO WORLD", "&foo=bar&aqs=12", 1},
+      {default_search_provider(), "hello world", "&foo=bar&aqs=123", 1},
+      {default_search_provider(), "hello world", "&foo=bar&aqs=1234", 1},
+  });
+
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({{"hello world", 500}});
+
+  provider_->DeleteMatch(provider_->matches()[0]);
+
+  // Make sure the deletion takes effect immediately in the provider even before
+  // the history service asynchronously performs the deletion.
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({});
+
+  // Wait until the history service performs the deletion.
+  WaitForHistoryService();
+
+  StartProviderAndWaitUntilDone();
+  ExpectMatches({});
+}
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp
index 98f52005..08d26f5 100644
--- a/components/page_info_strings.grdp
+++ b/components/page_info_strings.grdp
@@ -64,6 +64,9 @@
   <message name="IDS_PAGE_INFO_MIXED_CONTENT_DETAILS" desc="A short paragraph explaining a partially insecure site to the user.">
     Attackers might be able to see the images you’re looking at on this site and trick you by modifying them.
   </message>
+  <message name="IDS_PAGE_INFO_LEGACY_TLS_DETAILS" desc="A short paragraph explaining to the user a site that uses deprecated security configrations.">
+    This site uses an outdated security configuration, which may expose your information (for example, passwords or credit card numbers) when it is sent to this site.
+  </message>
   <message name="IDS_PAGE_INFO_NOT_SECURE_DETAILS" desc="A short paragraph explaining a non-secure site to the user.">
     You should not enter any sensitive information on this site (for example, passwords or credit cards), because it could be stolen by attackers.
   </message>
diff --git a/components/page_info_strings_grdp/IDS_PAGE_INFO_LEGACY_TLS_DETAILS.png.sha1 b/components/page_info_strings_grdp/IDS_PAGE_INFO_LEGACY_TLS_DETAILS.png.sha1
new file mode 100644
index 0000000..7a96004a
--- /dev/null
+++ b/components/page_info_strings_grdp/IDS_PAGE_INFO_LEGACY_TLS_DETAILS.png.sha1
@@ -0,0 +1 @@
+a14ab72434ec900a50134c13549e36657654eede
\ No newline at end of file
diff --git a/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc b/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
index 2ae80b11..83e88abe 100644
--- a/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
+++ b/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
-#include "build/build_config.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/browser/test_password_store.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
@@ -124,12 +123,7 @@
   DISALLOW_COPY_AND_ASSIGN(HttpCredentialCleanerTest);
 };
 
-#if defined(OS_MACOSX)
-#define MAYBE_ReportHttpMigrationMetrics DISABLED_ReportHttpMigrationMetrics
-#else
-#define MAYBE_ReportHttpMigrationMetrics ReportHttpMigrationMetrics
-#endif
-TEST_P(HttpCredentialCleanerTest, MAYBE_ReportHttpMigrationMetrics) {
+TEST_P(HttpCredentialCleanerTest, ReportHttpMigrationMetrics) {
   struct Histogram {
     bool test_hsts_enabled;
     HttpCredentialType test_type;
diff --git a/components/policy/core/browser/browser_policy_connector_base.cc b/components/policy/core/browser/browser_policy_connector_base.cc
index 526ffb4..ad6944c 100644
--- a/components/policy/core/browser/browser_policy_connector_base.cc
+++ b/components/policy/core/browser/browser_policy_connector_base.cc
@@ -112,7 +112,6 @@
   // If this function is used by a test then it must be called before the
   // browser is created, and GetPolicyService() gets called.
   CHECK(!g_created_policy_service);
-  DCHECK(!g_testing_provider);
   g_testing_provider = provider;
 }
 
diff --git a/components/safe_browsing/common/safe_browsing_prefs.cc b/components/safe_browsing/common/safe_browsing_prefs.cc
index ab8b00d..0b26d22 100644
--- a/components/safe_browsing/common/safe_browsing_prefs.cc
+++ b/components/safe_browsing/common/safe_browsing_prefs.cc
@@ -197,7 +197,7 @@
   registry->RegisterDictionaryPref(prefs::kSafeBrowsingTriggerEventTimestamps);
   registry->RegisterBooleanPref(prefs::kUnsafeEventsReportingEnabled, false);
   registry->RegisterIntegerPref(prefs::kBlockLargeFileTransfer, 0);
-  registry->RegisterIntegerPref(prefs::kDelayDeliveryUntilVerdict, 0);
+  registry->RegisterIntegerPref(prefs::kDelayDeliveryUntilVerdict, DELAY_NONE);
   registry->RegisterIntegerPref(
       prefs::kAllowPasswordProtectedFiles,
       AllowPasswordProtectedFilesValues::ALLOW_UPLOADS_AND_DOWNLOADS);
diff --git a/components/services/app_service/public/cpp/BUILD.gn b/components/services/app_service/public/cpp/BUILD.gn
index 502f85c..1e6408f 100644
--- a/components/services/app_service/public/cpp/BUILD.gn
+++ b/components/services/app_service/public/cpp/BUILD.gn
@@ -8,3 +8,14 @@
     "file_handler_info.h",
   ]
 }
+
+source_set("intent_util") {
+  sources = [
+    "intent_util.cc",
+    "intent_util.h",
+  ]
+
+  deps = [
+    "//base",
+  ]
+}
diff --git a/components/services/app_service/public/cpp/intent_util.cc b/components/services/app_service/public/cpp/intent_util.cc
new file mode 100644
index 0000000..fe37332
--- /dev/null
+++ b/components/services/app_service/public/cpp/intent_util.cc
@@ -0,0 +1,95 @@
+// 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 "components/services/app_service/public/cpp/intent_util.h"
+
+#include "base/compiler_specific.h"
+
+namespace apps_util {
+
+// TODO(crbug.com/853604): For glob match, it is currently only for Android
+// intent filters, so we will use the ARC intent filter implementation that is
+// transcribed from Android codebase, to prevent divergence from Android code.
+bool MatchGlob(const std::string& value, const std::string& pattern) {
+#define GET_CHAR(s, i) ((UNLIKELY(i >= s.length())) ? '\0' : s[i])
+
+  const size_t NP = pattern.length();
+  const size_t NS = value.length();
+  if (NP == 0) {
+    return NS == 0;
+  }
+  size_t ip = 0, is = 0;
+  char nextChar = GET_CHAR(pattern, 0);
+  while (ip < NP && is < NS) {
+    char c = nextChar;
+    ++ip;
+    nextChar = GET_CHAR(pattern, ip);
+    const bool escaped = (c == '\\');
+    if (escaped) {
+      c = nextChar;
+      ++ip;
+      nextChar = GET_CHAR(pattern, ip);
+    }
+    if (nextChar == '*') {
+      if (!escaped && c == '.') {
+        if (ip >= (NP - 1)) {
+          // At the end with a pattern match
+          return true;
+        }
+        ++ip;
+        nextChar = GET_CHAR(pattern, ip);
+        // Consume everything until the next char in the pattern is found.
+        if (nextChar == '\\') {
+          ++ip;
+          nextChar = GET_CHAR(pattern, ip);
+        }
+        do {
+          if (GET_CHAR(value, is) == nextChar) {
+            break;
+          }
+          ++is;
+        } while (is < NS);
+        if (is == NS) {
+          // Next char in the pattern didn't exist in the match.
+          return false;
+        }
+        ++ip;
+        nextChar = GET_CHAR(pattern, ip);
+        ++is;
+      } else {
+        // Consume only characters matching the one before '*'.
+        do {
+          if (GET_CHAR(value, is) != c) {
+            break;
+          }
+          ++is;
+        } while (is < NS);
+        ++ip;
+        nextChar = GET_CHAR(pattern, ip);
+      }
+    } else {
+      if (c != '.' && GET_CHAR(value, is) != c)
+        return false;
+      ++is;
+    }
+  }
+
+  if (ip >= NP && is >= NS) {
+    // Reached the end of both strings
+    return true;
+  }
+
+  // One last check: we may have finished the match string, but still have a
+  // '.*' at the end of the pattern, which is still a match.
+  if (ip == NP - 2 && GET_CHAR(pattern, ip) == '.' &&
+      GET_CHAR(pattern, ip + 1) == '*') {
+    return true;
+  }
+
+  return false;
+
+#undef GET_CHAR
+}
+
+}  // namespace apps_util
diff --git a/components/services/app_service/public/cpp/intent_util.h b/components/services/app_service/public/cpp/intent_util.h
new file mode 100644
index 0000000..acd6359
--- /dev/null
+++ b/components/services/app_service/public/cpp/intent_util.h
@@ -0,0 +1,31 @@
+// 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 COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_
+#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_
+
+// Utility functions for App Service intent handling.
+// This function is needed for both components/arc and
+// chrome/services/app_service at the moment. We are planning to remove the need
+// for this in the components/arc directory and this function can be combined
+// with other intent utility functions for the App service.
+
+#include <string>
+
+namespace apps_util {
+
+// Return true if |value| matches |pattern| with simple glob syntax.
+// In this syntax, you can use the '*' character to match against zero or
+// more occurrences of the character immediately before. If the character
+// before it is '.' it will match any character. The character '\' can be
+// used as an escape. This essentially provides only the '*' wildcard part
+// of a normal regexp.
+// This function is transcribed from android's PatternMatcher#matchPattern.
+// See
+// https://android.googlesource.com/platform/frameworks/base.git/+/e93165456c3c28278f275566bd90bfbcf1a0e5f7/core/java/android/os/PatternMatcher.java#186
+bool MatchGlob(const std::string& value, const std::string& pattern);
+
+}  // namespace apps_util
+
+#endif  // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_
\ No newline at end of file
diff --git a/components/signin/core/browser/android/BUILD.gn b/components/signin/core/browser/android/BUILD.gn
index 66ad7b1..fc0079f7 100644
--- a/components/signin/core/browser/android/BUILD.gn
+++ b/components/signin/core/browser/android/BUILD.gn
@@ -6,6 +6,7 @@
 
 generate_jni("jni_headers") {
   sources = [
+    "java/src/org/chromium/components/signin/AccountManagerFacade.java",
     "java/src/org/chromium/components/signin/AccountTrackerService.java",
     "java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java",
     "java/src/org/chromium/components/signin/ConsistencyCookieManager.java",
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
index d4e06fe..22e0f30 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
@@ -29,6 +29,7 @@
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.base.task.AsyncTask;
 import org.chromium.components.signin.util.PatternMatcher;
@@ -165,6 +166,7 @@
      * @return a singleton instance
      */
     @AnyThread
+    @CalledByNative
     public static AccountManagerFacade get() {
         AccountManagerFacade instance = sAtomicInstance.get();
         assert instance != null : "AccountManagerFacade is not initialized!";
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/OAuth2TokenService.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/OAuth2TokenService.java
index 8d1e47b3..7450dd1d 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/OAuth2TokenService.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/OAuth2TokenService.java
@@ -65,32 +65,40 @@
 
     private final long mNativeOAuth2TokenServiceDelegate;
     private final AccountTrackerService mAccountTrackerService;
+    private final AccountManagerFacade mAccountManagerFacade;
 
     private boolean mPendingUpdate;
 
-    private OAuth2TokenService(
-            long nativeOAuth2TokenServiceDelegate, AccountTrackerService accountTrackerService) {
+    @VisibleForTesting
+    public OAuth2TokenService(long nativeOAuth2TokenServiceDelegate,
+            AccountTrackerService accountTrackerService,
+            AccountManagerFacade accountManagerFacade) {
         mNativeOAuth2TokenServiceDelegate = nativeOAuth2TokenServiceDelegate;
         mAccountTrackerService = accountTrackerService;
+        mAccountManagerFacade = accountManagerFacade;
 
-        mAccountTrackerService.addSystemAccountsSeededListener(this);
+        // AccountTrackerService might be null in tests.
+        if (mAccountTrackerService != null) {
+            mAccountTrackerService.addSystemAccountsSeededListener(this);
+        }
     }
 
     @CalledByNative
-    private static OAuth2TokenService create(
-            long nativeOAuth2TokenServiceDelegate, AccountTrackerService accountTrackerService) {
-        ThreadUtils.assertOnUiThread();
-        return new OAuth2TokenService(nativeOAuth2TokenServiceDelegate, accountTrackerService);
+    private static OAuth2TokenService create(long nativeOAuth2TokenServiceDelegate,
+            AccountTrackerService accountTrackerService,
+            AccountManagerFacade accountManagerFacade) {
+        assert nativeOAuth2TokenServiceDelegate != 0;
+        return new OAuth2TokenService(
+                nativeOAuth2TokenServiceDelegate, accountTrackerService, accountManagerFacade);
     }
 
-    private static Account getAccountOrNullFromUsername(String username) {
+    private Account getAccountOrNullFromUsername(String username) {
         if (username == null) {
             Log.e(TAG, "Username is null");
             return null;
         }
 
-        AccountManagerFacade accountManagerFacade = AccountManagerFacade.get();
-        Account account = accountManagerFacade.getAccountFromName(username);
+        Account account = mAccountManagerFacade.getAccountFromName(username);
         if (account == null) {
             Log.e(TAG, "Account not found for provided username.");
             return null;
@@ -103,11 +111,11 @@
      */
     @VisibleForTesting
     @CalledByNative
-    public static String[] getSystemAccountNames() {
+    public String[] getSystemAccountNames() {
         // TODO(https://crbug.com/768366): Remove this after adding cache to account manager facade.
         // This function is called by native code on UI thread.
         try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
-            List<String> accountNames = AccountManagerFacade.get().tryGetGoogleAccountNames();
+            List<String> accountNames = mAccountManagerFacade.tryGetGoogleAccountNames();
             return accountNames.toArray(new String[accountNames.size()]);
         }
     }
@@ -118,6 +126,7 @@
      * from the OS. updateAccountList should be called to keep these two
      * in sync.
      */
+    @VisibleForTesting
     @CalledByNative
     public static String[] getAccounts() {
         return getStoredAccounts();
@@ -131,7 +140,7 @@
      */
     @MainThread
     @CalledByNative
-    private static void getAccessTokenFromNative(
+    private void getAccessTokenFromNative(
             String username, String scope, final long nativeCallback) {
         Account account = getAccountOrNullFromUsername(username);
         if (account == null) {
@@ -163,12 +172,11 @@
      * @param callback called on successful and unsuccessful fetching of auth token.
      */
     @MainThread
-    public static void getAccessToken(
-            Account account, String scope, GetAccessTokenCallback callback) {
+    public void getAccessToken(Account account, String scope, GetAccessTokenCallback callback) {
         ConnectionRetry.runAuthTask(new AuthTask<String>() {
             @Override
             public String run() throws AuthException {
-                return AccountManagerFacade.get().getAccessToken(account, scope);
+                return mAccountManagerFacade.getAccessToken(account, scope);
             }
             @Override
             public void onSuccess(String token) {
@@ -187,14 +195,14 @@
      */
     @MainThread
     @CalledByNative
-    public static void invalidateAccessToken(String accessToken) {
+    public void invalidateAccessToken(String accessToken) {
         if (TextUtils.isEmpty(accessToken)) {
             return;
         }
         ConnectionRetry.runAuthTask(new AuthTask<Boolean>() {
             @Override
             public Boolean run() throws AuthException {
-                AccountManagerFacade.get().invalidateAccessToken(accessToken);
+                mAccountManagerFacade.invalidateAccessToken(accessToken);
                 return true;
             }
             @Override
@@ -238,8 +246,8 @@
      * Called by native to check whether the account has an OAuth2 refresh token.
      */
     @CalledByNative
-    public static boolean hasOAuth2RefreshToken(String accountName) {
-        if (!AccountManagerFacade.get().isCachePopulated()) {
+    private boolean hasOAuth2RefreshToken(String accountName) {
+        if (!mAccountManagerFacade.isCachePopulated()) {
             return false;
         }
 
@@ -304,12 +312,12 @@
         return accounts == null ? new String[] {} : accounts.toArray(new String[0]);
     }
 
-    @CalledByNative
     /**
      * Called by native to save the account IDs that have associated OAuth2 refresh tokens.
      * This is called during updateAccountList to sync with getSystemAccountNames.
      * @param accounts IDs to save.
      */
+    @CalledByNative
     private static void setAccounts(String[] accounts) {
         Set<String> set = new HashSet<>(Arrays.asList(accounts));
         ContextUtils.getAppSharedPreferences()
diff --git a/components/signin/internal/base/BUILD.gn b/components/signin/internal/base/BUILD.gn
new file mode 100644
index 0000000..e1ff00f
--- /dev/null
+++ b/components/signin/internal/base/BUILD.gn
@@ -0,0 +1,18 @@
+# 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.
+
+# TODO(crbug.com/986435) Remove this target when IdentityServicesProvider
+# will provide AccountManagerFacade.
+source_set("base") {
+  if (is_android) {
+    sources = [
+      "account_manager_facade_android.cc",
+      "account_manager_facade_android.h",
+    ]
+    deps = [
+      "//base",
+      "//components/signin/core/browser/android:jni_headers",
+    ]
+  }
+}
diff --git a/components/signin/internal/base/DEPS b/components/signin/internal/base/DEPS
new file mode 100644
index 0000000..c079a1b
--- /dev/null
+++ b/components/signin/internal/base/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+]
+
+specific_include_rules = {
+  "account_manager_facade_android.cc": [
+    "+components/signin/core/browser/android/jni_headers/AccountManagerFacade_jni.h",
+  ],
+}
diff --git a/components/signin/internal/base/README.md b/components/signin/internal/base/README.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/components/signin/internal/base/README.md
diff --git a/components/signin/internal/base/account_manager_facade_android.cc b/components/signin/internal/base/account_manager_facade_android.cc
new file mode 100644
index 0000000..83ca3fc
--- /dev/null
+++ b/components/signin/internal/base/account_manager_facade_android.cc
@@ -0,0 +1,12 @@
+// 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 "components/signin/internal/base/account_manager_facade_android.h"
+
+#include "components/signin/core/browser/android/jni_headers/AccountManagerFacade_jni.h"
+
+base::android::ScopedJavaLocalRef<jobject>
+AccountManagerFacadeAndroid::GetJavaObject() {
+  return Java_AccountManagerFacade_get(base::android::AttachCurrentThread());
+}
diff --git a/components/signin/internal/base/account_manager_facade_android.h b/components/signin/internal/base/account_manager_facade_android.h
new file mode 100644
index 0000000..9508a6d1
--- /dev/null
+++ b/components/signin/internal/base/account_manager_facade_android.h
@@ -0,0 +1,19 @@
+// 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 COMPONENTS_SIGNIN_INTERNAL_BASE_ACCOUNT_MANAGER_FACADE_ANDROID_H_
+#define COMPONENTS_SIGNIN_INTERNAL_BASE_ACCOUNT_MANAGER_FACADE_ANDROID_H_
+
+#include "base/android/scoped_java_ref.h"
+
+// Simple accessor to java's AccountManagerFacade
+class AccountManagerFacadeAndroid {
+ public:
+  // Returns a reference to the corresponding Java AccountManagerFacade object.
+  // TODO(crbug.com/986435) Remove direct access to AccountManagerFacade.get
+  // from C++ when IdentityServicesProvider will handle its instance management.
+  static base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
+};
+
+#endif  // COMPONENTS_SIGNIN_INTERNAL_BASE_ACCOUNT_MANAGER_FACADE_ANDROID_H_
diff --git a/components/signin/internal/identity_manager/BUILD.gn b/components/signin/internal/identity_manager/BUILD.gn
index 92030b8d..9cfafc06 100644
--- a/components/signin/internal/identity_manager/BUILD.gn
+++ b/components/signin/internal/identity_manager/BUILD.gn
@@ -70,7 +70,10 @@
   ]
 
   if (is_android) {
-    deps += [ "//components/signin/core/browser/android:jni_headers" ]
+    deps += [
+      "//components/signin/core/browser/android:jni_headers",
+      "//components/signin/internal/base",
+    ]
   } else {
     sources += [
       "mutable_profile_oauth2_token_service_delegate.cc",
diff --git a/components/signin/internal/identity_manager/DEPS b/components/signin/internal/identity_manager/DEPS
index e653230..053a11e 100644
--- a/components/signin/internal/identity_manager/DEPS
+++ b/components/signin/internal/identity_manager/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+chromeos/constants/chromeos_features.h",
+  "+components/signin/internal/base",
   "+components/signin/public/base",
   "+components/signin/public/identity_manager",
   "+components/signin/public/webdata",
diff --git a/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.cc b/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.cc
index 84bfe8fb..5131d95 100644
--- a/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.cc
+++ b/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.cc
@@ -41,8 +41,10 @@
 
 class AndroidAccessTokenFetcher : public OAuth2AccessTokenFetcher {
  public:
-  AndroidAccessTokenFetcher(OAuth2AccessTokenConsumer* consumer,
-                            const std::string& account_id);
+  AndroidAccessTokenFetcher(
+      OAuth2TokenServiceDelegateAndroid* oauth2_token_service_delegate,
+      OAuth2AccessTokenConsumer* consumer,
+      const std::string& account_id);
   ~AndroidAccessTokenFetcher() override;
 
   // Overrides from OAuth2AccessTokenFetcher:
@@ -59,6 +61,7 @@
  private:
   std::string CombineScopes(const std::vector<std::string>& scopes);
 
+  OAuth2TokenServiceDelegateAndroid* oauth2_token_service_delegate_;
   std::string account_id_;
   bool request_was_cancelled_;
   base::WeakPtrFactory<AndroidAccessTokenFetcher> weak_factory_;
@@ -67,9 +70,11 @@
 };
 
 AndroidAccessTokenFetcher::AndroidAccessTokenFetcher(
+    OAuth2TokenServiceDelegateAndroid* oauth2_token_service_delegate,
     OAuth2AccessTokenConsumer* consumer,
     const std::string& account_id)
     : OAuth2AccessTokenFetcher(consumer),
+      oauth2_token_service_delegate_(oauth2_token_service_delegate),
       account_id_(account_id),
       request_was_cancelled_(false),
       weak_factory_(this) {}
@@ -91,7 +96,7 @@
 
   // Call into Java to get a new token.
   Java_OAuth2TokenService_getAccessTokenFromNative(
-      env, j_username, j_scope,
+      env, oauth2_token_service_delegate_->GetJavaObject(), j_username, j_scope,
       reinterpret_cast<intptr_t>(heap_callback.release()));
 }
 
@@ -132,19 +137,24 @@
 
 }  // namespace
 
+// TODO(crbug.com/1009957) Remove disable_interation_with_system_accounts_
+// from OAuth2TokenServiceDelegateAndroid
 bool OAuth2TokenServiceDelegateAndroid::
     disable_interaction_with_system_accounts_ = false;
 
 OAuth2TokenServiceDelegateAndroid::OAuth2TokenServiceDelegateAndroid(
-    AccountTrackerService* account_tracker_service)
+    AccountTrackerService* account_tracker_service,
+    const base::android::JavaRef<jobject>& account_manager_facade)
     : account_tracker_service_(account_tracker_service),
       fire_refresh_token_loaded_(RT_LOAD_NOT_START) {
   DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ctor";
   DCHECK(account_tracker_service_);
+
   JNIEnv* env = AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jobject> local_java_ref =
       Java_OAuth2TokenService_create(env, reinterpret_cast<intptr_t>(this),
-                                     account_tracker_service_->GetJavaObject());
+                                     account_tracker_service_->GetJavaObject(),
+                                     account_manager_facade);
   java_ref_.Reset(env, local_java_ref.obj());
 
   if (account_tracker_service_->GetMigrationState() ==
@@ -173,6 +183,10 @@
 
 bool OAuth2TokenServiceDelegateAndroid::RefreshTokenIsAvailable(
     const CoreAccountId& account_id) const {
+  DCHECK(!disable_interaction_with_system_accounts_)
+      << __FUNCTION__
+      << " needs to interact with system accounts and cannot be used with "
+         "disable_interaction_with_system_accounts_";
   DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::RefreshTokenIsAvailable"
            << " account= " << account_id;
   std::string account_name = MapAccountIdToAccountName(account_id);
@@ -187,7 +201,8 @@
   ScopedJavaLocalRef<jstring> j_account_id =
       ConvertUTF8ToJavaString(env, account_name);
   jboolean refresh_token_is_available =
-      Java_OAuth2TokenService_hasOAuth2RefreshToken(env, j_account_id);
+      Java_OAuth2TokenService_hasOAuth2RefreshToken(env, java_ref_,
+                                                    j_account_id);
   return refresh_token_is_available == JNI_TRUE;
 }
 
@@ -226,6 +241,7 @@
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobjectArray> j_accounts =
       Java_OAuth2TokenService_getAccounts(env);
+  ;
   // TODO(fgorski): We may decide to filter out some of the accounts.
   base::android::AppendJavaStringArrayToStringVector(env, j_accounts,
                                                      &accounts);
@@ -234,10 +250,14 @@
 
 std::vector<std::string>
 OAuth2TokenServiceDelegateAndroid::GetSystemAccountNames() {
+  DCHECK(!disable_interaction_with_system_accounts_)
+      << __FUNCTION__
+      << " needs to interact with system accounts and cannot be used with "
+         "disable_interaction_with_system_accounts_";
   std::vector<std::string> account_names;
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobjectArray> j_accounts =
-      Java_OAuth2TokenService_getSystemAccountNames(env);
+      Java_OAuth2TokenService_getSystemAccountNames(env, java_ref_);
   base::android::AppendJavaStringArrayToStringVector(env, j_accounts,
                                                      &account_names);
   return account_names;
@@ -284,7 +304,8 @@
   std::string account_name = MapAccountIdToAccountName(account_id);
   DCHECK(!account_name.empty())
       << "Cannot find account name for account id " << account_id;
-  return std::make_unique<AndroidAccessTokenFetcher>(consumer, account_name);
+  return std::make_unique<AndroidAccessTokenFetcher>(this, consumer,
+                                                     account_name);
 }
 
 void OAuth2TokenServiceDelegateAndroid::OnAccessTokenInvalidated(
@@ -292,11 +313,15 @@
     const std::string& client_id,
     const OAuth2AccessTokenManager::ScopeSet& scopes,
     const std::string& access_token) {
+  DCHECK(!disable_interaction_with_system_accounts_)
+      << __FUNCTION__
+      << " needs to interact with system accounts and cannot be used with "
+         "disable_interaction_with_system_accounts_";
   ValidateAccountId(account_id);
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jstring> j_access_token =
       ConvertUTF8ToJavaString(env, access_token);
-  Java_OAuth2TokenService_invalidateAccessToken(env, j_access_token);
+  Java_OAuth2TokenService_invalidateAccessToken(env, java_ref_, j_access_token);
 }
 
 void OAuth2TokenServiceDelegateAndroid::UpdateAccountList(
diff --git a/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.h b/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.h
index 206734e5..5e71e037 100644
--- a/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.h
+++ b/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.h
@@ -31,7 +31,8 @@
     : public ProfileOAuth2TokenServiceDelegate {
  public:
   OAuth2TokenServiceDelegateAndroid(
-      AccountTrackerService* account_tracker_service);
+      AccountTrackerService* account_tracker_service,
+      const base::android::JavaRef<jobject>& account_manager_facade);
   ~OAuth2TokenServiceDelegateAndroid() override;
 
   // Creates a new instance of the OAuth2TokenServiceDelegateAndroid.
@@ -41,12 +42,18 @@
   base::android::ScopedJavaLocalRef<jobject> GetJavaObject() override;
 
   // Called by the TestingProfile class to disable account validation in
-  // tests.  This prevents the token service from trying to look up system
-  // accounts which requires special permission.
+  // tests.  This prevents the token service from building the java objects
+  // which require prior initialization (AccountManagerFacade)
+  // TODO(crbug.com/1009957) Remove disable_interation_with_system_accounts_
+  // from OAuth2TokenServiceDelegateAndroid
   static void set_disable_interaction_with_system_accounts() {
     disable_interaction_with_system_accounts_ = true;
   }
 
+  static bool get_disable_interaction_with_system_accounts() {
+    return disable_interaction_with_system_accounts_;
+  }
+
   // ProfileOAuth2TokenServiceDelegate overrides:
   bool RefreshTokenIsAvailable(const CoreAccountId& account_id) const override;
   GoogleServiceAuthError GetAuthError(
@@ -132,6 +139,10 @@
   RefreshTokenLoadStatus fire_refresh_token_loaded_;
   base::Time last_update_accounts_time_;
 
+  // For testing, disables the creation of the java counterpart, see
+  // set_disable_interaction_with_system_accounts().
+  // TODO(crbug.com/1009957) Remove disable_interation_with_system_accounts_
+  // from OAuth2TokenServiceDelegateAndroid
   static bool disable_interaction_with_system_accounts_;
 
   DISALLOW_COPY_AND_ASSIGN(OAuth2TokenServiceDelegateAndroid);
diff --git a/components/signin/internal/identity_manager/oauth2_token_service_delegate_android_unittest.cc b/components/signin/internal/identity_manager/oauth2_token_service_delegate_android_unittest.cc
index 6f327204..072a21bf 100644
--- a/components/signin/internal/identity_manager/oauth2_token_service_delegate_android_unittest.cc
+++ b/components/signin/internal/identity_manager/oauth2_token_service_delegate_android_unittest.cc
@@ -23,7 +23,7 @@
  public:
   OAuth2TokenServiceDelegateAndroidForTest(
       AccountTrackerService* account_tracker_service)
-      : OAuth2TokenServiceDelegateAndroid(account_tracker_service) {}
+      : OAuth2TokenServiceDelegateAndroid(account_tracker_service, nullptr) {}
   MOCK_METHOD1(SetAccounts, void(const std::vector<CoreAccountId>&));
 };
 
@@ -45,8 +45,6 @@
     testing::Test::SetUp();
     AccountTrackerService::RegisterPrefs(pref_service_.registry());
     account_tracker_service_.Initialize(&pref_service_, base::FilePath());
-    OAuth2TokenServiceDelegateAndroid::
-        set_disable_interaction_with_system_accounts();
     delegate_ = std::make_unique<OAuth2TokenServiceDelegateAndroidForTest>(
         &account_tracker_service_);
     delegate_->AddObserver(&observer_);
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc
index 8544d3a..4ccaa74 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc
@@ -14,6 +14,7 @@
 #include "components/signin/public/base/signin_client.h"
 
 #if defined(OS_ANDROID)
+#include "components/signin/internal/base/account_manager_facade_android.h"
 #include "components/signin/internal/identity_manager/oauth2_token_service_delegate_android.h"
 #else
 #include "components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h"
@@ -35,10 +36,17 @@
 namespace {
 
 #if defined(OS_ANDROID)
+// TODO(crbug.com/986435) Provide AccountManagerFacade as a parameter once
+// IdentityServicesProvider owns its instance management.
 std::unique_ptr<OAuth2TokenServiceDelegateAndroid> CreateAndroidOAuthDelegate(
     AccountTrackerService* account_tracker_service) {
+  auto account_manager_facade =
+      OAuth2TokenServiceDelegateAndroid::
+              get_disable_interaction_with_system_accounts()
+          ? nullptr
+          : AccountManagerFacadeAndroid::GetJavaObject();
   return std::make_unique<OAuth2TokenServiceDelegateAndroid>(
-      account_tracker_service);
+      account_tracker_service, account_manager_facade);
 }
 #elif defined(OS_IOS)
 std::unique_ptr<ProfileOAuth2TokenServiceIOSDelegate> CreateIOSOAuthDelegate(
diff --git a/components/signin/public/identity_manager/identity_test_utils.h b/components/signin/public/identity_manager/identity_test_utils.h
index 9b01460..09a6983c 100644
--- a/components/signin/public/identity_manager/identity_test_utils.h
+++ b/components/signin/public/identity_manager/identity_test_utils.h
@@ -164,7 +164,8 @@
 void DisableAccessTokenFetchRetries(IdentityManager* identity_manager);
 
 #if defined(OS_ANDROID)
-// Disables interaction with system accounts, which requires special permission.
+// Disables interaction with system accounts, which requires special
+// initialization of the java subsystems (AccountManagerFacade).
 void DisableInteractionWithSystemAccounts();
 #endif
 
diff --git a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
index 90fd8f25..e2fc3021 100644
--- a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
+++ b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
@@ -164,8 +164,12 @@
       base::Contains(GetConsoleMessages(), GetFilterConsoleMessage(url)));
 }
 
-// crbug.com/1010061: disabled due to flakiness,
-TEST_F(SubframeNavigationFilteringThrottleTest, DISABLED_FilterOnRedirect) {
+#if defined(OS_MACOSX)
+#define MAYBE_FilterOnRedirect DISABLED_FilterOnRedirect
+#else
+#define MAYBE_FilterOnRedirect FilterOnRedirect
+#endif
+TEST_F(SubframeNavigationFilteringThrottleTest, MAYBE_FilterOnRedirect) {
   InitializeDocumentSubresourceFilter(GURL("https://example.test"));
   CreateTestSubframeAndInitNavigation(GURL("https://example.test/allowed.html"),
                                       main_rfh());
diff --git a/components/viz/host/client_frame_sink_video_capturer.cc b/components/viz/host/client_frame_sink_video_capturer.cc
index a37130a..84f158b 100644
--- a/components/viz/host/client_frame_sink_video_capturer.cc
+++ b/components/viz/host/client_frame_sink_video_capturer.cc
@@ -21,7 +21,7 @@
 
 ClientFrameSinkVideoCapturer::ClientFrameSinkVideoCapturer(
     EstablishConnectionCallback callback)
-    : establish_connection_callback_(callback), consumer_binding_(this) {
+    : establish_connection_callback_(callback) {
   EstablishConnection();
 }
 
@@ -101,7 +101,7 @@
 
   Stop();
   consumer_ = nullptr;
-  consumer_binding_.Close();
+  consumer_receiver_.reset();
 }
 
 void ClientFrameSinkVideoCapturer::RequestRefreshFrame() {
@@ -201,11 +201,9 @@
 }
 
 void ClientFrameSinkVideoCapturer::StartInternal() {
-  if (consumer_binding_)
-    consumer_binding_.Close();
-  mojom::FrameSinkVideoConsumerPtr consumer;
-  consumer_binding_.Bind(mojo::MakeRequest(&consumer));
-  capturer_->Start(std::move(consumer));
+  if (consumer_receiver_.is_bound())
+    consumer_receiver_.reset();
+  capturer_->Start(consumer_receiver_.BindNewPipeAndPassRemote());
 }
 
 void ClientFrameSinkVideoCapturer::OnOverlayDestroyed(Overlay* overlay) {
diff --git a/components/viz/host/client_frame_sink_video_capturer.h b/components/viz/host/client_frame_sink_video_capturer.h
index a5be9bf8..0607b4af 100644
--- a/components/viz/host/client_frame_sink_video_capturer.h
+++ b/components/viz/host/client_frame_sink_video_capturer.h
@@ -13,7 +13,7 @@
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/host/viz_host_export.h"
 #include "media/base/video_types.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -152,7 +152,7 @@
   mojom::FrameSinkVideoConsumer* consumer_ = nullptr;
   EstablishConnectionCallback establish_connection_callback_;
   mojom::FrameSinkVideoCapturerPtr capturer_;
-  mojo::Binding<mojom::FrameSinkVideoConsumer> consumer_binding_;
+  mojo::Receiver<mojom::FrameSinkVideoConsumer> consumer_receiver_{this};
 
   base::WeakPtrFactory<ClientFrameSinkVideoCapturer> weak_factory_{this};
 };
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 64c1dcb..c735719 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -233,15 +233,15 @@
 }
 
 void FrameSinkVideoCapturerImpl::Start(
-    mojom::FrameSinkVideoConsumerPtr consumer) {
+    mojo::PendingRemote<mojom::FrameSinkVideoConsumer> consumer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(consumer);
 
   Stop();
-  consumer_ = std::move(consumer);
+  consumer_.Bind(std::move(consumer));
   // In the future, if the connection to the consumer is lost before a call to
   // Stop(), make that call on its behalf.
-  consumer_.set_connection_error_handler(base::BindOnce(
+  consumer_.set_disconnect_handler(base::BindOnce(
       &FrameSinkVideoCapturerImpl::Stop, base::Unretained(this)));
   RefreshEntireSourceSoon();
 }
@@ -275,13 +275,13 @@
 
 void FrameSinkVideoCapturerImpl::CreateOverlay(
     int32_t stacking_index,
-    mojom::FrameSinkVideoCaptureOverlayRequest request) {
+    mojo::PendingReceiver<mojom::FrameSinkVideoCaptureOverlay> receiver) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // This will cause an existing overlay with the same stacking index to be
   // dropped, per mojom-documented behavior.
   overlays_.emplace(stacking_index, std::make_unique<VideoCaptureOverlay>(
-                                        this, std::move(request)));
+                                        this, std::move(receiver)));
 }
 
 void FrameSinkVideoCapturerImpl::ScheduleRefreshFrame() {
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
index e92ff6c..746856c 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
@@ -30,6 +30,8 @@
 #include "media/base/video_frame.h"
 #include "media/capture/content/video_capture_oracle.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/vector2d_f.h"
@@ -106,11 +108,12 @@
                                 bool use_fixed_aspect_ratio) final;
   void SetAutoThrottlingEnabled(bool enabled) final;
   void ChangeTarget(const base::Optional<FrameSinkId>& frame_sink_id) final;
-  void Start(mojom::FrameSinkVideoConsumerPtr consumer) final;
+  void Start(mojo::PendingRemote<mojom::FrameSinkVideoConsumer> consumer) final;
   void Stop() final;
   void RequestRefreshFrame() final;
   void CreateOverlay(int32_t stacking_index,
-                     mojom::FrameSinkVideoCaptureOverlayRequest request) final;
+                     mojo::PendingReceiver<mojom::FrameSinkVideoCaptureOverlay>
+                         receiver) final;
 
   // Default configuration.
   static constexpr media::VideoPixelFormat kDefaultPixelFormat =
@@ -256,7 +259,7 @@
 
   // The current video frame consumer. This is set when Start() is called and
   // cleared when Stop() is called.
-  mojom::FrameSinkVideoConsumerPtr consumer_;
+  mojo::Remote<mojom::FrameSinkVideoConsumer> consumer_;
 
   // The portion of the source content that has changed, but has not yet been
   // captured.
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
index c99df2b..a0ca78a 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
@@ -22,6 +22,8 @@
 #include "media/base/limits.h"
 #include "media/base/video_util.h"
 #include "media/capture/mojom/video_capture_types.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -117,7 +119,7 @@
 
 class MockConsumer : public mojom::FrameSinkVideoConsumer {
  public:
-  MockConsumer() : binding_(this) {}
+  MockConsumer() {}
 
   MOCK_METHOD0(OnFrameCapturedMock, void());
   MOCK_METHOD0(OnStopped, void());
@@ -131,10 +133,8 @@
     PropagateMojoTasks();
   }
 
-  mojom::FrameSinkVideoConsumerPtr BindVideoConsumer() {
-    mojom::FrameSinkVideoConsumerPtr ptr;
-    binding_.Bind(mojo::MakeRequest(&ptr));
-    return ptr;
+  mojo::PendingRemote<mojom::FrameSinkVideoConsumer> BindVideoConsumer() {
+    return receiver_.BindNewPipeAndPassRemote();
   }
 
  private:
@@ -178,7 +178,7 @@
                        std::move(callbacks)));
   }
 
-  mojo::Binding<mojom::FrameSinkVideoConsumer> binding_;
+  mojo::Receiver<mojom::FrameSinkVideoConsumer> receiver_{this};
   std::vector<scoped_refptr<VideoFrame>> frames_;
   std::vector<base::OnceClosure> done_callbacks_;
 };
diff --git a/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc b/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc
index d2ab761..3821ed5 100644
--- a/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc
+++ b/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc
@@ -28,10 +28,10 @@
 
 VideoCaptureOverlay::VideoCaptureOverlay(
     FrameSource* frame_source,
-    mojom::FrameSinkVideoCaptureOverlayRequest request)
-    : frame_source_(frame_source), binding_(this, std::move(request)) {
+    mojo::PendingReceiver<mojom::FrameSinkVideoCaptureOverlay> receiver)
+    : frame_source_(frame_source), receiver_(this, std::move(receiver)) {
   DCHECK(frame_source_);
-  binding_.set_connection_error_handler(
+  receiver_.set_disconnect_handler(
       base::BindOnce(&FrameSource::OnOverlayConnectionLost,
                      base::Unretained(frame_source_), this));
 }
diff --git a/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h b/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
index 2de2e7e..e88e371 100644
--- a/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
+++ b/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
@@ -16,7 +16,8 @@
 #include "base/sequence_checker.h"
 #include "components/viz/service/viz_service_export.h"
 #include "media/base/video_types.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/color_space.h"
@@ -78,8 +79,9 @@
   using OnceRenderer = base::OnceCallback<void(media::VideoFrame*)>;
 
   // |frame_source| must outlive this instance.
-  VideoCaptureOverlay(FrameSource* frame_source,
-                      mojom::FrameSinkVideoCaptureOverlayRequest request);
+  VideoCaptureOverlay(
+      FrameSource* frame_source,
+      mojo::PendingReceiver<mojom::FrameSinkVideoCaptureOverlay> receiver);
 
   ~VideoCaptureOverlay() final;
 
@@ -159,7 +161,7 @@
 
   FrameSource* const frame_source_;
 
-  mojo::Binding<mojom::FrameSinkVideoCaptureOverlay> binding_;
+  mojo::Receiver<mojom::FrameSinkVideoCaptureOverlay> receiver_;
 
   // The currently-set overlay image.
   SkBitmap image_;
diff --git a/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc b/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
index 2ebef7c..82e9b594 100644
--- a/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
+++ b/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
@@ -23,6 +23,8 @@
 #include "media/base/video_frame.h"
 #include "media/base/video_types.h"
 #include "media/base/video_util.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -62,8 +64,9 @@
   NiceMock<MockFrameSource>* frame_source() { return &frame_source_; }
 
   std::unique_ptr<VideoCaptureOverlay> CreateOverlay() {
+    mojo::Remote<mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
     return std::make_unique<VideoCaptureOverlay>(
-        frame_source(), mojom::FrameSinkVideoCaptureOverlayRequest());
+        frame_source(), overlay_remote.BindNewPipeAndPassReceiver());
   }
 
   void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
@@ -399,8 +402,9 @@
 // not scaled.
 TEST_P(VideoCaptureOverlayRenderTest, FullCover_NoScaling) {
   StrictMock<MockFrameSource> frame_source;
+  mojo::Remote<mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
   VideoCaptureOverlay overlay(&frame_source,
-                              mojom::FrameSinkVideoCaptureOverlayRequest());
+                              overlay_remote.BindNewPipeAndPassReceiver());
 
   EXPECT_CALL(frame_source, GetSourceSize())
       .WillRepeatedly(Return(kSourceSize));
@@ -424,8 +428,9 @@
 // scaled.
 TEST_P(VideoCaptureOverlayRenderTest, FullCover_WithScaling) {
   StrictMock<MockFrameSource> frame_source;
+  mojo::Remote<mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
   VideoCaptureOverlay overlay(&frame_source,
-                              mojom::FrameSinkVideoCaptureOverlayRequest());
+                              overlay_remote.BindNewPipeAndPassReceiver());
 
   EXPECT_CALL(frame_source, GetSourceSize())
       .WillRepeatedly(Return(kSourceSize));
@@ -452,8 +457,9 @@
   NiceMock<MockFrameSource> frame_source;
   EXPECT_CALL(frame_source, GetSourceSize())
       .WillRepeatedly(Return(kSourceSize));
+  mojo::Remote<mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
   VideoCaptureOverlay overlay(&frame_source,
-                              mojom::FrameSinkVideoCaptureOverlayRequest());
+                              overlay_remote.BindNewPipeAndPassReceiver());
 
   const SkBitmap test_bitmap = MakeTestBitmap(0);
   const gfx::Size frame_size(test_bitmap.width() * 4, test_bitmap.height() * 4);
@@ -517,8 +523,9 @@
   NiceMock<MockFrameSource> frame_source;
   EXPECT_CALL(frame_source, GetSourceSize())
       .WillRepeatedly(Return(kSourceSize));
+  mojo::Remote<mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
   VideoCaptureOverlay overlay(&frame_source,
-                              mojom::FrameSinkVideoCaptureOverlayRequest());
+                              overlay_remote.BindNewPipeAndPassReceiver());
 
   const SkBitmap test_bitmap = MakeTestBitmap(0);
   const gfx::Size frame_size(test_bitmap.width() * 4, test_bitmap.height() * 4);
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 23ad163..94bbb8a 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -17,6 +17,7 @@
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/screen_enumeration/screen_enumeration_impl.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
+#include "content/browser/speech/speech_recognition_dispatcher_host.h"
 #include "content/browser/wake_lock/wake_lock_service_impl.h"
 #include "content/browser/worker_host/dedicated_worker_host.h"
 #include "content/browser/worker_host/shared_worker_host.h"
@@ -53,6 +54,7 @@
 #include "third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom.h"
 #include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
 #include "third_party/blink/public/mojom/sms/sms_receiver.mojom.h"
+#include "third_party/blink/public/mojom/speech/speech_recognizer.mojom.h"
 #include "third_party/blink/public/mojom/speech/speech_synthesis.mojom.h"
 #include "third_party/blink/public/mojom/wake_lock/wake_lock.mojom.h"
 #include "third_party/blink/public/mojom/webaudio/audio_context_manager.mojom.h"
@@ -161,6 +163,11 @@
   map->Add<blink::mojom::PresentationService>(base::BindRepeating(
       &RenderFrameHostImpl::GetPresentationService, base::Unretained(host)));
 
+  map->Add<blink::mojom::SpeechRecognizer>(
+      base::BindRepeating(&SpeechRecognitionDispatcherHost::Create,
+                          host->GetProcess()->GetID(), host->GetRoutingID()),
+      base::CreateSingleThreadTaskRunner({BrowserThread::IO}));
+
   map->Add<blink::mojom::SpeechSynthesis>(base::BindRepeating(
       &RenderFrameHostImpl::GetSpeechSynthesis, base::Unretained(host)));
 
diff --git a/content/browser/devtools/devtools_video_consumer_unittest.cc b/content/browser/devtools/devtools_video_consumer_unittest.cc
index e248e2a..ee5038f 100644
--- a/content/browser/devtools/devtools_video_consumer_unittest.cc
+++ b/content/browser/devtools/devtools_video_consumer_unittest.cc
@@ -13,7 +13,10 @@
 #include "media/base/limits.h"
 #include "media/capture/mojom/video_capture_types.mojom.h"
 #include "mojo/public/cpp/base/shared_memory_utils.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using testing::_;
@@ -83,9 +86,10 @@
     MockChangeTarget(frame_sink_id_);
   }
   MOCK_METHOD1(MockChangeTarget, void(const viz::FrameSinkId& frame_sink_id));
-  void Start(viz::mojom::FrameSinkVideoConsumerPtr consumer) final {
+  void Start(
+      mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumer> consumer) final {
     DCHECK(!consumer_);
-    consumer_ = std::move(consumer);
+    consumer_.Bind(std::move(consumer));
     MockStart(consumer_.get());
   }
   MOCK_METHOD1(MockStart, void(viz::mojom::FrameSinkVideoConsumer* consumer));
@@ -96,9 +100,11 @@
   }
   MOCK_METHOD0(MockStop, void());
   MOCK_METHOD0(RequestRefreshFrame, void());
-  MOCK_METHOD2(CreateOverlay,
-               void(int32_t stacking_index,
-                    viz::mojom::FrameSinkVideoCaptureOverlayRequest request));
+  MOCK_METHOD2(
+      CreateOverlay,
+      void(int32_t stacking_index,
+           mojo::PendingReceiver<viz::mojom::FrameSinkVideoCaptureOverlay>
+               receiver));
 
   // Const accessors to get the cached variables.
   base::TimeDelta min_capture_period() const { return min_capture_period_; }
@@ -115,7 +121,7 @@
   gfx::Size min_frame_size_;
   gfx::Size max_frame_size_;
   viz::FrameSinkId frame_sink_id_;
-  viz::mojom::FrameSinkVideoConsumerPtr consumer_;
+  mojo::Remote<viz::mojom::FrameSinkVideoConsumer> consumer_;
 
   mojo::Receiver<viz::mojom::FrameSinkVideoCapturer> receiver_{this};
 };
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc
index d5a8503..ec04b2f 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -136,7 +136,11 @@
       legacy_localstorage_path, new_localstorage_path, special_storage_policy);
   SessionStorageContextMojo* mojo_session_state = nullptr;
   mojo_session_state = new SessionStorageContextMojo(
-      data_path, mojo_task_runner,
+      data_path,
+      base::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::ThreadPool(),
+           base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
+      mojo_task_runner,
 #if defined(OS_ANDROID)
       // On Android there is no support for session storage restoring, and
       // since the restoring code is responsible for database cleanup, we must
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper_unittest.cc b/content/browser/dom_storage/dom_storage_context_wrapper_unittest.cc
index e128419..89243ca 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper_unittest.cc
+++ b/content/browser/dom_storage/dom_storage_context_wrapper_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
+#include "base/task/post_task.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_simple_task_runner.h"
@@ -30,8 +31,12 @@
     storage_policy_ = new MockSpecialStoragePolicy();
     fake_mojo_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
     auto* session_storage_context = new SessionStorageContextMojo(
-        /*partition_path=*/base::FilePath(), fake_mojo_task_runner_,
-        SessionStorageContextMojo::BackingMode::kNoDisk, /*leveldb_name=*/"");
+        /*partition_path=*/base::FilePath(),
+        base::CreateSequencedTaskRunner(
+            {base::MayBlock(), base::ThreadPool(),
+             base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
+        fake_mojo_task_runner_, SessionStorageContextMojo::BackingMode::kNoDisk,
+        /*leveldb_name=*/"");
     session_storage_context->PretendToConnectForTesting();
     context_ = new DOMStorageContextWrapper(
         /*legacy_local_storage_path=*/base::FilePath(), fake_mojo_task_runner_,
diff --git a/content/browser/dom_storage/session_storage_context_mojo.cc b/content/browser/dom_storage/session_storage_context_mojo.cc
index 29e9faf..d136b45 100644
--- a/content/browser/dom_storage/session_storage_context_mojo.cc
+++ b/content/browser/dom_storage/session_storage_context_mojo.cc
@@ -102,15 +102,14 @@
 
 SessionStorageContextMojo::SessionStorageContextMojo(
     const base::FilePath& partition_directory,
+    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
     scoped_refptr<base::SequencedTaskRunner> memory_dump_task_runner,
     BackingMode backing_mode,
     std::string leveldb_name)
     : backing_mode_(backing_mode),
       leveldb_name_(std::move(leveldb_name)),
       partition_directory_(partition_directory),
-      leveldb_task_runner_(base::CreateSequencedTaskRunner(
-          {base::ThreadPool(), base::MayBlock(),
-           base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
+      leveldb_task_runner_(std::move(blocking_task_runner)),
       memory_dump_id_(base::StringPrintf("SessionStorage/0x%" PRIXPTR,
                                          reinterpret_cast<uintptr_t>(this))),
       is_low_end_device_(base::SysInfo::IsLowEndDevice()) {
diff --git a/content/browser/dom_storage/session_storage_context_mojo.h b/content/browser/dom_storage/session_storage_context_mojo.h
index 7444b6c..5ef022ba 100644
--- a/content/browser/dom_storage/session_storage_context_mojo.h
+++ b/content/browser/dom_storage/session_storage_context_mojo.h
@@ -75,7 +75,8 @@
 
   SessionStorageContextMojo(
       const base::FilePath& partition_directory,
-      scoped_refptr<base::SequencedTaskRunner> task_runner,
+      scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+      scoped_refptr<base::SequencedTaskRunner> memory_dump_task_runner,
       BackingMode backing_option,
       std::string leveldb_name);
 
diff --git a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
index c10f8c15..f5826f06 100644
--- a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
 #include "base/test/bind_test_util.h"
 #include "components/services/leveldb/public/cpp/util.h"
 #include "content/browser/child_process_security_policy_impl.h"
@@ -102,7 +103,8 @@
   SessionStorageContextMojo* context() {
     if (!context_) {
       context_ = new SessionStorageContextMojo(
-          temp_path(), base::SequencedTaskRunnerHandle::Get(), backing_mode_,
+          temp_path(), blocking_task_runner_,
+          base::SequencedTaskRunnerHandle::Get(), backing_mode_,
           kSessionStorageDirectory);
     }
     return context_;
@@ -179,6 +181,10 @@
   TestBrowserContext browser_context_;
   SessionStorageContextMojo::BackingMode backing_mode_ =
       SessionStorageContextMojo::BackingMode::kRestoreDiskState;
+  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_{
+      base::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::ThreadPool(),
+           base::TaskShutdownBehavior::BLOCK_SHUTDOWN})};
   SessionStorageContextMojo* context_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(SessionStorageContextMojoTest);
@@ -242,7 +248,7 @@
                                key_as_vector, String16ToUint8Vector(value))));
 }
 
-TEST_F(SessionStorageContextMojoTest, DISABLED_StartupShutdownSave) {
+TEST_F(SessionStorageContextMojoTest, StartupShutdownSave) {
   std::string namespace_id1 = base::GenerateGUID();
   url::Origin origin1 = url::Origin::Create(GURL("http://foobar.com"));
   context()->CreateSessionNamespace(namespace_id1);
@@ -479,7 +485,7 @@
   EXPECT_TRUE(bad_message_called_);
 }
 
-TEST_F(SessionStorageContextMojoTest, DISABLED_Scavenging) {
+TEST_F(SessionStorageContextMojoTest, Scavenging) {
   // Create our namespace, destroy our context and leave that namespace on disk,
   // and verify that it is scavenged if we re-create the context without calling
   // CreateSessionNamespace.
@@ -1028,7 +1034,7 @@
 }
 
 // TODO(https://crbug.com/1008697): Flakes when verifying no data found.
-TEST_F(SessionStorageContextMojoTest, DISABLED_ClearDiskState) {
+TEST_F(SessionStorageContextMojoTest, ClearDiskState) {
   SetBackingMode(SessionStorageContextMojo::BackingMode::kClearDiskStateOnOpen);
   std::string namespace_id1 = base::GenerateGUID();
   url::Origin origin1 = url::Origin::Create(GURL("http://foobar.com"));
diff --git a/content/browser/frame_host/back_forward_cache_metrics.cc b/content/browser/frame_host/back_forward_cache_metrics.cc
index da826ddc..c004112 100644
--- a/content/browser/frame_host/back_forward_cache_metrics.cc
+++ b/content/browser/frame_host/back_forward_cache_metrics.cc
@@ -5,6 +5,7 @@
 #include "content/browser/frame_host/back_forward_cache_metrics.h"
 
 #include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/frame_host/navigation_request.h"
 #include "content/public/browser/browser_thread.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
@@ -91,21 +92,19 @@
 }
 
 void BackForwardCacheMetrics::DidCommitNavigation(
-    int64_t navigation_id,
-    int64_t navigation_entry_id,
-    bool is_main_frame_navigation) {
+    NavigationRequest* navigation) {
   if (last_committed_main_frame_navigation_id_ != -1 &&
-      is_main_frame_navigation) {
+      navigation->IsInMainFrame()) {
     // We've visited an entry associated with this main frame document before,
     // so record metrics to determine whether it might be a back-forward cache
     // hit.
     ukm::builders::HistoryNavigation builder(ukm::ConvertToSourceId(
-        navigation_id, ukm::SourceIdType::NAVIGATION_ID));
+        navigation->GetNavigationId(), ukm::SourceIdType::NAVIGATION_ID));
     builder.SetLastCommittedSourceIdForTheSameDocument(
         ukm::ConvertToSourceId(last_committed_main_frame_navigation_id_,
                                ukm::SourceIdType::NAVIGATION_ID));
     builder.SetNavigatedToTheMostRecentEntryForDocument(
-        navigation_entry_id == last_committed_navigation_entry_id_);
+        navigation->nav_entry_id() == last_committed_navigation_entry_id_);
     builder.SetMainFrameFeatures(main_frame_features_);
     builder.SetSameOriginSubframesFeatures(same_origin_frames_features_);
     builder.SetCrossOriginSubframesFeatures(cross_origin_frames_features_);
@@ -121,9 +120,9 @@
     }
     builder.Record(ukm::UkmRecorder::Get());
   }
-  if (is_main_frame_navigation)
-    last_committed_main_frame_navigation_id_ = navigation_id;
-  last_committed_navigation_entry_id_ = navigation_entry_id;
+  if (navigation->IsInMainFrame())
+    last_committed_main_frame_navigation_id_ = navigation->GetNavigationId();
+  last_committed_navigation_entry_id_ = navigation->nav_entry_id();
 
   navigated_away_from_main_document_timestamp_ = base::nullopt;
   started_navigation_timestamp_ = base::nullopt;
diff --git a/content/browser/frame_host/back_forward_cache_metrics.h b/content/browser/frame_host/back_forward_cache_metrics.h
index e789c4f..f424666 100644
--- a/content/browser/frame_host/back_forward_cache_metrics.h
+++ b/content/browser/frame_host/back_forward_cache_metrics.h
@@ -18,6 +18,7 @@
 
 namespace content {
 class NavigationEntryImpl;
+class NavigationRequest;
 class RenderFrameHostImpl;
 
 // Helper class for recording metrics around history navigations.
@@ -68,9 +69,7 @@
   void MainFrameDidStartNavigationToDocument();
 
   // Notifies that an associated entry has committed a navigation.
-  void DidCommitNavigation(int64_t navigation_id,
-                           int64_t navigation_entry_id,
-                           bool is_main_frame_navigation);
+  void DidCommitNavigation(NavigationRequest* navigation_request);
 
   // Records when another navigation commits away from the most recent entry
   // associated with |this|.  This is the point in time that the previous
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index bf42f79..f383b8e 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -1125,8 +1125,7 @@
         std::move(back_forward_cache_metrics));
   }
   active_entry->back_forward_cache_metrics()->DidCommitNavigation(
-      navigation_request->GetNavigationId(), active_entry->GetUniqueID(),
-      rfh->frame_tree_node()->IsMainFrame());
+      navigation_request);
 
   // Grab the corresponding FrameNavigationEntry for a few updates, but only if
   // the SiteInstance matches (to avoid updating the wrong entry by mistake).
diff --git a/content/browser/frame_host/render_frame_host_android.cc b/content/browser/frame_host/render_frame_host_android.cc
index 735e854..a02acf1 100644
--- a/content/browser/frame_host/render_frame_host_android.cc
+++ b/content/browser/frame_host/render_frame_host_android.cc
@@ -15,6 +15,7 @@
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/android/content_jni_headers/RenderFrameHostImpl_jni.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/site_instance.h"
 #include "url/origin.h"
 
@@ -114,4 +115,10 @@
   return render_frame_host_->IsRenderFrameCreated();
 }
 
+jboolean RenderFrameHostAndroid::IsProcessBlocked(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>&) const {
+  return render_frame_host_->GetProcess()->IsBlocked();
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_android.h b/content/browser/frame_host/render_frame_host_android.h
index 35315276..9e46d9e 100644
--- a/content/browser/frame_host/render_frame_host_android.h
+++ b/content/browser/frame_host/render_frame_host_android.h
@@ -60,6 +60,9 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>&) const;
 
+  jboolean IsProcessBlocked(JNIEnv* env,
+                            const base::android::JavaParamRef<jobject>&) const;
+
   RenderFrameHostImpl* render_frame_host() const { return render_frame_host_; }
 
  private:
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index ec0c835..1c232cde 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -99,7 +99,6 @@
 #include "content/browser/scoped_active_url.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/sms/sms_service.h"
-#include "content/browser/speech/speech_recognition_dispatcher_host.h"
 #include "content/browser/speech/speech_synthesis_impl.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/browser/web_package/bundled_exchanges_handle.h"
@@ -4451,11 +4450,6 @@
   registry_->AddInterface(base::BindRepeating(
       &QuotaDispatcherHost::CreateForFrame, GetProcess(), routing_id_));
 
-  registry_->AddInterface(
-      base::BindRepeating(SpeechRecognitionDispatcherHost::Create,
-                          GetProcess()->GetID(), routing_id_),
-      base::CreateSingleThreadTaskRunner({BrowserThread::IO}));
-
   file_system_manager_.reset(new FileSystemManagerImpl(
       GetProcess()->GetID(),
       GetProcess()->GetStoragePartition()->GetFileSystemContext(),
diff --git a/content/browser/media/capture/desktop_streams_registry_impl.cc b/content/browser/media/capture/desktop_streams_registry_impl.cc
index 88ba5d4b..b8ce040a 100644
--- a/content/browser/media/capture/desktop_streams_registry_impl.cc
+++ b/content/browser/media/capture/desktop_streams_registry_impl.cc
@@ -51,7 +51,7 @@
 std::string DesktopStreamsRegistryImpl::RegisterStream(
     int render_process_id,
     int render_frame_id,
-    const GURL& origin,
+    const url::Origin& origin,
     const DesktopMediaID& source,
     const std::string& extension_name,
     const DesktopStreamRegistryType type) {
@@ -80,7 +80,7 @@
     const std::string& id,
     int render_process_id,
     int render_frame_id,
-    const GURL& origin,
+    const url::Origin& origin,
     std::string* extension_name,
     const DesktopStreamRegistryType type) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/content/browser/media/capture/desktop_streams_registry_impl.h b/content/browser/media/capture/desktop_streams_registry_impl.h
index baa45e15..ef094eb 100644
--- a/content/browser/media/capture/desktop_streams_registry_impl.h
+++ b/content/browser/media/capture/desktop_streams_registry_impl.h
@@ -11,7 +11,7 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/browser/desktop_streams_registry.h"
-#include "url/gurl.h"
+#include "url/origin.h"
 
 namespace content {
 
@@ -26,7 +26,7 @@
 
   std::string RegisterStream(int render_process_id,
                              int render_frame_id,
-                             const GURL& origin,
+                             const url::Origin& origin,
                              const DesktopMediaID& source,
                              const std::string& extension_name,
                              const DesktopStreamRegistryType type) override;
@@ -35,7 +35,7 @@
       const std::string& id,
       int render_process_id,
       int render_frame_id,
-      const GURL& origin,
+      const url::Origin& origin,
       std::string* extension_name,
       const DesktopStreamRegistryType type) override;
 
@@ -46,7 +46,7 @@
 
     int render_process_id;
     int render_frame_id;
-    GURL origin;
+    url::Origin origin;
     DesktopMediaID source;
     std::string extension_name;
     DesktopStreamRegistryType type;
diff --git a/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc b/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc
index 00de06a5..92483a8 100644
--- a/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc
+++ b/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc
@@ -20,6 +20,8 @@
 #include "media/capture/video_capture_types.h"
 #include "mojo/public/cpp/base/shared_memory_utils.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -104,9 +106,10 @@
     MockChangeTarget(frame_sink_id ? *frame_sink_id : viz::FrameSinkId());
   }
   MOCK_METHOD1(MockChangeTarget, void(const viz::FrameSinkId& frame_sink_id));
-  void Start(viz::mojom::FrameSinkVideoConsumerPtr consumer) final {
+  void Start(
+      mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumer> consumer) final {
     DCHECK_NOT_ON_DEVICE_THREAD();
-    consumer_ = std::move(consumer);
+    consumer_.Bind(std::move(consumer));
     MockStart(consumer_.get());
   }
   MOCK_METHOD1(MockStart, void(viz::mojom::FrameSinkVideoConsumer* consumer));
@@ -117,13 +120,15 @@
   }
   MOCK_METHOD0(MockStop, void());
   MOCK_METHOD0(RequestRefreshFrame, void());
-  MOCK_METHOD2(CreateOverlay,
-               void(int32_t stacking_index,
-                    viz::mojom::FrameSinkVideoCaptureOverlayRequest request));
+  MOCK_METHOD2(
+      CreateOverlay,
+      void(int32_t stacking_index,
+           mojo::PendingReceiver<viz::mojom::FrameSinkVideoCaptureOverlay>
+               receiver));
 
  private:
   mojo::Binding<viz::mojom::FrameSinkVideoCapturer> binding_;
-  viz::mojom::FrameSinkVideoConsumerPtr consumer_;
+  mojo::Remote<viz::mojom::FrameSinkVideoConsumer> consumer_;
 };
 
 // Represents the FrameSinkVideoConsumerFrameCallbacks instance in the VIZ
diff --git a/content/browser/media/capture/lame_capture_overlay_chromeos.cc b/content/browser/media/capture/lame_capture_overlay_chromeos.cc
index a9058787..95497843 100644
--- a/content/browser/media/capture/lame_capture_overlay_chromeos.cc
+++ b/content/browser/media/capture/lame_capture_overlay_chromeos.cc
@@ -23,10 +23,10 @@
 
 LameCaptureOverlayChromeOS::LameCaptureOverlayChromeOS(
     Owner* owner,
-    viz::mojom::FrameSinkVideoCaptureOverlayRequest request)
-    : binding_(this, std::move(request)) {
+    mojo::PendingReceiver<viz::mojom::FrameSinkVideoCaptureOverlay> receiver)
+    : receiver_(this, std::move(receiver)) {
   if (owner) {
-    binding_.set_connection_error_handler(base::BindOnce(
+    receiver_.set_disconnect_handler(base::BindOnce(
         &Owner::OnOverlayConnectionLost, base::Unretained(owner), this));
   }
 }
diff --git a/content/browser/media/capture/lame_capture_overlay_chromeos.h b/content/browser/media/capture/lame_capture_overlay_chromeos.h
index 9f8c5220..fc912f0 100644
--- a/content/browser/media/capture/lame_capture_overlay_chromeos.h
+++ b/content/browser/media/capture/lame_capture_overlay_chromeos.h
@@ -9,7 +9,8 @@
 #include "base/macros.h"
 #include "base/sequence_checker.h"
 #include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -54,7 +55,7 @@
 
   LameCaptureOverlayChromeOS(
       Owner* owner,
-      viz::mojom::FrameSinkVideoCaptureOverlayRequest request);
+      mojo::PendingReceiver<viz::mojom::FrameSinkVideoCaptureOverlay> receiver);
   ~LameCaptureOverlayChromeOS() final;
 
   // viz::mojom::FrameSinkVideoCaptureOverlay implementation.
@@ -70,7 +71,7 @@
  private:
   SEQUENCE_CHECKER(sequence_checker_);
 
-  mojo::Binding<viz::mojom::FrameSinkVideoCaptureOverlay> binding_;
+  mojo::Receiver<viz::mojom::FrameSinkVideoCaptureOverlay> receiver_;
 
   SkBitmap image_;
   gfx::RectF bounds_;
diff --git a/content/browser/media/capture/lame_capture_overlay_chromeos_unittest.cc b/content/browser/media/capture/lame_capture_overlay_chromeos_unittest.cc
index 8792629..6c29a34 100644
--- a/content/browser/media/capture/lame_capture_overlay_chromeos_unittest.cc
+++ b/content/browser/media/capture/lame_capture_overlay_chromeos_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "media/base/video_frame.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect.h"
@@ -68,8 +69,9 @@
 };
 
 TEST_F(LameCaptureOverlayChromeOSTest, UnsetImageNotRenderedOnFrame) {
+  mojo::Remote<viz::mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
   LameCaptureOverlayChromeOS overlay(
-      nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
+      nullptr, overlay_remote.BindNewPipeAndPassReceiver());
 
   // Bounds set, but no image. → Should not render anything.
   overlay.SetBounds(kSpanOfEntireFrame);
@@ -81,8 +83,9 @@
 }
 
 TEST_F(LameCaptureOverlayChromeOSTest, HiddenImageNotRenderedOnFrame) {
+  mojo::Remote<viz::mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
   LameCaptureOverlayChromeOS overlay(
-      nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
+      nullptr, overlay_remote.BindNewPipeAndPassReceiver());
 
   // Both image and bounds set. → Should render something.
   overlay.SetImageAndBounds(CreateTestBitmap(), kSpanOfEntireFrame);
@@ -94,8 +97,9 @@
 }
 
 TEST_F(LameCaptureOverlayChromeOSTest, OutOfBoundsOverlayNotRenderedOnFrame) {
+  mojo::Remote<viz::mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
   LameCaptureOverlayChromeOS overlay(
-      nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
+      nullptr, overlay_remote.BindNewPipeAndPassReceiver());
 
   // Both image and bounds set. → Should render something.
   overlay.SetImageAndBounds(CreateTestBitmap(), kSpanOfEntireFrame);
@@ -107,8 +111,9 @@
 }
 
 TEST_F(LameCaptureOverlayChromeOSTest, ImageRenderedOnFrame) {
+  mojo::Remote<viz::mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
   LameCaptureOverlayChromeOS overlay(
-      nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
+      nullptr, overlay_remote.BindNewPipeAndPassReceiver());
 
   // Create blank black frame. No non-zero pixels should be present.
   const auto frame = media::VideoFrame::CreateZeroInitializedFrame(
@@ -159,14 +164,14 @@
                  void(LameCaptureOverlayChromeOS* overlay));
   } mock_owner;
 
-  viz::mojom::FrameSinkVideoCaptureOverlayPtr overlay_ptr;
-  LameCaptureOverlayChromeOS overlay(&mock_owner,
-                                     mojo::MakeRequest(&overlay_ptr));
-  ASSERT_TRUE(overlay_ptr);
+  mojo::Remote<viz::mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
+  LameCaptureOverlayChromeOS overlay(
+      &mock_owner, overlay_remote.BindNewPipeAndPassReceiver());
+  ASSERT_TRUE(overlay_remote);
   RunUntilIdle();  // Propagate mojo tasks.
 
   EXPECT_CALL(mock_owner, OnOverlayConnectionLost(&overlay));
-  overlay_ptr.reset();
+  overlay_remote.reset();
   RunUntilIdle();  // Propagate mojo tasks.
 }
 
diff --git a/content/browser/media/capture/lame_window_capturer_chromeos.cc b/content/browser/media/capture/lame_window_capturer_chromeos.cc
index 8258354f..97bf732 100644
--- a/content/browser/media/capture/lame_window_capturer_chromeos.cc
+++ b/content/browser/media/capture/lame_window_capturer_chromeos.cc
@@ -106,15 +106,15 @@
 }
 
 void LameWindowCapturerChromeOS::Start(
-    viz::mojom::FrameSinkVideoConsumerPtr consumer) {
+    mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumer> consumer) {
   DCHECK(consumer);
 
   Stop();
 
-  consumer_ = std::move(consumer);
+  consumer_.Bind(std::move(consumer));
   // In the future, if the connection to the consumer is lost before a call to
   // Stop(), make that call on its behalf.
-  consumer_.set_connection_error_handler(base::BindOnce(
+  consumer_.set_disconnect_handler(base::BindOnce(
       &LameWindowCapturerChromeOS::Stop, base::Unretained(this)));
 
   timer_.Start(FROM_HERE, capture_period_, this,
@@ -141,11 +141,11 @@
 
 void LameWindowCapturerChromeOS::CreateOverlay(
     int32_t stacking_index,
-    viz::mojom::FrameSinkVideoCaptureOverlayRequest request) {
+    mojo::PendingReceiver<viz::mojom::FrameSinkVideoCaptureOverlay> receiver) {
   // LameWindowCapturerChromeOS only supports one overlay at a time. If one
   // already exists, the following will cause it to be dropped.
   overlay_ =
-      std::make_unique<LameCaptureOverlayChromeOS>(this, std::move(request));
+      std::make_unique<LameCaptureOverlayChromeOS>(this, std::move(receiver));
 }
 
 class LameWindowCapturerChromeOS::InFlightFrame
diff --git a/content/browser/media/capture/lame_window_capturer_chromeos.h b/content/browser/media/capture/lame_window_capturer_chromeos.h
index 2ea025f..98b8306 100644
--- a/content/browser/media/capture/lame_window_capturer_chromeos.h
+++ b/content/browser/media/capture/lame_window_capturer_chromeos.h
@@ -17,6 +17,9 @@
 #include "base/unguessable_token.h"
 #include "content/browser/media/capture/lame_capture_overlay_chromeos.h"
 #include "media/base/video_frame.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
@@ -65,12 +68,14 @@
   void SetAutoThrottlingEnabled(bool enabled) final;
   void ChangeTarget(
       const base::Optional<viz::FrameSinkId>& frame_sink_id) final;
-  void Start(viz::mojom::FrameSinkVideoConsumerPtr consumer) final;
+  void Start(
+      mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumer> consumer) final;
   void Stop() final;
   void RequestRefreshFrame() final;
   void CreateOverlay(
       int32_t stacking_index,
-      viz::mojom::FrameSinkVideoCaptureOverlayRequest request) final;
+      mojo::PendingReceiver<viz::mojom::FrameSinkVideoCaptureOverlay> receiver)
+      final;
 
  private:
   // Represents an in-flight frame, being populated by this capturer and then
@@ -106,7 +111,7 @@
   gfx::Size capture_size_ = gfx::Size(640, 360);
 
   // The current consumer. This is set by Start() and cleared by Stop().
-  viz::mojom::FrameSinkVideoConsumerPtr consumer_;
+  mojo::Remote<viz::mojom::FrameSinkVideoConsumer> consumer_;
 
   // A timer that calls CaptureNextFrame() periodically, according to the
   // currently-set |capture_period_|. This timer is only running while a
diff --git a/content/browser/media/encrypted_media_browsertest.cc b/content/browser/media/encrypted_media_browsertest.cc
index 0b87b9e..2993f08 100644
--- a/content/browser/media/encrypted_media_browsertest.cc
+++ b/content/browser/media/encrypted_media_browsertest.cc
@@ -206,8 +206,7 @@
   TestSimplePlayback("bear-320x240-av_enc-a.webm");
 }
 
-// crbug.com/1010061: disabled due to flakiness.
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, DISABLED_Playback_VideoAudio_WebM) {
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) {
   TestSimplePlayback("bear-320x240-av_enc-av.webm");
 }
 
@@ -227,9 +226,7 @@
   TestSimplePlayback("bear-320x240-av_enc-v.webm");
 }
 
-// crbug.com/1010061: disabled due to flakiness.
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
-                       DISABLED_Playback_AudioOnly_WebM_Opus) {
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM_Opus) {
 #if defined(OS_ANDROID)
   if (!media::MediaCodecUtil::IsOpusDecoderAvailable())
     return;
@@ -365,8 +362,7 @@
                       media::kError);
 }
 
-// crbug.com/1010061: disabled due to flakiness.
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, DISABLED_Playback_Encryption_CBCS) {
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_Encryption_CBCS) {
   std::string expected_result =
       BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) ? media::kEnded : media::kError;
   RunMultipleFileTest("bear-640x360-v_frag-cbcs.mp4",
diff --git a/content/browser/media/media_browsertest.cc b/content/browser/media/media_browsertest.cc
index 329e0d3d..8f07686 100644
--- a/content/browser/media/media_browsertest.cc
+++ b/content/browser/media/media_browsertest.cc
@@ -162,12 +162,12 @@
 }
 #endif  // !defined(OS_ANDROID)
 
-// crbug.com/1010061: disabled due to flakiness.
+// crbug.com/1001364: disabled due to flakiness.
 IN_PROC_BROWSER_TEST_P(MediaTest, DISABLED_VideoBearWebm) {
   PlayVideo("bear.webm", GetParam());
 }
 
-// crbug.com/1010061: disabled due to flakiness.
+// crbug.com/1001364: disabled due to flakiness.
 IN_PROC_BROWSER_TEST_P(MediaTest, DISABLED_AudioBearOpusWebm) {
   PlayVideo("bear-opus.webm", GetParam());
 }
@@ -212,7 +212,7 @@
   PlayVideo("bear_pcm_s16be.mov", GetParam());
 }
 
-// crbug.com/1010061: disabled due to flakiness.
+// crbug.com/1001364: disabled due to flakiness.
 IN_PROC_BROWSER_TEST_P(MediaTest, DISABLED_VideoBearMovPcmS24be) {
   PlayVideo("bear_pcm_s24be.mov", GetParam());
 }
@@ -302,12 +302,12 @@
   PlayAudio("bear_alaw.wav", GetParam());
 }
 
-// crbug.com/1010061: disabled due to flakiness.
+// crbug.com/1001364: disabled due to flakiness.
 IN_PROC_BROWSER_TEST_P(MediaTest, DISABLED_VideoBearWavMulaw) {
   PlayAudio("bear_mulaw.wav", GetParam());
 }
 
-// crbug.com/1010061: disabled due to flakiness.
+// crbug.com/1001364: disabled due to flakiness.
 IN_PROC_BROWSER_TEST_P(MediaTest, DISABLED_VideoBearWavPcm) {
   PlayAudio("bear_pcm.wav", GetParam());
 }
diff --git a/content/browser/media/media_source_browsertest.cc b/content/browser/media/media_source_browsertest.cc
index da596b45..9faa3f4 100644
--- a/content/browser/media/media_source_browsertest.cc
+++ b/content/browser/media/media_source_browsertest.cc
@@ -61,10 +61,9 @@
 }
 #endif
 
-// crbug.com/1010061: disabled due to flakiness.
 // Opus is not supported in Android as of now.
 #if !defined(OS_ANDROID)
-IN_PROC_BROWSER_TEST_F(MediaSourceTest, DISABLED_Playback_AudioOnly_Opus_WebM) {
+IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_AudioOnly_Opus_WebM) {
   TestSimplePlayback("bear-opus.webm", media::kEnded);
 }
 #endif
@@ -87,10 +86,8 @@
                    true);
 }
 
-// crbug.com/1010061: disabled due to flakiness.
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-IN_PROC_BROWSER_TEST_F(MediaSourceTest,
-                       DISABLED_Playback_Video_MP4_Audio_WEBM) {
+IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_Video_MP4_Audio_WEBM) {
   auto query_params = GetAudioVideoQueryParams("bear-320x240-audio-only.webm",
                                                "bear-640x360-v_frag.mp4");
   RunMediaTestPage("mse_different_containers.html", std::move(query_params),
@@ -106,8 +103,7 @@
 
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
-// crbug.com/1010061: disabled due to flakiness.
-IN_PROC_BROWSER_TEST_F(MediaSourceTest, DISABLED_Playback_AudioOnly_FLAC_MP4) {
+IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_AudioOnly_FLAC_MP4) {
   TestSimplePlayback("bear-flac_frag.mp4", media::kEnded);
 }
 
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 6b49aea..0ad75a52 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -1372,8 +1372,8 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   // Resolve DesktopMediaID for the specified device id.
   return DesktopStreamsRegistry::GetInstance()->RequestMediaForStreamId(
-      capture_device_id, requesting_process_id, requesting_frame_id, origin,
-      nullptr, kRegistryStreamTypeTab);
+      capture_device_id, requesting_process_id, requesting_frame_id,
+      url::Origin::Create(origin), nullptr, kRegistryStreamTypeTab);
 }
 
 void MediaStreamManager::FinishTabCaptureRequestSetupWithDeviceId(
diff --git a/content/browser/webrtc/webrtc_browsertest.cc b/content/browser/webrtc/webrtc_browsertest.cc
index c99ab4ab..0ddd811 100644
--- a/content/browser/webrtc/webrtc_browsertest.cc
+++ b/content/browser/webrtc/webrtc_browsertest.cc
@@ -60,9 +60,7 @@
   MakeTypicalPeerConnectionCall("call({video: true, audio: true});");
 }
 
-// crbug.com:1010061: disabled due to flakiness.
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
-                       DISABLED_NetworkProcessCrashRecovery) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, NetworkProcessCrashRecovery) {
   if (!IsOutOfProcessNetworkService())
     return;
   MakeTypicalPeerConnectionCall("call({video: true, audio: true});");
@@ -150,9 +148,8 @@
       "callAndForwardRemoteStream({video: true, audio: true});");
 }
 
-// crbug.com:1010061: disabled due to flakiness.
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
-                       DISABLED_NoCrashWhenConnectChromiumSinkToRemoteTrack) {
+                       NoCrashWhenConnectChromiumSinkToRemoteTrack) {
   MakeTypicalPeerConnectionCall("ConnectChromiumSinkToRemoteAudioTrack();");
 }
 
@@ -161,9 +158,15 @@
 // video is playing for the call even if the initiating client don't support
 // MSID. http://tools.ietf.org/html/draft-alvestrand-rtcweb-msid-02
 // Fails with TSAN. https://crbug.com/756568
-// crbug.com:1010061: disabled due to flakiness.
+#if defined(THREAD_SANITIZER)
+#define MAYBE_CanSetupAudioAndVideoCallWithoutMsidAndBundle \
+  DISABLED_CanSetupAudioAndVideoCallWithoutMsidAndBundle
+#else
+#define MAYBE_CanSetupAudioAndVideoCallWithoutMsidAndBundle \
+  CanSetupAudioAndVideoCallWithoutMsidAndBundle
+#endif
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
-                       DISABLED_CanSetupAudioAndVideoCallWithoutMsidAndBundle) {
+                       MAYBE_CanSetupAudioAndVideoCallWithoutMsidAndBundle) {
   MakeTypicalPeerConnectionCall("callWithoutMsidAndBundle();");
 }
 
@@ -203,9 +206,7 @@
       "callWithNewVideoMediaStreamLaterSwitchToAudio();");
 }
 
-// crbug.com:1010061: disabled due to flakiness.
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
-                       DISABLED_AddTwoMediaStreamsToOnePC) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, AddTwoMediaStreamsToOnePC) {
   MakeTypicalPeerConnectionCall("addTwoMediaStreamsToOneConnection();");
 }
 
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 11e3b39e..dfaef10 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -398,9 +398,6 @@
   WebRuntimeFeatures::EnableCooperativeScheduling(
       base::FeatureList::IsEnabled(features::kCooperativeScheduling));
 
-  WebRuntimeFeatures::EnableStreamsNative(
-      base::FeatureList::IsEnabled(blink::features::kStreamsNative));
-
   WebRuntimeFeatures::EnableMouseSubframeNoImplicitCapture(
       base::FeatureList::IsEnabled(features::kMouseSubframeNoImplicitCapture));
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java b/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java
index 34a911b..d5333e9f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java
@@ -126,6 +126,13 @@
                 mNativeRenderFrameHostAndroid, RenderFrameHostImpl.this);
     }
 
+    @Override
+    public boolean areInputEventsIgnored() {
+        if (mNativeRenderFrameHostAndroid == 0) return false;
+        return RenderFrameHostImplJni.get().isProcessBlocked(
+                mNativeRenderFrameHostAndroid, RenderFrameHostImpl.this);
+    }
+
     @NativeMethods
     interface Natives {
         String getLastCommittedURL(long nativeRenderFrameHostAndroid, RenderFrameHostImpl caller);
@@ -137,5 +144,6 @@
                 long nativeRenderFrameHostAndroid, RenderFrameHostImpl caller);
         void notifyUserActivation(long nativeRenderFrameHostAndroid, RenderFrameHostImpl caller);
         boolean isRenderFrameCreated(long nativeRenderFrameHostAndroid, RenderFrameHostImpl caller);
+        boolean isProcessBlocked(long nativeRenderFrameHostAndroid, RenderFrameHostImpl caller);
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java b/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java
index 9d1d36a3..7cc2324 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java
@@ -62,4 +62,9 @@
      * @return {@code true} if render frame is created.
      */
     boolean isRenderFrameCreated();
+
+    /**
+     * @return Whether input events from the renderer are ignored on the browser side.
+     */
+    boolean areInputEventsIgnored();
 }
diff --git a/content/public/app/content_browser_manifest.cc b/content/public/app/content_browser_manifest.cc
index e0043a3..b7d07f57 100644
--- a/content/public/app/content_browser_manifest.cc
+++ b/content/public/app/content_browser_manifest.cc
@@ -210,7 +210,6 @@
                   "blink.mojom.PrefetchURLLoaderService",
                   "blink.mojom.QuotaDispatcherHost",
                   "blink.mojom.SharedWorkerConnector",
-                  "blink.mojom.SpeechRecognizer",
                   "blink.mojom.TextSuggestionHost",
                   "blink.mojom.UnhandledTapNotifier",
                   "blink.mojom.WebUsbService",
diff --git a/content/public/browser/desktop_streams_registry.h b/content/public/browser/desktop_streams_registry.h
index ed9eb6a..600009c6 100644
--- a/content/public/browser/desktop_streams_registry.h
+++ b/content/public/browser/desktop_streams_registry.h
@@ -7,7 +7,9 @@
 
 #include "content/common/content_export.h"
 
-class GURL;
+namespace url {
+class Origin;
+}
 
 namespace content {
 
@@ -34,7 +36,7 @@
   // |render_frame_id| refers to the RenderFrame requesting the stream.
   virtual std::string RegisterStream(int render_process_id,
                                      int render_frame_id,
-                                     const GURL& origin,
+                                     const url::Origin& origin,
                                      const DesktopMediaID& source,
                                      const std::string& extension_name,
                                      const DesktopStreamRegistryType type) = 0;
@@ -48,7 +50,7 @@
       const std::string& id,
       int render_process_id,
       int render_frame_id,
-      const GURL& origin,
+      const url::Origin& origin,
       std::string* extension_name,
       const DesktopStreamRegistryType type) = 0;
 };
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java
index a26cc27..18ee3ae 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java
@@ -43,4 +43,9 @@
     public boolean isRenderFrameCreated() {
         return false;
     }
+
+    @Override
+    public boolean areInputEventsIgnored() {
+        return false;
+    }
 }
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 32f9378..ea1d749e5 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -209,6 +209,10 @@
     ]
 
     deps += [ "//dbus" ]
+
+    if (is_chromeos) {
+      deps += [ "//services/data_decoder/public/mojom" ]
+    }
   }
 
   if (is_linux) {
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
index 56decf7..3face5a 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -1518,26 +1518,6 @@
 
   BLUETOOTH_LOG(EVENT) << __func__;
 
-#if defined(OS_CHROMEOS)
-  device::BluetoothAdapterFactory::BleScanParserCallback
-      ble_scan_parser_callback =
-          device::BluetoothAdapterFactory::GetBleScanParserCallback();
-  if (ble_scan_parser_callback) {
-    // To avoid repeatedly restarting a crashed data decoder service,
-    // don't add a connection error handler here. Wait to establish a
-    // new connection after all discovery sessions are stopped.
-    ble_scan_parser_.Bind(ble_scan_parser_callback.Run());
-  } else {
-#if DCHECK_IS_ON()
-    static bool logged_once = false;
-    DLOG_IF(ERROR, !logged_once)
-        << "Attempted to connect to "
-           "unconfigured BluetoothAdapterFactory::GetBleScanParserCallback()";
-    logged_once = true;
-#endif  // DCHECK_IS_ON()
-  }
-#endif  // defined(OS_CHROMEOS)
-
   auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
 
   if (discovery_filter && !discovery_filter->IsDefault()) {
@@ -1678,6 +1658,27 @@
     DiscoverySessionErrorCallback error_callback) {
   // Report success on the original request and increment the count.
   BLUETOOTH_LOG(EVENT) << __func__;
+
+#if defined(OS_CHROMEOS)
+  device::BluetoothAdapterFactory::BleScanParserCallback
+      ble_scan_parser_callback =
+          device::BluetoothAdapterFactory::GetBleScanParserCallback();
+  if (ble_scan_parser_callback) {
+    // To avoid repeatedly restarting a crashed data decoder service,
+    // don't add a connection error handler here. Wait to establish a
+    // new connection after all discovery sessions are stopped.
+    ble_scan_parser_.Bind(ble_scan_parser_callback.Run());
+  } else {
+#if DCHECK_IS_ON()
+    static bool logged_once = false;
+    DLOG_IF(ERROR, !logged_once)
+        << "Attempted to connect to "
+           "unconfigured BluetoothAdapterFactory::GetBleScanParserCallback()";
+    logged_once = true;
+#endif  // DCHECK_IS_ON()
+  }
+#endif  // defined(OS_CHROMEOS)
+
   if (IsPresent()) {
     callback.Run();
   } else {
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.h b/device/bluetooth/bluez/bluetooth_adapter_bluez.h
index cdd9237..0734e5f 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.h
@@ -257,12 +257,14 @@
       device::BluetoothDevice::PairingDelegate* pairing_delegate) override;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(BluetoothBlueZTest, Shutdown);
+  FRIEND_TEST_ALL_PREFIXES(BluetoothBlueZTest, Shutdown_OnStartDiscovery);
+  FRIEND_TEST_ALL_PREFIXES(BluetoothBlueZTest, Shutdown_OnStartDiscoveryError);
+  FRIEND_TEST_ALL_PREFIXES(BluetoothBlueZTest, Shutdown_OnStopDiscovery);
+  FRIEND_TEST_ALL_PREFIXES(BluetoothBlueZTest, Shutdown_OnStopDiscoveryError);
+  FRIEND_TEST_ALL_PREFIXES(BluetoothBlueZTest,
+                           StartDiscovery_DiscoveringStopped_StartAgain);
   friend class BluetoothBlueZTest;
-  friend class BluetoothBlueZTest_Shutdown_Test;
-  friend class BluetoothBlueZTest_Shutdown_OnStartDiscovery_Test;
-  friend class BluetoothBlueZTest_Shutdown_OnStartDiscoveryError_Test;
-  friend class BluetoothBlueZTest_Shutdown_OnStopDiscovery_Test;
-  friend class BluetoothBlueZTest_Shutdown_OnStopDiscoveryError_Test;
   friend class device::BluetoothTestBlueZ;
 
   // typedef for callback parameters that are passed to AddDiscoverySession
diff --git a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
index 9133579..0daebdc 100644
--- a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/task_environment.h"
 #include "dbus/object_path.h"
 #include "device/bluetooth/bluetooth_adapter.h"
@@ -36,6 +37,12 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
+#if defined(OS_CHROMEOS)
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/data_decoder/public/mojom/ble_scan_parser.mojom.h"
+#endif
+
 using device::BluetoothAdapter;
 using device::BluetoothAdapterFactory;
 using device::BluetoothDevice;
@@ -69,6 +76,22 @@
   return -1;
 }
 
+#if defined(OS_CHROMEOS)
+class FakeBleScanParserImpl : public data_decoder::mojom::BleScanParser {
+ public:
+  FakeBleScanParserImpl() = default;
+  ~FakeBleScanParserImpl() override = default;
+
+  // mojom::BleScanParser:
+  void Parse(const std::vector<uint8_t>& advertisement_data,
+             ParseCallback callback) override {
+    std::move(callback).Run(nullptr);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBleScanParserImpl);
+};
+#endif
+
 class FakeBluetoothProfileServiceProviderDelegate
     : public bluez::BluetoothProfileServiceProvider::Delegate {
  public:
@@ -128,6 +151,18 @@
 
     fake_bluetooth_adapter_client_->SetSimulationIntervalMs(10);
 
+#if defined(OS_CHROMEOS)
+    device::BluetoothAdapterFactory::SetBleScanParserCallback(
+        base::BindLambdaForTesting([&]() {
+          mojo::PendingRemote<data_decoder::mojom::BleScanParser>
+              ble_scan_parser;
+          mojo::MakeSelfOwnedReceiver(
+              std::make_unique<FakeBleScanParserImpl>(),
+              ble_scan_parser.InitWithNewPipeAndPassReceiver());
+          return ble_scan_parser;
+        }));
+#endif
+
     callback_count_ = 0;
     error_callback_count_ = 0;
     last_connect_error_ = BluetoothDevice::ERROR_UNKNOWN;
@@ -135,6 +170,11 @@
   }
 
   void TearDown() override {
+#if defined(OS_CHROMEOS)
+    device::BluetoothAdapterFactory::SetBleScanParserCallback(
+        base::NullCallback());
+#endif
+
     for (const auto& session : discovery_sessions_) {
       if (!session->IsActive())
         continue;
@@ -4207,6 +4247,37 @@
   adapter_->RemovePairingDelegate(&pairing_delegate2);
 }
 
+TEST_F(BluetoothBlueZTest, StartDiscovery_DiscoveringStopped_StartAgain) {
+  GetAdapter();
+  BluetoothAdapterBlueZ* adapter_bluez =
+      static_cast<BluetoothAdapterBlueZ*>(adapter_.get());
+  {
+    base::RunLoop loop;
+    adapter_->StartDiscoverySession(
+        base::BindLambdaForTesting(
+            [&](std::unique_ptr<BluetoothDiscoverySession> session) {
+              loop.Quit();
+            }),
+        base::BindRepeating([]() {
+          ADD_FAILURE() << "Unexpected discovery session start error.";
+        }));
+    loop.Run();
+  }
+  adapter_bluez->DiscoveringChanged(false);
+  {
+    base::RunLoop loop;
+    adapter_->StartDiscoverySession(
+        base::BindLambdaForTesting(
+            [&](std::unique_ptr<BluetoothDiscoverySession> session) {
+              loop.Quit();
+            }),
+        base::BindRepeating([]() {
+          ADD_FAILURE() << "Unexpected discovery session start error.";
+        }));
+    loop.Run();
+  }
+}
+
 // Verifies post-Shutdown of discovery sessions and OnStartDiscovery.
 TEST_F(BluetoothBlueZTest, Shutdown_OnStartDiscovery) {
   const int kNumberOfDiscoverySessions = 10;
@@ -4314,6 +4385,35 @@
   EXPECT_EQ(kNumberOfDiscoverySessions, error_callback_count_);
 }
 
+TEST_F(BluetoothBlueZTest, StartDiscoveryError_ThenStartAgain) {
+  GetAdapter();
+  fake_bluetooth_adapter_client_->MakeStartDiscoveryFail();
+
+  {
+    base::RunLoop loop;
+    adapter_->StartDiscoverySession(
+        base::BindRepeating(
+            [](std::unique_ptr<BluetoothDiscoverySession> session) {
+              ADD_FAILURE() << "Unexpected discovery session start success.";
+            }),
+        loop.QuitClosure());
+    loop.Run();
+  }
+
+  {
+    base::RunLoop loop;
+    adapter_->StartDiscoverySession(
+        base::BindLambdaForTesting(
+            [&](std::unique_ptr<BluetoothDiscoverySession> session) {
+              loop.Quit();
+            }),
+        base::BindRepeating([]() {
+          ADD_FAILURE() << "Unexpected discovery session start error.";
+        }));
+    loop.Run();
+  }
+}
+
 TEST_F(BluetoothBlueZTest, ManufacturerDataChanged) {
   const BluetoothDevice::ManufacturerId kManufacturerId1 = 0x1234;
   const BluetoothDevice::ManufacturerId kManufacturerId2 = 0x2345;
diff --git a/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc b/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
index e9dd80f..45dfdecd 100644
--- a/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
@@ -142,6 +142,13 @@
     return;
   }
 
+  if (set_start_discovery_should_fail_) {
+    set_start_discovery_should_fail_ = false;
+    PostDelayedTask(
+        base::BindOnce(std::move(callback), Error(kUnknownAdapterError, "")));
+    return;
+  }
+
   ++discovering_count_;
   VLOG(1) << "StartDiscovery: " << object_path.value() << ", "
           << "count is now " << discovering_count_;
@@ -234,6 +241,10 @@
   set_discovery_filter_should_fail_ = true;
 }
 
+void FakeBluetoothAdapterClient::MakeStartDiscoveryFail() {
+  set_start_discovery_should_fail_ = true;
+}
+
 void FakeBluetoothAdapterClient::SetDiscoveryFilter(
     const dbus::ObjectPath& object_path,
     const DiscoveryFilter& discovery_filter,
diff --git a/device/bluetooth/dbus/fake_bluetooth_adapter_client.h b/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
index ea34ec9..acec03a 100644
--- a/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
+++ b/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
@@ -91,6 +91,9 @@
   // Make SetDiscoveryFilter fail when called next time.
   void MakeSetDiscoveryFilterFail();
 
+  // Make StartDiscovery fail when called next time.
+  void MakeStartDiscoveryFail();
+
   // Mark the adapter and second adapter as visible or invisible.
   void SetVisible(bool visible);
   void SetSecondVisible(bool visible);
@@ -145,6 +148,9 @@
   // When set, next call to SetDiscoveryFilter would fail.
   bool set_discovery_filter_should_fail_;
 
+  // When set, next call to StartDiscovery would fail.
+  bool set_start_discovery_should_fail_ = false;
+
   // Current timeout interval used when posting delayed tasks.
   int simulation_interval_ms_;
 
diff --git a/device/gamepad/gamepad_service.cc b/device/gamepad/gamepad_service.cc
index 2795589..d3998dc 100644
--- a/device/gamepad/gamepad_service.cc
+++ b/device/gamepad/gamepad_service.cc
@@ -142,9 +142,9 @@
   auto it = consumers_.find(consumer);
   if (it == consumers_.end())
     return false;
-  DCHECK_GT(num_active_consumers_, 0);
   if (it->is_active && --num_active_consumers_ == 0)
     provider_->Pause();
+  DCHECK_GE(num_active_consumers_, 0);
   consumers_.erase(it);
   inactive_consumer_state_.erase(consumer);
   return true;
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn
index 775c999..08993949 100644
--- a/device/vr/BUILD.gn
+++ b/device/vr/BUILD.gn
@@ -241,8 +241,8 @@
         "openxr/openxr_controller.h",
         "openxr/openxr_device.cc",
         "openxr/openxr_device.h",
-        "openxr/openxr_gamepad_helper.cc",
-        "openxr/openxr_gamepad_helper.h",
+        "openxr/openxr_input_helper.cc",
+        "openxr/openxr_input_helper.h",
         "openxr/openxr_render_loop.cc",
         "openxr/openxr_render_loop.h",
         "openxr/openxr_util.cc",
diff --git a/device/vr/openxr/openxr_api_wrapper.cc b/device/vr/openxr/openxr_api_wrapper.cc
index 7cf7f0d..1a5abc08 100644
--- a/device/vr/openxr/openxr_api_wrapper.cc
+++ b/device/vr/openxr/openxr_api_wrapper.cc
@@ -10,7 +10,7 @@
 #include <array>
 
 #include "base/logging.h"
-#include "device/vr/openxr/openxr_gamepad_helper.h"
+#include "device/vr/openxr/openxr_input_helper.h"
 #include "device/vr/openxr/openxr_util.h"
 #include "device/vr/test/test_hook.h"
 #include "ui/gfx/geometry/point3_f.h"
@@ -279,7 +279,7 @@
 // objects that may have been created before the failure.
 XrResult OpenXrApiWrapper::InitSession(
     const Microsoft::WRL::ComPtr<ID3D11Device>& d3d_device,
-    std::unique_ptr<OpenXrGamepadHelper>* gamepad_helper) {
+    std::unique_ptr<OpenXRInputHelper>* input_helper) {
   DCHECK(d3d_device.Get());
   DCHECK(IsInitialized());
 
@@ -290,7 +290,7 @@
   RETURN_IF_XR_FAILED(
       CreateSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, &local_space_));
   RETURN_IF_XR_FAILED(CreateSpace(XR_REFERENCE_SPACE_TYPE_VIEW, &view_space_));
-  RETURN_IF_XR_FAILED(CreateGamepadHelper(gamepad_helper));
+  RETURN_IF_XR_FAILED(CreateGamepadHelper(input_helper));
 
   // It's ok if stage_space_ fails since not all OpenXR devices are required to
   // support this reference space.
@@ -307,7 +307,7 @@
   DCHECK(HasColorSwapChain());
   DCHECK(HasSpace(XR_REFERENCE_SPACE_TYPE_LOCAL));
   DCHECK(HasSpace(XR_REFERENCE_SPACE_TYPE_VIEW));
-  DCHECK(gamepad_helper);
+  DCHECK(input_helper);
 
   return xr_result;
 }
@@ -388,12 +388,12 @@
 }
 
 XrResult OpenXrApiWrapper::CreateGamepadHelper(
-    std::unique_ptr<OpenXrGamepadHelper>* gamepad_helper) {
+    std::unique_ptr<OpenXRInputHelper>* input_helper) {
   DCHECK(HasSession());
   DCHECK(HasSpace(XR_REFERENCE_SPACE_TYPE_LOCAL));
 
-  return OpenXrGamepadHelper::CreateOpenXrGamepadHelper(
-      instance_, session_, local_space_, gamepad_helper);
+  return OpenXRInputHelper::CreateOpenXRInputHelper(instance_, session_,
+                                                    local_space_, input_helper);
 }
 
 XrResult OpenXrApiWrapper::BeginSession() {
diff --git a/device/vr/openxr/openxr_api_wrapper.h b/device/vr/openxr/openxr_api_wrapper.h
index 1848822..f5fbbf94 100644
--- a/device/vr/openxr/openxr_api_wrapper.h
+++ b/device/vr/openxr/openxr_api_wrapper.h
@@ -26,7 +26,7 @@
 
 namespace device {
 
-class OpenXrGamepadHelper;
+class OpenXRInputHelper;
 class VRTestHook;
 class ServiceTestHook;
 
@@ -46,7 +46,7 @@
   bool session_ended() const { return session_ended_; }
 
   XrResult InitSession(const Microsoft::WRL::ComPtr<ID3D11Device>& d3d_device,
-                       std::unique_ptr<OpenXrGamepadHelper>* gamepad_helper);
+                       std::unique_ptr<OpenXRInputHelper>* input_helper);
 
   XrResult BeginFrame(Microsoft::WRL::ComPtr<ID3D11Texture2D>* texture);
   XrResult EndFrame();
@@ -79,7 +79,7 @@
   XrResult CreateSwapchain();
   XrResult CreateSpace(XrReferenceSpaceType type, XrSpace* space);
   XrResult CreateGamepadHelper(
-      std::unique_ptr<OpenXrGamepadHelper>* gamepad_helper);
+      std::unique_ptr<OpenXRInputHelper>* input_helper);
 
   XrResult BeginSession();
   XrResult UpdateProjectionLayers();
diff --git a/device/vr/openxr/openxr_controller.cc b/device/vr/openxr/openxr_controller.cc
index 4824d13b..67d9f1a 100644
--- a/device/vr/openxr/openxr_controller.cc
+++ b/device/vr/openxr/openxr_controller.cc
@@ -7,8 +7,12 @@
 #include <stdint.h>
 
 #include "base/logging.h"
+#include "device/gamepad/public/cpp/gamepads.h"
 #include "device/vr/openxr/openxr_util.h"
 #include "device/vr/public/mojom/vr_service.mojom.h"
+#include "device/vr/util/xr_standard_gamepad_builder.h"
+#include "ui/gfx/geometry/quaternion.h"
+#include "ui/gfx/transform_util.h"
 
 namespace device {
 
@@ -17,22 +21,32 @@
 constexpr char kMicrosoftInteractionProfileName[] =
     "/interaction_profiles/microsoft/motion_controller";
 
-const char* GetStringFromType(OpenXrControllerType type) {
+const char* GetStringFromType(OpenXrHandednessType type) {
   switch (type) {
-    case OpenXrControllerType::kLeft:
+    case OpenXrHandednessType::kLeft:
       return "left";
-    case OpenXrControllerType::kRight:
+    case OpenXrHandednessType::kRight:
       return "right";
-    default:
+    case OpenXrHandednessType::kCount:
       NOTREACHED();
       return "";
   }
 }
 
+mojom::XRGamepadButtonPtr GetXRGamepadButtonPtr(
+    base::Optional<GamepadButton> button) {
+  mojom::XRGamepadButtonPtr ret = mojom::XRGamepadButton::New();
+  ret->pressed = button->pressed;
+  ret->touched = button->touched;
+  ret->value = button->value;
+  return ret;
+}
+
 }  // namespace
 
 OpenXrController::OpenXrController()
-    : type_(OpenXrControllerType::kCount),  // COUNT refers to invalid.
+    : description_(nullptr),
+      type_(OpenXrHandednessType::kCount),  // COUNT refers to invalid.
       session_(XR_NULL_HANDLE),
       action_set_(XR_NULL_HANDLE),
       grip_pose_action_{XR_NULL_HANDLE},
@@ -51,15 +65,15 @@
 }
 
 XrResult OpenXrController::Initialize(
-    OpenXrControllerType type,
+    OpenXrHandednessType type,
     XrInstance instance,
     XrSession session,
     std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings) {
   type_ = type;
   session_ = session;
-  std::string type_string = GetStringFromType(type_);
+  std::string handedness_string = GetStringFromType(type_);
 
-  std::string action_set_name = type_string + "_action_set";
+  std::string action_set_name = handedness_string + "_action_set";
   XrActionSetCreateInfo action_set_create_info = {
       XR_TYPE_ACTION_SET_CREATE_INFO};
 
@@ -75,20 +89,15 @@
   RETURN_IF_XR_FAILED(
       xrCreateActionSet(instance, &action_set_create_info, &action_set_));
 
-  RETURN_IF_XR_FAILED(
-      InitializeMicrosoftMotionControllers(instance, type_string, bindings));
+  RETURN_IF_XR_FAILED(InitializeMicrosoftMotionControllerActions(
+      instance, handedness_string, bindings));
 
-  XrActionSpaceCreateInfo action_space_create_info = {};
-  action_space_create_info.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
-  action_space_create_info.action = grip_pose_action_;
-  action_space_create_info.subactionPath = XR_NULL_PATH;
-  action_space_create_info.poseInActionSpace = PoseIdentity();
-  RETURN_IF_XR_FAILED(xrCreateActionSpace(session_, &action_space_create_info,
-                                          &grip_pose_space_));
+  RETURN_IF_XR_FAILED(InitializeMicrosoftMotionControllerSpaces());
+
   return xr_result;
 }
 
-XrResult OpenXrController::InitializeMicrosoftMotionControllers(
+XrResult OpenXrController::InitializeMicrosoftMotionControllerActions(
     XrInstance instance,
     const std::string& type_string,
     std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings) {
@@ -99,29 +108,41 @@
 
   RETURN_IF_XR_FAILED(CreateAction(
       instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
+      binding_prefix + "trigger/value", name_prefix + "trigger_button_press",
+      &(button_action_map_[OpenXrButtonType::kTrigger].press_action),
+      bindings));
+
+  RETURN_IF_XR_FAILED(CreateAction(
+      instance, XR_ACTION_TYPE_FLOAT_INPUT, kMicrosoftInteractionProfileName,
+      binding_prefix + "trigger/value", name_prefix + "trigger_button_value",
+      &(button_action_map_[OpenXrButtonType::kTrigger].value_action),
+      bindings));
+
+  RETURN_IF_XR_FAILED(CreateAction(
+      instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
+      binding_prefix + "thumbstick/click",
+      name_prefix + "thumbstick_button_press",
+      &(button_action_map_[OpenXrButtonType::kThumbstick].press_action),
+      bindings));
+
+  RETURN_IF_XR_FAILED(CreateAction(
+      instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
+      binding_prefix + "squeeze/click", name_prefix + "squeeze_button_press",
+      &(button_action_map_[OpenXrButtonType::kSqueeze].press_action),
+      bindings));
+
+  RETURN_IF_XR_FAILED(CreateAction(
+      instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
       binding_prefix + "trackpad/click", name_prefix + "trackpad_button_press",
       &(button_action_map_[OpenXrButtonType::kTrackpad].press_action),
       bindings));
 
   RETURN_IF_XR_FAILED(CreateAction(
       instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
-      binding_prefix + "trigger/value", name_prefix + "trigger_button_press",
-      &(button_action_map_[OpenXrButtonType::kTrigger].press_action),
+      binding_prefix + "trackpad/touch", name_prefix + "trackpad_button_touch",
+      &(button_action_map_[OpenXrButtonType::kTrackpad].touch_action),
       bindings));
 
-  // In OpenXR, this input is called 'squeeze'. However, the rest of Chromium
-  // uses the term 'grip' for this button, so the OpenXrButtonType is named
-  // kGrip for consistency.
-  RETURN_IF_XR_FAILED(CreateAction(
-      instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
-      binding_prefix + "squeeze/click", name_prefix + "squeeze_button_press",
-      &(button_action_map_[OpenXrButtonType::kGrip].press_action), bindings));
-
-  RETURN_IF_XR_FAILED(CreateAction(
-      instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
-      binding_prefix + "menu/click", name_prefix + "menu_button_press",
-      &(button_action_map_[OpenXrButtonType::kMenu].press_action), bindings));
-
   RETURN_IF_XR_FAILED(CreateAction(
       instance, XR_ACTION_TYPE_VECTOR2F_INPUT, kMicrosoftInteractionProfileName,
       binding_prefix + "trackpad", name_prefix + "trackpad_axis",
@@ -137,20 +158,36 @@
                    kMicrosoftInteractionProfileName, binding_prefix + "grip",
                    name_prefix + "grip_pose", &grip_pose_action_, bindings));
 
+  RETURN_IF_XR_FAILED(
+      CreateAction(instance, XR_ACTION_TYPE_POSE_INPUT,
+                   kMicrosoftInteractionProfileName, binding_prefix + "aim",
+                   name_prefix + "aim_pose", &pointer_pose_action_, bindings));
+
   return xr_result;
 }
 
-uint32_t OpenXrController::GetID() const {
+XrResult OpenXrController::InitializeMicrosoftMotionControllerSpaces() {
+  XrResult xr_result;
+
+  RETURN_IF_XR_FAILED(CreateActionSpace(grip_pose_action_, &grip_pose_space_));
+
+  RETURN_IF_XR_FAILED(
+      CreateActionSpace(pointer_pose_action_, &pointer_pose_space_));
+
+  return xr_result;
+}
+
+uint32_t OpenXrController::GetId() const {
   return static_cast<uint32_t>(type_);
 }
 
 device::mojom::XRHandedness OpenXrController::GetHandness() const {
   switch (type_) {
-    case OpenXrControllerType::kLeft:
+    case OpenXrHandednessType::kLeft:
       return device::mojom::XRHandedness::LEFT;
-    case OpenXrControllerType::kRight:
+    case OpenXrHandednessType::kRight:
       return device::mojom::XRHandedness::RIGHT;
-    default:
+    case OpenXrHandednessType::kCount:
       // LEFT controller and RIGHT controller are currently the only supported
       // controllers. In the future, other controllers such as sound (which
       // does not have a handedness) will be added here.
@@ -159,6 +196,32 @@
   }
 }
 
+device::mojom::XRInputSourceDescriptionPtr OpenXrController::GetDescription(
+    XrTime predicted_display_time) {
+  if (!description_) {
+    description_ = device::mojom::XRInputSourceDescription::New();
+    description_->handedness = GetHandness();
+    description_->target_ray_mode = device::mojom::XRTargetRayMode::POINTING;
+    // TODO(crbug.com/1006072):
+    // Query  USB vendor and product ID From OpenXR.
+    description_->profiles.push_back("windows-mixed-reality");
+    // This makes it clear that the controller actually has a squeeze button,
+    // trigger button, a touchpad and a thumbstick. Otherwise, it's ambiguous
+    // whether slots like the touchpad buttons + axes are hooked up vs just
+    // placeholders.
+    description_->profiles.push_back(
+        "generic-trigger-squeeze-touchpad-thumbstick");
+  }
+  // pointer_offset only need to be set once unless something changed about
+  // controller.
+  if (!description_->pointer_offset) {
+    description_->pointer_offset =
+        GetPointerFromGripTransform(predicted_display_time);
+  }
+
+  return description_.Clone();
+}
+
 std::vector<mojom::XRGamepadButtonPtr> OpenXrController::GetWebVrButtons()
     const {
   std::vector<mojom::XRGamepadButtonPtr> buttons;
@@ -166,37 +229,51 @@
   constexpr uint32_t kNumButtons =
       static_cast<uint32_t>(OpenXrButtonType::kMaxValue) + 1;
   for (uint32_t i = 0; i < kNumButtons; i++) {
-    mojom::XRGamepadButtonPtr mojo_button_ptr =
+    base::Optional<GamepadButton> button =
         GetButton(static_cast<OpenXrButtonType>(i));
-    if (!mojo_button_ptr) {
+    if (button) {
+      buttons.push_back(std::move(GetXRGamepadButtonPtr(button.value())));
+    } else {
       return {};
     }
-
-    buttons.push_back(std::move(mojo_button_ptr));
   }
 
   return buttons;
 }
 
-mojom::XRGamepadButtonPtr OpenXrController::GetButton(
+base::Optional<GamepadButton> OpenXrController::GetButton(
     OpenXrButtonType type) const {
+  GamepadButton ret;
+
+  DCHECK(button_action_map_.count(type) == 1);
+
   XrActionStateBoolean press_state_bool = {XR_TYPE_ACTION_STATE_BOOLEAN};
   if (XR_FAILED(QueryState(button_action_map_.at(type).press_action,
                            &press_state_bool)) ||
       !press_state_bool.isActive) {
-    return nullptr;
+    return base::nullopt;
+  }
+  ret.pressed = press_state_bool.currentState;
+
+  XrActionStateBoolean touch_state_bool = {XR_TYPE_ACTION_STATE_BOOLEAN};
+  if (button_action_map_.at(type).touch_action != XR_NULL_HANDLE &&
+      XR_SUCCEEDED(QueryState(button_action_map_.at(type).touch_action,
+                              &touch_state_bool)) &&
+      touch_state_bool.isActive) {
+    ret.touched = touch_state_bool.currentState;
+  } else {
+    ret.touched = ret.pressed;
   }
 
-  return GetGamepadButton(press_state_bool);
-}
-
-mojom::XRGamepadButtonPtr OpenXrController::GetGamepadButton(
-    const XrActionStateBoolean& action_state) const {
-  mojom::XRGamepadButtonPtr ret = mojom::XRGamepadButton::New();
-  bool button_pressed = action_state.currentState;
-  ret->touched = button_pressed;
-  ret->pressed = button_pressed;
-  ret->value = button_pressed ? 1.0 : 0.0;
+  XrActionStateFloat value_state_float = {XR_TYPE_ACTION_STATE_FLOAT};
+  if (button_action_map_.at(type).value_action != XR_NULL_HANDLE &&
+      XR_SUCCEEDED(QueryState(button_action_map_.at(type).value_action,
+                              &value_state_float)) &&
+      value_state_float.isActive) {
+    ret.value = value_state_float.currentState;
+  } else {
+    ret.value = ret.pressed ? 1.0 : 0.0;
+  }
 
   return ret;
 }
@@ -278,6 +355,44 @@
   return pose;
 }
 
+base::Optional<gfx::Transform> OpenXrController::GetMojoFromGripTransform(
+    XrTime predicted_display_time,
+    XrSpace local_space) const {
+  return GetTransformFromSpaces(predicted_display_time, grip_pose_space_,
+                                local_space);
+}
+
+base::Optional<gfx::Transform> OpenXrController::GetPointerFromGripTransform(
+    XrTime predicted_display_time) const {
+  return GetTransformFromSpaces(predicted_display_time, pointer_pose_space_,
+                                grip_pose_space_);
+}
+
+base::Optional<gfx::Transform> OpenXrController::GetTransformFromSpaces(
+    XrTime predicted_display_time,
+    XrSpace target,
+    XrSpace origin) const {
+  XrSpaceLocation location = {XR_TYPE_SPACE_LOCATION};
+  if (FAILED(
+          xrLocateSpace(target, origin, predicted_display_time, &location)) ||
+      !(location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) ||
+      !(location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT)) {
+    return base::nullopt;
+  }
+
+  // Convert the orientation and translation given by runtime into a
+  // transformation matrix.
+  gfx::DecomposedTransform decomp;
+  decomp.quaternion =
+      gfx::Quaternion(location.pose.orientation.x, location.pose.orientation.y,
+                      location.pose.orientation.z, location.pose.orientation.w);
+  decomp.translate[0] = location.pose.position.x;
+  decomp.translate[1] = location.pose.position.y;
+  decomp.translate[2] = location.pose.position.z;
+
+  return gfx::ComposeTransform(decomp);
+}
+
 XrActionSet OpenXrController::GetActionSet() const {
   return action_set_;
 }
@@ -312,4 +427,13 @@
   return xr_result;
 }
 
+XrResult OpenXrController::CreateActionSpace(XrAction action, XrSpace* space) {
+  XrActionSpaceCreateInfo action_space_create_info = {};
+  action_space_create_info.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
+  action_space_create_info.action = action;
+  action_space_create_info.subactionPath = XR_NULL_PATH;
+  action_space_create_info.poseInActionSpace = PoseIdentity();
+  return xrCreateActionSpace(session_, &action_space_create_info, space);
+}
+
 }  // namespace device
diff --git a/device/vr/openxr/openxr_controller.h b/device/vr/openxr/openxr_controller.h
index 7b430173..8d836b4 100644
--- a/device/vr/openxr/openxr_controller.h
+++ b/device/vr/openxr/openxr_controller.h
@@ -8,15 +8,16 @@
 #include <stdint.h>
 #include <unordered_map>
 
+#include "base/optional.h"
 #include "device/vr/public/mojom/isolated_xr_service.mojom.h"
-#include "device/vr/util/gamepad_builder.h"
 #include "third_party/openxr/src/include/openxr/openxr.h"
+#include "ui/gfx/transform.h"
 
 namespace device {
 
 constexpr uint32_t kAxisDimensions = 2;
 
-enum class OpenXrControllerType {
+enum class OpenXrHandednessType {
   kLeft = 0,
   kRight = 1,
   kCount = 2,
@@ -24,9 +25,9 @@
 
 enum class OpenXrButtonType {
   kTrigger = 0,
-  kTrackpad = 1,
-  kGrip = 2,
-  kMenu = 3,
+  kSqueeze = 1,
+  kTrackpad = 2,
+  kThumbstick = 3,
   kMaxValue = 3,
 };
 
@@ -42,34 +43,50 @@
   ~OpenXrController();
 
   XrResult Initialize(
-      OpenXrControllerType type,
+      OpenXrHandednessType type,
       XrInstance instance,
       XrSession session,
       std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings);
 
   XrActionSet GetActionSet() const;
-  uint32_t GetID() const;
+  uint32_t GetId() const;
   device::mojom::XRHandedness GetHandness() const;
 
+  device::mojom::XRInputSourceDescriptionPtr GetDescription(
+      XrTime predicted_display_time);
+
+  base::Optional<GamepadButton> GetButton(OpenXrButtonType type) const;
   std::vector<mojom::XRGamepadButtonPtr> GetWebVrButtons() const;
+  std::vector<double> GetAxis(OpenXrAxisType type) const;
   std::vector<double> GetWebVrAxes() const;
   mojom::VRPosePtr GetPose(XrTime predicted_display_time,
                            XrSpace local_space) const;
 
+  base::Optional<gfx::Transform> GetMojoFromGripTransform(
+      XrTime predicted_display_time,
+      XrSpace local_space) const;
+
  private:
   // ActionButton struct is used to store all XrAction that is related to the
   // button. For example, we may need to query the analog value for button press
   // which require a seperate XrAction than the current boolean XrAction.
   struct ActionButton {
     XrAction press_action;
-    ActionButton() : press_action(XR_NULL_HANDLE) {}
+    XrAction touch_action;
+    XrAction value_action;
+    ActionButton()
+        : press_action(XR_NULL_HANDLE),
+          touch_action(XR_NULL_HANDLE),
+          value_action(XR_NULL_HANDLE) {}
   };
 
-  XrResult InitializeMicrosoftMotionControllers(
+  XrResult InitializeMicrosoftMotionControllerActions(
       XrInstance instance,
       const std::string& type_string,
       std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings);
 
+  XrResult InitializeMicrosoftMotionControllerSpaces();
+
   XrResult CreateAction(
       XrInstance instance,
       XrActionType type,
@@ -79,6 +96,16 @@
       XrAction* action,
       std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings);
 
+  XrResult CreateActionSpace(XrAction action, XrSpace* space);
+
+  base::Optional<gfx::Transform> GetPointerFromGripTransform(
+      XrTime predicted_display_time) const;
+
+  base::Optional<gfx::Transform> GetTransformFromSpaces(
+      XrTime predicted_display_time,
+      XrSpace target,
+      XrSpace origin) const;
+
   template <typename T>
   XrResult QueryState(XrAction action, T* action_state) const {
     // this function should never be called because each valid XrActionState
@@ -88,6 +115,16 @@
   }
 
   template <>
+  XrResult QueryState<XrActionStateFloat>(
+      XrAction action,
+      XrActionStateFloat* action_state) const {
+    action_state->type = XR_TYPE_ACTION_STATE_FLOAT;
+    XrActionStateGetInfo get_info = {XR_TYPE_ACTION_STATE_GET_INFO};
+    get_info.action = action;
+    return xrGetActionStateFloat(session_, &get_info, action_state);
+  }
+
+  template <>
   XrResult QueryState<XrActionStateBoolean>(
       XrAction action,
       XrActionStateBoolean* action_state) const {
@@ -117,16 +154,15 @@
     return xrGetActionStatePose(session_, &get_info, action_state);
   }
 
-  std::vector<double> GetAxis(OpenXrAxisType type) const;
-  mojom::XRGamepadButtonPtr GetButton(OpenXrButtonType type) const;
-  mojom::XRGamepadButtonPtr GetGamepadButton(
-      const XrActionStateBoolean& action_state) const;
+  device::mojom::XRInputSourceDescriptionPtr description_;
 
-  OpenXrControllerType type_;
+  OpenXrHandednessType type_;
   XrSession session_;
   XrActionSet action_set_;
   XrAction grip_pose_action_;
   XrSpace grip_pose_space_;
+  XrAction pointer_pose_action_;
+  XrSpace pointer_pose_space_;
 
   std::unordered_map<OpenXrButtonType, ActionButton> button_action_map_;
   std::unordered_map<OpenXrAxisType, XrAction> axis_action_map_;
diff --git a/device/vr/openxr/openxr_gamepad_helper.cc b/device/vr/openxr/openxr_gamepad_helper.cc
deleted file mode 100644
index 418d9f7..0000000
--- a/device/vr/openxr/openxr_gamepad_helper.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// 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 "device/vr/openxr/openxr_gamepad_helper.h"
-
-#include "device/vr/openxr/openxr_util.h"
-
-namespace device {
-
-XrResult OpenXrGamepadHelper::CreateOpenXrGamepadHelper(
-    XrInstance instance,
-    XrSession session,
-    XrSpace local_space,
-    std::unique_ptr<OpenXrGamepadHelper>* helper) {
-  XrResult xr_result;
-
-  std::unique_ptr<OpenXrGamepadHelper> new_helper =
-      std::make_unique<OpenXrGamepadHelper>(session, local_space);
-
-  // This map is used to store bindings for different kinds of interaction
-  // profiles. This allows the runtime to choose a different input sources based
-  // on availability.
-  std::map<XrPath, std::vector<XrActionSuggestedBinding>> bindings;
-  DCHECK(new_helper->controllers_.size() ==
-         new_helper->active_action_sets_.size());
-  for (size_t i = 0; i < new_helper->controllers_.size(); i++) {
-    RETURN_IF_XR_FAILED(new_helper->controllers_[i].Initialize(
-        static_cast<OpenXrControllerType>(i), instance, session, &bindings));
-
-    new_helper->active_action_sets_[i].actionSet =
-        new_helper->controllers_[i].GetActionSet();
-    new_helper->active_action_sets_[i].subactionPath = XR_NULL_PATH;
-  }
-
-  for (auto it = bindings.begin(); it != bindings.end(); it++) {
-    XrInteractionProfileSuggestedBinding profile_suggested_bindings = {
-        XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING};
-    profile_suggested_bindings.interactionProfile = it->first;
-    profile_suggested_bindings.suggestedBindings = it->second.data();
-    profile_suggested_bindings.countSuggestedBindings = it->second.size();
-
-    RETURN_IF_XR_FAILED(xrSuggestInteractionProfileBindings(
-        instance, &profile_suggested_bindings));
-  }
-
-  std::vector<XrActionSet> action_sets(new_helper->controllers_.size());
-  for (size_t i = 0; i < new_helper->controllers_.size(); i++) {
-    action_sets[i] = new_helper->controllers_[i].GetActionSet();
-  }
-
-  XrSessionActionSetsAttachInfo attach_info = {
-      XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO};
-  attach_info.countActionSets = action_sets.size();
-  attach_info.actionSets = action_sets.data();
-  RETURN_IF_XR_FAILED(xrAttachSessionActionSets(session, &attach_info));
-
-  *helper = std::move(new_helper);
-  return xr_result;
-}
-
-OpenXrGamepadHelper::OpenXrGamepadHelper(XrSession session, XrSpace local_space)
-    : session_(session), local_space_(local_space) {}
-
-OpenXrGamepadHelper::~OpenXrGamepadHelper() = default;
-
-mojom::XRGamepadDataPtr OpenXrGamepadHelper::GetGamepadData(
-    XrTime predicted_display_time) {
-  XrActionsSyncInfo sync_info = {XR_TYPE_ACTIONS_SYNC_INFO};
-  sync_info.countActiveActionSets = active_action_sets_.size();
-  sync_info.activeActionSets = active_action_sets_.data();
-  if (XR_FAILED(xrSyncActions(session_, &sync_info)))
-    return nullptr;
-
-  mojom::XRGamepadDataPtr gamepad_data_ptr = mojom::XRGamepadData::New();
-  for (const OpenXrController& controller : controllers_) {
-    mojom::XRGamepadPtr gamepad_ptr = mojom::XRGamepad::New();
-    gamepad_ptr->controller_id = controller.GetID();
-    gamepad_ptr->timestamp = base::TimeTicks::Now();
-    gamepad_ptr->hand = controller.GetHandness();
-
-    std::vector<mojom::XRGamepadButtonPtr> buttons =
-        controller.GetWebVrButtons();
-    if (buttons.empty())
-      continue;
-    gamepad_ptr->buttons = std::move(buttons);
-
-    std::vector<double> axes = controller.GetWebVrAxes();
-    if (axes.empty())
-      continue;
-    gamepad_ptr->axes = std::move(axes);
-
-    gamepad_ptr->pose =
-        controller.GetPose(predicted_display_time, local_space_);
-    if (!gamepad_ptr->pose)
-      continue;
-    gamepad_ptr->can_provide_position = gamepad_ptr->pose->position.has_value();
-    gamepad_ptr->can_provide_orientation =
-        gamepad_ptr->pose->orientation.has_value();
-
-    gamepad_data_ptr->gamepads.push_back(std::move(gamepad_ptr));
-  }
-
-  return gamepad_data_ptr;
-}
-
-}  // namespace device
diff --git a/device/vr/openxr/openxr_gamepad_helper.h b/device/vr/openxr/openxr_gamepad_helper.h
deleted file mode 100644
index f5e6763d..0000000
--- a/device/vr/openxr/openxr_gamepad_helper.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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 DEVICE_VR_OPENXR_OPENXR_GAMEPAD_HELPER_H_
-#define DEVICE_VR_OPENXR_OPENXR_GAMEPAD_HELPER_H_
-
-#include "device/vr/openxr/openxr_controller.h"
-#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
-
-namespace device {
-
-class OpenXrGamepadHelper {
- public:
-  static XrResult CreateOpenXrGamepadHelper(
-      XrInstance instance,
-      XrSession session,
-      XrSpace local_space,
-      std::unique_ptr<OpenXrGamepadHelper>* helper);
-
-  OpenXrGamepadHelper(XrSession session, XrSpace local_space);
-
-  ~OpenXrGamepadHelper();
-
-  mojom::XRGamepadDataPtr GetGamepadData(XrTime predicted_display_time);
-
- private:
-  XrSession session_;
-  XrSpace local_space_;
-
-  std::array<OpenXrController,
-             static_cast<size_t>(OpenXrControllerType::kCount)>
-      controllers_;
-  std::array<XrActiveActionSet,
-             static_cast<size_t>(OpenXrControllerType::kCount)>
-      active_action_sets_;
-
-  DISALLOW_COPY_AND_ASSIGN(OpenXrGamepadHelper);
-};
-
-}  // namespace device
-
-#endif  // DEVICE_VR_OPENXR_OPENXR_GAMEPAD_HELPER_H_
diff --git a/device/vr/openxr/openxr_input_helper.cc b/device/vr/openxr/openxr_input_helper.cc
new file mode 100644
index 0000000..6a8cfa2
--- /dev/null
+++ b/device/vr/openxr/openxr_input_helper.cc
@@ -0,0 +1,235 @@
+// 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 "device/vr/openxr/openxr_input_helper.h"
+
+#include "device/vr/openxr/openxr_util.h"
+#include "device/vr/util/xr_standard_gamepad_builder.h"
+
+namespace device {
+
+namespace {
+base::Optional<GamepadBuilder::ButtonData> GetAxisButtonData(
+    OpenXrAxisType openxr_button_type,
+    base::Optional<GamepadButton> button_data,
+    std::vector<double> axis) {
+  GamepadBuilder::ButtonData data;
+  if (!button_data || axis.size() != 2) {
+    return base::nullopt;
+  }
+
+  switch (openxr_button_type) {
+    case OpenXrAxisType::kThumbstick:
+      data.type = GamepadBuilder::ButtonData::Type::kThumbstick;
+      break;
+    case OpenXrAxisType::kTrackpad:
+      data.type = GamepadBuilder::ButtonData::Type::kTouchpad;
+      break;
+  }
+  data.touched = button_data->touched;
+  data.pressed = button_data->pressed;
+  data.value = button_data->value;
+  // Invert the y axis because -1 is up in the Gamepad API, but down in
+  // OpenXR.
+  data.x_axis = axis.at(0);
+  data.y_axis = -axis.at(1);
+  return data;
+}
+}  // namespace
+
+XrResult OpenXRInputHelper::CreateOpenXRInputHelper(
+    XrInstance instance,
+    XrSession session,
+    XrSpace local_space,
+    std::unique_ptr<OpenXRInputHelper>* helper) {
+  XrResult xr_result;
+
+  std::unique_ptr<OpenXRInputHelper> new_helper =
+      std::make_unique<OpenXRInputHelper>(session, local_space);
+
+  // This map is used to store bindings for different kinds of interaction
+  // profiles. This allows the runtime to choose a different input sources based
+  // on availability.
+  std::map<XrPath, std::vector<XrActionSuggestedBinding>> bindings;
+
+  for (size_t i = 0; i < new_helper->controller_states_.size(); i++) {
+    RETURN_IF_XR_FAILED(new_helper->controller_states_[i].controller.Initialize(
+        static_cast<OpenXrHandednessType>(i), instance, session, &bindings));
+    new_helper->controller_states_[i].primary_button_pressed = false;
+  }
+
+  for (auto it = bindings.begin(); it != bindings.end(); it++) {
+    XrInteractionProfileSuggestedBinding profile_suggested_bindings = {
+        XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING};
+    profile_suggested_bindings.interactionProfile = it->first;
+    profile_suggested_bindings.suggestedBindings = it->second.data();
+    profile_suggested_bindings.countSuggestedBindings = it->second.size();
+
+    RETURN_IF_XR_FAILED(xrSuggestInteractionProfileBindings(
+        instance, &profile_suggested_bindings));
+  }
+
+  std::vector<XrActionSet> action_sets(new_helper->controller_states_.size());
+  for (size_t i = 0; i < new_helper->controller_states_.size(); i++) {
+    action_sets[i] =
+        new_helper->controller_states_[i].controller.GetActionSet();
+  }
+
+  XrSessionActionSetsAttachInfo attach_info = {
+      XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO};
+  attach_info.countActionSets = action_sets.size();
+  attach_info.actionSets = action_sets.data();
+  RETURN_IF_XR_FAILED(xrAttachSessionActionSets(session, &attach_info));
+
+  *helper = std::move(new_helper);
+  return xr_result;
+}
+
+OpenXRInputHelper::OpenXRInputHelper(XrSession session, XrSpace local_space)
+    : session_(session), local_space_(local_space) {}
+
+OpenXRInputHelper::~OpenXRInputHelper() = default;
+
+mojom::XRGamepadDataPtr OpenXRInputHelper::GetGamepadData(
+    XrTime predicted_display_time) {
+  if (XR_FAILED(SyncActions(predicted_display_time)))
+    return nullptr;
+
+  mojom::XRGamepadDataPtr gamepad_data_ptr = mojom::XRGamepadData::New();
+  for (const OpenXrControllerState& controller_state : controller_states_) {
+    const OpenXrController& controller = controller_state.controller;
+    mojom::XRGamepadPtr gamepad_ptr = mojom::XRGamepad::New();
+    gamepad_ptr->controller_id = controller.GetId();
+    gamepad_ptr->timestamp = base::TimeTicks::Now();
+    gamepad_ptr->hand = controller.GetHandness();
+
+    std::vector<mojom::XRGamepadButtonPtr> buttons =
+        controller.GetWebVrButtons();
+    if (buttons.empty())
+      continue;
+    gamepad_ptr->buttons = std::move(buttons);
+
+    std::vector<double> axes = controller.GetWebVrAxes();
+    if (axes.empty())
+      continue;
+    gamepad_ptr->axes = std::move(axes);
+
+    gamepad_ptr->pose =
+        controller.GetPose(predicted_display_time, local_space_);
+    if (!gamepad_ptr->pose)
+      continue;
+    gamepad_ptr->can_provide_position = gamepad_ptr->pose->position.has_value();
+    gamepad_ptr->can_provide_orientation =
+        gamepad_ptr->pose->orientation.has_value();
+
+    gamepad_data_ptr->gamepads.push_back(std::move(gamepad_ptr));
+  }
+
+  return gamepad_data_ptr;
+}
+
+std::vector<mojom::XRInputSourceStatePtr> OpenXRInputHelper::GetInputState(
+    XrTime predicted_display_time) {
+  std::vector<mojom::XRInputSourceStatePtr> input_states;
+  if (XR_FAILED(SyncActions(predicted_display_time))) {
+    for (OpenXrControllerState& state : controller_states_) {
+      state.primary_button_pressed = false;
+    }
+    return input_states;
+  }
+
+  for (uint32_t i = 0; i < controller_states_.size(); i++) {
+    device::OpenXrController* controller = &controller_states_[i].controller;
+
+    base::Optional<GamepadButton> trigger_button =
+        controller->GetButton(OpenXrButtonType::kTrigger);
+
+    // Having a trigger button is the minimum for an webxr input.
+    // No trigger button indicates input is not connected.
+    if (!trigger_button) {
+      continue;
+    }
+
+    device::mojom::XRInputSourceStatePtr state =
+        device::mojom::XRInputSourceState::New();
+
+    // ID 0 will cause a DCHECK in the hash table used on the blink side.
+    // To ensure that we don't have any collisions with other ids, increment
+    // all of the ids by one.
+    state->source_id = i + 1;
+
+    state->description = controller->GetDescription(predicted_display_time);
+
+    state->grip = controller->GetMojoFromGripTransform(predicted_display_time,
+                                                       local_space_);
+    state->emulated_position = false;
+    state->primary_input_pressed = trigger_button.value().pressed;
+    state->primary_input_clicked =
+        controller_states_[i].primary_button_pressed &&
+        !state->primary_input_pressed;
+    controller_states_[i].primary_button_pressed = state->primary_input_pressed;
+    state->gamepad = GetWebXRGamepad(*controller);
+    input_states.push_back(std::move(state));
+  }
+
+  return input_states;
+}
+
+base::Optional<Gamepad> OpenXRInputHelper::GetWebXRGamepad(
+    const OpenXrController& controller) const {
+  XRStandardGamepadBuilder builder(controller.GetHandness());
+
+  base::Optional<GamepadButton> trigger_button =
+      controller.GetButton(OpenXrButtonType::kTrigger);
+  if (!trigger_button)
+    return base::nullopt;
+
+  builder.SetPrimaryButton(trigger_button.value());
+
+  base::Optional<GamepadButton> squeeze_button =
+      controller.GetButton(OpenXrButtonType::kSqueeze);
+  if (squeeze_button)
+    builder.SetSecondaryButton(squeeze_button.value());
+
+  base::Optional<GamepadButton> trackpad_button =
+      controller.GetButton(OpenXrButtonType::kTrackpad);
+  std::vector<double> trackpad_axis =
+      controller.GetAxis(OpenXrAxisType::kTrackpad);
+  base::Optional<GamepadBuilder::ButtonData> trackpad_button_data =
+      GetAxisButtonData(OpenXrAxisType::kTrackpad, trackpad_button,
+                        trackpad_axis);
+
+  if (trackpad_button_data)
+    builder.SetTouchpadData(trackpad_button_data.value());
+
+  base::Optional<GamepadButton> thumbstick_button =
+      controller.GetButton(OpenXrButtonType::kThumbstick);
+  std::vector<double> thumbstick_axis =
+      controller.GetAxis(OpenXrAxisType::kThumbstick);
+  base::Optional<GamepadBuilder::ButtonData> thumbstick_button_data =
+      GetAxisButtonData(OpenXrAxisType::kThumbstick, thumbstick_button,
+                        thumbstick_axis);
+
+  if (thumbstick_button_data)
+    builder.SetThumbstickData(thumbstick_button_data.value());
+
+  return builder.GetGamepad();
+}
+
+XrResult OpenXRInputHelper::SyncActions(XrTime predicted_display_time) {
+  std::vector<XrActiveActionSet> active_action_sets(controller_states_.size());
+
+  for (size_t i = 0; i < controller_states_.size(); i++) {
+    active_action_sets[i].actionSet =
+        controller_states_[i].controller.GetActionSet();
+    active_action_sets[i].subactionPath = XR_NULL_PATH;
+  }
+
+  XrActionsSyncInfo sync_info = {XR_TYPE_ACTIONS_SYNC_INFO};
+  sync_info.countActiveActionSets = active_action_sets.size();
+  sync_info.activeActionSets = active_action_sets.data();
+  return xrSyncActions(session_, &sync_info);
+}
+
+}  // namespace device
diff --git a/device/vr/openxr/openxr_input_helper.h b/device/vr/openxr/openxr_input_helper.h
new file mode 100644
index 0000000..4e3909e
--- /dev/null
+++ b/device/vr/openxr/openxr_input_helper.h
@@ -0,0 +1,58 @@
+// 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 DEVICE_VR_OPENXR_OPENXR_INPUT_HELPER_H_
+#define DEVICE_VR_OPENXR_OPENXR_INPUT_HELPER_H_
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "base/optional.h"
+
+#include "device/vr/openxr/openxr_controller.h"
+#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+
+namespace device {
+
+class OpenXRInputHelper {
+ public:
+  static XrResult CreateOpenXRInputHelper(
+      XrInstance instance,
+      XrSession session,
+      XrSpace local_space,
+      std::unique_ptr<OpenXRInputHelper>* helper);
+
+  OpenXRInputHelper(XrSession session, XrSpace local_space);
+
+  ~OpenXRInputHelper();
+
+  mojom::XRGamepadDataPtr GetGamepadData(XrTime predicted_display_time);
+
+  std::vector<mojom::XRInputSourceStatePtr> GetInputState(
+      XrTime predicted_display_time);
+
+ private:
+  base::Optional<Gamepad> GetWebXRGamepad(
+      const OpenXrController& controller) const;
+
+  XrResult SyncActions(XrTime predicted_display_time);
+
+  XrSession session_;
+  XrSpace local_space_;
+
+  struct OpenXrControllerState {
+    OpenXrController controller;
+    bool primary_button_pressed;
+  };
+  std::array<OpenXrControllerState,
+             static_cast<size_t>(OpenXrHandednessType::kCount)>
+      controller_states_;
+
+  DISALLOW_COPY_AND_ASSIGN(OpenXRInputHelper);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_VR_OPENXR_OPENXR_INPUT_HELPER_H_
diff --git a/device/vr/openxr/openxr_render_loop.cc b/device/vr/openxr/openxr_render_loop.cc
index a4f5108c..fa4378b9 100644
--- a/device/vr/openxr/openxr_render_loop.cc
+++ b/device/vr/openxr/openxr_render_loop.cc
@@ -7,7 +7,7 @@
 #include <directxmath.h>
 
 #include "device/vr/openxr/openxr_api_wrapper.h"
-#include "device/vr/openxr/openxr_gamepad_helper.h"
+#include "device/vr/openxr/openxr_input_helper.h"
 #include "device/vr/util/transform_utils.h"
 
 namespace device {
@@ -40,10 +40,13 @@
   frame_data->time_delta =
       base::TimeDelta::FromNanoseconds(openxr_->GetPredictedDisplayTime());
 
+  frame_data->pose = mojom::VRPose::New();
+  frame_data->pose->input_state =
+      input_helper_->GetInputState(openxr_->GetPredictedDisplayTime());
+
   base::Optional<gfx::Quaternion> orientation;
   base::Optional<gfx::Point3F> position;
   if (XR_SUCCEEDED(openxr_->GetHeadPose(&orientation, &position))) {
-    frame_data->pose = mojom::VRPose::New();
 
     if (orientation.has_value())
       frame_data->pose->orientation = orientation;
@@ -78,12 +81,12 @@
 }
 
 mojom::XRGamepadDataPtr OpenXrRenderLoop::GetNextGamepadData() {
-  return gamepad_helper_->GetGamepadData(openxr_->GetPredictedDisplayTime());
+  return input_helper_->GetGamepadData(openxr_->GetPredictedDisplayTime());
 }
 
 bool OpenXrRenderLoop::StartRuntime() {
   DCHECK(!openxr_);
-  DCHECK(!gamepad_helper_);
+  DCHECK(!input_helper_);
   DCHECK(!current_display_info_);
 
   // The new wrapper object is stored in a temporary variable instead of
@@ -100,7 +103,7 @@
       !texture_helper_.SetAdapterLUID(luid) ||
       !texture_helper_.EnsureInitialized() ||
       XR_FAILED(
-          openxr->InitSession(texture_helper_.GetDevice(), &gamepad_helper_))) {
+          openxr->InitSession(texture_helper_.GetDevice(), &input_helper_))) {
     texture_helper_.Reset();
     return false;
   }
@@ -111,16 +114,16 @@
   texture_helper_.SetDefaultSize(GetViewSize());
 
   DCHECK(openxr_);
-  DCHECK(gamepad_helper_);
+  DCHECK(input_helper_);
 
   return true;
 }
 
 void OpenXrRenderLoop::StopRuntime() {
-  // Has to reset gamepad_helper_ before reset openxr_. If we destroy openxr_
-  // first, gamepad_helper_destructor will try to call the actual openxr runtime
+  // Has to reset input_helper_ before reset openxr_. If we destroy openxr_
+  // first, input_helper_destructor will try to call the actual openxr runtime
   // rather than the mock in tests.
-  gamepad_helper_.reset();
+  input_helper_.reset();
   openxr_ = nullptr;
   current_display_info_ = nullptr;
   texture_helper_.Reset();
diff --git a/device/vr/openxr/openxr_render_loop.h b/device/vr/openxr/openxr_render_loop.h
index 6c1cb17e..2a59389 100644
--- a/device/vr/openxr/openxr_render_loop.h
+++ b/device/vr/openxr/openxr_render_loop.h
@@ -16,7 +16,7 @@
 namespace device {
 
 class OpenXrApiWrapper;
-class OpenXrGamepadHelper;
+class OpenXRInputHelper;
 
 class OpenXrRenderLoop : public XRCompositorCommon {
  public:
@@ -46,7 +46,7 @@
   bool UpdateStageParameters();
 
   std::unique_ptr<OpenXrApiWrapper> openxr_;
-  std::unique_ptr<OpenXrGamepadHelper> gamepad_helper_;
+  std::unique_ptr<OpenXRInputHelper> input_helper_;
 
   base::RepeatingCallback<void(mojom::VRDisplayInfoPtr)>
       on_display_info_changed_;
diff --git a/device/vr/openxr/test/fake_openxr_impl_api.cc b/device/vr/openxr/test/fake_openxr_impl_api.cc
index 0c26859c..75e8b01 100644
--- a/device/vr/openxr/test/fake_openxr_impl_api.cc
+++ b/device/vr/openxr/test/fake_openxr_impl_api.cc
@@ -112,7 +112,8 @@
   RETURN_IF_XR_FAILED(g_test_helper.ValidateSession(session));
   RETURN_IF_XR_FAILED(
       g_test_helper.ValidateActionSpaceCreateInfo(*create_info));
-  *space = g_test_helper.CreateActionSpace();
+  RETURN_IF_XR_FAILED(g_test_helper.ValidateAction(create_info->action));
+  *space = g_test_helper.CreateActionSpace(create_info->action);
 
   return XR_SUCCESS;
 }
@@ -169,17 +170,7 @@
   RETURN_IF_XR_FAILED(g_test_helper.ValidateXrPosefIsIdentity(
       create_info->poseInReferenceSpace));
 
-  switch (create_info->referenceSpaceType) {
-    case XR_REFERENCE_SPACE_TYPE_LOCAL:
-      *space = g_test_helper.CreateLocalSpace();
-      break;
-    case XR_REFERENCE_SPACE_TYPE_VIEW:
-      *space = g_test_helper.CreateViewSpace();
-      break;
-    default:
-      RETURN_IF_FALSE(false, XR_ERROR_VALIDATION_FAILURE,
-                      "XrReferenceSpaceCreateInfo referenceSpaceType invalid");
-  }
+  *space = g_test_helper.CreateReferenceSpace(create_info->referenceSpaceType);
 
   return XR_SUCCESS;
 }
@@ -449,6 +440,26 @@
                   "Unable to create query DXGI Adapter");
 }
 
+XrResult xrGetActionStateFloat(XrSession session,
+                               const XrActionStateGetInfo* get_info,
+                               XrActionStateFloat* state) {
+  DLOG(INFO) << __FUNCTION__;
+  XrResult xr_result;
+  RETURN_IF_XR_FAILED(g_test_helper.ValidateSession(session));
+  RETURN_IF(get_info->type != XR_TYPE_ACTION_STATE_GET_INFO,
+            XR_ERROR_VALIDATION_FAILURE,
+            "xrGetActionStateFloat get_info has wrong type");
+  RETURN_IF_XR_FAILED(g_test_helper.ValidateAction(get_info->action));
+  RETURN_IF(get_info->subactionPath != XR_NULL_PATH,
+            XR_ERROR_VALIDATION_FAILURE,
+            "xrGetActionStateFloat has subactionPath != nullptr which is not "
+            "supported by current version of test.");
+  RETURN_IF_XR_FAILED(
+      g_test_helper.GetActionStateFloat(get_info->action, state));
+
+  return XR_SUCCESS;
+}
+
 XrResult xrGetActionStateBoolean(XrSession session,
                                  const XrActionStateGetInfo* get_info,
                                  XrActionStateBoolean* state) {
@@ -561,7 +572,7 @@
   RETURN_IF_XR_FAILED(g_test_helper.ValidateSpace(baseSpace));
   RETURN_IF_XR_FAILED(g_test_helper.ValidatePredictedDisplayTime(time));
 
-  g_test_helper.GetPose(&(location->pose));
+  g_test_helper.LocateSpace(space, &(location->pose));
 
   location->locationFlags = XR_SPACE_LOCATION_ORIENTATION_VALID_BIT |
                             XR_SPACE_LOCATION_POSITION_VALID_BIT;
diff --git a/device/vr/openxr/test/openxr_negotiate.h b/device/vr/openxr/test/openxr_negotiate.h
index a1b0221c..4eea098 100644
--- a/device/vr/openxr/test/openxr_negotiate.h
+++ b/device/vr/openxr/test/openxr_negotiate.h
@@ -68,6 +68,8 @@
   } else if (strcmp(name, "xrGetD3D11GraphicsRequirementsKHR") == 0) {
     *function =
         reinterpret_cast<PFN_xrVoidFunction>(xrGetD3D11GraphicsRequirementsKHR);
+  } else if (strcmp(name, "xrGetActionStateFloat") == 0) {
+    *function = reinterpret_cast<PFN_xrVoidFunction>(xrGetActionStateFloat);
   } else if (strcmp(name, "xrGetActionStateBoolean") == 0) {
     *function = reinterpret_cast<PFN_xrVoidFunction>(xrGetActionStateBoolean);
   } else if (strcmp(name, "xrGetActionStateVector2f") == 0) {
diff --git a/device/vr/openxr/test/openxr_test_helper.cc b/device/vr/openxr/test/openxr_test_helper.cc
index 9491b52..24b05180 100644
--- a/device/vr/openxr/test/openxr_test_helper.cc
+++ b/device/vr/openxr/test/openxr_test_helper.cc
@@ -52,8 +52,6 @@
       session_(XR_NULL_HANDLE),
       session_state_(XR_SESSION_STATE_UNKNOWN),
       swapchain_(XR_NULL_HANDLE),
-      local_space_(XR_NULL_HANDLE),
-      view_space_(XR_NULL_HANDLE),
       acquired_swapchain_texture_(0),
       next_action_space_(0),
       next_predicted_display_time_(0) {}
@@ -127,6 +125,18 @@
   return swapchain_;
 }
 
+XrResult OpenXrTestHelper::GetActionStateFloat(XrAction action,
+                                               XrActionStateFloat* data) const {
+  XrResult xr_result;
+
+  RETURN_IF_XR_FAILED(ValidateAction(action));
+  const ActionProperties& cur_action_properties = actions_.at(action);
+  RETURN_IF(cur_action_properties.type != XR_ACTION_TYPE_FLOAT_INPUT,
+            XR_ERROR_ACTION_TYPE_MISMATCH, "GetActionStateFloat type mismatch");
+  *data = float_action_states_.at(action);
+  return XR_SUCCESS;
+}
+
 XrResult OpenXrTestHelper::GetActionStateBoolean(
     XrAction action,
     XrActionStateBoolean* data) const {
@@ -168,14 +178,20 @@
   return XR_SUCCESS;
 }
 
-XrSpace OpenXrTestHelper::CreateLocalSpace() {
-  local_space_ = TreatIntegerAsHandle<XrSpace>(++next_action_space_);
-  return local_space_;
-}
-
-XrSpace OpenXrTestHelper::CreateViewSpace() {
-  view_space_ = TreatIntegerAsHandle<XrSpace>(++next_action_space_);
-  return view_space_;
+XrSpace OpenXrTestHelper::CreateReferenceSpace(XrReferenceSpaceType type) {
+  XrSpace cur_space = TreatIntegerAsHandle<XrSpace>(++next_action_space_);
+  switch (type) {
+    case XR_REFERENCE_SPACE_TYPE_VIEW:
+      reference_spaces_[cur_space] = "/reference_space/view";
+      break;
+    case XR_REFERENCE_SPACE_TYPE_LOCAL:
+      reference_spaces_[cur_space] = "/reference_space/local";
+      break;
+    default:
+      NOTREACHED() << "Test currently only supports to create View space and "
+                      "local space";
+  }
+  return cur_space;
 }
 
 XrAction OpenXrTestHelper::CreateAction(XrActionSet action_set,
@@ -187,6 +203,10 @@
   ActionProperties cur_action_properties;
   cur_action_properties.type = create_info.actionType;
   switch (create_info.actionType) {
+    case XR_ACTION_TYPE_FLOAT_INPUT: {
+      float_action_states_[cur_action];
+      break;
+    }
     case XR_ACTION_TYPE_BOOLEAN_INPUT: {
       boolean_action_states_[cur_action];
       break;
@@ -222,8 +242,10 @@
   return cur_action_set;
 }
 
-XrSpace OpenXrTestHelper::CreateActionSpace() {
-  return TreatIntegerAsHandle<XrSpace>(++next_action_space_);
+XrSpace OpenXrTestHelper::CreateActionSpace(XrAction action) {
+  XrSpace cur_space = TreatIntegerAsHandle<XrSpace>(++next_action_space_);
+  action_spaces_[cur_space] = action;
+  return cur_space;
 }
 
 XrPath OpenXrTestHelper::GetPath(const char* path_string) {
@@ -258,6 +280,8 @@
             "BindActionAndPath action is bind to more than one path, this is "
             "not cupported with current test");
   current_action.binding = binding.binding;
+  std::string path_string = PathToString(current_action.binding);
+  DLOG(ERROR) << path_string;
   return XR_SUCCESS;
 }
 
@@ -307,27 +331,23 @@
   RETURN_IF_FALSE(
       support_path, XR_ERROR_VALIDATION_FAILURE,
       "UpdateAction this action has a path that is not supported by test now");
-  device::ControllerFrameData data;
-  device::ControllerRole role;
-  if (PathContainsString(path_string, "/user/hand/left/")) {
-    role = device::kControllerRoleLeft;
-  } else if (PathContainsString(path_string, "/user/hand/right/")) {
-    role = device::kControllerRoleRight;
-  } else {
-    LOG(ERROR) << "Currently Action should belong to either left or right";
-    NOTREACHED();
-  }
-  for (uint32_t i = 0; i < data_arr_.size(); i++) {
-    if (data_arr_[i].role == role) {
-      data = data_arr_[i];
-    }
-  }
+
+  device::ControllerFrameData data = GetControllerDataFromPath(path_string);
 
   switch (cur_action_properties.type) {
+    case XR_ACTION_TYPE_FLOAT_INPUT: {
+      if (!PathContainsString(path_string, "/trigger")) {
+        NOTREACHED() << "Only trigger button has float action";
+      }
+      float_action_states_[action].isActive = data.is_valid;
+      break;
+    }
     case XR_ACTION_TYPE_BOOLEAN_INPUT: {
       device::XrButtonId button_id = device::kMax;
       if (PathContainsString(path_string, "/trackpad/")) {
         button_id = device::kAxisTrackpad;
+      } else if (PathContainsString(path_string, "/thumbstick/")) {
+        button_id = device::kAxisThumbstick;
       } else if (PathContainsString(path_string, "/trigger/")) {
         button_id = device::kAxisTrigger;
       } else if (PathContainsString(path_string, "/squeeze/")) {
@@ -340,18 +360,43 @@
       uint64_t button_mask = XrButtonMaskFromId(button_id);
 
       // This bool pressed is needed because XrActionStateBoolean.currentState
-      // is XrBool32 which is uint32_t. And it won't behave correctly if we try
-      // to set is using uint64_t value like button_mask. like the following:
-      // boolean_action_states_[].currentState = data.buttons_pressed &
-      // button_mask
-      bool pressed = data.buttons_pressed & button_mask;
-      boolean_action_states_[action].currentState = pressed;
+      // is XrBool32 which is uint32_t. And XrActionStateBoolean.currentState
+      // won't behave correctly if we try to set it using an uint64_t value like
+      // button_mask, like: boolean_action_states_[].currentState =
+      // data.buttons_pressed & button_mask
       boolean_action_states_[action].isActive = data.is_valid;
+      bool button_supported = data.supported_buttons & button_mask;
+
+      if (PathContainsString(path_string, "/value") ||
+          PathContainsString(path_string, "/click")) {
+        bool pressed = data.buttons_pressed & button_mask;
+        boolean_action_states_[action].currentState =
+            button_supported && pressed;
+      } else if (PathContainsString(path_string, "/touch")) {
+        bool touched = data.buttons_touched & button_mask;
+        boolean_action_states_[action].currentState =
+            button_supported && touched;
+      } else {
+        NOTREACHED() << "Boolean actions only supports path string ends with "
+                        "value, click or touch";
+      }
       break;
     }
     case XR_ACTION_TYPE_VECTOR2F_INPUT: {
-      // index is the same as the sequence action is created they should be
-      // consistent when set in the tests
+      device::XrButtonId button_id = device::kMax;
+      if (PathContainsString(path_string, "/trackpad")) {
+        button_id = device::kAxisTrackpad;
+      } else if (PathContainsString(path_string, "/thumbstick")) {
+        button_id = device::kAxisThumbstick;
+      } else {
+        NOTREACHED() << "Path is " << path_string
+                     << "But only Trackpad and thumbstick has 2d vector action";
+      }
+      uint64_t axis_mask = XrAxisOffsetFromId(button_id);
+      v2f_action_states_[action].currentState.x = data.axis_data[axis_mask].x;
+      // we have to negate y because webxr has different direction for y than
+      // openxr
+      v2f_action_states_[action].currentState.y = -data.axis_data[axis_mask].y;
       v2f_action_states_[action].isActive = data.is_valid;
       break;
     }
@@ -417,30 +462,70 @@
   return !session_state_event_queue_.empty();
 }
 
-void OpenXrTestHelper::GetPose(XrPosef* pose) {
-  *pose = device::PoseIdentity();
-
+base::Optional<gfx::Transform> OpenXrTestHelper::GetPose() {
   base::AutoLock lock(lock_);
   if (test_hook_) {
     device::PoseFrameData pose_data = test_hook_->WaitGetPresentingPose();
     if (pose_data.is_valid) {
-      gfx::Transform transform = PoseFrameDataToTransform(pose_data);
-
-      gfx::DecomposedTransform decomposed_transform;
-      bool decomposable =
-          gfx::DecomposeTransform(&decomposed_transform, transform);
-      DCHECK(decomposable);
-
-      pose->orientation.x = decomposed_transform.quaternion.x();
-      pose->orientation.y = decomposed_transform.quaternion.y();
-      pose->orientation.z = decomposed_transform.quaternion.z();
-      pose->orientation.w = decomposed_transform.quaternion.w();
-
-      pose->position.x = decomposed_transform.translate[0];
-      pose->position.y = decomposed_transform.translate[1];
-      pose->position.z = decomposed_transform.translate[2];
+      return PoseFrameDataToTransform(pose_data);
     }
   }
+  return base::nullopt;
+}
+
+device::ControllerFrameData OpenXrTestHelper::GetControllerDataFromPath(
+    std::string path_string) const {
+  device::ControllerRole role;
+  if (PathContainsString(path_string, "/user/hand/left/")) {
+    role = device::kControllerRoleLeft;
+  } else if (PathContainsString(path_string, "/user/hand/right/")) {
+    role = device::kControllerRoleRight;
+  } else {
+    NOTREACHED() << "Currently Path should belong to either left or right";
+  }
+  device::ControllerFrameData data;
+  for (uint32_t i = 0; i < data_arr_.size(); i++) {
+    if (data_arr_[i].role == role) {
+      data = data_arr_[i];
+    }
+  }
+  return data;
+}
+
+void OpenXrTestHelper::LocateSpace(XrSpace space, XrPosef* pose) {
+  *pose = device::PoseIdentity();
+  base::Optional<gfx::Transform> transform = base::nullopt;
+
+  if (reference_spaces_.count(space) == 1) {
+    transform = GetPose();
+  } else if (action_spaces_.count(space) == 1) {
+    XrAction cur_action = action_spaces_.at(space);
+    ActionProperties cur_action_properties = actions_[cur_action];
+    std::string path_string = PathToString(cur_action_properties.binding);
+    device::ControllerFrameData data = GetControllerDataFromPath(path_string);
+    if (data.pose_data.is_valid) {
+      transform = PoseFrameDataToTransform(data.pose_data);
+    }
+  } else {
+    NOTREACHED() << "Locate Space only supports reference space or action "
+                    "space for controller";
+  }
+
+  if (transform) {
+    gfx::DecomposedTransform decomposed_transform;
+    bool decomposable =
+        gfx::DecomposeTransform(&decomposed_transform, transform.value());
+    DCHECK(decomposable);
+
+    pose->orientation.x = decomposed_transform.quaternion.x();
+    pose->orientation.y = decomposed_transform.quaternion.y();
+    pose->orientation.z = decomposed_transform.quaternion.z();
+    pose->orientation.w = decomposed_transform.quaternion.w();
+
+    pose->position.x = decomposed_transform.translate[0];
+    pose->position.y = decomposed_transform.translate[1];
+    pose->position.z = decomposed_transform.translate[2];
+  }
 }
 
 std::string OpenXrTestHelper::PathToString(XrPath path) const {
@@ -578,8 +663,9 @@
 XrResult OpenXrTestHelper::ValidateSpace(XrSpace space) const {
   RETURN_IF(space == XR_NULL_HANDLE, XR_ERROR_HANDLE_INVALID,
             "XrSpace has not been queried");
-  RETURN_IF(MakeHandleGeneric(space) > next_action_space_,
-            XR_ERROR_HANDLE_INVALID, "XrSpace invalid");
+  if (reference_spaces_.count(space) != 1 && action_spaces_.count(space) != 1) {
+    RETURN_IF(true, XR_ERROR_HANDLE_INVALID, "XrSpace invalid");
+  }
 
   return XR_SUCCESS;
 }
diff --git a/device/vr/openxr/test/openxr_test_helper.h b/device/vr/openxr/test/openxr_test_helper.h
index bbcc9b1..7caff71 100644
--- a/device/vr/openxr/test/openxr_test_helper.h
+++ b/device/vr/openxr/test/openxr_test_helper.h
@@ -14,10 +14,15 @@
 #include <unordered_set>
 #include <vector>
 
+#include "base/optional.h"
 #include "base/synchronization/lock.h"
 #include "device/vr/test/test_hook.h"
 #include "third_party/openxr/src/include/openxr/openxr.h"
 
+namespace gfx {
+class Transform;
+}  // namespace gfx
+
 class OpenXrTestHelper : public device::ServiceTestHook {
  public:
   OpenXrTestHelper();
@@ -38,17 +43,17 @@
 
   XrSystemId GetSystemId();
   XrSwapchain GetSwapchain();
+  XrResult GetActionStateFloat(XrAction action, XrActionStateFloat* data) const;
   XrResult GetActionStateBoolean(XrAction action,
                                  XrActionStateBoolean* data) const;
   XrResult GetActionStateVector2f(XrAction action,
                                   XrActionStateVector2f* data) const;
   XrResult GetActionStatePose(XrAction action, XrActionStatePose* data) const;
-  XrSpace CreateLocalSpace();
-  XrSpace CreateViewSpace();
+  XrSpace CreateReferenceSpace(XrReferenceSpaceType type);
   XrAction CreateAction(XrActionSet action_set,
                         const XrActionCreateInfo& create_info);
   XrActionSet CreateActionSet(const XrActionSetCreateInfo& createInfo);
-  XrSpace CreateActionSpace();
+  XrSpace CreateActionSpace(XrAction);
   XrPath GetPath(const char* path_string);
 
   XrResult GetSession(XrSession* session);
@@ -61,7 +66,7 @@
   XrResult SyncActionData(XrActionSet action_set);
   const std::vector<Microsoft::WRL::ComPtr<ID3D11Texture2D>>&
   GetSwapchainTextures() const;
-  void GetPose(XrPosef* pose);
+  void LocateSpace(XrSpace space, XrPosef* pose);
   std::string PathToString(XrPath path) const;
   bool UpdateData();
   bool UpdateViewFOV(XrView views[], uint32_t size);
@@ -114,6 +119,9 @@
 
   XrResult UpdateAction(XrAction action);
   void SetSessionState(XrSessionState state);
+  base::Optional<gfx::Transform> GetPose();
+  device::ControllerFrameData GetControllerDataFromPath(
+      std::string path_string) const;
 
   // Properties of the mock OpenXR runtime that doesn't change throughout the
   // lifetime of the instance. However, these aren't static because they are
@@ -124,8 +132,6 @@
   XrSession session_;
   XrSessionState session_state_;
   XrSwapchain swapchain_;
-  XrSpace local_space_;
-  XrSpace view_space_;
 
   // Properties that changes depending on the state of the runtime.
   Microsoft::WRL::ComPtr<ID3D11Device> d3d_device_;
@@ -141,7 +147,10 @@
   // index_in_action_state_arr member which can help index into the following
   // *_action_states_ vector and retrieve data.
   std::unordered_map<XrAction, ActionProperties> actions_;
+  std::unordered_map<XrSpace, XrAction> action_spaces_;
+  std::unordered_map<XrSpace, std::string> reference_spaces_;
   std::unordered_map<XrActionSet, std::vector<XrAction>> action_sets_;
+  std::unordered_map<XrAction, XrActionStateFloat> float_action_states_;
   std::unordered_map<XrAction, XrActionStateBoolean> boolean_action_states_;
   std::unordered_map<XrAction, XrActionStateVector2f> v2f_action_states_;
   std::unordered_map<XrAction, XrActionStatePose> pose_action_state_;
diff --git a/device/vr/public/mojom/isolated_xr_service.mojom b/device/vr/public/mojom/isolated_xr_service.mojom
index b1dd8b75..7754ce5 100644
--- a/device/vr/public/mojom/isolated_xr_service.mojom
+++ b/device/vr/public/mojom/isolated_xr_service.mojom
@@ -73,8 +73,9 @@
 
   // The browser may register for changes to a device. Initial VRDisplayInfo
   // will immediately be returned to the listener to prevent races.
-  ListenToDeviceChanges(associated XRRuntimeEventListener listener) =>
-      (VRDisplayInfo? display_info);
+  ListenToDeviceChanges(
+      pending_associated_remote<XRRuntimeEventListener> listener) =>
+          (VRDisplayInfo? display_info);
 
   // Ensure that the runtime has installed most prerequisites, and is ready to
   // start. May result in updated display info being sent to registered
diff --git a/device/vr/vr_device_base.cc b/device/vr/vr_device_base.cc
index cd79fb6..1122f329 100644
--- a/device/vr/vr_device_base.cc
+++ b/device/vr/vr_device_base.cc
@@ -43,7 +43,7 @@
 }
 
 void VRDeviceBase::ListenToDeviceChanges(
-    mojom::XRRuntimeEventListenerAssociatedPtrInfo listener_info,
+    mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener> listener_info,
     mojom::XRRuntime::ListenToDeviceChangesCallback callback) {
   listener_.Bind(std::move(listener_info));
   std::move(callback).Run(display_info_.Clone());
diff --git a/device/vr/vr_device_base.h b/device/vr/vr_device_base.h
index 3bb0e28..b12cd79 100644
--- a/device/vr/vr_device_base.h
+++ b/device/vr/vr_device_base.h
@@ -13,7 +13,9 @@
 #include "device/vr/public/mojom/vr_service.mojom.h"
 #include "device/vr/vr_device.h"
 #include "device/vr/vr_export.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "ui/display/display.h"
 
 namespace device {
@@ -28,7 +30,7 @@
 
   // VRDevice Implementation
   void ListenToDeviceChanges(
-      mojom::XRRuntimeEventListenerAssociatedPtrInfo listener,
+      mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener> listener,
       mojom::XRRuntime::ListenToDeviceChangesCallback callback) final;
   void SetListeningForActivate(bool is_listening) override;
   void EnsureInitialized(EnsureInitializedCallback callback) override;
@@ -75,7 +77,7 @@
   // TODO(https://crbug.com/842227): Rename methods to HandleOnXXX
   virtual void OnListeningForActivate(bool listening);
 
-  mojom::XRRuntimeEventListenerAssociatedPtr listener_;
+  mojo::AssociatedRemote<mojom::XRRuntimeEventListener> listener_;
 
   bool presenting_ = false;
 
diff --git a/device/vr/vr_device_base_unittest.cc b/device/vr/vr_device_base_unittest.cc
index 36c01d9..5fd1e29 100644
--- a/device/vr/vr_device_base_unittest.cc
+++ b/device/vr/vr_device_base_unittest.cc
@@ -13,7 +13,7 @@
 #include "device/vr/public/mojom/vr_service.mojom.h"
 #include "device/vr/test/fake_vr_device.h"
 #include "device/vr/vr_device_base.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -52,8 +52,8 @@
 
 class StubVRDeviceEventListener : public mojom::XRRuntimeEventListener {
  public:
-  StubVRDeviceEventListener() : binding_(this) {}
-  ~StubVRDeviceEventListener() override {}
+  StubVRDeviceEventListener() = default;
+  ~StubVRDeviceEventListener() override = default;
 
   MOCK_METHOD1(DoOnChanged, void(mojom::VRDisplayInfo* vr_device_info));
   void OnDisplayInfoChanged(mojom::VRDisplayInfoPtr vr_device_info) override {
@@ -75,13 +75,12 @@
   MOCK_METHOD1(OnDeviceIdle, void(mojom::VRDisplayEventReason));
   MOCK_METHOD0(OnInitialized, void());
 
-  mojom::XRRuntimeEventListenerAssociatedPtrInfo BindPtrInfo() {
-    mojom::XRRuntimeEventListenerAssociatedPtrInfo ret;
-    binding_.Bind(mojo::MakeRequest(&ret));
-    return ret;
+  mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener>
+  BindPendingRemote() {
+    return receiver_.BindNewEndpointAndPassRemote();
   }
 
-  mojo::AssociatedBinding<mojom::XRRuntimeEventListener> binding_;
+  mojo::AssociatedReceiver<mojom::XRRuntimeEventListener> receiver_{this};
 };
 
 }  // namespace
@@ -119,7 +118,7 @@
   auto device_ptr = device->BindXRRuntimePtr();
   StubVRDeviceEventListener listener;
   device_ptr->ListenToDeviceChanges(
-      listener.BindPtrInfo(),
+      listener.BindPendingRemote(),
       base::DoNothing());  // TODO: consider getting initial info
   base::RunLoop().RunUntilIdle();
   EXPECT_CALL(listener, DoOnChanged(testing::_)).Times(1);
@@ -134,7 +133,7 @@
   auto device_ptr = device->BindXRRuntimePtr();
   StubVRDeviceEventListener listener;
   device_ptr->ListenToDeviceChanges(
-      listener.BindPtrInfo(),
+      listener.BindPendingRemote(),
       base::DoNothing());  // TODO: consider getting initial data
   base::RunLoop().RunUntilIdle();
 
diff --git a/docs/media/gpu/video_decoder_test_usage.md b/docs/media/gpu/video_decoder_test_usage.md
index e86cc82..81675a0 100644
--- a/docs/media/gpu/video_decoder_test_usage.md
+++ b/docs/media/gpu/video_decoder_test_usage.md
@@ -67,8 +67,9 @@
     --vmodule            enable verbose mode for the specified module,
                          e.g. --vmodule=*media/gpu*=2.
     --disable_validator  disable frame validation.
-    --output_frames      write all decoded video frames to the
-                         "<testname>" folder.
+    --output_frames      write the selected video frames to disk, possible
+                         values are "all|corrupt", the default output folder
+                         is "<testname>".
     --output_folder      overwrite the default output folder used when
                          "--output_frames" is specified.
     --use_vd             use the new VD-based video decoders, instead of
diff --git a/fuchsia/runners/cast/cast_runner_integration_test.cc b/fuchsia/runners/cast/cast_runner_integration_test.cc
index 2de8956..38d2e6b 100644
--- a/fuchsia/runners/cast/cast_runner_integration_test.cc
+++ b/fuchsia/runners/cast/cast_runner_integration_test.cc
@@ -170,7 +170,9 @@
     constexpr fuchsia::web::ContextFeatureFlags kFeatures = {};
     cast_runner_ = std::make_unique<CastRunner>(
         &outgoing_directory_,
-        WebContentRunner::CreateIncognitoWebContext(kFeatures));
+        WebContentRunner::CreateWebContext(
+            WebContentRunner::BuildCreateContextParams(
+                fidl::InterfaceHandle<fuchsia::io::Directory>(), kFeatures)));
 
     // Connect to the CastRunner's fuchsia.sys.Runner interface.
     fidl::InterfaceHandle<fuchsia::io::Directory> directory;
diff --git a/fuchsia/runners/cast/main.cc b/fuchsia/runners/cast/main.cc
index 7998e29..91e97597 100644
--- a/fuchsia/runners/cast/main.cc
+++ b/fuchsia/runners/cast/main.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <fuchsia/sys/cpp/fidl.h>
 #include <lib/sys/cpp/component_context.h>
 
 #include "base/command_line.h"
@@ -34,9 +35,17 @@
   if (!BUILDFLAG(ENABLE_SOFTWARE_VIDEO_DECODERS))
     features |= fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER_ONLY;
 
+  fuchsia::web::CreateContextParams create_context_params =
+      WebContentRunner::BuildCreateContextParams(
+          fidl::InterfaceHandle<fuchsia::io::Directory>(), features);
+
+  // TODO(b/141956135): Use CrKey version provided by the Agent.
+  create_context_params.set_user_agent_product("CrKey");
+  create_context_params.set_user_agent_version("0");
+
   CastRunner runner(
       base::fuchsia::ComponentContextForCurrentProcess()->outgoing().get(),
-      WebContentRunner::CreateIncognitoWebContext(features));
+      WebContentRunner::CreateWebContext(std::move(create_context_params)));
 
   base::fuchsia::ComponentContextForCurrentProcess()
       ->outgoing()
diff --git a/fuchsia/runners/common/web_content_runner.cc b/fuchsia/runners/common/web_content_runner.cc
index 2469821..f87b726c 100644
--- a/fuchsia/runners/common/web_content_runner.cc
+++ b/fuchsia/runners/common/web_content_runner.cc
@@ -31,29 +31,15 @@
   return directory;
 }
 
-fuchsia::web::ContextPtr CreateWebContextWithDataDirectory(
-    fidl::InterfaceHandle<fuchsia::io::Directory> data_directory,
-    fuchsia::web::ContextFeatureFlags features) {
+}  // namespace
+
+// static
+fuchsia::web::ContextPtr WebContentRunner::CreateWebContext(
+    fuchsia::web::CreateContextParams create_params) {
   auto web_context_provider = base::fuchsia::ComponentContextForCurrentProcess()
                                   ->svc()
                                   ->Connect<fuchsia::web::ContextProvider>();
 
-  fuchsia::web::CreateContextParams create_params;
-
-  // Pass /svc and /data to the context.
-  create_params.set_service_directory(OpenDirectoryOrFail(
-      base::FilePath(base::fuchsia::kServiceDirectoryPath)));
-  if (data_directory)
-    create_params.set_data_directory(std::move(data_directory));
-
-  create_params.set_features(features);
-
-  // Set |remote_debugging_port| on the context, if set.
-  if (BUILDFLAG(ENABLE_REMOTE_DEBUGGING_ON_PORT) != 0) {
-    create_params.set_remote_debugging_port(
-        BUILDFLAG(ENABLE_REMOTE_DEBUGGING_ON_PORT));
-  }
-
   fuchsia::web::ContextPtr web_context;
   web_context_provider->Create(std::move(create_params),
                                web_context.NewRequest());
@@ -66,22 +52,33 @@
   return web_context;
 }
 
-}  // namespace
-
 // static
 fuchsia::web::ContextPtr WebContentRunner::CreateDefaultWebContext(
     fuchsia::web::ContextFeatureFlags features) {
-  return CreateWebContextWithDataDirectory(
+  return CreateWebContext(BuildCreateContextParams(
       OpenDirectoryOrFail(
           base::FilePath(base::fuchsia::kPersistedDataDirectoryPath)),
-      features);
+      features));
 }
 
 // static
-fuchsia::web::ContextPtr WebContentRunner::CreateIncognitoWebContext(
+fuchsia::web::CreateContextParams WebContentRunner::BuildCreateContextParams(
+    fidl::InterfaceHandle<fuchsia::io::Directory> data_directory,
     fuchsia::web::ContextFeatureFlags features) {
-  return CreateWebContextWithDataDirectory(
-      fidl::InterfaceHandle<fuchsia::io::Directory>(), features);
+  fuchsia::web::CreateContextParams create_params;
+  create_params.set_service_directory(OpenDirectoryOrFail(
+      base::FilePath(base::fuchsia::kServiceDirectoryPath)));
+
+  if (data_directory)
+    create_params.set_data_directory(std::move(data_directory));
+
+  // Set |remote_debugging_port| on the context, if set.
+  if (BUILDFLAG(ENABLE_REMOTE_DEBUGGING_ON_PORT) != 0) {
+    create_params.set_remote_debugging_port(
+        BUILDFLAG(ENABLE_REMOTE_DEBUGGING_ON_PORT));
+  }
+
+  return create_params;
 }
 
 WebContentRunner::WebContentRunner(sys::OutgoingDirectory* outgoing_directory,
diff --git a/fuchsia/runners/common/web_content_runner.h b/fuchsia/runners/common/web_content_runner.h
index b1c6323..c6ff2a5 100644
--- a/fuchsia/runners/common/web_content_runner.h
+++ b/fuchsia/runners/common/web_content_runner.h
@@ -26,10 +26,16 @@
   static fuchsia::web::ContextPtr CreateDefaultWebContext(
       fuchsia::web::ContextFeatureFlags features);
 
-  // Creates and returns an incognito web.Context  with access to the same
-  // services as this Runner. The returned binding is configured to exit this
-  // process on error.
-  static fuchsia::web::ContextPtr CreateIncognitoWebContext(
+  // Creates and returns a web.Context built with |create_params|.
+  // The returned binding is configured to exit this process on error.
+  static fuchsia::web::ContextPtr CreateWebContext(
+      fuchsia::web::CreateContextParams create_params);
+
+  // Returns a CreateContextParams that can be used as a base for creating a
+  // web.Context with a custom configuration.
+  // An incognito web.Context will be created if |data_directory| is unbound.
+  static fuchsia::web::CreateContextParams BuildCreateContextParams(
+      fidl::InterfaceHandle<fuchsia::io::Directory> data_directory,
       fuchsia::web::ContextFeatureFlags features);
 
   // |outgoing_directory|: OutgoingDirectory into which this Runner will be
diff --git a/gpu/vulkan/win32/vulkan_implementation_win32.cc b/gpu/vulkan/win32/vulkan_implementation_win32.cc
index c59f36d..77b8f99cb 100644
--- a/gpu/vulkan/win32/vulkan_implementation_win32.cc
+++ b/gpu/vulkan/win32/vulkan_implementation_win32.cc
@@ -77,7 +77,8 @@
   }
 
   return std::make_unique<VulkanSurface>(vulkan_instance_.vk_instance(),
-                                         surface);
+                                         surface,
+                                         /* use_protected_memory */ false);
 }
 
 bool VulkanImplementationWin32::GetPhysicalDevicePresentationSupport(
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 981225a1..a2b8353 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -88,6 +88,65 @@
        storage_type == VideoFrame::STORAGE_MOJO_SHARED_BUFFER);
 }
 
+// static
+bool VideoFrame::IsValidPlane(VideoPixelFormat format, size_t plane) {
+  DCHECK_LE(NumPlanes(format), static_cast<size_t>(kMaxPlanes));
+  return plane < NumPlanes(format);
+}
+
+// static
+gfx::Size VideoFrame::SampleSize(VideoPixelFormat format, size_t plane) {
+  DCHECK(IsValidPlane(format, plane));
+
+  switch (plane) {
+    case kYPlane:  // and kARGBPlane:
+    case kAPlane:
+      return gfx::Size(1, 1);
+
+    case kUPlane:  // and kUVPlane:
+    case kVPlane:
+      switch (format) {
+        case PIXEL_FORMAT_I444:
+        case PIXEL_FORMAT_YUV444P9:
+        case PIXEL_FORMAT_YUV444P10:
+        case PIXEL_FORMAT_YUV444P12:
+        case PIXEL_FORMAT_Y16:
+          return gfx::Size(1, 1);
+
+        case PIXEL_FORMAT_I422:
+        case PIXEL_FORMAT_YUV422P9:
+        case PIXEL_FORMAT_YUV422P10:
+        case PIXEL_FORMAT_YUV422P12:
+          return gfx::Size(2, 1);
+
+        case PIXEL_FORMAT_YV12:
+        case PIXEL_FORMAT_I420:
+        case PIXEL_FORMAT_I420A:
+        case PIXEL_FORMAT_NV12:
+        case PIXEL_FORMAT_NV21:
+        case PIXEL_FORMAT_YUV420P9:
+        case PIXEL_FORMAT_YUV420P10:
+        case PIXEL_FORMAT_YUV420P12:
+        case PIXEL_FORMAT_P016LE:
+          return gfx::Size(2, 2);
+
+        case PIXEL_FORMAT_UNKNOWN:
+        case PIXEL_FORMAT_YUY2:
+        case PIXEL_FORMAT_ARGB:
+        case PIXEL_FORMAT_XRGB:
+        case PIXEL_FORMAT_RGB24:
+        case PIXEL_FORMAT_MJPEG:
+        case PIXEL_FORMAT_ABGR:
+        case PIXEL_FORMAT_XBGR:
+        case PIXEL_FORMAT_XR30:
+        case PIXEL_FORMAT_XB30:
+          break;
+      }
+  }
+  NOTREACHED();
+  return gfx::Size();
+}
+
 // Checks if |source_format| can be wrapped into a |target_format| frame.
 static bool AreValidPixelFormatsForWrap(VideoPixelFormat source_format,
                                         VideoPixelFormat target_format) {
@@ -743,7 +802,7 @@
 gfx::Size VideoFrame::PlaneSize(VideoPixelFormat format,
                                 size_t plane,
                                 const gfx::Size& coded_size) {
-  DCHECK(IsValidPlane(plane, format));
+  DCHECK(IsValidPlane(format, plane));
 
   int width = coded_size.width();
   int height = coded_size.height();
@@ -765,7 +824,7 @@
 // static
 int VideoFrame::PlaneHorizontalBitsPerPixel(VideoPixelFormat format,
                                             size_t plane) {
-  DCHECK(IsValidPlane(plane, format));
+  DCHECK(IsValidPlane(format, plane));
   const int bits_per_element = 8 * BytesPerElement(format, plane);
   const int horiz_pixels_per_element = SampleSize(format, plane).width();
   DCHECK_EQ(bits_per_element % horiz_pixels_per_element, 0);
@@ -774,20 +833,20 @@
 
 // static
 int VideoFrame::PlaneBitsPerPixel(VideoPixelFormat format, size_t plane) {
-  DCHECK(IsValidPlane(plane, format));
+  DCHECK(IsValidPlane(format, plane));
   return PlaneHorizontalBitsPerPixel(format, plane) /
       SampleSize(format, plane).height();
 }
 
 // static
 size_t VideoFrame::RowBytes(size_t plane, VideoPixelFormat format, int width) {
-  DCHECK(IsValidPlane(plane, format));
+  DCHECK(IsValidPlane(format, plane));
   return BytesPerElement(format, plane) * Columns(plane, format, width);
 }
 
 // static
 int VideoFrame::BytesPerElement(VideoPixelFormat format, size_t plane) {
-  DCHECK(IsValidPlane(plane, format));
+  DCHECK(IsValidPlane(format, plane));
   switch (format) {
     case PIXEL_FORMAT_ARGB:
     case PIXEL_FORMAT_XRGB:
@@ -850,14 +909,14 @@
 
 // static
 size_t VideoFrame::Rows(size_t plane, VideoPixelFormat format, int height) {
-  DCHECK(IsValidPlane(plane, format));
+  DCHECK(IsValidPlane(format, plane));
   const int sample_height = SampleSize(format, plane).height();
   return base::bits::Align(height, sample_height) / sample_height;
 }
 
 // static
 size_t VideoFrame::Columns(size_t plane, VideoPixelFormat format, int width) {
-  DCHECK(IsValidPlane(plane, format));
+  DCHECK(IsValidPlane(format, plane));
   const int sample_width = SampleSize(format, plane).width();
   return base::bits::Align(width, sample_width) / sample_width;
 }
@@ -954,7 +1013,7 @@
 }
 
 const uint8_t* VideoFrame::visible_data(size_t plane) const {
-  DCHECK(IsValidPlane(plane, format()));
+  DCHECK(IsValidPlane(format(), plane));
   DCHECK(IsMappable());
 
   // Calculate an offset that is properly aligned for all planes.
@@ -980,7 +1039,7 @@
 const gpu::MailboxHolder&
 VideoFrame::mailbox_holder(size_t texture_index) const {
   DCHECK(HasTextures());
-  DCHECK(IsValidPlane(texture_index, format()));
+  DCHECK(IsValidPlane(format(), texture_index));
   return wrapped_frame_ ? wrapped_frame_->mailbox_holders_[texture_index]
                         : mailbox_holders_[texture_index];
 }
@@ -1112,12 +1171,6 @@
 }
 
 // static
-bool VideoFrame::IsValidPlane(size_t plane, VideoPixelFormat format) {
-  DCHECK_LE(NumPlanes(format), static_cast<size_t>(kMaxPlanes));
-  return (plane < NumPlanes(format));
-}
-
-// static
 gfx::Size VideoFrame::DetermineAlignedSize(VideoPixelFormat format,
                                            const gfx::Size& dimensions) {
   const gfx::Size alignment = CommonAlignment(format);
@@ -1174,59 +1227,6 @@
 }
 
 // static
-gfx::Size VideoFrame::SampleSize(VideoPixelFormat format, size_t plane) {
-  DCHECK(IsValidPlane(plane, format));
-
-  switch (plane) {
-    case kYPlane:  // and kARGBPlane:
-    case kAPlane:
-      return gfx::Size(1, 1);
-
-    case kUPlane:  // and kUVPlane:
-    case kVPlane:
-      switch (format) {
-        case PIXEL_FORMAT_I444:
-        case PIXEL_FORMAT_YUV444P9:
-        case PIXEL_FORMAT_YUV444P10:
-        case PIXEL_FORMAT_YUV444P12:
-        case PIXEL_FORMAT_Y16:
-          return gfx::Size(1, 1);
-
-        case PIXEL_FORMAT_I422:
-        case PIXEL_FORMAT_YUV422P9:
-        case PIXEL_FORMAT_YUV422P10:
-        case PIXEL_FORMAT_YUV422P12:
-          return gfx::Size(2, 1);
-
-        case PIXEL_FORMAT_YV12:
-        case PIXEL_FORMAT_I420:
-        case PIXEL_FORMAT_I420A:
-        case PIXEL_FORMAT_NV12:
-        case PIXEL_FORMAT_NV21:
-        case PIXEL_FORMAT_YUV420P9:
-        case PIXEL_FORMAT_YUV420P10:
-        case PIXEL_FORMAT_YUV420P12:
-        case PIXEL_FORMAT_P016LE:
-          return gfx::Size(2, 2);
-
-        case PIXEL_FORMAT_UNKNOWN:
-        case PIXEL_FORMAT_YUY2:
-        case PIXEL_FORMAT_ARGB:
-        case PIXEL_FORMAT_XRGB:
-        case PIXEL_FORMAT_RGB24:
-        case PIXEL_FORMAT_MJPEG:
-        case PIXEL_FORMAT_ABGR:
-        case PIXEL_FORMAT_XBGR:
-        case PIXEL_FORMAT_XR30:
-        case PIXEL_FORMAT_XB30:
-          break;
-      }
-  }
-  NOTREACHED();
-  return gfx::Size();
-}
-
-// static
 gfx::Size VideoFrame::CommonAlignment(VideoPixelFormat format) {
   int max_sample_width = 0;
   int max_sample_height = 0;
@@ -1302,7 +1302,7 @@
     // overreads by one line in some cases, see libavcodec/utils.c:
     // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
     // put_h264_chroma_mc4_ssse3().
-    DCHECK(IsValidPlane(kUPlane, format()));
+    DCHECK(IsValidPlane(format(), kUPlane));
     plane_size.back() += std::abs(stride(kUPlane)) + kFrameSizePadding;
   }
   return plane_size;
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index 641caade..eebca84 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -352,6 +352,13 @@
   // static
   static bool IsStorageTypeMappable(VideoFrame::StorageType storage_type);
 
+  // Returns true if |plane| is a valid plane index for the given |format|.
+  static bool IsValidPlane(VideoPixelFormat format, size_t plane);
+
+  // Returns the pixel size of each subsample for a given |plane| and |format|.
+  // E.g. 2x2 for the U-plane in PIXEL_FORMAT_I420.
+  static gfx::Size SampleSize(VideoPixelFormat format, size_t plane);
+
   // A video frame wrapping external data may be backed by an unsafe shared
   // memory region. These methods are used to appropriately transform a
   // VideoFrame created with WrapExternalData, WrapExternalYuvaData, etc. The
@@ -424,7 +431,7 @@
   const gfx::Size& natural_size() const { return natural_size_; }
 
   int stride(size_t plane) const {
-    DCHECK(IsValidPlane(plane, format()));
+    DCHECK(IsValidPlane(format(), plane));
     DCHECK_LT(plane, layout_.num_planes());
     return layout_.planes()[plane].stride;
   }
@@ -440,12 +447,12 @@
   // IsMappable() frame type. The memory is owned by VideoFrame object and must
   // not be freed by the caller.
   const uint8_t* data(size_t plane) const {
-    DCHECK(IsValidPlane(plane, format()));
+    DCHECK(IsValidPlane(format(), plane));
     DCHECK(IsMappable());
     return data_[plane];
   }
   uint8_t* data(size_t plane) {
-    DCHECK(IsValidPlane(plane, format()));
+    DCHECK(IsValidPlane(format(), plane));
     DCHECK(IsMappable());
     return data_[plane];
   }
@@ -569,15 +576,12 @@
                                     const gfx::Rect& visible_rect,
                                     const gfx::Size& natural_size);
 
-  // Returns true if |plane| is a valid plane index for the given |format|.
-  static bool IsValidPlane(size_t plane, VideoPixelFormat format);
-
   // Returns |dimensions| adjusted to appropriate boundaries based on |format|.
   static gfx::Size DetermineAlignedSize(VideoPixelFormat format,
                                         const gfx::Size& dimensions);
 
   void set_data(size_t plane, uint8_t* ptr) {
-    DCHECK(IsValidPlane(plane, format()));
+    DCHECK(IsValidPlane(format(), plane));
     DCHECK(ptr);
     data_[plane] = ptr;
   }
@@ -591,10 +595,6 @@
       base::TimeDelta timestamp,
       bool zero_initialize_memory);
 
-  // Returns the pixel size of each subsample for a given |plane| and |format|.
-  // E.g. 2x2 for the U-plane in PIXEL_FORMAT_I420.
-  static gfx::Size SampleSize(VideoPixelFormat format, size_t plane);
-
   // Return the alignment for the whole frame, calculated as the max of the
   // alignment for each individual plane.
   static gfx::Size CommonAlignment(VideoPixelFormat format);
diff --git a/media/gpu/test/video_frame_file_writer.cc b/media/gpu/test/video_frame_file_writer.cc
index cc647c8..163a6473 100644
--- a/media/gpu/test/video_frame_file_writer.cc
+++ b/media/gpu/test/video_frame_file_writer.cc
@@ -20,9 +20,11 @@
 namespace test {
 
 VideoFrameFileWriter::VideoFrameFileWriter(const base::FilePath& output_folder,
-                                           OutputFormat output_format)
+                                           OutputFormat output_format,
+                                           size_t output_limit)
     : output_folder_(output_folder),
       output_format_(output_format),
+      output_limit_(output_limit),
       num_frames_writing_(0),
       frame_writer_thread_("FrameWriterThread"),
       frame_writer_cv_(&frame_writer_lock_) {
@@ -40,7 +42,8 @@
 // static
 std::unique_ptr<VideoFrameFileWriter> VideoFrameFileWriter::Create(
     const base::FilePath& output_folder,
-    OutputFormat output_format) {
+    OutputFormat output_format,
+    size_t output_limit) {
   // If the directory is not absolute, consider it relative to our working dir.
   base::FilePath resolved_output_folder(output_folder);
   if (!resolved_output_folder.IsAbsolute()) {
@@ -58,8 +61,8 @@
     return nullptr;
   }
 
-  auto frame_file_writer = base::WrapUnique(
-      new VideoFrameFileWriter(resolved_output_folder, output_format));
+  auto frame_file_writer = base::WrapUnique(new VideoFrameFileWriter(
+      resolved_output_folder, output_format, output_limit));
   if (!frame_file_writer->Initialize()) {
     LOG(ERROR) << "Failed to initialize VideoFrameFileWriter";
     return nullptr;
@@ -80,6 +83,12 @@
 void VideoFrameFileWriter::ProcessVideoFrame(
     scoped_refptr<const VideoFrame> video_frame,
     size_t frame_index) {
+  // Don't write more frames than the specified output limit.
+  if (num_frames_writes_requested_ >= output_limit_)
+    return;
+
+  num_frames_writes_requested_++;
+
   base::AutoLock auto_lock(frame_writer_lock_);
   num_frames_writing_++;
 
diff --git a/media/gpu/test/video_frame_file_writer.h b/media/gpu/test/video_frame_file_writer.h
index 92c4f24..b3149a2e 100644
--- a/media/gpu/test/video_frame_file_writer.h
+++ b/media/gpu/test/video_frame_file_writer.h
@@ -5,6 +5,7 @@
 #ifndef MEDIA_GPU_TEST_VIDEO_FRAME_FILE_WRITER_H_
 #define MEDIA_GPU_TEST_VIDEO_FRAME_FILE_WRITER_H_
 
+#include <limits>
 #include <memory>
 
 #include "base/files/file_path.h"
@@ -34,9 +35,13 @@
   ~VideoFrameFileWriter() override;
 
   // Create an instance of the video frame file writer.
+  // |output_folder| specifies the folder video frames will be written to.
+  // |output_format| specifies the output file format.
+  // |output_limit| limits the max number of files that can be written.
   static std::unique_ptr<VideoFrameFileWriter> Create(
       const base::FilePath& output_folder,
-      OutputFormat output_format = OutputFormat::kPNG);
+      OutputFormat output_format = OutputFormat::kPNG,
+      size_t output_limit = std::numeric_limits<size_t>::max());
 
   // Interface VideoFrameProcessor
   void ProcessVideoFrame(scoped_refptr<const VideoFrame> video_frame,
@@ -46,7 +51,8 @@
 
  private:
   VideoFrameFileWriter(const base::FilePath& output_folder,
-                       OutputFormat output_format);
+                       OutputFormat output_format,
+                       size_t output_limit);
 
   // Initialize the video frame file writer.
   bool Initialize();
@@ -66,12 +72,16 @@
   const base::FilePath output_folder_;
   // Output format of the frames.
   const OutputFormat output_format_;
+  // The maximum number of frames that can be written.
+  const size_t output_limit_;
 
   // The video frame mapper used to gain access to the raw video frame memory.
   std::unique_ptr<VideoFrameMapper> video_frame_mapper_;
 
   // The number of frames currently queued for writing.
   size_t num_frames_writing_ GUARDED_BY(frame_writer_lock_);
+  // The number of frames currently written or queued to be written.
+  size_t num_frames_writes_requested_ = 0u;
 
   // Thread on which video frame writing is done.
   base::Thread frame_writer_thread_;
diff --git a/media/gpu/test/video_frame_validator.cc b/media/gpu/test/video_frame_validator.cc
index d51bd99..7b193c4 100644
--- a/media/gpu/test/video_frame_validator.cc
+++ b/media/gpu/test/video_frame_validator.cc
@@ -23,9 +23,11 @@
 // static
 std::unique_ptr<VideoFrameValidator> VideoFrameValidator::Create(
     const std::vector<std::string>& expected_frame_checksums,
-    const VideoPixelFormat validation_format) {
+    const VideoPixelFormat validation_format,
+    std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor) {
   auto video_frame_validator = base::WrapUnique(
-      new VideoFrameValidator(expected_frame_checksums, validation_format));
+      new VideoFrameValidator(expected_frame_checksums, validation_format,
+                              std::move(corrupt_frame_processor)));
   if (!video_frame_validator->Initialize()) {
     LOG(ERROR) << "Failed to initialize VideoFrameValidator.";
     return nullptr;
@@ -36,9 +38,11 @@
 
 VideoFrameValidator::VideoFrameValidator(
     std::vector<std::string> expected_frame_checksums,
-    VideoPixelFormat validation_format)
+    VideoPixelFormat validation_format,
+    std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor)
     : expected_frame_checksums_(std::move(expected_frame_checksums)),
       validation_format_(validation_format),
+      corrupt_frame_processor_(std::move(corrupt_frame_processor)),
       num_frames_validating_(0),
       frame_validator_thread_("FrameValidatorThread"),
       frame_validator_cv_(&frame_validator_lock_) {
@@ -97,6 +101,9 @@
     frame_validator_cv_.Wait();
   }
 
+  if (corrupt_frame_processor_ && !corrupt_frame_processor_->WaitUntilDone())
+    return false;
+
   if (mismatched_frames_.size() > 0u) {
     LOG(ERROR) << mismatched_frames_.size() << " frames failed to validate.";
     return false;
@@ -148,6 +155,9 @@
     if (computed_md5 != expected_md5) {
       mismatched_frames_.push_back(
           MismatchedFrameInfo{frame_index, computed_md5, expected_md5});
+      // Perform additional processing on the corrupt video frame if requested.
+      if (corrupt_frame_processor_)
+        corrupt_frame_processor_->ProcessVideoFrame(video_frame, frame_index);
     }
   }
 
diff --git a/media/gpu/test/video_frame_validator.h b/media/gpu/test/video_frame_validator.h
index e1430d78..3eb6ec1 100644
--- a/media/gpu/test/video_frame_validator.h
+++ b/media/gpu/test/video_frame_validator.h
@@ -47,9 +47,15 @@
   // Create an instance of the video frame validator. The calculated checksums
   // will be compared to the values in |expected_frame_checksums|. If no
   // checksums are provided only checksum calculation will be done.
+  // |validation_format| specifies the pixel format used when calculating the
+  // checksum. Pixel format conversion will be performed if required. The
+  // |corrupt_frame_processor| is an optional video frame processor that will be
+  // called on each frame that fails validation. Ownership of the corrupt frame
+  // processor will be transferred to the frame validator.
   static std::unique_ptr<VideoFrameValidator> Create(
       const std::vector<std::string>& expected_frame_checksums,
-      const VideoPixelFormat validation_format = PIXEL_FORMAT_I420);
+      const VideoPixelFormat validation_format = PIXEL_FORMAT_I420,
+      std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor = nullptr);
 
   ~VideoFrameValidator() override;
 
@@ -71,8 +77,10 @@
   bool WaitUntilDone() override;
 
  private:
-  VideoFrameValidator(std::vector<std::string> expected_frame_checksums,
-                      VideoPixelFormat validation_format);
+  VideoFrameValidator(
+      std::vector<std::string> expected_frame_checksums,
+      VideoPixelFormat validation_format,
+      std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor);
 
   // Start the frame validation thread.
   bool Initialize();
@@ -98,6 +106,10 @@
   // VideoPixelFormat the VideoFrame will be converted to for validation.
   const VideoPixelFormat validation_format_;
 
+  // An optional video frame processor that all corrupted frames will be
+  // forwarded to. This can be used to e.g. write corrupted frames to disk.
+  const std::unique_ptr<VideoFrameProcessor> corrupt_frame_processor_;
+
   // The number of frames currently queued for validation.
   size_t num_frames_validating_ GUARDED_BY(frame_validator_lock_);
 
diff --git a/media/gpu/test/video_player/video_player_test_environment.cc b/media/gpu/test/video_player/video_player_test_environment.cc
index e6fc7892..aa4a111 100644
--- a/media/gpu/test/video_player/video_player_test_environment.cc
+++ b/media/gpu/test/video_player/video_player_test_environment.cc
@@ -22,7 +22,7 @@
     const base::FilePath& video_path,
     const base::FilePath& video_metadata_path,
     bool enable_validator,
-    bool output_frames,
+    FrameOutputMode frame_output_mode,
     const base::FilePath& output_folder,
     bool use_vd) {
   auto video = std::make_unique<media::test::Video>(
@@ -34,18 +34,19 @@
   }
 
   return new VideoPlayerTestEnvironment(std::move(video), enable_validator,
-                                        output_frames, output_folder, use_vd);
+                                        frame_output_mode, output_folder,
+                                        use_vd);
 }
 
 VideoPlayerTestEnvironment::VideoPlayerTestEnvironment(
     std::unique_ptr<media::test::Video> video,
     bool enable_validator,
-    bool output_frames,
+    FrameOutputMode frame_output_mode,
     const base::FilePath& output_folder,
     bool use_vd)
     : video_(std::move(video)),
       enable_validator_(enable_validator),
-      output_frames_(output_frames),
+      frame_output_mode_(frame_output_mode),
       output_folder_(output_folder),
       use_vd_(use_vd) {}
 
@@ -81,8 +82,8 @@
   return enable_validator_;
 }
 
-bool VideoPlayerTestEnvironment::IsFramesOutputEnabled() const {
-  return output_frames_;
+FrameOutputMode VideoPlayerTestEnvironment::GetFrameOutputMode() const {
+  return frame_output_mode_;
 }
 
 const base::FilePath& VideoPlayerTestEnvironment::OutputFolder() const {
diff --git a/media/gpu/test/video_player/video_player_test_environment.h b/media/gpu/test/video_player/video_player_test_environment.h
index 746a7b29..3c3f2e8 100644
--- a/media/gpu/test/video_player/video_player_test_environment.h
+++ b/media/gpu/test/video_player/video_player_test_environment.h
@@ -15,6 +15,16 @@
 
 class Video;
 
+// The frame output mode allows controlling which video frames are written to
+// disk. Writing frames will greatly slow down the test and generate a lot of
+// test artifacts, so be careful when configuring other modes than kNone in
+// automated testing.
+enum class FrameOutputMode {
+  kNone,     // Don't output any frames.
+  kCorrupt,  // Only output corrupt frames.
+  kAll       // Output all frames.
+};
+
 // Test environment for video decode tests. Performs setup and teardown once for
 // the entire test run.
 class VideoPlayerTestEnvironment : public VideoTestEnvironment {
@@ -23,7 +33,7 @@
       const base::FilePath& video_path,
       const base::FilePath& video_metadata_path,
       bool enable_validator,
-      bool output_frames,
+      FrameOutputMode frame_output_mode,
       const base::FilePath& output_folder,
       bool use_vd);
   ~VideoPlayerTestEnvironment() override;
@@ -35,8 +45,8 @@
   const media::test::Video* Video() const;
   // Check whether frame validation is enabled.
   bool IsValidatorEnabled() const;
-  // Check whether outputting frames is enabled.
-  bool IsFramesOutputEnabled() const;
+  // Get the frame output mode.
+  FrameOutputMode GetFrameOutputMode() const;
   // Get the output folder.
   const base::FilePath& OutputFolder() const;
   // Check whether we should use VD-based video decoders instead of VDA-based.
@@ -47,13 +57,13 @@
  private:
   VideoPlayerTestEnvironment(std::unique_ptr<media::test::Video> video,
                              bool enable_validator,
-                             bool output_frames,
+                             FrameOutputMode frame_output_mode,
                              const base::FilePath& output_folder,
                              bool use_vd);
 
   const std::unique_ptr<media::test::Video> video_;
   const bool enable_validator_;
-  const bool output_frames_;
+  const FrameOutputMode frame_output_mode_;
   const base::FilePath output_folder_;
   const bool use_vd_;
   // TODO(dstaessens): Remove this once all allocate-only platforms reached EOL.
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index 4afafc5b..496c819 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -1492,36 +1492,26 @@
   DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id;
   DCHECK(child_task_runner_->BelongsToCurrentThread());
 
-  std::vector<base::ScopedFD> dmabuf_fds;
-#if defined(USE_OZONE)
-  // If the driver does not accept as many fds as we received from the client,
-  // we have to check if the additional fds are actually duplicated fds pointing
-  // to previous planes; if so, we can close the duplicates and keep only the
-  // original fd(s).
-  // Assume that an fd is a duplicate of a previous plane's fd if offset != 0.
-  // Otherwise, if offset == 0, return error as it may be pointing to a new
-  // plane.
-  for (auto& plane : gpu_memory_buffer_handle.native_pixmap_handle.planes) {
-    dmabuf_fds.push_back(std::move(plane.fd));
-  }
-  for (size_t i = dmabuf_fds.size() - 1; i >= gl_image_planes_count_; i--) {
-    if (gpu_memory_buffer_handle.native_pixmap_handle.planes[i].offset == 0) {
-      VLOGF(1) << "The dmabuf fd points to a new buffer, ";
-      NOTIFY_ERROR(INVALID_ARGUMENT);
-      return;
-    }
-    // Drop safely, because this fd is duplicate dmabuf fd pointing to previous
-    // buffer and the appropriate address can be accessed by associated offset.
-    dmabuf_fds.pop_back();
-  }
-#endif
-
   if (output_mode_ != Config::OutputMode::IMPORT) {
     VLOGF(1) << "Cannot import in non-import mode";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
 
+  decoder_thread_.task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureForImportTask,
+          base::Unretained(this), picture_buffer_id, pixel_format,
+          std::move(gpu_memory_buffer_handle.native_pixmap_handle)));
+}
+
+void V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureForImportTask(
+    int32_t picture_buffer_id,
+    VideoPixelFormat pixel_format,
+    gfx::NativePixmapHandle handle) {
+  DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
+
   if (pixel_format !=
       V4L2Device::V4L2PixFmtToVideoPixelFormat(gl_image_format_fourcc_)) {
     VLOGF(1) << "Unsupported import format: "
@@ -1530,11 +1520,31 @@
     return;
   }
 
-  decoder_thread_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureTask,
-          base::Unretained(this), picture_buffer_id, std::move(dmabuf_fds)));
+  std::vector<base::ScopedFD> dmabuf_fds;
+  for (auto& plane : handle.planes) {
+    dmabuf_fds.push_back(std::move(plane.fd));
+  }
+
+  // If the driver does not accept as many fds as we received from the client,
+  // we have to check if the additional fds are actually duplicated fds pointing
+  // to previous planes; if so, we can close the duplicates and keep only the
+  // original fd(s).
+  // Assume that an fd is a duplicate of a previous plane's fd if offset != 0.
+  // Otherwise, if offset == 0, return error as it may be pointing to a new
+  // plane.
+  while (dmabuf_fds.size() > gl_image_planes_count_) {
+    const size_t idx = dmabuf_fds.size() - 1;
+    if (handle.planes[idx].offset == 0) {
+      VLOGF(1) << "The dmabuf fd points to a new buffer, ";
+      NOTIFY_ERROR(INVALID_ARGUMENT);
+      return;
+    }
+    // Drop safely, because this fd is duplicate dmabuf fd pointing to previous
+    // buffer and the appropriate address can be accessed by associated offset.
+    dmabuf_fds.pop_back();
+  }
+
+  ImportBufferForPictureTask(picture_buffer_id, std::move(dmabuf_fds));
 }
 
 void V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureTask(
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h
index 2049b0b..73e0fab 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h
@@ -270,6 +270,12 @@
       int32_t picture_buffer_id,
       std::vector<base::ScopedFD> passed_dmabuf_fds);
 
+  // Check that |planes| and |dmabuf_fds| are valid in import mode and call
+  // ImportBufferForPictureTask.
+  void ImportBufferForPictureForImportTask(int32_t picture_buffer_id,
+                                           VideoPixelFormat pixel_format,
+                                           gfx::NativePixmapHandle handle);
+
   // Create a GLImage for the buffer associated with V4L2 |buffer_index| and
   // for |picture_buffer_id|, backed by dmabuf file descriptors in
   // |passed_dmabuf_fds|, taking ownership of them.
diff --git a/media/gpu/video_decode_accelerator_perf_tests.cc b/media/gpu/video_decode_accelerator_perf_tests.cc
index 50549ce6e..4deacd68 100644
--- a/media/gpu/video_decode_accelerator_perf_tests.cc
+++ b/media/gpu/video_decode_accelerator_perf_tests.cc
@@ -422,8 +422,9 @@
   // Set up our test environment.
   media::test::VideoPlayerTestEnvironment* test_environment =
       media::test::VideoPlayerTestEnvironment::Create(
-          video_path, video_metadata_path, false, false,
-          base::FilePath(output_folder), use_vd);
+          video_path, video_metadata_path, false,
+          media::test::FrameOutputMode::kAll, base::FilePath(output_folder),
+          use_vd);
   if (!test_environment)
     return EXIT_FAILURE;
 
diff --git a/media/gpu/video_decode_accelerator_tests.cc b/media/gpu/video_decode_accelerator_tests.cc
index cf10dc4..c008648 100644
--- a/media/gpu/video_decode_accelerator_tests.cc
+++ b/media/gpu/video_decode_accelerator_tests.cc
@@ -25,8 +25,9 @@
 constexpr const char* usage_msg =
     "usage: video_decode_accelerator_tests\n"
     "           [-v=<level>] [--vmodule=<config>] [--disable_validator]\n"
-    "           [--output_frames] [output_folder] [--use_vd] [--gtest_help]\n"
-    "           [--help] [<video path>] [<video metadata path>]\n";
+    "           [--output_frames=(all|corrupt)] [--output_folder=<folder>]\n"
+    "           [--use_vd] [--gtest_help] [--help]\n"
+    "           [<video path>] [<video metadata path>]\n";
 
 // Video decoder tests help message.
 constexpr const char* help_msg =
@@ -41,8 +42,9 @@
     "  --vmodule            enable verbose mode for the specified module,\n"
     "                       e.g. --vmodule=*media/gpu*=2.\n"
     "  --disable_validator  disable frame validation.\n"
-    "  --output_frames      write all decoded video frames to the\n"
-    "                       \"<testname>\" folder.\n"
+    "  --output_frames      write the selected video frames to disk, possible\n"
+    "                       values are \"all|corrupt\", the default output\n"
+    "                       folder is \"<testname>\".\n"
     "  --output_folder      overwrite the default output folder used when\n"
     "                       \"--output_frames\" is specified.\n"
     "  --use_vd             use the new VD-based video decoders, instead of\n"
@@ -50,6 +52,12 @@
     "  --gtest_help         display the gtest help and exit.\n"
     "  --help               display this help and exit.\n";
 
+// The output format used when writing frames to disk.
+constexpr VideoFrameFileWriter::OutputFormat kOutputFormat =
+    VideoFrameFileWriter::OutputFormat::kPNG;
+// The max number of corrupt frames to write to disk.
+constexpr size_t kCorruptFrameWriteLimit = 3;
+
 media::test::VideoPlayerTestEnvironment* g_env;
 
 // Video decode test class. Performs setup and teardown for each single test.
@@ -67,23 +75,32 @@
     if (!g_env->ImportSupported())
       config.allocation_mode = AllocationMode::kAllocate;
 
-    // Use the video frame validator to validate decoded video frames if import
-    // mode is supported and enabled.
-    if (g_env->IsValidatorEnabled() &&
+    base::FilePath output_folder = base::FilePath(g_env->OutputFolder())
+                                       .Append(g_env->GetTestOutputFilePath());
+
+    // Write all video frames to the '<testname>' folder if the frame output
+    // mode is 'all'. Only supported if import mode is supported and enabled.
+    if (g_env->GetFrameOutputMode() == FrameOutputMode::kAll &&
         config.allocation_mode == AllocationMode::kImport) {
       frame_processors.push_back(
-          media::test::VideoFrameValidator::Create(video->FrameChecksums()));
+          VideoFrameFileWriter::Create(output_folder, kOutputFormat));
+      VLOG(0) << "Writing video frames to: " << output_folder;
     }
 
-    // Write decoded video frames to the '<testname>' folder if import mode is
-    // supported and enabled.
-    if (g_env->IsFramesOutputEnabled() &&
+    // Use the video frame validator to validate decoded video frames if
+    // enabled. If the frame output mode is 'corrupt', a frame writer will be
+    // attached to forward corrupted frames to. The maximum number of corrupt
+    // frames written to disk will be limited, to reduce the size of generated
+    // test artifacts. Only supported if import mode is supported and enabled.
+    if (g_env->IsValidatorEnabled() &&
         config.allocation_mode == AllocationMode::kImport) {
-      base::FilePath output_folder =
-          base::FilePath(g_env->OutputFolder())
-              .Append(g_env->GetTestOutputFilePath());
-      frame_processors.push_back(VideoFrameFileWriter::Create(output_folder));
-      VLOG(0) << "Writing video frames to: " << output_folder;
+      std::unique_ptr<VideoFrameFileWriter> frame_writer;
+      if (g_env->GetFrameOutputMode() == FrameOutputMode::kCorrupt) {
+        frame_writer = VideoFrameFileWriter::Create(
+            output_folder, kOutputFormat, kCorruptFrameWriteLimit);
+      }
+      frame_processors.push_back(media::test::VideoFrameValidator::Create(
+          video->FrameChecksums(), PIXEL_FORMAT_I420, std::move(frame_writer)));
     }
 
     // Use the new VD-based video decoders if requested.
@@ -95,7 +112,7 @@
     LOG_ASSERT(video_player->Initialize(video));
 
     // Increase event timeout when outputting video frames.
-    if (g_env->IsFramesOutputEnabled()) {
+    if (g_env->GetFrameOutputMode() != FrameOutputMode::kNone) {
       video_player->SetEventWaitTimeout(std::max(
           kDefaultEventWaitTimeout, g_env->Video()->GetDuration() * 10));
     }
@@ -393,7 +410,8 @@
 
   // Parse command line arguments.
   bool enable_validator = true;
-  bool output_frames = false;
+  media::test::FrameOutputMode frame_output_mode =
+      media::test::FrameOutputMode::kNone;
   base::FilePath::StringType output_folder = base::FilePath::kCurrentDirectory;
   bool use_vd = false;
   base::CommandLine::SwitchMap switches = cmd_line->GetSwitches();
@@ -407,7 +425,15 @@
     if (it->first == "disable_validator") {
       enable_validator = false;
     } else if (it->first == "output_frames") {
-      output_frames = true;
+      if (it->second == "all") {
+        frame_output_mode = media::test::FrameOutputMode::kAll;
+      } else if (it->second == "corrupt") {
+        frame_output_mode = media::test::FrameOutputMode::kCorrupt;
+      } else {
+        std::cout << "unknown frame output mode \"" << it->second
+                  << "\", possible values are \"all|corrupt\"\n";
+        return EXIT_FAILURE;
+      }
     } else if (it->first == "output_folder") {
       output_folder = it->second;
     } else if (it->first == "use_vd") {
@@ -424,7 +450,7 @@
   // Set up our test environment.
   media::test::VideoPlayerTestEnvironment* test_environment =
       media::test::VideoPlayerTestEnvironment::Create(
-          video_path, video_metadata_path, enable_validator, output_frames,
+          video_path, video_metadata_path, enable_validator, frame_output_mode,
           base::FilePath(output_folder), use_vd);
   if (!test_environment)
     return EXIT_FAILURE;
diff --git a/media/mojo/common/mojo_shared_buffer_video_frame.cc b/media/mojo/common/mojo_shared_buffer_video_frame.cc
index 0c6950d..cf26fe8 100644
--- a/media/mojo/common/mojo_shared_buffer_video_frame.cc
+++ b/media/mojo/common/mojo_shared_buffer_video_frame.cc
@@ -252,7 +252,7 @@
 }
 
 size_t MojoSharedBufferVideoFrame::PlaneOffset(size_t plane) const {
-  DCHECK(IsValidPlane(plane, format()));
+  DCHECK(IsValidPlane(format(), plane));
   return offsets_[plane];
 }
 
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index 75029910..a5a32c4 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -7,9 +7,15 @@
 #include <GLES3/gl3.h>
 #include <limits>
 
+#include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/numerics/checked_math.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/system/sys_info.h"
+#include "base/task/post_task.h"
+#include "base/threading/thread_restrictions.h"
 #include "cc/paint/paint_canvas.h"
 #include "cc/paint/paint_flags.h"
 #include "cc/paint/paint_image_builder.h"
@@ -382,6 +388,167 @@
   }
 }
 
+// TODO(thomasanderson): Remove these and use std::gcd and std::lcm once we're
+// building with C++17.
+size_t GCD(size_t a, size_t b) {
+  return a == 0 ? b : GCD(b % a, a);
+}
+size_t LCM(size_t a, size_t b) {
+  return a / GCD(a, b) * b;
+}
+
+void ConvertVideoFrameToRGBPixelsTask(const VideoFrame* video_frame,
+                                      void* rgb_pixels,
+                                      size_t row_bytes,
+                                      size_t task_index,
+                                      size_t n_tasks,
+                                      base::RepeatingClosure* done) {
+  size_t rows_per_chunk = 1;
+  for (size_t plane = 0; plane < VideoFrame::kMaxPlanes; ++plane) {
+    if (VideoFrame::IsValidPlane(video_frame->format(), plane)) {
+      rows_per_chunk =
+          LCM(rows_per_chunk,
+              VideoFrame::SampleSize(video_frame->format(), plane).height());
+    }
+  }
+
+  int width = video_frame->visible_rect().width();
+  int height = video_frame->visible_rect().height();
+
+  base::CheckedNumeric<size_t> chunks = height / rows_per_chunk;
+  DCHECK_EQ(height % rows_per_chunk, 0UL);
+  size_t chunk_start = (chunks * task_index / n_tasks).ValueOrDie();
+  size_t chunk_end = (chunks * (task_index + 1) / n_tasks).ValueOrDie();
+
+  struct {
+    int stride;
+    const uint8_t* data;
+  } plane_meta[VideoFrame::kMaxPlanes];
+
+  for (size_t plane = 0; plane < VideoFrame::kMaxPlanes; ++plane) {
+    if (VideoFrame::IsValidPlane(video_frame->format(), plane)) {
+      auto& meta = plane_meta[plane];
+      meta.stride = video_frame->stride(plane);
+
+      const uint8_t* data = video_frame->visible_data(plane);
+      int rows = video_frame->rows(plane);
+      meta.data =
+          data + meta.stride * chunk_start * rows_per_chunk * rows / height;
+    }
+  }
+
+  uint8_t* pixels = static_cast<uint8_t*>(rgb_pixels) +
+                    row_bytes * chunk_start * rows_per_chunk;
+  size_t rows = (chunk_end - chunk_start) * rows_per_chunk;
+
+  // TODO(hubbe): This should really default to the rec709 colorspace.
+  // https://crbug.com/828599
+  SkYUVColorSpace color_space = kRec601_SkYUVColorSpace;
+  video_frame->ColorSpace().ToSkYUVColorSpace(&color_space);
+
+  auto convert_yuv = [&](auto&& func) {
+    func(plane_meta[VideoFrame::kYPlane].data,
+         plane_meta[VideoFrame::kYPlane].stride,
+         plane_meta[VideoFrame::kUPlane].data,
+         plane_meta[VideoFrame::kUPlane].stride,
+         plane_meta[VideoFrame::kVPlane].data,
+         plane_meta[VideoFrame::kVPlane].stride, pixels, row_bytes, width,
+         rows);
+  };
+
+  switch (video_frame->format()) {
+    case PIXEL_FORMAT_YV12:
+    case PIXEL_FORMAT_I420:
+      switch (color_space) {
+        case kJPEG_SkYUVColorSpace:
+          convert_yuv(LIBYUV_J420_TO_ARGB);
+          break;
+        case kRec709_SkYUVColorSpace: {
+          convert_yuv(LIBYUV_H420_TO_ARGB);
+          break;
+        }
+        case kRec601_SkYUVColorSpace:
+          convert_yuv(LIBYUV_I420_TO_ARGB);
+          break;
+        default:
+          NOTREACHED();
+      }
+      break;
+    case PIXEL_FORMAT_I422:
+      convert_yuv(LIBYUV_I422_TO_ARGB);
+      break;
+
+    case PIXEL_FORMAT_I420A:
+      LIBYUV_I420ALPHA_TO_ARGB(
+          plane_meta[VideoFrame::kYPlane].data,
+          plane_meta[VideoFrame::kYPlane].stride,
+          plane_meta[VideoFrame::kUPlane].data,
+          plane_meta[VideoFrame::kUPlane].stride,
+          plane_meta[VideoFrame::kVPlane].data,
+          plane_meta[VideoFrame::kVPlane].stride,
+          plane_meta[VideoFrame::kAPlane].data,
+          plane_meta[VideoFrame::kAPlane].stride, pixels, row_bytes, width,
+          rows,
+          1);  // 1 = enable RGB premultiplication by Alpha.
+      break;
+
+    case PIXEL_FORMAT_I444:
+      convert_yuv(LIBYUV_I444_TO_ARGB);
+      break;
+
+    case PIXEL_FORMAT_YUV420P10:
+      (color_space == kRec709_SkYUVColorSpace
+           ? LIBYUV_H010_TO_ARGB
+           : LIBYUV_I010_TO_ARGB)(reinterpret_cast<const uint16_t*>(
+                                      plane_meta[VideoFrame::kYPlane].data),
+                                  plane_meta[VideoFrame::kYPlane].stride / 2,
+                                  reinterpret_cast<const uint16_t*>(
+                                      plane_meta[VideoFrame::kUPlane].data),
+                                  plane_meta[VideoFrame::kUPlane].stride / 2,
+                                  reinterpret_cast<const uint16_t*>(
+                                      plane_meta[VideoFrame::kVPlane].data),
+                                  plane_meta[VideoFrame::kVPlane].stride / 2,
+                                  pixels, row_bytes, width, rows);
+      break;
+
+    case PIXEL_FORMAT_YUV420P9:
+    case PIXEL_FORMAT_YUV422P9:
+    case PIXEL_FORMAT_YUV444P9:
+    case PIXEL_FORMAT_YUV422P10:
+    case PIXEL_FORMAT_YUV444P10:
+    case PIXEL_FORMAT_YUV420P12:
+    case PIXEL_FORMAT_YUV422P12:
+    case PIXEL_FORMAT_YUV444P12:
+    case PIXEL_FORMAT_Y16:
+      NOTREACHED() << "These cases should be handled above";
+      break;
+
+    case PIXEL_FORMAT_NV12:
+      LIBYUV_NV12_TO_ARGB(plane_meta[VideoFrame::kYPlane].data,
+                          plane_meta[VideoFrame::kYPlane].stride,
+                          plane_meta[VideoFrame::kUPlane].data,
+                          plane_meta[VideoFrame::kUPlane].stride, pixels,
+                          row_bytes, width, rows);
+      break;
+
+    case PIXEL_FORMAT_NV21:
+    case PIXEL_FORMAT_YUY2:
+    case PIXEL_FORMAT_ARGB:
+    case PIXEL_FORMAT_XRGB:
+    case PIXEL_FORMAT_RGB24:
+    case PIXEL_FORMAT_MJPEG:
+    case PIXEL_FORMAT_ABGR:
+    case PIXEL_FORMAT_XBGR:
+    case PIXEL_FORMAT_P016LE:
+    case PIXEL_FORMAT_XR30:
+    case PIXEL_FORMAT_XB30:
+    case PIXEL_FORMAT_UNKNOWN:
+      NOTREACHED() << "Only YUV formats and Y16 are supported, got: "
+                   << media::VideoPixelFormatToString(video_frame->format());
+  }
+  done->Run();
+}
+
 }  // anonymous namespace
 
 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
@@ -880,122 +1047,9 @@
     return;
   }
 
-  // TODO(hubbe): This should really default to the rec709 colorspace.
-  // https://crbug.com/828599
-  SkYUVColorSpace color_space = kRec601_SkYUVColorSpace;
-  video_frame->ColorSpace().ToSkYUVColorSpace(&color_space);
-
+  scoped_refptr<VideoFrame> temporary_frame;
+  // TODO(thomasanderson): Parallelize converting these formats.
   switch (video_frame->format()) {
-    case PIXEL_FORMAT_YV12:
-    case PIXEL_FORMAT_I420:
-      switch (color_space) {
-        case kJPEG_SkYUVColorSpace:
-          LIBYUV_J420_TO_ARGB(video_frame->visible_data(VideoFrame::kYPlane),
-                              video_frame->stride(VideoFrame::kYPlane),
-                              video_frame->visible_data(VideoFrame::kUPlane),
-                              video_frame->stride(VideoFrame::kUPlane),
-                              video_frame->visible_data(VideoFrame::kVPlane),
-                              video_frame->stride(VideoFrame::kVPlane),
-                              static_cast<uint8_t*>(rgb_pixels), row_bytes,
-                              video_frame->visible_rect().width(),
-                              video_frame->visible_rect().height());
-          break;
-        case kRec709_SkYUVColorSpace:
-          LIBYUV_H420_TO_ARGB(video_frame->visible_data(VideoFrame::kYPlane),
-                              video_frame->stride(VideoFrame::kYPlane),
-                              video_frame->visible_data(VideoFrame::kUPlane),
-                              video_frame->stride(VideoFrame::kUPlane),
-                              video_frame->visible_data(VideoFrame::kVPlane),
-                              video_frame->stride(VideoFrame::kVPlane),
-                              static_cast<uint8_t*>(rgb_pixels), row_bytes,
-                              video_frame->visible_rect().width(),
-                              video_frame->visible_rect().height());
-          break;
-        case kRec601_SkYUVColorSpace:
-          LIBYUV_I420_TO_ARGB(video_frame->visible_data(VideoFrame::kYPlane),
-                              video_frame->stride(VideoFrame::kYPlane),
-                              video_frame->visible_data(VideoFrame::kUPlane),
-                              video_frame->stride(VideoFrame::kUPlane),
-                              video_frame->visible_data(VideoFrame::kVPlane),
-                              video_frame->stride(VideoFrame::kVPlane),
-                              static_cast<uint8_t*>(rgb_pixels), row_bytes,
-                              video_frame->visible_rect().width(),
-                              video_frame->visible_rect().height());
-          break;
-        default:
-          NOTREACHED();
-      }
-      break;
-    case PIXEL_FORMAT_I422:
-      LIBYUV_I422_TO_ARGB(video_frame->visible_data(VideoFrame::kYPlane),
-                          video_frame->stride(VideoFrame::kYPlane),
-                          video_frame->visible_data(VideoFrame::kUPlane),
-                          video_frame->stride(VideoFrame::kUPlane),
-                          video_frame->visible_data(VideoFrame::kVPlane),
-                          video_frame->stride(VideoFrame::kVPlane),
-                          static_cast<uint8_t*>(rgb_pixels), row_bytes,
-                          video_frame->visible_rect().width(),
-                          video_frame->visible_rect().height());
-      break;
-
-    case PIXEL_FORMAT_I420A:
-      LIBYUV_I420ALPHA_TO_ARGB(
-          video_frame->visible_data(VideoFrame::kYPlane),
-          video_frame->stride(VideoFrame::kYPlane),
-          video_frame->visible_data(VideoFrame::kUPlane),
-          video_frame->stride(VideoFrame::kUPlane),
-          video_frame->visible_data(VideoFrame::kVPlane),
-          video_frame->stride(VideoFrame::kVPlane),
-          video_frame->visible_data(VideoFrame::kAPlane),
-          video_frame->stride(VideoFrame::kAPlane),
-          static_cast<uint8_t*>(rgb_pixels), row_bytes,
-          video_frame->visible_rect().width(),
-          video_frame->visible_rect().height(),
-          1);  // 1 = enable RGB premultiplication by Alpha.
-      break;
-
-    case PIXEL_FORMAT_I444:
-      LIBYUV_I444_TO_ARGB(video_frame->visible_data(VideoFrame::kYPlane),
-                          video_frame->stride(VideoFrame::kYPlane),
-                          video_frame->visible_data(VideoFrame::kUPlane),
-                          video_frame->stride(VideoFrame::kUPlane),
-                          video_frame->visible_data(VideoFrame::kVPlane),
-                          video_frame->stride(VideoFrame::kVPlane),
-                          static_cast<uint8_t*>(rgb_pixels), row_bytes,
-                          video_frame->visible_rect().width(),
-                          video_frame->visible_rect().height());
-      break;
-
-    case PIXEL_FORMAT_YUV420P10:
-      if (color_space == kRec709_SkYUVColorSpace) {
-        LIBYUV_H010_TO_ARGB(reinterpret_cast<const uint16_t*>(
-                                video_frame->visible_data(VideoFrame::kYPlane)),
-                            video_frame->stride(VideoFrame::kYPlane) / 2,
-                            reinterpret_cast<const uint16_t*>(
-                                video_frame->visible_data(VideoFrame::kUPlane)),
-                            video_frame->stride(VideoFrame::kUPlane) / 2,
-                            reinterpret_cast<const uint16_t*>(
-                                video_frame->visible_data(VideoFrame::kVPlane)),
-                            video_frame->stride(VideoFrame::kVPlane) / 2,
-                            static_cast<uint8_t*>(rgb_pixels), row_bytes,
-                            video_frame->visible_rect().width(),
-                            video_frame->visible_rect().height());
-      } else {
-        LIBYUV_I010_TO_ARGB(reinterpret_cast<const uint16_t*>(
-                                video_frame->visible_data(VideoFrame::kYPlane)),
-                            video_frame->stride(VideoFrame::kYPlane) / 2,
-                            reinterpret_cast<const uint16_t*>(
-                                video_frame->visible_data(VideoFrame::kUPlane)),
-                            video_frame->stride(VideoFrame::kUPlane) / 2,
-                            reinterpret_cast<const uint16_t*>(
-                                video_frame->visible_data(VideoFrame::kVPlane)),
-                            video_frame->stride(VideoFrame::kVPlane) / 2,
-                            static_cast<uint8_t*>(rgb_pixels), row_bytes,
-                            video_frame->visible_rect().width(),
-                            video_frame->visible_rect().height());
-      }
-      break;
-
     case PIXEL_FORMAT_YUV420P9:
     case PIXEL_FORMAT_YUV422P9:
     case PIXEL_FORMAT_YUV444P9:
@@ -1003,45 +1057,41 @@
     case PIXEL_FORMAT_YUV444P10:
     case PIXEL_FORMAT_YUV420P12:
     case PIXEL_FORMAT_YUV422P12:
-    case PIXEL_FORMAT_YUV444P12: {
-      scoped_refptr<VideoFrame> temporary_frame =
-          DownShiftHighbitVideoFrame(video_frame);
-      ConvertVideoFrameToRGBPixels(temporary_frame.get(), rgb_pixels,
-                                   row_bytes);
+    case PIXEL_FORMAT_YUV444P12:
+      temporary_frame = DownShiftHighbitVideoFrame(video_frame);
+      video_frame = temporary_frame.get();
       break;
-    }
-
     case PIXEL_FORMAT_Y16:
-      // Since it is grayscale conversion, we disregard SK_PMCOLOR_BYTE_ORDER
-      // and always use GL_RGBA.
+      // Since it is grayscale conversion, we disregard
+      // SK_PMCOLOR_BYTE_ORDER and always use GL_RGBA.
       FlipAndConvertY16(video_frame, static_cast<uint8_t*>(rgb_pixels), GL_RGBA,
                         GL_UNSIGNED_BYTE, false /*flip_y*/, row_bytes);
+      return;
+    default:
       break;
+  }
 
-    case PIXEL_FORMAT_NV12:
-      LIBYUV_NV12_TO_ARGB(video_frame->visible_data(VideoFrame::kYPlane),
-                          video_frame->stride(VideoFrame::kYPlane),
-                          video_frame->visible_data(VideoFrame::kUVPlane),
-                          video_frame->stride(VideoFrame::kUVPlane),
-                          static_cast<uint8_t*>(rgb_pixels), row_bytes,
-                          video_frame->visible_rect().width(),
-                          video_frame->visible_rect().height());
-      break;
+  constexpr size_t task_bytes = 1024 * 1024;  // 1 MiB
+  size_t frame_bytes = row_bytes * video_frame->visible_rect().height();
+  size_t n_tasks =
+      std::min<size_t>(std::max<size_t>(1, frame_bytes / task_bytes),
+                       base::SysInfo::NumberOfProcessors());
+  base::WaitableEvent event;
+  base::RepeatingClosure barrier = base::BarrierClosure(
+      n_tasks,
+      base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event)));
 
-    case PIXEL_FORMAT_NV21:
-    case PIXEL_FORMAT_YUY2:
-    case PIXEL_FORMAT_ARGB:
-    case PIXEL_FORMAT_XRGB:
-    case PIXEL_FORMAT_RGB24:
-    case PIXEL_FORMAT_MJPEG:
-    case PIXEL_FORMAT_ABGR:
-    case PIXEL_FORMAT_XBGR:
-    case PIXEL_FORMAT_P016LE:
-    case PIXEL_FORMAT_XR30:
-    case PIXEL_FORMAT_XB30:
-    case PIXEL_FORMAT_UNKNOWN:
-      NOTREACHED() << "Only YUV formats and Y16 are supported, got: "
-                   << media::VideoPixelFormatToString(video_frame->format());
+  for (size_t i = 1; i < n_tasks; ++i) {
+    base::PostTask(FROM_HERE,
+                   base::BindOnce(ConvertVideoFrameToRGBPixelsTask,
+                                  base::Unretained(video_frame), rgb_pixels,
+                                  row_bytes, i, n_tasks, &barrier));
+  }
+  ConvertVideoFrameToRGBPixelsTask(video_frame, rgb_pixels, row_bytes, 0,
+                                   n_tasks, &barrier);
+  {
+    base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
+    event.Wait();
   }
 }
 
diff --git a/mojo/core/multiprocess_message_pipe_unittest.cc b/mojo/core/multiprocess_message_pipe_unittest.cc
index a241f57..bb06bccb 100644
--- a/mojo/core/multiprocess_message_pipe_unittest.cc
+++ b/mojo/core/multiprocess_message_pipe_unittest.cc
@@ -1311,6 +1311,38 @@
     CloseHandle(handles[i]);
 }
 
+TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
+       ReceiveMessagesSentJustBeforeProcessDeath) {
+  // Regression test for https://crbug.com/1005510. The client will write a
+  // message to the pipe it gives us and then it will die immediately. We should
+  // always be able to read the message received on that pipe.
+  RunTestClient("SpotaneouslyDyingProcess", [&](MojoHandle child) {
+    MojoHandle receiver;
+    EXPECT_EQ("receiver", ReadMessageWithHandles(child, &receiver, 1));
+    EXPECT_EQ("ok", ReadMessage(receiver));
+  });
+}
+
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(SpotaneouslyDyingProcess,
+                                  MultiprocessMessagePipeTest,
+                                  parent) {
+  MojoHandle sender;
+  MojoHandle receiver;
+  CreateMessagePipe(&sender, &receiver);
+
+  WriteMessageWithHandles(parent, "receiver", &receiver, 1);
+
+  // Wait for the pipe to actually appear as remote. Before this happens, it's
+  // possible for message transmission to be deferred to the IO thread, and
+  // sudden termination might preempt that work.
+  WaitForSignals(sender, MOJO_HANDLE_SIGNAL_PEER_REMOTE);
+
+  WriteMessage(sender, "ok");
+
+  // Here process termination is imminent. If the bug reappears this test will
+  // fail flakily.
+}
+
 TEST_F(MultiprocessMessagePipeTest, MessagePipeStatusChangeInTransit) {
   MojoHandle local_handles[4];
   MojoHandle sent_handles[4];
diff --git a/mojo/core/ports/node.cc b/mojo/core/ports/node.cc
index ec1e05c..476594d 100644
--- a/mojo/core/ports/node.cc
+++ b/mojo/core/ports/node.cc
@@ -87,6 +87,8 @@
   if (port->state == Port::kClosed)
     return false;
   if (port->peer_closed || port->remove_proxy_on_last_message) {
+    if (port->peer_lost_unexpectedly)
+      return port->message_queue.HasNextMessage();
     if (port->last_sequence_num_to_receive == next_sequence_num - 1)
       return false;
   }
@@ -1538,9 +1540,7 @@
           // messages.
 
           port->peer_closed = true;
-          port->last_sequence_num_to_receive =
-              port->message_queue.next_sequence_num() - 1;
-
+          port->peer_lost_unexpectedly = true;
           if (port->state == Port::kReceiving)
             ports_to_notify.push_back(local_port_ref);
         }
diff --git a/mojo/core/ports/port.cc b/mojo/core/ports/port.cc
index c3ead1e..0d2aa746 100644
--- a/mojo/core/ports/port.cc
+++ b/mojo/core/ports/port.cc
@@ -18,7 +18,8 @@
       sequence_num_to_acknowledge(0),
       message_queue(next_sequence_num_to_receive),
       remove_proxy_on_last_message(false),
-      peer_closed(false) {}
+      peer_closed(false),
+      peer_lost_unexpectedly(false) {}
 
 Port::~Port() {}
 
diff --git a/mojo/core/ports/port.h b/mojo/core/ports/port.h
index cc36568..cd798df0 100644
--- a/mojo/core/ports/port.h
+++ b/mojo/core/ports/port.h
@@ -166,6 +166,13 @@
   // non-zero cyclic routing distance) receiving Port has been closed.
   bool peer_closed;
 
+  // Indicates that this Port lost its peer unexpectedly (e.g. via process death
+  // rather than receiving an ObserveClosure event). In this case
+  // |peer_closed| will be true but |last_sequence_num_to_receive| cannot be
+  // known. Such ports will continue to make message available until their
+  // message queue is empty.
+  bool peer_lost_unexpectedly;
+
   Port(uint64_t next_sequence_num_to_send,
        uint64_t next_sequence_num_to_receive);
 
diff --git a/net/cert/cert_verify_proc_builtin.cc b/net/cert/cert_verify_proc_builtin.cc
index 5984834..b8f3ba2 100644
--- a/net/cert/cert_verify_proc_builtin.cc
+++ b/net/cert/cert_verify_proc_builtin.cc
@@ -445,7 +445,7 @@
     const scoped_refptr<ParsedCertificate>& target,
     CertIssuerSourceStatic* intermediates,
     SystemTrustStore* ssl_trust_store,
-    base::Time verification_time,
+    const der::GeneralizedTime& der_verification_time,
     base::TimeTicks deadline,
     VerificationType verification_type,
     SimplePathBuilderDelegate::DigestPolicy digest_policy,
@@ -455,13 +455,6 @@
     CertNetFetcher* net_fetcher,
     const EVRootCAMetadata* ev_metadata,
     bool* checked_revocation) {
-  der::GeneralizedTime der_verification_time;
-  if (!der::EncodeTimeAsGeneralizedTime(verification_time,
-                                        &der_verification_time)) {
-    // This shouldn't be possible.
-    return CertPathBuilder::Result();
-  }
-
   // Path building will require candidate paths to conform to at least one of
   // the policies in |user_initial_policy_set|.
   std::set<der::Input> user_initial_policy_set;
@@ -612,6 +605,15 @@
   base::Time verification_time = base::Time::Now();
   base::TimeTicks deadline = base::TimeTicks::Now() + kMaxVerificationTime;
 
+  der::GeneralizedTime der_verification_time;
+  if (!der::EncodeTimeAsGeneralizedTime(verification_time,
+                                        &der_verification_time)) {
+    // This shouldn't be possible.
+    // We don't really have a good error code for this type of error.
+    verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
+    return ERR_CERT_AUTHORITY_INVALID;
+  }
+
   // Parse the target certificate.
   scoped_refptr<ParsedCertificate> target =
       ParseCertificateFromBuffer(input_cert->cert_buffer(), &parsing_errors);
@@ -678,7 +680,7 @@
 
     // Run the attempt through the path builder.
     result = TryBuildPath(
-        target, &intermediates, ssl_trust_store.get(), verification_time,
+        target, &intermediates, ssl_trust_store.get(), der_verification_time,
         deadline, cur_attempt.verification_type, cur_attempt.digest_policy,
         flags, ocsp_response, crl_set, net_fetcher_.get(), ev_metadata,
         &checked_revocation_for_some_path);
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index a6fbc30f..919820c 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -104,8 +104,8 @@
     "src/sandbox_policy.h",
     "src/sandbox_policy_base.cc",
     "src/sandbox_policy_base.h",
-    "src/sandbox_policy_info.cc",
-    "src/sandbox_policy_info.h",
+    "src/sandbox_policy_diagnostic.cc",
+    "src/sandbox_policy_diagnostic.h",
     "src/sandbox_rand.cc",
     "src/sandbox_rand.h",
     "src/sandbox_types.h",
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc
index 2fc8a7a..bc9da0c 100644
--- a/sandbox/win/src/broker_services.cc
+++ b/sandbox/win/src/broker_services.cc
@@ -22,6 +22,7 @@
 #include "sandbox/win/src/process_mitigations.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/sandbox_policy_diagnostic.h"
 #include "sandbox/win/src/target_process.h"
 #include "sandbox/win/src/win2k_threadpool.h"
 #include "sandbox/win/src/win_utils.h"
@@ -126,6 +127,26 @@
                                reinterpret_cast<LPOVERLAPPED>(tracker));
 }
 
+// Helper class to send policy lists
+class PolicyDiagnosticList final : public sandbox::PolicyList {
+ public:
+  PolicyDiagnosticList() {}
+  ~PolicyDiagnosticList() override {}
+  void push_back(std::unique_ptr<sandbox::PolicyInfo> info) {
+    internal_list_.push_back(std::move(info));
+  }
+  std::vector<std::unique_ptr<sandbox::PolicyInfo>>::iterator begin() override {
+    return internal_list_.begin();
+  }
+  std::vector<std::unique_ptr<sandbox::PolicyInfo>>::iterator end() override {
+    return internal_list_.end();
+  }
+  size_t size() const override { return internal_list_.size(); }
+
+ private:
+  std::vector<std::unique_ptr<sandbox::PolicyInfo>> internal_list_;
+};
+
 }  // namespace
 
 namespace sandbox {
@@ -335,17 +356,17 @@
       receiver.reset(static_cast<PolicyDiagnosticsReceiver*>(
           reinterpret_cast<void*>(ovl)));
       // The PollicyInfo ctor copies essential information from the trackers.
-      auto policy_list = std::make_unique<PolicyList>();
+      auto policy_list = std::make_unique<PolicyDiagnosticList>();
       for (auto&& process_tracker : processes) {
         if (process_tracker->policy) {
-          policy_list->push_back(
-              std::make_unique<PolicyInfo>(process_tracker->policy.get()));
+          policy_list->push_back(std::make_unique<PolicyDiagnostic>(
+              process_tracker->policy.get()));
         }
       }
       for (auto&& job_tracker : jobs) {
         if (job_tracker->policy) {
           policy_list->push_back(
-              std::make_unique<PolicyInfo>(job_tracker->policy.get()));
+              std::make_unique<PolicyDiagnostic>(job_tracker->policy.get()));
         }
       }
       // Receiver should return quickly.
diff --git a/sandbox/win/src/broker_services.h b/sandbox/win/src/broker_services.h
index 360d9f7..c268b07 100644
--- a/sandbox/win/src/broker_services.h
+++ b/sandbox/win/src/broker_services.h
@@ -18,7 +18,6 @@
 #include "sandbox/win/src/crosscall_server.h"
 #include "sandbox/win/src/job.h"
 #include "sandbox/win/src/sandbox.h"
-#include "sandbox/win/src/sandbox_policy_info.h"
 #include "sandbox/win/src/sharedmem_ipc_server.h"
 #include "sandbox/win/src/win2k_threadpool.h"
 #include "sandbox/win/src/win_utils.h"
diff --git a/sandbox/win/src/sandbox.h b/sandbox/win/src/sandbox.h
index 7e9662c2..9dfebfcc1 100644
--- a/sandbox/win/src/sandbox.h
+++ b/sandbox/win/src/sandbox.h
@@ -38,13 +38,10 @@
 
 class BrokerServices;
 class PolicyDiagnosticsReceiver;
-class PolicyInfo;
 class ProcessState;
 class TargetPolicy;
 class TargetServices;
 
-using PolicyList = std::vector<std::unique_ptr<PolicyInfo>>;
-
 // BrokerServices exposes all the broker API.
 // The basic use is to start the target(s) and wait for them to end.
 //
@@ -165,6 +162,24 @@
   ~TargetServices() {}
 };
 
+class PolicyInfo {
+ public:
+  // Returns a JSON representation of the policy snapshot.
+  // This pointer has the same lifetime as this PolicyInfo object.
+  virtual const char* JsonString() = 0;
+  virtual ~PolicyInfo() {}
+};
+
+// This is returned by BrokerServices::GetPolicyDiagnostics().
+// PolicyInfo entries need not be ordered.
+class PolicyList {
+ public:
+  virtual std::vector<std::unique_ptr<PolicyInfo>>::iterator begin() = 0;
+  virtual std::vector<std::unique_ptr<PolicyInfo>>::iterator end() = 0;
+  virtual size_t size() const = 0;
+  virtual ~PolicyList() {}
+};
+
 // This class mediates calls to BrokerServices::GetPolicyDiagnostics().
 class PolicyDiagnosticsReceiver {
  public:
diff --git a/sandbox/win/src/sandbox_constants.cc b/sandbox/win/src/sandbox_constants.cc
index 90c33d3..1d93242 100644
--- a/sandbox/win/src/sandbox_constants.cc
+++ b/sandbox/win/src/sandbox_constants.cc
@@ -5,7 +5,13 @@
 #include "sandbox/win/src/sandbox_constants.h"
 
 namespace sandbox {
-// Strings used as keys in base::Value snapshots of Policies.
-extern const char kProcessIds[] = "process_ids";
-
+// Strings used as keys in base::Value snapshots of Policies for WebUI.
+extern const char kAppContainerSid[] = "appContainerSid";
+extern const char kDesiredIntegrityLevel[] = "desiredIntegrityLevel";
+extern const char kDesiredMitigations[] = "desiredMitigations";
+extern const char kJobLevel[] = "jobLevel";
+extern const char kLockdownLevel[] = "lockdownLevel";
+extern const char kLowboxSid[] = "lowboxSid";
+extern const char kPlatformMitigations[] = "platformMitigations";
+extern const char kProcessIds[] = "processIds";
 }  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_constants.h b/sandbox/win/src/sandbox_constants.h
index 76d4d91..baf9a1e4 100644
--- a/sandbox/win/src/sandbox_constants.h
+++ b/sandbox/win/src/sandbox_constants.h
@@ -7,6 +7,13 @@
 
 namespace sandbox {
 // Strings used as keys in base::Value snapshots of Policies.
+extern const char kAppContainerSid[];
+extern const char kDesiredIntegrityLevel[];
+extern const char kDesiredMitigations[];
+extern const char kJobLevel[];
+extern const char kLockdownLevel[];
+extern const char kLowboxSid[];
+extern const char kPlatformMitigations[];
 extern const char kProcessIds[];
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index 0f5e26ac..03a8948 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -32,7 +32,7 @@
 namespace sandbox {
 
 class LowLevelPolicy;
-class PolicyInfo;
+class PolicyDiagnostic;
 class TargetProcess;
 struct PolicyGlobal;
 
@@ -115,7 +115,7 @@
 
  private:
   // Allow PolicyInfo to snapshot PolicyBase for diagnostics.
-  friend class PolicyInfo;
+  friend class PolicyDiagnostic;
   ~PolicyBase();
 
   // Sets up interceptions for a new target.
diff --git a/sandbox/win/src/sandbox_policy_diagnostic.cc b/sandbox/win/src/sandbox_policy_diagnostic.cc
new file mode 100644
index 0000000..50a28ae0
--- /dev/null
+++ b/sandbox/win/src/sandbox_policy_diagnostic.cc
@@ -0,0 +1,195 @@
+// 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 "sandbox/win/src/sandbox_policy_diagnostic.h"
+
+#include <stddef.h>
+
+#include <cinttypes>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "sandbox/win/src/sandbox_constants.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/target_process.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+namespace {
+
+base::Value ProcessIdList(std::vector<uint32_t> process_ids) {
+  base::Value results(base::Value::Type::LIST);
+  for (const auto pid : process_ids) {
+    results.GetList().push_back(base::Value(base::strict_cast<double>(pid)));
+  }
+  return results;
+}
+
+std::string GetTokenLevelInEnglish(TokenLevel token) {
+  switch (token) {
+    case USER_LOCKDOWN:
+      return "Lockdown";
+    case USER_RESTRICTED:
+      return "Restricted";
+    case USER_LIMITED:
+      return "Limited";
+    case USER_INTERACTIVE:
+      return "Interactive";
+    case USER_NON_ADMIN:
+      return "Non Admin";
+    case USER_RESTRICTED_SAME_ACCESS:
+      return "Restricted Same Access";
+    case USER_UNPROTECTED:
+      return "Unprotected";
+    case USER_LAST:
+    default:
+      DCHECK(false) << "Unknown TokenType";
+      return "Unknown";
+  }
+}
+
+std::string GetJobLevelInEnglish(JobLevel job) {
+  switch (job) {
+    case JOB_LOCKDOWN:
+      return "Lockdown";
+    case JOB_RESTRICTED:
+      return "Restricted";
+    case JOB_LIMITED_USER:
+      return "Limited User";
+    case JOB_INTERACTIVE:
+      return "Interactive";
+    case JOB_UNPROTECTED:
+      return "Unprotected";
+    case JOB_NONE:
+      return "None";
+    default:
+      DCHECK(false) << "Unknown JobLevel";
+      return "Unknown";
+  }
+}
+
+std::string GetIntegrityLevelInEnglish(IntegrityLevel integrity) {
+  switch (integrity) {
+    case INTEGRITY_LEVEL_SYSTEM:
+      return "S-1-16-16384 System";
+    case INTEGRITY_LEVEL_HIGH:
+      return "S-1-16-12288 High";
+    case INTEGRITY_LEVEL_MEDIUM:
+      return "S-1-16-8192 Medium";
+    case INTEGRITY_LEVEL_MEDIUM_LOW:
+      return "S-1-16-6144 Medium Low";
+    case INTEGRITY_LEVEL_LOW:
+      return "S-1-16-4096 Low";
+    case INTEGRITY_LEVEL_BELOW_LOW:
+      return "S-1-16-2048 Below Low";
+    case INTEGRITY_LEVEL_UNTRUSTED:
+      return "S-1-16-0 Untrusted";
+    case INTEGRITY_LEVEL_LAST:
+      return "Default";
+    default:
+      DCHECK(false) << "Unknown IntegrityLevel";
+      return "Unknown";
+  }
+}
+
+base::string16 GetSidAsString(const Sid* sid) {
+  base::string16 result;
+  if (!sid->ToSddlString(&result))
+    DCHECK(false) << "Failed to make sddl string";
+  return result;
+}
+
+std::string GetMitigationsAsHex(MitigationFlags mitigations) {
+  return base::StringPrintf("%016" PRIx64,
+                            base::checked_cast<uint64_t>(mitigations));
+}
+
+std::string GetPlatformMitigationsAsHex(MitigationFlags mitigations) {
+  DWORD64 platform_flags[2] = {0};
+  size_t flags_size = 0;
+  sandbox::ConvertProcessMitigationsToPolicy(mitigations, &(platform_flags[0]),
+                                             &flags_size);
+  DCHECK(flags_size / sizeof(DWORD64) <= 2)
+      << "Unexpected mitigation flags size";
+  if (flags_size == 2 * sizeof(DWORD64))
+    return base::StringPrintf("%016" PRIx64 "%016" PRIx64, platform_flags[0],
+                              platform_flags[1]);
+  return base::StringPrintf("%016" PRIx64, platform_flags[0]);
+}
+
+}  // namespace
+
+// We are a friend of PolicyBase so that we can steal its private members
+// quickly in the BrokerServices tracker thread.
+PolicyDiagnostic::PolicyDiagnostic(PolicyBase* policy) {
+  DCHECK(policy);
+  // TODO(crbug/997273) Add more fields once webui plumbing is complete.
+  {
+    AutoLock lock(&policy->lock_);
+    for (auto&& target_process : policy->targets_) {
+      process_ids_.push_back(
+          base::strict_cast<uint32_t>(target_process->ProcessId()));
+    }
+  }
+  lockdown_level_ = policy->lockdown_level_;
+  job_level_ = policy->job_level_;
+
+  // Select the final integrity level.
+  if (policy->delayed_integrity_level_ == INTEGRITY_LEVEL_LAST)
+    desired_integrity_level_ = policy->integrity_level_;
+  else
+    desired_integrity_level_ = policy->delayed_integrity_level_;
+
+  desired_mitigations_ = policy->mitigations_ | policy->delayed_mitigations_;
+
+  if (policy->app_container_profile_)
+    app_container_sid_ =
+        std::make_unique<Sid>(policy->app_container_profile_->GetPackageSid());
+  if (policy->lowbox_sid_)
+    lowbox_sid_ = std::make_unique<Sid>(policy->lowbox_sid_);
+}
+
+PolicyDiagnostic::~PolicyDiagnostic() = default;
+
+const char* PolicyDiagnostic::JsonString() {
+  // Lazily constructs json_string_.
+  if (json_string_)
+    return json_string_->c_str();
+
+  base::Value value(base::Value::Type::DICTIONARY);
+  value.SetKey(kProcessIds, ProcessIdList(process_ids_));
+  value.SetKey(kLockdownLevel,
+               base::Value(GetTokenLevelInEnglish(lockdown_level_)));
+  value.SetKey(kJobLevel, base::Value(GetJobLevelInEnglish(job_level_)));
+  value.SetKey(
+      kDesiredIntegrityLevel,
+      base::Value(GetIntegrityLevelInEnglish(desired_integrity_level_)));
+  value.SetKey(kDesiredMitigations,
+               base::Value(GetMitigationsAsHex(desired_mitigations_)));
+  value.SetKey(kPlatformMitigations,
+               base::Value(GetPlatformMitigationsAsHex(desired_mitigations_)));
+
+  if (app_container_sid_)
+    value.SetKey(kAppContainerSid,
+                 base::Value(GetSidAsString(app_container_sid_.get())));
+
+  if (lowbox_sid_)
+    value.SetKey(kLowboxSid, base::Value(GetSidAsString(lowbox_sid_.get())));
+
+  auto json_string = std::make_unique<std::string>();
+  JSONStringValueSerializer to_json(json_string.get());
+  CHECK(to_json.Serialize(value));
+  json_string_ = std::move(json_string);
+  return json_string_->c_str();
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_policy_diagnostic.h b/sandbox/win/src/sandbox_policy_diagnostic.h
new file mode 100644
index 0000000..0fb4da7
--- /dev/null
+++ b/sandbox/win/src/sandbox_policy_diagnostic.h
@@ -0,0 +1,51 @@
+// 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 SANDBOX_WIN_SRC_SANDBOX_POLICY_DIAGNOSTIC_H_
+#define SANDBOX_WIN_SRC_SANDBOX_POLICY_DIAGNOSTIC_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/values.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/security_level.h"
+#include "sandbox/win/src/sid.h"
+
+namespace sandbox {
+
+class PolicyBase;
+
+// Intended to rhyme with TargetPolicy, may eventually share a common base
+// with a configuration holding class (i.e. this class will extend with dynamic
+// members such as the |process_ids_| list.)
+class PolicyDiagnostic final : public PolicyInfo {
+ public:
+  // This should quickly copy what it needs from PolicyBase.
+  PolicyDiagnostic(PolicyBase* policy);
+  ~PolicyDiagnostic() override;
+  const char* JsonString() override;
+
+ private:
+  // |json_string_| is lazily constructed.
+  std::unique_ptr<std::string> json_string_;
+  std::vector<uint32_t> process_ids_;
+  TokenLevel lockdown_level_ = USER_LAST;
+  JobLevel job_level_ = JOB_NONE;
+  IntegrityLevel desired_integrity_level_ = INTEGRITY_LEVEL_LAST;
+  MitigationFlags desired_mitigations_ = 0;
+  std::unique_ptr<Sid> app_container_sid_ = nullptr;
+  std::unique_ptr<Sid> lowbox_sid_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyDiagnostic);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SANDBOX_POLICY_DIAGNOSTIC_H_
diff --git a/sandbox/win/src/sandbox_policy_info.cc b/sandbox/win/src/sandbox_policy_info.cc
deleted file mode 100644
index 10360fa8..0000000
--- a/sandbox/win/src/sandbox_policy_info.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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 "sandbox/win/src/sandbox_policy_info.h"
-
-#include "base/numerics/safe_conversions.h"
-#include "base/values.h"
-#include "sandbox/win/src/sandbox_constants.h"
-#include "sandbox/win/src/sandbox_policy_base.h"
-#include "sandbox/win/src/target_process.h"
-
-namespace sandbox {
-
-namespace {
-
-base::Value ProcessIdList(std::vector<uint32_t>& pids) {
-  base::ListValue results;
-  for (auto pid : pids) {
-    results.GetList().push_back(base::Value(base::strict_cast<double>(pid)));
-  }
-
-  return std::move(results);
-}
-}  // namespace
-
-// We are a friend of PolicyBase so that we can steal its private members
-// quickly in the BrokerServices tracker thread.
-PolicyInfo::PolicyInfo(PolicyBase* policy) {
-  DCHECK(policy);
-  // TODO(crbug/997273) Add more fields once webui plumbing is complete.
-  {
-    AutoLock lock(&policy->lock_);
-    for (auto&& target_process : policy->targets_) {
-      process_ids_.push_back(
-          base::strict_cast<uint32_t>(target_process->ProcessId()));
-    }
-  }
-}
-
-PolicyInfo::~PolicyInfo() {}
-
-base::Value PolicyInfo::GetValue() {
-  // TODO(crbug/997273) Add more fields once webui plumbing is complete.
-  base::DictionaryValue val;
-  val.SetKey(kProcessIds, ProcessIdList(process_ids_));
-  return std::move(val);
-}
-
-}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_policy_info.h b/sandbox/win/src/sandbox_policy_info.h
deleted file mode 100644
index b329402..0000000
--- a/sandbox/win/src/sandbox_policy_info.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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 SANDBOX_WIN_SRC_SANDBOX_POLICY_INFO_H_
-#define SANDBOX_WIN_SRC_SANDBOX_POLICY_INFO_H_
-
-#include <vector>
-
-#include "base/values.h"
-
-namespace sandbox {
-
-class PolicyBase;
-
-// Intended to rhyme with TargetPolicy, may eventually share a common base
-// with a configuration holding class (i.e. this class will extend with dynamic
-// members such as the |process_ids_| list.)
-class PolicyInfo {
- public:
-  // This should quickly copy what it needs from PolicyBase.
-  PolicyInfo(PolicyBase* policy);
-  ~PolicyInfo();
-
-  base::Value GetValue();
-
- private:
-  std::vector<uint32_t> process_ids_;
-
-  DISALLOW_COPY_AND_ASSIGN(PolicyInfo);
-};
-
-}  // namespace sandbox
-
-#endif  // SANDBOX_WIN_SRC_SANDBOX_POLICY_INFO_H_
diff --git a/sandbox/win/tests/integration_tests/integration_tests_test.cc b/sandbox/win/tests/integration_tests/integration_tests_test.cc
index 55665f0..52f11828 100644
--- a/sandbox/win/tests/integration_tests/integration_tests_test.cc
+++ b/sandbox/win/tests/integration_tests/integration_tests_test.cc
@@ -13,7 +13,6 @@
 #include "base/win/scoped_handle.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_factory.h"
-#include "sandbox/win/src/sandbox_policy_info.h"
 #include "sandbox/win/src/target_services.h"
 #include "sandbox/win/tests/common/controller.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/services/service_manager/sandbox/BUILD.gn b/services/service_manager/sandbox/BUILD.gn
index 0121475..b6c932f 100644
--- a/services/service_manager/sandbox/BUILD.gn
+++ b/services/service_manager/sandbox/BUILD.gn
@@ -96,6 +96,8 @@
   }
   if (is_win) {
     sources += [
+      "win/sandbox_diagnostics.cc",
+      "win/sandbox_diagnostics.h",
       "win/sandbox_win.cc",
       "win/sandbox_win.h",
     ]
diff --git a/services/service_manager/sandbox/win/sandbox_diagnostics.cc b/services/service_manager/sandbox/win/sandbox_diagnostics.cc
new file mode 100644
index 0000000..e0eed53e7
--- /dev/null
+++ b/services/service_manager/sandbox/win/sandbox_diagnostics.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/service_manager/sandbox/win/sandbox_diagnostics.h"
+
+#include <stddef.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/json/json_reader.h"
+#include "base/values.h"
+
+namespace service_manager {
+namespace {
+// Runs on a non-sandbox thread to ensure that response callback is not
+// invoked from sandbox process and job tracker thread, and that conversion
+// work does not block process or job registration. Converts |policies|
+// into base::Value form, then invokes |response| on the same sequence.
+static void ConvertToValuesAndRespond(
+    std::unique_ptr<sandbox::PolicyList> policies,
+    base::OnceCallback<void(base::Value)> response) {
+  base::Value policy_values(base::Value::Type::LIST);
+  for (auto&& item : *policies) {
+    auto snapshot = base::JSONReader::ReadAndReturnValueWithError(
+        item->JsonString(), base::JSON_PARSE_RFC);
+    CHECK(base::JSONReader::JSON_NO_ERROR == snapshot.error_code);
+    policy_values.GetList().push_back(std::move(snapshot.value.value()));
+  }
+  std::move(response).Run(std::move(policy_values));
+}
+
+// Runs on a non-sandbox thread to ensure that response callback is not
+// invoked from sandbox process and job tracker thread.
+static void RespondWithEmptyList(
+    base::OnceCallback<void(base::Value)> response) {
+  base::Value empty(base::Value::Type::LIST);
+  std::move(response).Run(std::move(empty));
+}
+
+}  // namespace
+
+ServiceManagerDiagnosticsReceiver::ServiceManagerDiagnosticsReceiver(
+    scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
+    base::OnceCallback<void(base::Value)> response)
+    : response_(std::move(response)), origin_task_runner_(origin_task_runner) {}
+
+ServiceManagerDiagnosticsReceiver::~ServiceManagerDiagnosticsReceiver() {}
+
+// This is called by the sandbox's process and job tracking thread and must
+// return quickly.
+void ServiceManagerDiagnosticsReceiver::ReceiveDiagnostics(
+    std::unique_ptr<sandbox::PolicyList> policies) {
+  // Need to run the conversion work on the origin thread.
+  origin_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&ConvertToValuesAndRespond, std::move(policies),
+                                std::move(response_)));
+}
+
+// This is called by the sandbox's process and job tracking thread and must
+// return quickly so we post to the origin thread.
+void ServiceManagerDiagnosticsReceiver::OnError(sandbox::ResultCode error) {
+  origin_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&RespondWithEmptyList, std::move(response_)));
+}
+
+}  // namespace service_manager
diff --git a/services/service_manager/sandbox/win/sandbox_diagnostics.h b/services/service_manager/sandbox/win/sandbox_diagnostics.h
new file mode 100644
index 0000000..5470fe1
--- /dev/null
+++ b/services/service_manager/sandbox/win/sandbox_diagnostics.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_SERVICE_MANAGER_SANDBOX_WIN_SANDBOX_DIAGNOSTICS_H_
+#define SERVICES_SERVICE_MANAGER_SANDBOX_WIN_SANDBOX_DIAGNOSTICS_H_
+
+#include "services/service_manager/sandbox/win/sandbox_win.h"
+
+#include <stddef.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/sequenced_task_runner.h"
+#include "base/values.h"
+#include "sandbox/constants.h"
+#include "sandbox/win/src/sandbox.h"
+
+namespace service_manager {
+
+// Mediates response from sandbox::BrokerServices->GetPolicyDiagnostics.
+class ServiceManagerDiagnosticsReceiver
+    : public sandbox::PolicyDiagnosticsReceiver {
+ public:
+  ~ServiceManagerDiagnosticsReceiver() final;
+  ServiceManagerDiagnosticsReceiver(
+      scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
+      base::OnceCallback<void(base::Value)> response);
+
+  // This is called by the sandbox's process and job tracking thread and must
+  // return quickly.
+  void ReceiveDiagnostics(
+      std::unique_ptr<sandbox::PolicyList> policies) override;
+
+  // This is called by the sandbox's process and job tracking thread and must
+  // return quickly.
+  void OnError(sandbox::ResultCode error) override;
+
+ private:
+  base::OnceCallback<void(base::Value)> response_;
+  scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
+};
+}  // namespace service_manager
+
+#endif  // SERVICES_SERVICE_MANAGER_SANDBOX_WIN_SANDBOX_DIAGNOSTICS_H_
diff --git a/services/service_manager/sandbox/win/sandbox_win.cc b/services/service_manager/sandbox/win/sandbox_win.cc
index 6abb333..7fca3e21 100644
--- a/services/service_manager/sandbox/win/sandbox_win.cc
+++ b/services/service_manager/sandbox/win/sandbox_win.cc
@@ -24,7 +24,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
-#include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string16.h"
@@ -34,25 +33,22 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
-#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
-#include "base/values.h"
 #include "base/win/iat_patch_function.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/win_util.h"
 #include "base/win/windows_version.h"
-#include "sandbox/constants.h"
 #include "sandbox/win/src/app_container_profile.h"
 #include "sandbox/win/src/job.h"
 #include "sandbox/win/src/process_mitigations.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_nt_util.h"
 #include "sandbox/win/src/sandbox_policy_base.h"
-#include "sandbox/win/src/sandbox_policy_info.h"
 #include "sandbox/win/src/win_utils.h"
 #include "services/service_manager/sandbox/features.h"
 #include "services/service_manager/sandbox/sandbox_type.h"
 #include "services/service_manager/sandbox/switches.h"
+#include "services/service_manager/sandbox/win/sandbox_diagnostics.h"
 
 namespace service_manager {
 namespace {
@@ -669,60 +665,6 @@
   return sandbox::SBOX_ALL_OK;
 }
 
-// Runs on a non-sandbox thread to ensure that response callback is not
-// invoked from sandbox process and job tracker thread, and that conversion
-// work does not block process or job registration. Converts |policies|
-// into base::Value form, then invokes |response| on the same thread.
-static void ConvertToValuesAndRespond(
-    std::unique_ptr<sandbox::PolicyList> policies,
-    base::OnceCallback<void(base::Value)> response) {
-  base::Value policy_values(base::Value::Type::LIST);
-  for (auto&& item : *policies) {
-    base::Value policy_value = item->GetValue();
-    policy_values.GetList().push_back(std::move(policy_value));
-  }
-  std::move(response).Run(std::move(policy_values));
-}
-
-// Runs on a non-sandbox thread to ensure that response callback is not
-// invoked from sandbox process and job tracker thread.
-static void RespondWithEmptyList(
-    base::OnceCallback<void(base::Value)> response) {
-  base::Value empty(base::Value::Type::LIST);
-  std::move(response).Run(std::move(empty));
-}
-
-// Mediates response from sandbox::BrokerServices->GetPolicyDiagnostics.
-class ServiceManagerDiagnosticsReceiver
-    : public sandbox::PolicyDiagnosticsReceiver {
- public:
-  ~ServiceManagerDiagnosticsReceiver() final {}
-  ServiceManagerDiagnosticsReceiver(
-      scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
-      base::OnceCallback<void(base::Value)> response)
-      : response_(std::move(response)),
-        origin_task_runner_(origin_task_runner) {}
-  // This is called by the sandbox's process and job tracking thread and must
-  // return quickly.
-  void ReceiveDiagnostics(
-      std::unique_ptr<sandbox::PolicyList> policies) override {
-    // Need to run the conversion work on the origin thread.
-    origin_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&ConvertToValuesAndRespond,
-                                  std::move(policies), std::move(response_)));
-  }
-  // This is called by the sandbox's process and job tracking thread and must
-  // return quickly so we post to the origin thread.
-  void OnError(sandbox::ResultCode error) override {
-    origin_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&RespondWithEmptyList, std::move(response_)));
-  }
-
- private:
-  base::OnceCallback<void(base::Value)> response_;
-  scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
-};
-
 }  // namespace
 
 // static
diff --git a/services/service_manager/sandbox/win/sandbox_win.h b/services/service_manager/sandbox/win/sandbox_win.h
index 6b12fd5..aa67fd3 100644
--- a/services/service_manager/sandbox/win/sandbox_win.h
+++ b/services/service_manager/sandbox/win/sandbox_win.h
@@ -9,6 +9,7 @@
 
 #include <string>
 
+#include "base/bind.h"
 #include "base/callback_forward.h"
 #include "base/process/launch.h"
 #include "base/process/process_handle.h"
diff --git a/services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom b/services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom
index 4e64279..5b83e33b 100644
--- a/services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom
+++ b/services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom
@@ -121,7 +121,7 @@
   ChangeTarget(FrameSinkId? frame_sink_id);
 
   // Starts emitting video frames to the given |consumer|.
-  Start(FrameSinkVideoConsumer consumer);
+  Start(pending_remote<FrameSinkVideoConsumer> consumer);
 
   // Stops capturing "soon." Meaning, no new frame captures will be started, but
   // there may already be some in-flight for delivery. Wait for the "end of
@@ -138,7 +138,8 @@
   // "on top of" those with lesser values. Specifying the same index as an
   // existing overlay will cause the existing one to be dropped and replaced
   // with a new one.
-  CreateOverlay(int32 stacking_index, FrameSinkVideoCaptureOverlay& request);
+  CreateOverlay(int32 stacking_index,
+                pending_receiver<FrameSinkVideoCaptureOverlay> receiver);
 };
 
 // Control interface for a small image to be composited on top of each captured
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index 05fdc25..5adda6e 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -451,6 +451,23 @@
             }
           ]
         },
+        "test": "profile_provider_unittest"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-16.04",
+              "pool": "chrome.tests.cros-vm"
+            }
+          ]
+        },
         "test": "sandbox_linux_unittests"
       },
       {
@@ -987,6 +1004,23 @@
             }
           ]
         },
+        "test": "profile_provider_unittest"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-16.04",
+              "pool": "chrome.tests.cros-vm"
+            }
+          ]
+        },
         "test": "sandbox_linux_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index b4b1982..d3cdb8ce 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -457,6 +457,23 @@
             }
           ]
         },
+        "test": "profile_provider_unittest"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-16.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
         "test": "sandbox_linux_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 37ad168..6aa4057 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -8624,6 +8624,26 @@
           "hard_timeout": 3600,
           "io_timeout": 3600
         },
+        "test": "profile_provider_unittest"
+      },
+      {
+        "isolate_coverage_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-16.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ],
+          "hard_timeout": 3600,
+          "io_timeout": 3600
+        },
         "test": "sandbox_linux_unittests"
       },
       {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 12639828..4e8d2dfe 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -2288,6 +2288,10 @@
     "label": "//printing:printing_unittests",
     "type": "console_test_launcher",
   },
+  "profile_provider_unittest": {
+    "label": "//chrome/browser/metrics/perf:profile_provider_unittest",
+    "type": "raw",
+  },
   "prtime_fuzzer": {
     "label": "//testing/libfuzzer/fuzzers:prtime_fuzzer",
     "type": "fuzzer",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index edf688d..26cc559a 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -423,6 +423,7 @@
       'ozone_unittests': {},
       'pdf_unittests': {},
       'printing_unittests': {},
+      'profile_provider_unittest': {},
       'sandbox_linux_unittests': {},
       'sql_unittests': {},
       'url_unittests': {},
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 07dc766..99a8b35 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -271,12 +271,6 @@
 const base::Feature kDecodeLossyWebPImagesToYUV{
     "DecodeLossyWebPImagesToYUV", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables usage of render frame observer as the receiver of the resource
-// loading hints in the render process.
-// https://crbug.com/891328.
-const base::Feature kSendPreviewsLoadingHintsBeforeCommit{
-    "SendPreviewsLoadingHintsBeforeCommit", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables cache-aware WebFonts loading. See https://crbug.com/570205.
 // The feature is disabled on Android for WebView API issue discussed at
 // https://crbug.com/942440.
@@ -352,11 +346,6 @@
 const base::Feature kCanvasAlwaysDeferral{"CanvasAlwaysDeferral",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Use the new C++ implementation of WHATWG Streams. See
-// https://crbug.com/977500.
-const base::Feature kStreamsNative{"StreamsNative",
-                                   base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Blink garbage collection.
 // Enables compaction of backing stores on Blink's heap.
 const base::Feature kBlinkHeapCompaction{"BlinkHeapCompaction",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 4e3c03df..6b297d1 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -81,9 +81,6 @@
 BLINK_COMMON_EXPORT extern const base::Feature kDecodeLossyWebPImagesToYUV;
 
 BLINK_COMMON_EXPORT extern const base::Feature
-    kSendPreviewsLoadingHintsBeforeCommit;
-
-BLINK_COMMON_EXPORT extern const base::Feature
     kWebFontsCacheAwareTimeoutAdaption;
 BLINK_COMMON_EXPORT extern const base::Feature
     kBlockingFocusWithoutUserActivation;
@@ -108,8 +105,6 @@
 
 BLINK_COMMON_EXPORT extern const base::Feature kCanvasAlwaysDeferral;
 
-BLINK_COMMON_EXPORT extern const base::Feature kStreamsNative;
-
 // Blink garbage collection.
 BLINK_COMMON_EXPORT extern const base::Feature kBlinkHeapCompaction;
 BLINK_COMMON_EXPORT extern const base::Feature kBlinkHeapConcurrentMarking;
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index 1ea5aad..9ce62ac 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -239,7 +239,6 @@
   BLINK_PLATFORM_EXPORT static void
   EnablePauseExecutionContextOnBackgroundFreeze(bool);
   BLINK_PLATFORM_EXPORT static void EnableConsolidatedMovementXY(bool);
-  BLINK_PLATFORM_EXPORT static void EnableStreamsNative(bool);
   BLINK_PLATFORM_EXPORT static void EnableMouseSubframeNoImplicitCapture(bool);
   BLINK_PLATFORM_EXPORT static void EnableBackForwardCache(bool);
 
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index 0b9a7778..7b70a23f 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -26,8 +26,6 @@
                     "core/v8/custom/v8_message_channel_custom.cc",
                     "core/v8/custom/v8_pop_state_event_custom.cc",
                     "core/v8/custom/v8_promise_rejection_event_custom.cc",
-                    "core/v8/custom/v8_readable_stream_custom.cc",
-                    "core/v8/custom/v8_writable_stream_custom.cc",
                     "core/v8/custom/v8_shadow_root_custom.cc",
                     "core/v8/custom/v8_window_custom.cc",
                     "core/v8/custom/v8_xml_http_request_custom.cc",
@@ -42,8 +40,6 @@
                     "core/v8/idl_dictionary_base.h",
                     "core/v8/idl_types.h",
                     "core/v8/idl_types_base.h",
-                    "core/v8/initialize_v8_extras_binding.cc",
-                    "core/v8/initialize_v8_extras_binding.h",
                     "core/v8/iterable.h",
                     "core/v8/js_based_event_listener.cc",
                     "core/v8/js_based_event_listener.h",
@@ -193,7 +189,6 @@
           "core/v8/binding_security_test.cc",
           "core/v8/dictionary_test.cc",
           "core/v8/dom_wrapper_world_test.cc",
-          "core/v8/initialize_v8_extras_binding_test.cc",
           "core/v8/idl_types_test.cc",
           "core/v8/module_record_test.cc",
           "core/v8/boxed_v8_module_test.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc b/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc
deleted file mode 100644
index e1baf4a..0000000
--- a/third_party/blink/renderer/bindings/core/v8/custom/v8_readable_stream_custom.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_native.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_wrapper.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-void V8ReadableStream::ConstructorCustom(
-    const v8::FunctionCallbackInfo<v8::Value>& info) {
-  RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(
-      info.GetIsolate(), "Blink_ReadableStream_ConstructorCallback");
-
-  ExceptionState exception_state(info.GetIsolate(),
-                                 ExceptionState::kConstructionContext,
-                                 "ReadableStream");
-  ScriptState* script_state =
-      ScriptState::From(info.NewTarget().As<v8::Object>()->CreationContext());
-
-  ScriptValue underlying_source =
-      ScriptValue(info.GetIsolate(), v8::Undefined(info.GetIsolate()));
-  ScriptValue strategy =
-      ScriptValue(info.GetIsolate(), v8::Undefined(info.GetIsolate()));
-  int num_args = info.Length();
-  if (num_args >= 1) {
-    underlying_source = ScriptValue(info.GetIsolate(), info[0]);
-  }
-  if (num_args >= 2)
-    strategy = ScriptValue(info.GetIsolate(), info[1]);
-
-  v8::Local<v8::Object> wrapper = info.Holder();
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    auto* impl = MakeGarbageCollected<ReadableStreamNative>(
-        script_state, underlying_source, strategy, false, exception_state);
-    if (exception_state.HadException()) {
-      return;
-    }
-    wrapper = impl->AssociateWithWrapper(
-        info.GetIsolate(), V8ReadableStream::GetWrapperTypeInfo(), wrapper);
-  } else {
-    auto* impl = MakeGarbageCollected<ReadableStreamWrapper>();
-    wrapper = impl->AssociateWithWrapper(
-        info.GetIsolate(), V8ReadableStream::GetWrapperTypeInfo(), wrapper);
-
-    impl->Init(script_state, underlying_source, strategy, exception_state);
-    if (exception_state.HadException()) {
-      return;
-    }
-  }
-  V8SetReturnValue(info, wrapper);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/custom/v8_writable_stream_custom.cc b/third_party/blink/renderer/bindings/core/v8/custom/v8_writable_stream_custom.cc
deleted file mode 100644
index d9c253d1..0000000
--- a/third_party/blink/renderer/bindings/core/v8/custom/v8_writable_stream_custom.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this sink code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/core/streams/writable_stream_native.h"
-#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-void V8WritableStream::ConstructorCustom(
-    const v8::FunctionCallbackInfo<v8::Value>& info) {
-  RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(
-      info.GetIsolate(), "Blink_WritableStream_ConstructorCallback");
-
-  ExceptionState exception_state(info.GetIsolate(),
-                                 ExceptionState::kConstructionContext,
-                                 "WritableStream");
-  ScriptState* script_state =
-      ScriptState::From(info.NewTarget().As<v8::Object>()->CreationContext());
-
-  ScriptValue underlying_sink =
-      ScriptValue(info.GetIsolate(), v8::Undefined(info.GetIsolate()));
-  ScriptValue strategy =
-      ScriptValue(info.GetIsolate(), v8::Undefined(info.GetIsolate()));
-  int num_args = info.Length();
-  if (num_args >= 1) {
-    underlying_sink = ScriptValue(info.GetIsolate(), info[0]);
-  }
-  if (num_args >= 2)
-    strategy = ScriptValue(info.GetIsolate(), info[1]);
-  v8::Local<v8::Object> wrapper = info.Holder();
-
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    auto* impl = MakeGarbageCollected<WritableStreamNative>(
-        script_state, underlying_sink, strategy, exception_state);
-    if (exception_state.HadException()) {
-      return;
-    }
-    wrapper = impl->AssociateWithWrapper(
-        info.GetIsolate(), V8WritableStream::GetWrapperTypeInfo(), wrapper);
-  } else {
-    auto* impl = MakeGarbageCollected<WritableStreamWrapper>();
-    wrapper = impl->AssociateWithWrapper(
-        info.GetIsolate(), V8WritableStream::GetWrapperTypeInfo(), wrapper);
-    impl->Init(script_state, underlying_sink, strategy, exception_state);
-    if (exception_state.HadException()) {
-      return;
-    }
-  }
-
-  V8SetReturnValue(info, wrapper);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc b/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
deleted file mode 100644
index 13c3a909..0000000
--- a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.h"
-
-#include <algorithm>
-#include <iterator>
-
-#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
-#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/platform/bindings/to_v8.h"
-#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-namespace {
-
-// This macro avoids duplicating the name and hence prevents typos.
-#define WEB_FEATURE_ID_NAME_LOOKUP_ENTRY(id) \
-  { #id, WebFeature::k##id }
-
-struct WebFeatureIdNameLookupEntry {
-  const char* const name;
-  const WebFeature id;
-};
-
-// TODO(ricea): Replace with a more efficient data structure if the
-// number of entries increases.
-constexpr WebFeatureIdNameLookupEntry web_feature_id_name_lookup_table[] = {
-    WEB_FEATURE_ID_NAME_LOOKUP_ENTRY(ReadableStreamConstructor),
-    WEB_FEATURE_ID_NAME_LOOKUP_ENTRY(WritableStreamConstructor),
-    WEB_FEATURE_ID_NAME_LOOKUP_ENTRY(TransformStreamConstructor),
-};
-
-#undef WEB_FEATURE_ID_NAME_LOOKUP_ENTRY
-
-class CountUseForBindings : public ScriptFunction {
- public:
-  static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
-    auto* self = MakeGarbageCollected<CountUseForBindings>(script_state);
-    return self->BindToV8Function();
-  }
-
-  explicit CountUseForBindings(ScriptState* script_state)
-      : ScriptFunction(script_state) {}
-
- private:
-  ScriptValue Call(ScriptValue value) override {
-    String string_id;
-    if (!value.ToString(string_id)) {
-      V8ThrowException::ThrowTypeError(GetScriptState()->GetIsolate(),
-                                       "countUse requires a string argument");
-      return ScriptValue();
-    }
-
-    auto* const it =
-        std::find_if(std::begin(web_feature_id_name_lookup_table),
-                     std::end(web_feature_id_name_lookup_table),
-                     [&string_id](const WebFeatureIdNameLookupEntry& entry) {
-                       return string_id == entry.name;
-                     });
-
-    if (it == std::end(web_feature_id_name_lookup_table)) {
-      V8ThrowException::ThrowTypeError(GetScriptState()->GetIsolate(),
-                                       "unknown use counter");
-      return ScriptValue();
-    }
-
-    UseCounter::Count(ExecutionContext::From(GetScriptState()), it->id);
-
-    return ScriptValue::From(GetScriptState(), ToV8UndefinedGenerator());
-  }
-};
-
-void AddQueuingStrategies(ScriptState* script_state,
-                          v8::Local<v8::Object> binding) {
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled())
-    return;
-
-  v8::Local<v8::Context> context = script_state->GetContext();
-  v8::Local<v8::Object> global = context->Global();
-  v8::Isolate* isolate = script_state->GetIsolate();
-
-  constexpr const char* constructors[] = {"CountQueuingStrategy",
-                                          "ByteLengthQueuingStrategy"};
-  for (const auto* constructor : constructors) {
-    auto v8name = V8AtomicString(isolate, constructor);
-    // There's no meaningful way we can recover if the lookup fails.
-    auto value = binding->Get(context, v8name).ToLocalChecked();
-    bool result =
-        global->DefineOwnProperty(context, v8name, value, v8::DontEnum)
-            .ToChecked();
-    DCHECK(result);
-  }
-}
-
-void AddCountUse(ScriptState* script_state, v8::Local<v8::Object> binding) {
-  v8::Local<v8::Function> fn =
-      CountUseForBindings::CreateFunction(script_state);
-  v8::Local<v8::String> name =
-      V8AtomicString(script_state->GetIsolate(), "countUse");
-  binding->Set(script_state->GetContext(), name, fn).ToChecked();
-}
-
-void AddOriginals(ScriptState* script_state, v8::Local<v8::Object> binding) {
-  // These values are only used when serialization is enabled.
-  if (!RuntimeEnabledFeatures::TransferableStreamsEnabled())
-    return;
-
-  v8::Local<v8::Object> global = script_state->GetContext()->Global();
-  v8::Local<v8::Context> context = script_state->GetContext();
-  v8::Isolate* isolate = script_state->GetIsolate();
-
-  const auto ObjectGet = [&context, &isolate](v8::Local<v8::Value> object,
-                                              const char* property) {
-    DCHECK(object->IsObject());
-    return object.As<v8::Object>()
-        ->Get(context, V8AtomicString(isolate, property))
-        .ToLocalChecked();
-  };
-
-  const auto GetPrototype = [&ObjectGet](v8::Local<v8::Value> object) {
-    return ObjectGet(object, "prototype");
-  };
-
-  const auto GetOwnPD = [&context, &isolate](v8::Local<v8::Value> object,
-                                             const char* property) {
-    DCHECK(object->IsObject());
-    return object.As<v8::Object>()
-        ->GetOwnPropertyDescriptor(context, V8AtomicString(isolate, property))
-        .ToLocalChecked();
-  };
-
-  const auto GetOwnPDGet = [&ObjectGet, &GetOwnPD](v8::Local<v8::Value> object,
-                                                   const char* property) {
-    return ObjectGet(GetOwnPD(object, property), "get");
-  };
-
-  const auto Bind = [&context, &isolate, &binding](const char* name,
-                                                   v8::Local<v8::Value> value) {
-    bool result =
-        binding
-            ->CreateDataProperty(context, V8AtomicString(isolate, name), value)
-            .ToChecked();
-    DCHECK(result);
-  };
-
-  v8::Local<v8::Value> message_port = ObjectGet(global, "MessagePort");
-  v8::Local<v8::Value> dom_exception = ObjectGet(global, "DOMException");
-
-  // Most Worklets don't have MessagePort. In this case, serialization will
-  // fail. AudioWorklet has MessagePort but no DOMException, so it can't use
-  // serialization for now.
-  if (message_port->IsUndefined() || dom_exception->IsUndefined()) {
-    // Allow V8 Extras JavaScript to safely detect that MessagePort is not
-    // available. Without this, lookups of MessagePort_postMessage will follow
-    // the prototype chain.
-    Bind("MessagePort_postMessage", v8::Undefined(isolate));
-    return;
-  }
-
-  v8::Local<v8::Value> event_target_prototype =
-      GetPrototype(ObjectGet(global, "EventTarget"));
-  Bind("EventTarget_addEventListener",
-       ObjectGet(event_target_prototype, "addEventListener"));
-
-  v8::Local<v8::Value> message_port_prototype = GetPrototype(message_port);
-  Bind("MessagePort_postMessage",
-       ObjectGet(message_port_prototype, "postMessage"));
-  Bind("MessagePort_close", ObjectGet(message_port_prototype, "close"));
-  Bind("MessagePort_start", ObjectGet(message_port_prototype, "start"));
-
-  v8::Local<v8::Value> message_event_prototype =
-      GetPrototype(ObjectGet(global, "MessageEvent"));
-
-  Bind("MessageEvent_data_get", GetOwnPDGet(message_event_prototype, "data"));
-
-  Bind("DOMException", dom_exception);
-
-  v8::Local<v8::Value> dom_exception_prototype = GetPrototype(dom_exception);
-  Bind("DOMException_message_get",
-       GetOwnPDGet(dom_exception_prototype, "message"));
-  Bind("DOMException_name_get", GetOwnPDGet(dom_exception_prototype, "name"));
-}
-
-}  // namespace
-
-void InitializeV8ExtrasBinding(ScriptState* script_state) {
-  v8::Local<v8::Object> binding =
-      script_state->GetContext()->GetExtrasBindingObject();
-  AddQueuingStrategies(script_state, binding);
-  AddCountUse(script_state, binding);
-  AddOriginals(script_state, binding);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.h b/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.h
deleted file mode 100644
index c48ca71..0000000
--- a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_INITIALIZE_V8_EXTRAS_BINDING_H_
-#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_INITIALIZE_V8_EXTRAS_BINDING_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-
-namespace blink {
-
-class ScriptState;
-
-// Copy CountQueuingStrategy and ByteLengthQueuingStrategy to the global object.
-//
-// Also add the JavaScript function countUse() to the "binding" object that is
-// exposed to the JavaScript streams implementations.
-//
-// binding.countUse() takes a string and calls UseCounter::Count() on the
-// matching ID. It only does anything the first time it is called in a
-// particular execution context. The use of a string argument avoids duplicating
-// the IDs in the JS files, but means that JS code should avoid calling it more
-// than once to avoid unnecessary overhead. Only string IDs that this code
-// specifically knows about will work.
-//
-// Also copy the original values of MessageChannel, MessagePort and MessageEvent
-// methods and accessors to the binding object where they can be used for
-// serialization by the streams code.
-//
-// This function must be called during initialisation of the V8 context. When
-// the StreamsNative feature is enabled it does nothing.
-//
-// countUse() is not available during snapshot creation.
-void CORE_EXPORT InitializeV8ExtrasBinding(ScriptState*);
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_INITIALIZE_V8_EXTRAS_BINDING_H_
diff --git a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding_test.cc b/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding_test.cc
deleted file mode 100644
index 8aa6643..0000000
--- a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding_test.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-namespace {
-
-// Add "binding" to the global object. Production code should never do this;
-// it would be a huge security hole.
-void AddExtrasBindingToGlobal(V8TestingScope* scope) {
-  auto context = scope->GetContext();
-  v8::Local<v8::Object> global = context->Global();
-  v8::Local<v8::Object> binding = context->GetExtrasBindingObject();
-  v8::Local<v8::String> key = V8AtomicString(scope->GetIsolate(), "binding");
-  global->Set(context, key, binding).FromJust();
-}
-
-TEST(InitializeV8ExtrasBindingTest, SupportedId) {
-  ScopedStreamsNativeForTest enabled(false);
-  V8TestingScope scope;
-  InitializeV8ExtrasBinding(scope.GetScriptState());
-  AddExtrasBindingToGlobal(&scope);
-  Page::InsertOrdinaryPageForTesting(&scope.GetPage());
-
-  ScriptValue rv = EvalWithPrintingError(
-      &scope, "binding.countUse('TransformStreamConstructor');");
-  EXPECT_TRUE(rv.IsUndefined());
-  EXPECT_TRUE(scope.GetDocument().IsUseCounted(
-      WebFeature::kTransformStreamConstructor));
-}
-
-TEST(InitializeV8ExtrasBindingTest, UnsupportedId) {
-  ScopedStreamsNativeForTest enabled(false);
-  V8TestingScope scope;
-  InitializeV8ExtrasBinding(scope.GetScriptState());
-  AddExtrasBindingToGlobal(&scope);
-
-  ScriptValue rv = EvalWithPrintingError(&scope,
-                                         "let result;"
-                                         "try {"
-                                         "  binding.countUse('WindowEvent');"
-                                         "  result = 'FAIL';"
-                                         "} catch (e) {"
-                                         "  result = e.name;"
-                                         "}"
-                                         "result");
-  String result;
-  EXPECT_TRUE(rv.ToString(result));
-  EXPECT_EQ("TypeError", result);
-}
-
-}  // namespace
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
index 116f103..4eb7d114 100644
--- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
+++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
@@ -30,7 +30,6 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/local_window_proxy.h"
 
-#include "third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.h"
 #include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
@@ -216,10 +215,6 @@
 
   InstallConditionalFeatures();
 
-  // This needs to go after everything else since it accesses the window object.
-  // WARNING: May modify the global object!
-  InitializeV8ExtrasBinding(script_state_);
-
   if (World().IsMainWorld()) {
     GetFrame()->Loader().DispatchDidClearWindowObjectInMainWorld();
   }
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.cc b/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.cc
index 3332019..0bad9aa 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h"
 
+#include "third_party/blink/public/mojom/messaging/user_activation_snapshot.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/frame.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h b/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h
index 2edf1d69..0dce019 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SERIALIZATION_POST_MESSAGE_HELPER_H_
 
 #include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/mojom/messaging/user_activation_snapshot.mojom-blink.h"
+#include "third_party/blink/public/mojom/messaging/user_activation_snapshot.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "v8/include/v8.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
index b6555d1..94ce5a1 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
@@ -525,22 +525,4 @@
     V8Initializer::MessageHandlerInWorker(message, exception);
 }
 
-v8::MaybeLocal<v8::Value> V8ScriptRunner::CallExtraHelper(
-    ScriptState* script_state,
-    const char* name,
-    uint32_t num_args,
-    v8::Local<v8::Value>* args) {
-  v8::Isolate* isolate = script_state->GetIsolate();
-  v8::Local<v8::Value> function_value;
-  v8::Local<v8::Context> context = script_state->GetContext();
-  if (!context->GetExtrasBindingObject()
-           ->Get(context, V8AtomicString(isolate, name))
-           .ToLocal(&function_value))
-    return v8::MaybeLocal<v8::Value>();
-  v8::Local<v8::Function> function = function_value.As<v8::Function>();
-  return V8ScriptRunner::CallInternalFunction(
-      isolate, ToMicrotaskQueue(script_state), function, v8::Undefined(isolate),
-      num_args, args);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h
index 002f4ce7c..fb0ad51e 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.h
@@ -103,26 +103,12 @@
                                        const String& file_name,
                                        const WTF::TextPosition&);
 
-  // Calls a function on the V8 extras binding object.
-  template <uint32_t N>
-  static v8::MaybeLocal<v8::Value> CallExtra(ScriptState* script_state,
-                                             const char* name,
-                                             v8::Local<v8::Value> (&args)[N]) {
-    return CallExtraHelper(script_state, name, N, args);
-  }
-
   // Reports an exception to the message handler, as if it were an uncaught
   // exception. Can only be called on the main thread.
   //
   // TODO(adamk): This should live on V8ThrowException, but it depends on
   // V8Initializer and so can't trivially move to platform/bindings.
   static void ReportException(v8::Isolate*, v8::Local<v8::Value> exception);
-
- private:
-  static v8::MaybeLocal<v8::Value> CallExtraHelper(ScriptState*,
-                                                   const char* name,
-                                                   uint32_t num_args,
-                                                   v8::Local<v8::Value>* args);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
index 7382cbd..57106f4 100644
--- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
@@ -33,7 +33,6 @@
 #include <memory>
 
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.h"
 #include "third_party/blink/renderer/bindings/core/v8/referrer_script_info.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
@@ -308,11 +307,6 @@
   wrapper_type_info->InstallConditionalFeatures(
       context, *world_, global_object, v8::Local<v8::Object>(),
       v8::Local<v8::Function>(), global_interface_template);
-
-  // This can only be called after the global object is fully initialised, as it
-  // reads values from it.
-  // WARNING: May modify the global object!
-  InitializeV8ExtrasBinding(script_state_);
 }
 
 void WorkerOrWorkletScriptController::DisableEvalInternal(
diff --git a/third_party/blink/renderer/controller/blink_initializer.cc b/third_party/blink/renderer/controller/blink_initializer.cc
index 8c3dcd1..bf1baaf 100644
--- a/third_party/blink/renderer/controller/blink_initializer.cc
+++ b/third_party/blink/renderer/controller/blink_initializer.cc
@@ -196,12 +196,6 @@
 
   frame.GetInterfaceRegistry()->AddInterface(WTF::BindRepeating(
       &LocalFrame::PauseSubresourceLoading, WrapWeakPersistent(&frame)));
-  if (!base::FeatureList::IsEnabled(
-          blink::features::kSendPreviewsLoadingHintsBeforeCommit)) {
-    frame.GetInterfaceRegistry()->AddInterface(WTF::BindRepeating(
-        &LocalFrame::BindPreviewsResourceLoadingHintsReceiver,
-        WrapWeakPersistent(&frame)));
-  }
   ModulesInitializer::InitLocalFrame(frame);
 }
 
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 177ab33..3c414a8 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1535,7 +1535,6 @@
     "scroll/scrollbar_theme_overlay_test.cc",
     "streams/miscellaneous_operations_test.cc",
     "streams/queue_with_sizes_test.cc",
-    "streams/readable_stream_operations_test.cc",
     "streams/readable_stream_test.cc",
     "streams/stream_promise_resolver_test.cc",
     "streams/test_underlying_source.h",
diff --git a/third_party/blink/renderer/core/exported/web_document_loader_impl.cc b/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
index e151b55..620a58b 100644
--- a/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_document_loader_impl.cc
@@ -152,11 +152,6 @@
 
 void WebDocumentLoaderImpl::SetLoadingHintsProvider(
     std::unique_ptr<blink::WebLoadingHintsProvider> loading_hints_provider) {
-  if (!base::FeatureList::IsEnabled(
-          blink::features::kSendPreviewsLoadingHintsBeforeCommit)) {
-    return;
-  }
-
   DocumentLoader::SetPreviewsResourceLoadingHints(
       PreviewsResourceLoadingHints::CreateFromLoadingHintsProvider(
           *GetFrame()->GetDocument(), std::move(loading_hints_provider)));
diff --git a/third_party/blink/renderer/core/fileapi/blob.cc b/third_party/blink/renderer/core/fileapi/blob.cc
index 09f21e5..e3701368 100644
--- a/third_party/blink/renderer/core/fileapi/blob.cc
+++ b/third_party/blink/renderer/core/fileapi/blob.cc
@@ -40,8 +40,6 @@
 #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h"
 #include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_operations.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_wrapper.h"
 #include "third_party/blink/renderer/core/url/dom_url.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 5e8ec60..0c69b3a 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -95,7 +95,6 @@
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
 #include "third_party/blink/renderer/core/loader/idleness_detector.h"
-#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h"
 #include "third_party/blink/renderer/core/page/drag_controller.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/page/plugin_data.h"
@@ -430,7 +429,6 @@
   GetInputMethodController().DidAttachDocument(document);
   GetSpellChecker().DidAttachDocument(document);
   GetTextSuggestionController().DidAttachDocument(document);
-  previews_resource_loading_hints_receiver_.reset();
 }
 
 void LocalFrame::Reload(WebFrameLoadType load_type) {
@@ -1502,15 +1500,6 @@
   GetEventHandler().AnimateSnapFling(monotonic_time);
 }
 
-void LocalFrame::BindPreviewsResourceLoadingHintsReceiver(
-    mojo::PendingReceiver<
-        blink::mojom::blink::PreviewsResourceLoadingHintsReceiver> receiver) {
-  DCHECK(!previews_resource_loading_hints_receiver_);
-  previews_resource_loading_hints_receiver_ =
-      std::make_unique<PreviewsResourceLoadingHintsReceiverImpl>(
-          std::move(receiver), GetDocument());
-}
-
 SmoothScrollSequencer& LocalFrame::GetSmoothScrollSequencer() {
   if (!IsLocalRoot())
     return LocalFrameRoot().GetSmoothScrollSequencer();
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index c46222b..0e571be 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -41,7 +41,6 @@
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom-blink-forward.h"
-#include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/reporting/reporting.mojom-blink.h"
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink-forward.h"
 #include "third_party/blink/public/platform/task_type.h"
@@ -403,10 +402,6 @@
     return client_hints_preferences_;
   }
 
-  void BindPreviewsResourceLoadingHintsReceiver(
-      mojo::PendingReceiver<
-          blink::mojom::blink::PreviewsResourceLoadingHintsReceiver> receiver);
-
   SmoothScrollSequencer& GetSmoothScrollSequencer();
 
   const mojo::Remote<mojom::blink::ReportingServiceProxy>& GetReportingService()
@@ -571,9 +566,6 @@
   // Per-frame URLLoader factory.
   std::unique_ptr<WebURLLoaderFactory> url_loader_factory_;
 
-  std::unique_ptr<mojom::blink::PreviewsResourceLoadingHintsReceiver>
-      previews_resource_loading_hints_receiver_;
-
   ClientHintsPreferences client_hints_preferences_;
 
   // The value of |is_save_data_enabled_| is read once per frame from
diff --git a/third_party/blink/renderer/core/html/forms/date_time_chooser.h b/third_party/blink/renderer/core/html/forms/date_time_chooser.h
index 94fcbd5..07cbacb6 100644
--- a/third_party/blink/renderer/core/html/forms/date_time_chooser.h
+++ b/third_party/blink/renderer/core/html/forms/date_time_chooser.h
@@ -63,6 +63,9 @@
   bool required;
   bool is_anchor_element_rtl;
   // The fields below are used for type="time".
+  // For some locales the am/pm is the first field, so is_ampm_first informs
+  // the time popup when the am/pm column should be the first one.
+  bool is_ampm_first;
   bool has_ampm;
   bool has_second;
   bool has_millisecond;
diff --git a/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc b/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
index 69f7dd5..d06ef511 100644
--- a/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
+++ b/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
@@ -178,6 +178,7 @@
   AddProperty("isFormControlsRefreshEnabled",
               RuntimeEnabledFeatures::FormControlsRefreshEnabled(), data);
   AddProperty("mode", parameters_->type.GetString(), data);
+  AddProperty("isAMPMFirst", parameters_->is_ampm_first, data);
   AddProperty("hasAMPM", parameters_->has_ampm, data);
   AddProperty("hasSecond", parameters_->has_second, data);
   AddProperty("hasMillisecond", parameters_->has_millisecond, data);
diff --git a/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc b/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
index 8a2cd35..6b53778c 100644
--- a/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
+++ b/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
@@ -841,6 +841,11 @@
   return false;
 }
 
+bool DateTimeEditElement::IsFirstFieldAMPM() const {
+  const auto* first_field = FieldAt(0);
+  return first_field && first_field->Type() == DateTimeField::kAMPM;
+}
+
 bool DateTimeEditElement::HasFocusedField() {
   return FocusedFieldIndex() != kInvalidFieldIndex;
 }
diff --git a/third_party/blink/renderer/core/html/forms/date_time_edit_element.h b/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
index e2ce2c1..02e0cee 100644
--- a/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
+++ b/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
@@ -111,6 +111,7 @@
   String Value() const;
   DateTimeFieldsState ValueAsDateTimeFieldsState() const;
   bool HasField(DateTimeField) const;
+  bool IsFirstFieldAMPM() const;
 
  private:
   static const wtf_size_t kInvalidFieldIndex = UINT_MAX;
diff --git a/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc b/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc
index 04fed82..2cda4c4 100644
--- a/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc
+++ b/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc
@@ -314,6 +314,7 @@
     DateTimeChooserParameters& parameters) {
   // TODO(iopopesc): Get the field information by parsing the datetime format.
   if (DateTimeEditElement* edit = GetDateTimeEditElement()) {
+    parameters.is_ampm_first = edit->IsFirstFieldAMPM();
     parameters.has_ampm = edit->HasField(DateTimeField::kAMPM);
     parameters.has_second = edit->HasField(DateTimeField::kSecond);
     parameters.has_millisecond = edit->HasField(DateTimeField::kMillisecond);
diff --git a/third_party/blink/renderer/core/html/forms/resources/calendarPicker.js b/third_party/blink/renderer/core/html/forms/resources/calendarPicker.js
index 006f968..f30d7e4 100644
--- a/third_party/blink/renderer/core/html/forms/resources/calendarPicker.js
+++ b/third_party/blink/renderer/core/html/forms/resources/calendarPicker.js
@@ -60,6 +60,7 @@
     isLocaleRTL: false,
     isFormControlsRefreshEnabled: false,
     mode: 'date',
+    isAMPMFirst: false,
     hasAMPM: false,
     hasSecond: false,
     hasMillisecond: false,
diff --git a/third_party/blink/renderer/core/html/forms/resources/time_picker.js b/third_party/blink/renderer/core/html/forms/resources/time_picker.js
index 625a1ce..321a32bf 100644
--- a/third_party/blink/renderer/core/html/forms/resources/time_picker.js
+++ b/third_party/blink/renderer/core/html/forms/resources/time_picker.js
@@ -24,6 +24,17 @@
   MINUTE: 2,
   SECOND: 3,
   MILLISECOND: 4,
+  AMPM: 5,
+};
+
+
+/**
+ * Supported label types.
+ * @enum {number}
+ */
+const Label = {
+  AM: 0,
+  PM: 1,
 };
 
 /**
@@ -65,10 +76,13 @@
     }
   };
 
-  value = (columnType) => {
+  value = (columnType, hasAMPM) => {
     switch (columnType) {
       case TimeColumnType.HOUR:
-        return this.hour_.toString().padStart(2, '0');
+        let hour = hasAMPM ?
+            (this.hour_ % Time.Maximum_Hour_AMPM || Time.Maximum_Hour_AMPM) :
+            this.hour_;
+        return hour.toString().padStart(2, '0');
       case TimeColumnType.MINUTE:
         return this.minute_.toString().padStart(2, '0');
       case TimeColumnType.SECOND:
@@ -90,6 +104,16 @@
     return value;
   };
 
+  clone =
+      () => {
+        return new Time(
+            this.hour_, this.minute_, this.second_, this.millisecond_);
+      }
+
+  isAM = () => {
+    return this.hour_ < Time.Maximum_Hour_AMPM;
+  };
+
   static parse = (str) => {
     var match = Time.ISOStringRegExp.exec(str);
     if (!match)
@@ -112,10 +136,10 @@
         currentDate.getSeconds(), currentDate.getMilliseconds());
   };
 
-  static numberOfValues = (columnType) => {
+  static numberOfValues = (columnType, hasAMPM) => {
     switch (columnType) {
       case TimeColumnType.HOUR:
-        return Time.HOUR_VALUES;
+        return hasAMPM ? Time.HOUR_VALUES_AMPM : Time.HOUR_VALUES;
       case TimeColumnType.MINUTE:
         return Time.MINUTE_VALUES;
       case TimeColumnType.SECOND:
@@ -128,8 +152,11 @@
 // See platform/date_components.h.
 Time.Minimum = new Time(0, 0, 0, 0);
 Time.Maximum = new Time(23, 59, 59, 999);
+Time.Maximum_Hour_AMPM = 12;
 Time.ISOStringRegExp = /^(\d+):(\d+):?(\d*).?(\d*)/;
+// Number of values for each column.
 Time.HOUR_VALUES = 24;
+Time.HOUR_VALUES_AMPM = 12;
 Time.MINUTE_VALUES = 60;
 Time.SECOND_VALUES = 60;
 Time.MILLISECOND_VALUES = 10;
@@ -159,6 +186,7 @@
                                           : Time.currentTime();
     this.hasSecond_ = config.hasSecond;
     this.hasMillisecond_ = config.hasMillisecond;
+    this.hasAMPM_ = config.hasAMPM;
   }
 
   onSubmitButtonClick_ = () => {
@@ -184,6 +212,10 @@
     return this.hasMillisecond_;
   }
 
+  get hasAMPM() {
+    return this.hasAMPM_;
+  }
+
   get width() {
     return this.timeColumns_.width;
   }
@@ -215,10 +247,18 @@
 
     this.className = TimeColumns.ClassName;
     this.hourColumn_ = new TimeColumn(TimeColumnType.HOUR, timePicker);
-    this.width_ = TimePicker.ColumnWidth;
+    this.width_ = 0;
     this.minuteColumn_ = new TimeColumn(TimeColumnType.MINUTE, timePicker);
-    this.append(this.hourColumn_, this.minuteColumn_);
-    this.width_ += TimePicker.ColumnWidth;
+    if (timePicker.hasAMPM) {
+      this.ampmColumn_ = new TimeColumn(TimeColumnType.AMPM, timePicker);
+    }
+    if (timePicker.hasAMPM && global.params.isAMPMFirst) {
+      this.append(this.ampmColumn_, this.hourColumn_, this.minuteColumn_);
+      this.width_ += 3 * TimePicker.ColumnWidth;
+    } else {
+      this.append(this.hourColumn_, this.minuteColumn_);
+      this.width_ += 2 * TimePicker.ColumnWidth;
+    }
     if (timePicker.hasSecond) {
       this.secondColumn_ = new TimeColumn(TimeColumnType.SECOND, timePicker);
       this.append(this.secondColumn_);
@@ -230,6 +270,10 @@
       this.append(this.millisecondColumn_);
       this.width_ += TimePicker.ColumnWidth;
     }
+    if (timePicker.hasAMPM && !global.params.isAMPMFirst) {
+      this.append(this.ampmColumn_);
+      this.width_ += TimePicker.ColumnWidth;
+    }
   }
 
   get width() {
@@ -237,7 +281,7 @@
   }
 
   selectedValue = () => {
-    const hour = parseInt(this.hourColumn_.selectedTimeCell.value, 10);
+    let hour = parseInt(this.hourColumn_.selectedTimeCell.value, 10);
     const minute = parseInt(this.minuteColumn_.selectedTimeCell.value, 10);
     const second = this.secondColumn_ ?
         parseInt(this.secondColumn_.selectedTimeCell.value, 10) :
@@ -245,6 +289,15 @@
     const millisecond = this.millisecondColumn_ ?
         parseInt(this.millisecondColumn_.selectedTimeCell.value, 10) :
         0;
+    if (this.ampmColumn_) {
+      const isAM = this.ampmColumn_.selectedTimeCell.textContent ==
+          global.params.ampmLabels[Label.AM];
+      if (isAM && hour == Time.Maximum_Hour_AMPM) {
+        hour = 0;
+      } else if (!isAM && hour != Time.Maximum_Hour_AMPM) {
+        hour += Time.Maximum_Hour_AMPM;
+      }
+    }
     return new Time(hour, minute, second, millisecond);
   }
 }
@@ -260,17 +313,22 @@
 
     this.className = TimeColumn.ClassName;
     this.columnType_ = columnType;
-    this.createAndInitializeCells_(timePicker);
+    if (this.columnType_ == TimeColumnType.AMPM) {
+      this.createAndInitializeAMPMCells_(timePicker);
+    } else {
+      this.createAndInitializeCells_(timePicker);
+    }
 
     this.addEventListener('click', this.onClick_);
   }
 
   createAndInitializeCells_ = (timePicker) => {
-    const totalCells = Time.numberOfValues(this.columnType_);
-    let currentTime = timePicker.selectedTime;
+    const totalCells = Time.numberOfValues(this.columnType_, timePicker.hasAMPM);
+    let currentTime = timePicker.selectedTime.clone();
     let cells = [];
     for (let i = 0; i < totalCells; i++) {
-      let timeCell = new TimeCell(currentTime.value(this.columnType_));
+      let value = currentTime.value(this.columnType_, timePicker.hasAMPM);
+      let timeCell = new TimeCell(value, localizeNumber(value));
       cells.push(timeCell);
       currentTime.next(this.columnType_);
     }
@@ -278,6 +336,23 @@
     this.append(...cells);
   }
 
+  createAndInitializeAMPMCells_ = (timePicker) => {
+    let cells = [];
+    for (let i = 0; i < 2; i++) {
+      let value = global.params.ampmLabels[i];
+      let timeCell = new TimeCell(value, value);
+      cells.push(timeCell);
+    }
+
+    if (timePicker.selectedTime.isAM()) {
+      this.append(cells[Label.AM], cells[Label.PM]);
+      this.selectedTimeCell = cells[Label.AM];
+    } else {
+      this.append(cells[Label.PM], cells[Label.AM]);
+      this.selectedTimeCell = cells[Label.PM];
+    }
+  }
+
   onClick_ = (event) => {
     this.selectedTimeCell = event.target;
   }
@@ -301,11 +376,11 @@
  * TimeCell: List item with a custom look that displays a time value.
  */
 class TimeCell extends HTMLLIElement {
-  constructor(value) {
+  constructor(value, localizedValue) {
     super();
 
     this.className = TimeCell.ClassName;
-    this.textContent = localizeNumber(value);
+    this.textContent = localizedValue;
     this.value = value;
   }
 }
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index 0e6d2e2..cf4d96e4 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -261,6 +261,54 @@
   }
 }
 
+// static
+LayoutUnit FlexItem::AlignmentOffset(LayoutUnit available_free_space,
+                                     ItemPosition position,
+                                     LayoutUnit ascent,
+                                     LayoutUnit max_ascent,
+                                     bool is_wrap_reverse,
+                                     bool is_deprecated_webkit_box) {
+  switch (position) {
+    case ItemPosition::kLegacy:
+    case ItemPosition::kAuto:
+    case ItemPosition::kNormal:
+      NOTREACHED();
+      break;
+    case ItemPosition::kStretch:
+      // Actual stretching must be handled by the caller. Since wrap-reverse
+      // flips cross start and cross end, stretch children should be aligned
+      // with the cross end. This matters because applyStretchAlignment
+      // doesn't always stretch or stretch fully (explicit cross size given, or
+      // stretching constrained by max-height/max-width). For flex-start and
+      // flex-end this is handled by alignmentForChild().
+      if (is_wrap_reverse)
+        return available_free_space;
+      break;
+    case ItemPosition::kFlexStart:
+      break;
+    case ItemPosition::kFlexEnd:
+      return available_free_space;
+    case ItemPosition::kCenter: {
+      const LayoutUnit result = (available_free_space / 2);
+      return is_deprecated_webkit_box ? result.ClampNegativeToZero() : result;
+    }
+    case ItemPosition::kBaseline:
+      // FIXME: If we get here in columns, we want the use the descent, except
+      // we currently can't get the ascent/descent of orthogonal children.
+      // https://bugs.webkit.org/show_bug.cgi?id=98076
+      return max_ascent - ascent;
+    case ItemPosition::kLastBaseline:
+    case ItemPosition::kSelfStart:
+    case ItemPosition::kSelfEnd:
+    case ItemPosition::kStart:
+    case ItemPosition::kEnd:
+    case ItemPosition::kLeft:
+    case ItemPosition::kRight:
+      // TODO(jferanndez): Implement these (https://crbug.com/722287).
+      break;
+  }
+  return LayoutUnit();
+}
 void FlexLine::FreezeViolations(ViolationsVector& violations) {
   const ComputedStyle& flex_box_style = algorithm->StyleRef();
   for (size_t i = 0; i < violations.size(); ++i) {
@@ -655,6 +703,62 @@
   }
 }
 
+void FlexLayoutAlgorithm::AlignChildren() {
+  // Keep track of the space between the baseline edge and the after edge of
+  // the box for each line.
+  Vector<LayoutUnit> min_margin_after_baselines;
+
+  for (FlexLine& line_context : flex_lines_) {
+    LayoutUnit min_margin_after_baseline = LayoutUnit::Max();
+    LayoutUnit max_ascent = line_context.max_ascent;
+
+    for (FlexItem& flex_item : line_context.line_items) {
+      DCHECK(!flex_item.box->IsOutOfFlowPositioned());
+
+      if (flex_item.UpdateAutoMarginsInCrossAxis(
+              std::max(LayoutUnit(), flex_item.AvailableAlignmentSpace()))) {
+        continue;
+      }
+
+      ItemPosition position = flex_item.Alignment();
+      if (position == ItemPosition::kStretch)
+        flex_item.ComputeStretchedSize();
+      LayoutUnit available_space = flex_item.AvailableAlignmentSpace();
+      LayoutUnit offset = FlexItem::AlignmentOffset(
+          available_space, position, flex_item.MarginBoxAscent(), max_ascent,
+          StyleRef().FlexWrap() == EFlexWrap::kWrapReverse,
+          StyleRef().IsDeprecatedWebkitBox());
+      flex_item.desired_location.Move(LayoutUnit(), offset);
+      if (position == ItemPosition::kBaseline &&
+          StyleRef().FlexWrap() == EFlexWrap::kWrapReverse) {
+        min_margin_after_baseline =
+            std::min(min_margin_after_baseline,
+                     flex_item.AvailableAlignmentSpace() - offset);
+      }
+    }
+    min_margin_after_baselines.push_back(min_margin_after_baseline);
+  }
+
+  if (StyleRef().FlexWrap() != EFlexWrap::kWrapReverse)
+    return;
+
+  // wrap-reverse flips the cross axis start and end. For baseline alignment,
+  // this means we need to align the after edge of baseline elements with the
+  // after edge of the flex line.
+  wtf_size_t line_number = 0;
+  for (FlexLine& line_context : flex_lines_) {
+    LayoutUnit min_margin_after_baseline =
+        min_margin_after_baselines[line_number++];
+    for (FlexItem& flex_item : line_context.line_items) {
+      if (flex_item.Alignment() == ItemPosition::kBaseline &&
+          !flex_item.HasAutoMarginsInCrossAxis() && min_margin_after_baseline) {
+        flex_item.desired_location.Move(LayoutUnit(),
+                                        min_margin_after_baseline);
+      }
+    }
+  }
+}
+
 TransformedWritingMode FlexLayoutAlgorithm::GetTransformedWritingMode() const {
   return GetTransformedWritingMode(*style_);
 }
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index 2099705..c845fdd 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -171,6 +171,13 @@
 
   inline const FlexLine* Line() const;
 
+  static LayoutUnit AlignmentOffset(LayoutUnit available_free_space,
+                                    ItemPosition position,
+                                    LayoutUnit ascent,
+                                    LayoutUnit max_ascent,
+                                    bool is_wrap_reverse,
+                                    bool is_deprecated_webkit_box);
+
   FlexLayoutAlgorithm* algorithm;
   wtf_size_t line_number;
   LayoutBox* box;
@@ -378,6 +385,10 @@
   // FlexLine::cross_axis_extent.
   void AlignFlexLines(LayoutUnit cross_axis_content_extent);
 
+  // Positions flex items by modifying FlexItem::desired_location.
+  // When lines stretch, also modifies FlexItem::cross_axis_size.
+  void AlignChildren();
+
   static TransformedWritingMode GetTransformedWritingMode(const ComputedStyle&);
 
   static const StyleContentAlignmentData& ContentAlignmentNormalBehavior();
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index bd605360..dcf2bd5 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -419,7 +419,7 @@
 
   AlignFlexLines(algorithm);
 
-  AlignChildren(line_contexts);
+  AlignChildren(algorithm);
 
   if (StyleRef().FlexWrap() == EFlexWrap::kWrapReverse)
     FlipForWrapReverse(line_contexts, cross_axis_start_edge);
@@ -1208,54 +1208,6 @@
                           border_and_padding, margin);
 }
 
-static LayoutUnit AlignmentOffset(LayoutUnit available_free_space,
-                                  ItemPosition position,
-                                  LayoutUnit ascent,
-                                  LayoutUnit max_ascent,
-                                  bool is_wrap_reverse,
-                                  bool is_deprecated_webkit_box) {
-  switch (position) {
-    case ItemPosition::kLegacy:
-    case ItemPosition::kAuto:
-    case ItemPosition::kNormal:
-      NOTREACHED();
-      break;
-    case ItemPosition::kStretch:
-      // Actual stretching must be handled by the caller. Since wrap-reverse
-      // flips cross start and cross end, stretch children should be aligned
-      // with the cross end. This matters because applyStretchAlignment
-      // doesn't always stretch or stretch fully (explicit cross size given, or
-      // stretching constrained by max-height/max-width). For flex-start and
-      // flex-end this is handled by alignmentForChild().
-      if (is_wrap_reverse)
-        return available_free_space;
-      break;
-    case ItemPosition::kFlexStart:
-      break;
-    case ItemPosition::kFlexEnd:
-      return available_free_space;
-    case ItemPosition::kCenter: {
-      const LayoutUnit result = (available_free_space / 2);
-      return is_deprecated_webkit_box ? result.ClampNegativeToZero() : result;
-    }
-    case ItemPosition::kBaseline:
-      // FIXME: If we get here in columns, we want the use the descent, except
-      // we currently can't get the ascent/descent of orthogonal children.
-      // https://bugs.webkit.org/show_bug.cgi?id=98076
-      return max_ascent - ascent;
-    case ItemPosition::kLastBaseline:
-    case ItemPosition::kSelfStart:
-    case ItemPosition::kSelfEnd:
-    case ItemPosition::kStart:
-    case ItemPosition::kEnd:
-    case ItemPosition::kLeft:
-    case ItemPosition::kRight:
-      // TODO(jferanndez): Implement these (https://crbug.com/722287).
-      break;
-  }
-  return LayoutUnit();
-}
-
 void LayoutFlexibleBox::SetOverrideMainAxisContentSizeForChild(FlexItem& item) {
   if (MainAxisIsInlineAxis(*item.box)) {
     item.box->SetOverrideLogicalWidth(item.FlexedBorderBoxSize());
@@ -1283,7 +1235,7 @@
     const LayoutBox& child) {
   LayoutUnit available_space =
       CrossAxisContentExtent() - CrossAxisExtentForChild(child);
-  return AlignmentOffset(
+  return FlexItem::AlignmentOffset(
       available_space,
       FlexLayoutAlgorithm::AlignmentForChild(StyleRef(), child.StyleRef()),
       LayoutUnit(), LayoutUnit(),
@@ -1588,60 +1540,17 @@
       child, {FlowAwareLocationForChild(child).X(), new_cross_axis_position});
 }
 
-void LayoutFlexibleBox::AlignChildren(Vector<FlexLine>& line_contexts) {
-  // Keep track of the space between the baseline edge and the after edge of
-  // the box for each line.
-  // TODO(cbiesinger): This should be stored in FlexLine
-  Vector<LayoutUnit> min_margin_after_baselines;
+void LayoutFlexibleBox::AlignChildren(FlexLayoutAlgorithm& algorithm) {
+  Vector<FlexLine>& line_contexts = algorithm.FlexLines();
 
-  for (FlexLine& line_context : line_contexts) {
-    LayoutUnit min_margin_after_baseline = LayoutUnit::Max();
-    LayoutUnit max_ascent = line_context.max_ascent;
-
+  algorithm.AlignChildren();
+  for (unsigned line_number = 0; line_number < line_contexts.size();
+       ++line_number) {
+    FlexLine& line_context = line_contexts[line_number];
     for (FlexItem& flex_item : line_context.line_items) {
-      DCHECK(!flex_item.box->IsOutOfFlowPositioned());
-
-      if (flex_item.UpdateAutoMarginsInCrossAxis(
-              std::max(LayoutUnit(), flex_item.AvailableAlignmentSpace()))) {
-        ResetAlignmentForChild(*flex_item.box, flex_item.desired_location.Y());
-        continue;
-      }
-
-      ItemPosition position = flex_item.Alignment();
-      if (position == ItemPosition::kStretch) {
-        flex_item.ComputeStretchedSize();
+      if (flex_item.Alignment() == ItemPosition::kStretch)
         ApplyStretchAlignmentToChild(flex_item);
-      }
-      LayoutUnit available_space = flex_item.AvailableAlignmentSpace();
-      LayoutUnit offset = AlignmentOffset(
-          available_space, position, flex_item.MarginBoxAscent(), max_ascent,
-          StyleRef().FlexWrap() == EFlexWrap::kWrapReverse,
-          StyleRef().IsDeprecatedWebkitBox());
-      AdjustAlignmentForChild(*flex_item.box, offset);
-      if (position == ItemPosition::kBaseline &&
-          StyleRef().FlexWrap() == EFlexWrap::kWrapReverse) {
-        min_margin_after_baseline =
-            std::min(min_margin_after_baseline,
-                     flex_item.AvailableAlignmentSpace() - offset);
-      }
-    }
-    min_margin_after_baselines.push_back(min_margin_after_baseline);
-  }
-
-  if (StyleRef().FlexWrap() != EFlexWrap::kWrapReverse)
-    return;
-
-  // wrap-reverse flips the cross axis start and end. For baseline alignment,
-  // this means we need to align the after edge of baseline elements with the
-  // after edge of the flex line.
-  wtf_size_t line_number = 0;
-  for (FlexLine& line_context : line_contexts) {
-    LayoutUnit min_margin_after_baseline =
-        min_margin_after_baselines[line_number++];
-    for (FlexItem& flex_item : line_context.line_items) {
-      if (flex_item.Alignment() == ItemPosition::kBaseline &&
-          !flex_item.HasAutoMarginsInCrossAxis() && min_margin_after_baseline)
-        AdjustAlignmentForChild(*flex_item.box, min_margin_after_baseline);
+      ResetAlignmentForChild(*flex_item.box, flex_item.desired_location.Y());
     }
   }
 }
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.h b/third_party/blink/renderer/core/layout/layout_flexible_box.h
index 47977523..b9296655 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -201,7 +201,7 @@
                            LayoutUnit cross_axis_offset,
                            LayoutUnit available_free_space);
   void AlignFlexLines(FlexLayoutAlgorithm&);
-  void AlignChildren(Vector<FlexLine>&);
+  void AlignChildren(FlexLayoutAlgorithm&);
   void ApplyStretchAlignmentToChild(FlexItem& child);
   void FlipForRightToLeftColumn(const Vector<FlexLine>& line_contexts);
   void FlipForWrapReverse(const Vector<FlexLine>&,
diff --git a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
index b658a7a4c..93f1ea27 100644
--- a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
+++ b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
@@ -303,9 +303,7 @@
     }
   }
 
-  if (RuntimeEnabledFeatures::LayoutInstabilityAPIEnabled(
-          frame.GetDocument()) &&
-      frame.DomWindow()) {
+  if (frame.DomWindow()) {
     WindowPerformance* performance =
         DOMWindowPerformance::performance(*frame.DomWindow());
     if (performance) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
index bbfc903..6fe62c3 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -527,10 +527,36 @@
   return container_builder_.ToBoxFragment();
 }
 
+void NGFlexLayoutAlgorithm::ApplyStretchAlignmentToChild(FlexItem& flex_item) {
+  WritingMode child_writing_mode =
+      flex_item.ng_input_node.Style().GetWritingMode();
+  NGConstraintSpaceBuilder space_builder(ConstraintSpace(), child_writing_mode,
+                                         /* is_new_fc */ true);
+  SetOrthogonalFallbackInlineSizeIfNeeded(Style(), flex_item.ng_input_node,
+                                          &space_builder);
+
+  LogicalSize available_size(
+      flex_item.flexed_content_size + flex_item.main_axis_border_padding,
+      flex_item.cross_axis_size);
+  if (is_column_) {
+    available_size.Transpose();
+    if (!IsColumnContainerMainSizeDefinite() &&
+        !IsItemMainSizeDefinite(flex_item.ng_input_node)) {
+      space_builder.SetIsFixedBlockSizeIndefinite(true);
+    }
+  }
+  space_builder.SetAvailableSize(available_size);
+  space_builder.SetPercentageResolutionSize(content_box_size_);
+  space_builder.SetIsFixedInlineSize(true);
+  space_builder.SetIsFixedBlockSize(true);
+  NGConstraintSpace child_space = space_builder.ToConstraintSpace();
+  flex_item.layout_result =
+      flex_item.ng_input_node.Layout(child_space, /* break_token */ nullptr);
+}
+
 void NGFlexLayoutAlgorithm::GiveLinesAndItemsFinalPositionAndSize() {
-  // TODO(dgrogan): This needs to eventually encompass all of the behavior in
-  // LayoutFlexibleBox::RepositionLogicalHeightDependentFlexItems. It currently
-  // does AlignFlexLines and the stretch part of AlignChildren.
+  // TODO(dgrogan): Implement the behavior from
+  // LayoutFlexibleBox::LayoutColumnReverse here.
   LayoutUnit final_content_cross_size =
       is_column_ ? container_builder_.InlineSize() -
                        border_scrollbar_padding_.InlineSum()
@@ -541,46 +567,18 @@
 
   algorithm_->AlignFlexLines(final_content_cross_size);
 
+  algorithm_->AlignChildren();
+
+  // TODO(dgrogan): Implement behavior from legacy's FlipForWrapReverse and
+  // FlipForRightToLeftColumn here.
+
   for (FlexLine& line_context : algorithm_->FlexLines()) {
     for (wtf_size_t child_number = 0;
          child_number < line_context.line_items.size(); ++child_number) {
       FlexItem& flex_item = line_context.line_items[child_number];
 
-      // UpdateAutoMarginsInCrossAxis updates the flex_item's desired_location
-      // if the auto margins have an effect.
-      if (!flex_item.UpdateAutoMarginsInCrossAxis(
-              std::max(LayoutUnit(), flex_item.AvailableAlignmentSpace())) &&
-          flex_item.Alignment() == ItemPosition::kStretch) {
-        flex_item.ComputeStretchedSize();
-
-        WritingMode child_writing_mode =
-            flex_item.ng_input_node.Style().GetWritingMode();
-        NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
-                                               child_writing_mode,
-                                               /* is_new_fc */ true);
-        SetOrthogonalFallbackInlineSizeIfNeeded(
-            Style(), flex_item.ng_input_node, &space_builder);
-
-        LogicalSize available_size(
-            flex_item.flexed_content_size + flex_item.main_axis_border_padding,
-            flex_item.cross_axis_size);
-        if (is_column_) {
-          available_size.Transpose();
-          if (!IsColumnContainerMainSizeDefinite() &&
-              !IsItemMainSizeDefinite(flex_item.ng_input_node)) {
-            space_builder.SetIsFixedBlockSizeIndefinite(true);
-          }
-        }
-        space_builder.SetAvailableSize(available_size);
-        space_builder.SetPercentageResolutionSize(content_box_size_);
-        space_builder.SetIsFixedInlineSize(true);
-        space_builder.SetIsFixedBlockSize(true);
-        NGConstraintSpace child_space = space_builder.ToConstraintSpace();
-        flex_item.layout_result = flex_item.ng_input_node.Layout(
-            child_space, /* break_token */ nullptr);
-      }
-      // TODO(dgrogan): Add an extra pass for kColumnReverse containers like
-      // legacy does in LayoutColumnReverse.
+      if (DoesItemStretch(flex_item.ng_input_node))
+        ApplyStretchAlignmentToChild(flex_item);
 
       // flex_item.desired_location stores the main axis offset in X and the
       // cross axis offset in Y. But AddChild wants offset from parent
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
index b9af9a2..f525ca5 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
@@ -43,6 +43,7 @@
   NGConstraintSpace BuildConstraintSpaceForDeterminingFlexBasis(
       const NGBlockNode& flex_item) const;
   void ConstructAndAppendFlexItems();
+  void ApplyStretchAlignmentToChild(FlexItem& flex_item);
   void GiveLinesAndItemsFinalPositionAndSize();
   // This is same method as FlexItem but we need that logic before FlexItem is
   // constructed.
diff --git a/third_party/blink/renderer/core/loader/BUILD.gn b/third_party/blink/renderer/core/loader/BUILD.gn
index 4178ea6f..0b517e74 100644
--- a/third_party/blink/renderer/core/loader/BUILD.gn
+++ b/third_party/blink/renderer/core/loader/BUILD.gn
@@ -103,8 +103,6 @@
     "prerenderer_client.h",
     "previews_resource_loading_hints.cc",
     "previews_resource_loading_hints.h",
-    "previews_resource_loading_hints_receiver_impl.cc",
-    "previews_resource_loading_hints_receiver_impl.h",
     "private/frame_client_hints_preferences_context.cc",
     "private/frame_client_hints_preferences_context.h",
     "private/prerender_handle.cc",
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc
deleted file mode 100644
index 5847eab..0000000
--- a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "third_party/blink/public/common/features.h"
-#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-PreviewsResourceLoadingHintsReceiverImpl::
-    PreviewsResourceLoadingHintsReceiverImpl(
-        mojo::PendingReceiver<
-            mojom::blink::PreviewsResourceLoadingHintsReceiver> receiver,
-        Document* document)
-    : receiver_(this, std::move(receiver)), document_(document) {
-  DCHECK(!base::FeatureList::IsEnabled(
-      blink::features::kSendPreviewsLoadingHintsBeforeCommit));
-}
-
-PreviewsResourceLoadingHintsReceiverImpl::
-    ~PreviewsResourceLoadingHintsReceiverImpl() {}
-
-void PreviewsResourceLoadingHintsReceiverImpl::SetResourceLoadingHints(
-    mojom::blink::PreviewsResourceLoadingHintsPtr resource_loading_hints) {
-  // TODO(tbansal): https://crbug.com/856247. Block loading of resources based
-  // on |resource_loading_hints|.
-  UMA_HISTOGRAM_COUNTS_100(
-      "ResourceLoadingHints.CountBlockedSubresourcePatterns",
-      resource_loading_hints->subresources_to_block.size());
-
-  Vector<WTF::String> subresource_patterns_to_block;
-  for (const auto& subresource :
-       resource_loading_hints->subresources_to_block) {
-    subresource_patterns_to_block.push_back(subresource);
-  }
-
-  document_->Loader()->SetPreviewsResourceLoadingHints(
-      PreviewsResourceLoadingHints::Create(
-          *(document_.Get()), resource_loading_hints->ukm_source_id,
-          subresource_patterns_to_block));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h
deleted file mode 100644
index 0d165a9c..0000000
--- a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_RECEIVER_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_RECEIVER_IMPL_H_
-
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom-blink.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-
-namespace blink {
-
-// Created and attached to a LocalFrame when the frame receives a
-// PreviewsResourceLoadingHintsReceiver interface receiver from the browser
-// process.
-class PreviewsResourceLoadingHintsReceiverImpl
-    : public mojom::blink::PreviewsResourceLoadingHintsReceiver {
- public:
-  PreviewsResourceLoadingHintsReceiverImpl(
-      mojo::PendingReceiver<mojom::blink::PreviewsResourceLoadingHintsReceiver>
-          receiver,
-      Document* document);
-  ~PreviewsResourceLoadingHintsReceiverImpl() override;
-
- private:
-  void SetResourceLoadingHints(mojom::blink::PreviewsResourceLoadingHintsPtr
-                                   resource_loading_hints) override;
-
-  // TODO(tbansal): https://crbug.com/800641. Consider using a RevocableBinding.
-  mojo::Receiver<mojom::blink::PreviewsResourceLoadingHintsReceiver> receiver_;
-
-  WeakPersistent<Document> document_;
-
-  DISALLOW_COPY_AND_ASSIGN(PreviewsResourceLoadingHintsReceiverImpl);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_RECEIVER_IMPL_H_
diff --git a/third_party/blink/renderer/core/streams/BUILD.gn b/third_party/blink/renderer/core/streams/BUILD.gn
index e747d5e7..0b7a700 100644
--- a/third_party/blink/renderer/core/streams/BUILD.gn
+++ b/third_party/blink/renderer/core/streams/BUILD.gn
@@ -27,12 +27,8 @@
     "readable_stream_default_reader.h",
     "readable_stream_native.cc",
     "readable_stream_native.h",
-    "readable_stream_operations.cc",
-    "readable_stream_operations.h",
     "readable_stream_reader.cc",
     "readable_stream_reader.h",
-    "readable_stream_wrapper.cc",
-    "readable_stream_wrapper.h",
     "stream_algorithms.h",
     "stream_promise_resolver.cc",
     "stream_promise_resolver.h",
@@ -43,13 +39,9 @@
     "transform_stream_default_controller.cc",
     "transform_stream_default_controller.h",
     "transform_stream_default_controller_interface.h",
-    "transform_stream_default_controller_wrapper.cc",
-    "transform_stream_default_controller_wrapper.h",
     "transform_stream_native.cc",
     "transform_stream_native.h",
     "transform_stream_transformer.h",
-    "transform_stream_wrapper.cc",
-    "transform_stream_wrapper.h",
     "underlying_sink_base.h",
     "underlying_source_base.cc",
     "underlying_source_base.h",
@@ -63,7 +55,5 @@
     "writable_stream_default_writer.h",
     "writable_stream_native.cc",
     "writable_stream_native.h",
-    "writable_stream_wrapper.cc",
-    "writable_stream_wrapper.h",
   ]
 }
diff --git a/third_party/blink/renderer/core/streams/ByteLengthQueuingStrategy.js b/third_party/blink/renderer/core/streams/ByteLengthQueuingStrategy.js
deleted file mode 100644
index 3b7ea7e2..0000000
--- a/third_party/blink/renderer/core/streams/ByteLengthQueuingStrategy.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// eslint-disable-next-line no-unused-vars
-(function(global, binding, v8) {
-  'use strict';
-
-  const defineProperty = global.Object.defineProperty;
-
-  class ByteLengthQueuingStrategy {
-    constructor(options) {
-      defineProperty(this, 'highWaterMark', {
-        value: options.highWaterMark,
-        enumerable: true,
-        configurable: true,
-        writable: true
-      });
-    }
-    size(chunk) {
-      return chunk.byteLength;
-    }
-  }
-
-  binding.ByteLengthQueuingStrategy = ByteLengthQueuingStrategy;
-});
diff --git a/third_party/blink/renderer/core/streams/CommonOperations.js b/third_party/blink/renderer/core/streams/CommonOperations.js
deleted file mode 100644
index 24dc719..0000000
--- a/third_party/blink/renderer/core/streams/CommonOperations.js
+++ /dev/null
@@ -1,624 +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.
-
-// Implementation of functions that are shared between ReadableStream and
-// WritableStream.
-
-(function(global, binding, v8) {
-  'use strict';
-
-  // Common private symbols. These correspond directly to internal slots in the
-  // standard. "[[X]]" in the standard is spelt _X here.
-  const _queue = v8.createPrivateSymbol('[[queue]]');
-  const _queueTotalSize = v8.createPrivateSymbol('[[queueTotalSize]]');
-
-  // A symbol to protect against double-resolution of promises. This
-  // functionality is not explicit in the standard, but is implied in the way
-  // the operations are defined.
-  const _isSettled = v8.createPrivateSymbol('isSettled');
-
-  // Javascript functions. It is important to use these copies for security and
-  // robustness. See "V8 Extras Design Doc", section "Security Considerations".
-  // https://docs.google.com/document/d/1AT5-T0aHGp7Lt29vPWFr2-qG8r3l9CByyvKwEuA8Ec0/edit#heading=h.9yixony1a18r
-  const Boolean = global.Boolean;
-  const Number = global.Number;
-  const Number_isFinite = Number.isFinite;
-  const Number_isNaN = Number.isNaN;
-
-  const RangeError = global.RangeError;
-  const TypeError = global.TypeError;
-  const TypeError_prototype = TypeError.prototype;
-
-  const hasOwnProperty = v8.uncurryThis(global.Object.hasOwnProperty);
-  const getPrototypeOf = global.Object.getPrototypeOf.bind(global.Object);
-  const getOwnPropertyDescriptor =
-        global.Object.getOwnPropertyDescriptor.bind(global.Object);
-
-  const thenPromise = v8.uncurryThis(Promise.prototype.then);
-
-  const JSON_parse = global.JSON.parse.bind(global.JSON);
-  const JSON_stringify = global.JSON.stringify.bind(global.JSON);
-
-  function hasOwnPropertyNoThrow(x, property) {
-    // The cast of |x| to Boolean will eliminate undefined and null, which would
-    // cause hasOwnProperty to throw a TypeError, as well as some other values
-    // that can't be objects and so will fail the check anyway.
-    return Boolean(x) && hasOwnProperty(x, property);
-  }
-
-  //
-  // Assert is not normally enabled, to avoid the space and time overhead. To
-  // enable, uncomment this definition and then in the file you wish to enable
-  // asserts for, uncomment the assert statements and add this definition:
-  // const assert = pred => binding.SimpleAssert(pred);
-  //
-  // binding.SimpleAssert = pred => {
-  //   if (pred) {
-  //     return;
-  //   }
-  //   v8.log('\n\n\n  *** ASSERTION FAILURE ***\n\n');
-  //   v8.logStackTrace();
-  //   v8.log('**************************************************\n\n');
-  //   class StreamsAssertionError extends Error {}
-  //   throw new StreamsAssertionError('Streams Assertion Failure');
-  // };
-
-  //
-  // Promise-manipulation functions
-  //
-
-  // Not exported.
-  function streamInternalError() {
-    throw new RangeError('Stream API Internal Error');
-  }
-
-  // For safety, this must always be used in place of calling v8.createPromise()
-  // directly.
-  function createPromise() {
-    const p = v8.createPromise();
-    p[_isSettled] = false;
-    return p;
-  }
-
-  // Calling v8.rejectPromise() directly is very dangerous. Always use this
-  // wrapper.
-  function rejectPromise(p, reason) {
-    if (!v8.isPromise(p)) {
-      streamInternalError();
-    }
-
-    // assert(typeof p[_isSettled] === 'boolean',
-    //        'Type(p.[[isSettled]]) is `"boolean"`');
-
-    // Note that this makes the function a no-op for promises that were not
-    // created via createPromise(). This is critical for security.
-    if (p[_isSettled] !== false) {
-      return;
-    }
-    p[_isSettled] = true;
-
-    v8.rejectPromise(p, reason);
-  }
-
-  // This must always be used instead of Promise.reject().
-  function createRejectedPromise(reason) {
-    const p = createPromise();
-    rejectPromise(p, reason);
-    return p;
-  }
-
-  // Calling v8.resolvePromise() directly is very dangerous. Always use this
-  // wrapper. If |value| is an object this will look up Object.prototype.then
-  // and so may be re-entrant.
-  function resolvePromise(p, value) {
-    if (!v8.isPromise(p)) {
-      streamInternalError();
-    }
-
-    // assert(typeof p[_isSettled] === 'boolean',
-    //        'Type(p.[[isSettled]]) is `"boolean"`');
-
-    // Note that this makes the function a no-op for promises that were not
-    // created via createPromise(). This is critical for security.
-    if (p[_isSettled] !== false) {
-      return;
-    }
-    p[_isSettled] = true;
-
-    v8.resolvePromise(p, value);
-  }
-
-  // This must always be used instead of Promise.resolve(). If |value| is an
-  // object this will look up Object.prototype.then and so may be re-entrant.
-  function createResolvedPromise(value) {
-    if (v8.isPromise(value)) {
-      // This case applies when an underlying method returns a promise. Promises
-      // that are passed through in this way are not used with resolvePromise()
-      // or rejectPromise().
-      return value;
-    }
-    const p = createPromise();
-    resolvePromise(p, value);
-    return p;
-  }
-
-  function markPromiseAsHandled(p) {
-    if (!v8.isPromise(p)) {
-      streamInternalError();
-    }
-    v8.markPromiseAsHandled(p);
-  }
-
-  function promiseState(p) {
-    if (!v8.isPromise(p)) {
-      streamInternalError();
-    }
-    return v8.promiseState(p);
-  }
-
-  //
-  // Queue-with-Sizes Operations
-  //
-  function DequeueValue(container) {
-    // assert(
-    //     hasOwnProperty(container, _queue) &&
-    //         hasOwnProperty(container, _queueTotalSize),
-    //     '_container_ has [[queue]] and [[queueTotalSize]] internal slots.');
-    // assert(container[_queue].length !== 0,
-    //        '_container_.[[queue]] is not empty.');
-    const pair = container[_queue].shift();
-    container[_queueTotalSize] -= pair.size;
-    if (container[_queueTotalSize] < 0) {
-      container[_queueTotalSize] = 0;
-    }
-    return pair.value;
-  }
-
-  function EnqueueValueWithSize(container, value, size) {
-    // assert(
-    //     hasOwnProperty(container, _queue) &&
-    //         hasOwnProperty(container, _queueTotalSize),
-    //     '_container_ has [[queue]] and [[queueTotalSize]] internal 'slots.');
-    size = Number(size);
-    if (!IsFiniteNonNegativeNumber(size)) {
-      throw new RangeError(binding.streamErrors.invalidSize);
-    }
-
-    container[_queue].push({value, size});
-    container[_queueTotalSize] += size;
-  }
-
-  function PeekQueueValue(container) {
-    // assert(
-    //     hasOwnProperty(container, _queue) &&
-    //         hasOwnProperty(container, _queueTotalSize),
-    //     '_container_ has [[queue]] and [[queueTotalSize]] internal slots.');
-    // assert(container[_queue].length !== 0,
-    //        '_container_.[[queue]] is not empty.');
-    const pair = container[_queue].peek();
-    return pair.value;
-  }
-
-  function ResetQueue(container) {
-    // assert(
-    //     hasOwnProperty(container, _queue) &&
-    //         hasOwnProperty(container, _queueTotalSize),
-    //     '_container_ has [[queue]] and [[queueTotalSize]] internal slots.');
-    container[_queue] = new binding.SimpleQueue();
-    container[_queueTotalSize] = 0;
-  }
-
-  // Not exported.
-  function IsFiniteNonNegativeNumber(v) {
-    return Number_isFinite(v) && v >= 0;
-  }
-
-  function ValidateAndNormalizeHighWaterMark(highWaterMark) {
-    highWaterMark = Number(highWaterMark);
-    if (Number_isNaN(highWaterMark)) {
-      throw new RangeError(binding.streamErrors.invalidHWM);
-    }
-    if (highWaterMark < 0) {
-      throw new RangeError(binding.streamErrors.invalidHWM);
-    }
-    return highWaterMark;
-  }
-
-  // Unlike the version in the standard, this implementation returns the
-  // original function as-is if it is set. This means users of the return value
-  // need to be careful to explicitly set |this| when calling it.
-  function MakeSizeAlgorithmFromSizeFunction(size) {
-    if (size === undefined) {
-      return () => 1;
-    }
-
-    if (typeof size !== 'function') {
-      throw new TypeError(binding.streamErrors.sizeNotAFunction);
-    }
-
-    return size;
-  }
-
-  //
-  // Invoking functions.
-  // These differ from the Invoke versions in the spec in that they take a fixed
-  // number of arguments rather than a list, and also take a name to be used for
-  // the function on error.
-  //
-
-  // Internal utility functions. Not exported.
-  const callFunction = v8.uncurryThis(global.Function.prototype.call);
-  const errTmplMustBeFunctionOrUndefined = name =>
-      `${name} must be a function or undefined`;
-  const Function_bind = v8.uncurryThis(global.Function.prototype.bind);
-
-  function resolveMethod(O, P, nameForError) {
-    const method = O[P];
-
-    if (typeof method !== 'function' && typeof method !== 'undefined') {
-      throw new TypeError(errTmplMustBeFunctionOrUndefined(nameForError));
-    }
-
-    return method;
-  }
-
-  function CreateAlgorithmFromUnderlyingMethod(
-      underlyingObject, methodName, algoArgCount, methodNameForError) {
-    // assert(underlyingObject !== undefined,
-    //        'underlyingObject is not undefined.');
-    // assert(IsPropertyKey(methodName),
-    // '! IsPropertyKey(methodName) is true.');
-    // assert(algoArgCount === 0 || algoArgCount === 1,
-    // 'algoArgCount is 0 or 1.');
-    // assert(
-    //     typeof methodNameForError === 'string',
-    //     'methodNameForError is a string');
-    const method =
-        resolveMethod(underlyingObject, methodName, methodNameForError);
-    // The implementation uses bound functions rather than lambdas where
-    // possible to give the compiler the maximum opportunity to optimise.
-    if (method === undefined) {
-      return () => createResolvedPromise();
-    }
-
-    if (algoArgCount === 0) {
-      return Function_bind(PromiseCall0, undefined, method, underlyingObject);
-    }
-
-    return Function_bind(PromiseCall1, undefined, method, underlyingObject);
-  }
-
-  function CreateAlgorithmFromUnderlyingMethodPassingController(
-      underlyingObject, methodName, algoArgCount, controller,
-      methodNameForError) {
-    // assert(underlyingObject !== undefined,
-    //        'underlyingObject is not undefined.');
-    // assert(IsPropertyKey(methodName),
-    // '! IsPropertyKey(methodName) is true.');
-    // assert(algoArgCount === 0 || algoArgCount === 1,
-    // 'algoArgCount is 0 or 1.');
-    // assert(typeof controller === 'object', 'controller is an object');
-    // assert(
-    //     typeof methodNameForError === 'string',
-    //     'methodNameForError is a string');
-    const method =
-        resolveMethod(underlyingObject, methodName, methodNameForError);
-    if (method === undefined) {
-      return () => createResolvedPromise();
-    }
-
-    if (algoArgCount === 0) {
-      return Function_bind(
-          PromiseCall1, undefined, method, underlyingObject, controller);
-    }
-
-    return arg => PromiseCall2(method, underlyingObject, arg, controller);
-  }
-
-  // Modified from InvokeOrNoop in spec. Takes 1 argument.
-  function CallOrNoop1(O, P, arg0, nameForError) {
-    const method = resolveMethod(O, P, nameForError);
-    if (method === undefined) {
-      return undefined;
-    }
-
-    return callFunction(method, O, arg0);
-  }
-
-  function PromiseCall0(F, V) {
-    // assert(typeof F === 'function', 'IsCallable(F) is true.');
-    // assert(V !== undefined, 'V is not undefined.');
-    try {
-      return createResolvedPromise(callFunction(F, V));
-    } catch (e) {
-      return createRejectedPromise(e);
-    }
-  }
-
-  function PromiseCall1(F, V, arg0) {
-    // assert(typeof F === 'function', 'IsCallable(F) is true.');
-    // assert(V !== undefined, 'V is not undefined.');
-    try {
-      return createResolvedPromise(callFunction(F, V, arg0));
-    } catch (e) {
-      return createRejectedPromise(e);
-    }
-  }
-
-  function PromiseCall2(F, V, arg0, arg1) {
-    // assert(typeof F === 'function', 'IsCallable(F) is true.');
-    // assert(V !== undefined, 'V is not undefined.');
-    try {
-      return createResolvedPromise(callFunction(F, V, arg0, arg1));
-    } catch (e) {
-      return createRejectedPromise(e);
-    }
-  }
-
-  // Functions for transferable streams. See design doc
-  // https://docs.google.com/document/d/1_KuZzg5c3pncLJPFa8SuVm23AP4tft6mzPCL5at3I9M/edit
-
-  const kPull = 1;
-  const kCancel = 2;
-  const kChunk = 3;
-  const kClose = 4;
-  const kAbort = 5;
-  const kError = 6;
-
-  function isATypeError(object) {
-    // There doesn't appear to be a 100% reliable way to identify a TypeError
-    // from JS.
-    return object !== null && getPrototypeOf(object) === TypeError_prototype;
-  }
-
-  function isADOMException(object) {
-    try {
-      callFunction(binding.DOMException_name_get, object);
-      return true;
-    } catch (e) {
-      return false;
-    }
-  }
-
-  // We'd like to able to transfer TypeError exceptions, but we can't, so we
-  // hack around it. packReason() is guaranteed not to throw and the object
-  // produced is guaranteed to be serializable by postMessage().
-  function packReason(reason) {
-    switch (typeof reason) {
-      case 'string':
-      case 'number':
-      case 'boolean':
-        return {encoder: 'json', string: JSON_stringify(reason)};
-
-      case 'object':
-        try {
-          if (isATypeError(reason)) {
-            // "message" on TypeError is a normal property, meaning that if it
-            // is set, it is set on the object itself. We can take advantage of
-            // this to avoid executing user JavaScript in the case when the
-            // TypeError was generated internally.
-            let message;
-            const descriptor = getOwnPropertyDescriptor(reason, 'message');
-            if (descriptor) {
-              message = descriptor.value;
-              if (typeof message !== 'string') {
-                message = undefined;
-              }
-            }
-            return {encoder: 'typeerror', string: message};
-          }
-
-          if (isADOMException(reason)) {
-            const message =
-                  callFunction(binding.DOMException_message_get, reason);
-            const name = callFunction(binding.DOMException_name_get, reason);
-            return {
-              encoder: 'domexception',
-              string: JSON_stringify({message, name})
-            };
-          }
-
-          // JSON_stringify() is lossy, but it will serialise things that
-          // postMessage() won't.
-          return {encoder: 'json', string: JSON_stringify(reason)};
-        } catch (e) {
-          return {encoder: 'typeerror', string: 'Cannot transfer message'};
-        }
-
-      default:
-        return {encoder: 'undefined', string: undefined};
-    }
-  }
-
-  function unpackReason(packedReason) {
-    const {encoder, string} = packedReason;
-    switch (encoder) {
-      case 'json':
-        return JSON_parse(string);
-
-      case 'typeerror':
-        return new TypeError(string);
-
-      case 'domexception':
-        const {message, name} = JSON_parse(string);
-        return new binding.DOMException(message, name);
-
-      case 'undefined':
-        return undefined;
-    }
-  }
-
-  function CreateCrossRealmTransformWritable(port) {
-    let backpressurePromise = createPromise();
-
-    callFunction(binding.EventTarget_addEventListener, port, 'message', evt => {
-      const {type, value} = callFunction(binding.MessageEvent_data_get, evt);
-      // assert(type === kPull || type === kCancel || type === kError);
-      switch (type) {
-        case kPull:
-          // assert(backPressurePromise !== undefined);
-          resolvePromise(backpressurePromise);
-          backpressurePromise = undefined;
-          break;
-
-        case kCancel:
-        case kError:
-          binding.WritableStreamDefaultControllerErrorIfNeeded(
-              controller, unpackReason(value));
-          if (backpressurePromise !== undefined) {
-            resolvePromise(backpressurePromise);
-            backpressurePromise = undefined;
-          }
-          break;
-      }
-    });
-
-    callFunction(
-        binding.EventTarget_addEventListener, port, 'messageerror', () => {
-          const error = new binding.DOMException('chunk could not be cloned',
-                                                 'DataCloneError');
-          callFunction(binding.MessagePort_postMessage, port,
-                       {type: kError, value: packReason(error)});
-          callFunction(binding.MessagePort_close, port);
-          binding.WritableStreamDefaultControllerErrorIfNeeded(controller,
-                                                               error);
-        });
-
-    callFunction(binding.MessagePort_start, port);
-
-    function doWrite(chunk) {
-      backpressurePromise = createPromise();
-      try {
-        callFunction(
-            binding.MessagePort_postMessage, port,
-            {type: kChunk, value: chunk});
-      } catch (e) {
-        callFunction(
-            binding.MessagePort_postMessage, port,
-            {type: kError, value: packReason(e)});
-        callFunction(binding.MessagePort_close, port);
-        throw e;
-      }
-    }
-
-    const stream = binding.CreateWritableStream(
-        () => undefined,
-        chunk => {
-          if (!backpressurePromise) {
-            return PromiseCall1(doWrite, null, chunk);
-          }
-          return thenPromise(backpressurePromise, () => doWrite(chunk));
-        },
-        () => {
-          callFunction(
-              binding.MessagePort_postMessage, port,
-              {type: kClose, value: undefined});
-          callFunction(binding.MessagePort_close, port);
-          return createResolvedPromise();
-        },
-        reason => {
-          callFunction(
-              binding.MessagePort_postMessage, port,
-              {type: kAbort, value: packReason(reason)});
-          callFunction(binding.MessagePort_close, port);
-          return createResolvedPromise();
-        });
-
-    const controller = binding.getWritableStreamController(stream);
-    return stream;
-  }
-
-  function CreateCrossRealmTransformReadable(port) {
-    let backpressurePromise = createPromise();
-    let finished = false;
-
-    callFunction(binding.EventTarget_addEventListener, port, 'message', evt => {
-      const {type, value} = callFunction(binding.MessageEvent_data_get, evt);
-      // assert(type === kChunk || type === kClose || type === kAbort ||
-      //        type=kError);
-      if (finished) {
-        return;
-      }
-      switch (type) {
-        case kChunk:
-          binding.ReadableStreamDefaultControllerEnqueue(controller, value);
-          resolvePromise(backpressurePromise);
-          backpressurePromise = createPromise();
-          break;
-
-        case kClose:
-          finished = true;
-          binding.ReadableStreamDefaultControllerClose(controller);
-          callFunction(binding.MessagePort_close, port);
-          break;
-
-        case kAbort:
-        case kError:
-          finished = true;
-          binding.ReadableStreamDefaultControllerError(
-              controller, unpackReason(value));
-          callFunction(binding.MessagePort_close, port);
-          break;
-      }
-    });
-
-    callFunction(
-        binding.EventTarget_addEventListener, port, 'messageerror', () => {
-          const error = new binding.DOMException('chunk could not be cloned',
-                                                 'DataCloneError');
-          callFunction(binding.MessagePort_postMessage, port,
-                       {type: kError, value: packReason(error)});
-          callFunction(binding.MessagePort_close, port);
-          binding.ReadableStreamDefaultControllerError(controller, error);
-        });
-
-    callFunction(binding.MessagePort_start, port);
-
-    const stream = binding.CreateReadableStream(
-        () => undefined,
-        () => {
-          callFunction(
-              binding.MessagePort_postMessage, port,
-              {type: kPull, value: undefined});
-          return backpressurePromise;
-        },
-        reason => {
-          finished = true;
-          callFunction(
-              binding.MessagePort_postMessage, port,
-              {type: kCancel, value: packReason(reason)});
-          callFunction(binding.MessagePort_close, port);
-          return createResolvedPromise();
-        },
-        /* highWaterMark = */ 0);
-
-    const controller = binding.getReadableStreamController(stream);
-    return stream;
-  }
-
-  binding.streamOperations = {
-    _queue,
-    _queueTotalSize,
-    createPromise,
-    createRejectedPromise,
-    createResolvedPromise,
-    hasOwnPropertyNoThrow,
-    rejectPromise,
-    resolvePromise,
-    markPromiseAsHandled,
-    promiseState,
-    CreateAlgorithmFromUnderlyingMethod,
-    CreateAlgorithmFromUnderlyingMethodPassingController,
-    CreateCrossRealmTransformWritable,
-    CreateCrossRealmTransformReadable,
-    DequeueValue,
-    EnqueueValueWithSize,
-    PeekQueueValue,
-    ResetQueue,
-    ValidateAndNormalizeHighWaterMark,
-    MakeSizeAlgorithmFromSizeFunction,
-    CallOrNoop1,
-    PromiseCall2
-  };
-});
diff --git a/third_party/blink/renderer/core/streams/CommonStrings.js b/third_party/blink/renderer/core/streams/CommonStrings.js
deleted file mode 100644
index 72395d7..0000000
--- a/third_party/blink/renderer/core/streams/CommonStrings.js
+++ /dev/null
@@ -1,24 +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.
-
-// User-visible strings shared between ReadableStream and WritableStream.
-
-// eslint-disable-next-line no-unused-vars
-(function(global, binding, v8) {
-  'use strict';
-
-  binding.streamErrors = {
-    cannotTransferLockedStream: 'Cannot transfer a locked stream',
-    cannotTransferContext: 'Cannot transfer from this context',
-    illegalInvocation: 'Illegal invocation',
-    illegalConstructor: 'Illegal constructor',
-    invalidType: 'Invalid type is specified',
-    invalidSize: 'The return value of a queuing strategy\'s size function ' +
-        'must be a finite, non-NaN, non-negative number',
-    sizeNotAFunction: 'A queuing strategy\'s size property must be a function',
-    invalidHWM:
-    'A queueing strategy\'s highWaterMark property must be a nonnegative, ' +
-        'non-NaN number',
-  };
-});
diff --git a/third_party/blink/renderer/core/streams/CountQueuingStrategy.js b/third_party/blink/renderer/core/streams/CountQueuingStrategy.js
deleted file mode 100644
index 61d2334..0000000
--- a/third_party/blink/renderer/core/streams/CountQueuingStrategy.js
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// eslint-disable-next-line no-unused-vars
-(function(global, binding, v8) {
-  'use strict';
-
-  const defineProperty = global.Object.defineProperty;
-
-  class CountQueuingStrategy {
-    constructor(options) {
-      defineProperty(this, 'highWaterMark', {
-        value: options.highWaterMark,
-        enumerable: true,
-        configurable: true,
-        writable: true
-      });
-    }
-
-    size() {
-      return 1;
-    }
-  }
-
-  // Export a separate copy that doesn't need options objects and can't be
-  // interfered with.
-  class BuiltInCountQueuingStrategy {
-    constructor(highWaterMark) {
-      defineProperty(this, 'highWaterMark', {value: highWaterMark});
-    }
-
-    size() {
-      return 1;
-    }
-  }
-
-  binding.CountQueuingStrategy = CountQueuingStrategy;
-
-  binding.createBuiltInCountQueuingStrategy = highWaterMark =>
-    new BuiltInCountQueuingStrategy(highWaterMark);
-});
diff --git a/third_party/blink/renderer/core/streams/README.md b/third_party/blink/renderer/core/streams/README.md
index 1b845c20..cdd66717 100644
--- a/third_party/blink/renderer/core/streams/README.md
+++ b/third_party/blink/renderer/core/streams/README.md
@@ -3,38 +3,7 @@
 This directory contains the Blink implementation of [the WHATWG Streams
 standard][1].
 
-We use [V8 extras][2] to implement it.
-
-There is also a new implementation that is written in C++ rather than
-JavaScript. It is currently off by default, behind the Blink "StreamsNative"
-feature. The following files are part of the new implementation:
-
-    readable_stream_default_controller.idl
-    readable_stream_default_controller_interface.cc
-    readable_stream_default_controller_interface.h
-    readable_stream_default_reader.h
-    readable_stream_default_reader.idl
-    readable_stream_native.cc
-    readable_stream_native.h
-    readable_stream_reader.cc
-    readable_stream_reader.h
-    writable_stream_default_controller.cc
-    writable_stream_default_controller.h
-    writable_stream_default_controller.idl
-    writable_stream_default_writer.cc
-    writable_stream_default_writer.h
-    writable_stream_default_writer.idl
-    writable_stream_native.cc
-    writable_stream_native.h
-    transferable_streams.cc
-    transferable_streams.h
-    transform_stream_default_controller.cc
-    transform_stream_default_controller.h
-    transform_stream_native.cc
-    transform_stream_native.h
-
-See also [Streams C++ port design doc][3].
+See [Streams C++ port design doc][2].
 
 [1]: https://streams.spec.whatwg.org/
-[2]: https://docs.google.com/document/d/1AT5-T0aHGp7Lt29vPWFr2-qG8r3l9CByyvKwEuA8Ec0
-[3]: https://docs.google.com/document/d/1n0IIRmJb0R-DFc2IhhJfS2-LUwl6iKSBNaR0klr3o40/edit
+[2]: https://docs.google.com/document/d/1n0IIRmJb0R-DFc2IhhJfS2-LUwl6iKSBNaR0klr3o40/edit
diff --git a/third_party/blink/renderer/core/streams/ReadableStream.js b/third_party/blink/renderer/core/streams/ReadableStream.js
deleted file mode 100644
index b34ad33..0000000
--- a/third_party/blink/renderer/core/streams/ReadableStream.js
+++ /dev/null
@@ -1,1145 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(function(global, binding, v8) {
-  'use strict';
-
-  const _reader = v8.createPrivateSymbol('[[reader]]');
-  const _storedError = v8.createPrivateSymbol('[[storedError]]');
-  const _controller = v8.createPrivateSymbol('[[controller]]');
-
-  const _closedPromise = v8.createPrivateSymbol('[[closedPromise]]');
-  const _ownerReadableStream =
-        v8.createPrivateSymbol('[[ownerReadableStream]]');
-
-  const _readRequests = v8.createPrivateSymbol('[[readRequests]]');
-
-  const createWithExternalControllerSentinel =
-        v8.createPrivateSymbol('flag for UA-created ReadableStream to pass');
-
-  const _readableStreamBits =
-        v8.createPrivateSymbol('bit field for [[state]] and [[disturbed]]');
-  const DISTURBED = 0b1;
-  // The 2nd and 3rd bit are for [[state]].
-  const STATE_MASK = 0b110;
-  const STATE_BITS_OFFSET = 1;
-  const STATE_READABLE = 0;
-  const STATE_CLOSED = 1;
-  const STATE_ERRORED = 2;
-
-  const _controlledReadableStream =
-        v8.createPrivateSymbol('[[controlledReadableStream]]');
-  const _strategyHWM = v8.createPrivateSymbol('[[strategyHWM]]');
-
-  const _readableStreamDefaultControllerBits = v8.createPrivateSymbol(
-      'bit field for [[started]], [[closeRequested]], [[pulling]], ' +
-        '[[pullAgain]]');
-  const internalReadableStreamSymbol = v8.createPrivateSymbol(
-      'internal ReadableStream in exposed ReadableStream interface');
-  // Remove this once C++ code has been updated to use CreateReadableStream.
-  const _strategySizeAlgorithm = v8.createPrivateSymbol(
-      '[[strategySizeAlgorithm]]');
-  const _pullAlgorithm = v8.createPrivateSymbol('[[pullAlgorithm]]');
-  const _cancelAlgorithm = v8.createPrivateSymbol('[[cancelAlgorithm]]');
-  const STARTED = 0b1;
-  const CLOSE_REQUESTED = 0b10;
-  const PULLING = 0b100;
-  const PULL_AGAIN = 0b1000;
-
-  const ObjectCreate = global.Object.create;
-
-  const callFunction = v8.uncurryThis(global.Function.prototype.call);
-  const applyFunction = v8.uncurryThis(global.Function.prototype.apply);
-
-  const TypeError = global.TypeError;
-  const RangeError = global.RangeError;
-
-  const String = global.String;
-
-  const Promise = global.Promise;
-  const thenPromise = v8.uncurryThis(Promise.prototype.then);
-
-  // From CommonOperations.js
-  const {
-    _queue,
-    _queueTotalSize,
-    createPromise,
-    createRejectedPromise,
-    createResolvedPromise,
-    hasOwnPropertyNoThrow,
-    rejectPromise,
-    resolvePromise,
-    markPromiseAsHandled,
-    CallOrNoop1,
-    CreateAlgorithmFromUnderlyingMethod,
-    CreateAlgorithmFromUnderlyingMethodPassingController,
-    CreateCrossRealmTransformReadable,
-    CreateCrossRealmTransformWritable,
-    DequeueValue,
-    EnqueueValueWithSize,
-    MakeSizeAlgorithmFromSizeFunction,
-    ValidateAndNormalizeHighWaterMark,
-  } = binding.streamOperations;
-
-  const streamErrors = binding.streamErrors;
-  const errEnqueueCloseRequestedStream =
-        'Cannot enqueue a chunk into a readable stream that is closed or ' +
-        'has been requested to be closed';
-  const errCancelReleasedReader =
-        'This readable stream reader has been released and cannot be used ' +
-        'to cancel its previous owner stream';
-  const errReadReleasedReader =
-        'This readable stream reader has been released and cannot be used ' +
-        'to read from its previous owner stream';
-  const errCloseCloseRequestedStream =
-        'Cannot close a readable stream that has already been requested to ' +
-        'be closed';
-  const errEnqueueClosedStream =
-        'Cannot enqueue a chunk into a closed readable stream';
-  const errEnqueueErroredStream =
-        'Cannot enqueue a chunk into an errored readable stream';
-  const errCloseClosedStream = 'Cannot close a closed readable stream';
-  const errCloseErroredStream = 'Cannot close an errored readable stream';
-  const errReaderConstructorBadArgument =
-        'ReadableStreamReader constructor argument is not a readable stream';
-  const errReaderConstructorStreamAlreadyLocked =
-        'ReadableStreamReader constructor can only accept readable streams ' +
-        'that are not yet locked to a reader';
-  const errReleaseReaderWithPendingRead =
-        'Cannot release a readable stream reader when it still has ' +
-        'outstanding read() calls that have not yet settled';
-  const errReleasedReaderClosedPromise =
-        'This readable stream reader has been released and cannot be used ' +
-        'to monitor the stream\'s state';
-
-  const errDestinationStreamClosed = 'Destination stream closed';
-
-  let useCounted = false;
-
-  class ReadableStream {
-    // TODO(ricea): Remove |internalArgument| once
-    // blink::ReadableStreamOperations has been updated to use
-    // CreateReadableStream.
-    constructor(underlyingSource = {}, strategy = {},
-                internalArgument = undefined) {
-      const createdByUA =
-            internalArgument === createWithExternalControllerSentinel;
-
-      if (!useCounted && !createdByUA) {
-        binding.countUse('ReadableStreamConstructor');
-        useCounted = true;
-      }
-
-      InitializeReadableStream(this);
-      const size = strategy.size;
-      let highWaterMark = strategy.highWaterMark;
-      const type = underlyingSource.type;
-      const typeString = String(type);
-
-      if (typeString === 'bytes') {
-        throw new RangeError('bytes type is not yet implemented');
-      }
-
-      if (type !== undefined) {
-        throw new RangeError(streamErrors.invalidType);
-      }
-
-      const sizeAlgorithm = MakeSizeAlgorithmFromSizeFunction(size);
-
-      if (highWaterMark === undefined) {
-        highWaterMark = 1;
-      }
-
-      highWaterMark = ValidateAndNormalizeHighWaterMark(highWaterMark);
-      SetUpReadableStreamDefaultControllerFromUnderlyingSource(
-          this, underlyingSource, highWaterMark, sizeAlgorithm);
-    }
-  }
-
-  const ReadableStream_prototype = ReadableStream.prototype;
-
-  function ReadableStreamPipeTo(
-      readable, dest, preventClose, preventAbort, preventCancel) {
-    // Callers of this function must ensure that the following invariants
-    // are enforced:
-    // assert(IsReadableStream(readable));
-    // assert(binding.IsWritableStream(dest));
-    // assert(!IsReadableStreamLocked(readable));
-    // assert(!binding.IsWritableStreamLocked(dest));
-
-    const reader = AcquireReadableStreamDefaultReader(readable);
-    const writer = binding.AcquireWritableStreamDefaultWriter(dest);
-    let shuttingDown = false;
-    const promise = createPromise();
-    let reading = false;
-    let lastWrite;
-
-    if (checkInitialState()) {
-      // Need to detect closing and error when we are not reading.
-      thenPromise(reader[_closedPromise], onReaderClosed, readableError);
-      // Need to detect error when we are not writing.
-      thenPromise(
-          binding.getWritableStreamDefaultWriterClosedPromise(writer),
-          undefined, writableError);
-      pump();
-    }
-
-    // Checks the state of the streams and executes the shutdown handlers if
-    // necessary. Returns true if piping can continue.
-    function checkInitialState() {
-      const state = ReadableStreamGetState(readable);
-
-      // Both streams can be errored or closed. To perform the right action the
-      // order of the checks must match the standard.
-      if (state === STATE_ERRORED) {
-        readableError(readable[_storedError]);
-        return false;
-      }
-
-      if (binding.isWritableStreamErrored(dest)) {
-        writableError(binding.getWritableStreamStoredError(dest));
-        return false;
-      }
-
-      if (state === STATE_CLOSED) {
-        readableClosed();
-        return false;
-      }
-
-      if (binding.isWritableStreamClosingOrClosed(dest)) {
-        writableStartedClosed();
-        return false;
-      }
-
-      return true;
-    }
-
-    function pump() {
-      if (shuttingDown) {
-        return;
-      }
-      const desiredSize =
-            binding.WritableStreamDefaultWriterGetDesiredSize(writer);
-      if (desiredSize === null) {
-        // This can happen if abort() is queued but not yet started when
-        // pipeTo() is called. In that case [[storedError]] is not set yet, and
-        // we need to wait until it is before we can cancel the pipe. Once
-        // [[storedError]] has been set, the rejection handler set on the writer
-        // closed promise above will detect it, so all we need to do here is
-        // nothing.
-        return;
-      }
-      if (desiredSize <= 0) {
-        thenPromise(
-            binding.getWritableStreamDefaultWriterReadyPromise(writer), pump,
-            writableError);
-        return;
-      }
-      reading = true;
-      thenPromise(
-          ReadableStreamDefaultReaderRead(reader), readFulfilled, readRejected);
-    }
-
-    function readFulfilled({value, done}) {
-      reading = false;
-      if (done) {
-        readableClosed();
-        return;
-      }
-      const write = binding.WritableStreamDefaultWriterWrite(writer, value);
-      lastWrite = write;
-      thenPromise(write, undefined, writableError);
-      pump();
-    }
-
-    function readRejected() {
-      reading = false;
-      readableError(readable[_storedError]);
-    }
-
-    // If read() is in progress, then wait for it to tell us that the stream is
-    // closed so that we write all the data before shutdown.
-    function onReaderClosed() {
-      if (!reading) {
-        readableClosed();
-      }
-    }
-
-    // These steps are from "Errors must be propagated forward" in the
-    // standard.
-    function readableError(error) {
-      if (!preventAbort) {
-        shutdownWithAction(
-            binding.WritableStreamAbort, [dest, error], error, true);
-      } else {
-        shutdown(error, true);
-      }
-    }
-
-    // These steps are from "Errors must be propagated backward".
-    function writableError(error) {
-      if (!preventCancel) {
-        shutdownWithAction(
-            ReadableStreamCancel, [readable, error], error, true);
-      } else {
-        shutdown(error, true);
-      }
-    }
-
-    // These steps are from "Closing must be propagated forward".
-    function readableClosed() {
-      if (!preventClose) {
-        shutdownWithAction(
-            binding.WritableStreamDefaultWriterCloseWithErrorPropagation,
-            [writer]);
-      } else {
-        shutdown();
-      }
-    }
-
-    // These steps are from "Closing must be propagated backward".
-    function writableStartedClosed() {
-      const destClosed = new TypeError(errDestinationStreamClosed);
-      if (!preventCancel) {
-        shutdownWithAction(
-            ReadableStreamCancel, [readable, destClosed], destClosed, true);
-      } else {
-        shutdown(destClosed, true);
-      }
-    }
-
-    function shutdownWithAction(
-        action, args, originalError = undefined, errorGiven = false) {
-      if (shuttingDown) {
-        return;
-      }
-      shuttingDown = true;
-      let p;
-      if (shouldWriteQueuedChunks()) {
-        p = thenPromise(writeQueuedChunks(),
-                        () => applyFunction(action, undefined, args));
-      } else {
-        p = applyFunction(action, undefined, args);
-      }
-      thenPromise(
-          p, () => finalize(originalError, errorGiven),
-          newError => finalize(newError, true));
-    }
-
-    function shutdown(error = undefined, errorGiven = false) {
-      if (shuttingDown) {
-        return;
-      }
-      shuttingDown = true;
-      if (shouldWriteQueuedChunks()) {
-        thenPromise(writeQueuedChunks(), () => finalize(error, errorGiven));
-      } else {
-        finalize(error, errorGiven);
-      }
-    }
-
-    function finalize(error, errorGiven) {
-      binding.WritableStreamDefaultWriterRelease(writer);
-      ReadableStreamReaderGenericRelease(reader);
-      if (errorGiven) {
-        rejectPromise(promise, error);
-      } else {
-        resolvePromise(promise, undefined);
-      }
-    }
-
-    function shouldWriteQueuedChunks() {
-      return binding.isWritableStreamWritable(dest) &&
-          !binding.WritableStreamCloseQueuedOrInFlight(dest);
-    }
-
-    function writeQueuedChunks() {
-      if (lastWrite) {
-        // "Wait until every chunk that has been read has been written (i.e.
-        // the corresponding promises have settled)"
-        // This implies that we behave the same whether the promise fulfills or
-        // rejects.
-        return thenPromise(lastWrite, () => undefined, () => undefined);
-      }
-      return createResolvedPromise(undefined);
-    }
-
-    return promise;
-  }
-
-  //
-  // Readable stream abstract operations
-  //
-
-  function AcquireReadableStreamDefaultReader(stream) {
-    return new ReadableStreamDefaultReader(stream);
-  }
-
-  function CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm,
-                                highWaterMark, sizeAlgorithm) {
-    if (highWaterMark === undefined) {
-      highWaterMark = 1;
-    }
-    if (sizeAlgorithm === undefined) {
-      sizeAlgorithm = () => 1;
-    }
-    // assert(IsNonNegativeNumber(highWaterMark),
-    //        '! IsNonNegativeNumber(highWaterMark) is true.');
-    const stream = ObjectCreate(ReadableStream_prototype);
-    InitializeReadableStream(stream);
-    const controller = ObjectCreate(ReadableStreamDefaultController_prototype);
-    SetUpReadableStreamDefaultController(
-        stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm,
-        highWaterMark, sizeAlgorithm);
-    return stream;
-  }
-
-  function InitializeReadableStream(stream) {
-    stream[_readableStreamBits] = 0b0;
-    ReadableStreamSetState(stream, STATE_READABLE);
-    stream[_reader] = undefined;
-    stream[_storedError] = undefined;
-  }
-
-  function IsReadableStream(x) {
-    return hasOwnPropertyNoThrow(x, _controller);
-  }
-
-  function IsReadableStreamDisturbed(stream) {
-    return stream[_readableStreamBits] & DISTURBED;
-  }
-
-  function IsReadableStreamLocked(stream) {
-    return stream[_reader] !== undefined;
-  }
-
-  // TODO(domenic): cloneForBranch2 argument from spec not supported yet
-  function ReadableStreamTee(stream) {
-    const reader = AcquireReadableStreamDefaultReader(stream);
-
-    let closedOrErrored = false;
-    let canceled1 = false;
-    let canceled2 = false;
-    let reason1;
-    let reason2;
-    const cancelPromise = createPromise();
-
-    function pullAlgorithm() {
-      return thenPromise(
-          ReadableStreamDefaultReaderRead(reader), ({value, done}) => {
-            if (done && !closedOrErrored) {
-              if (!canceled1) {
-                ReadableStreamDefaultControllerClose(branch1controller);
-              }
-              if (!canceled2) {
-                ReadableStreamDefaultControllerClose(branch2controller);
-              }
-              closedOrErrored = true;
-            }
-
-            if (closedOrErrored) {
-              return;
-            }
-
-            // TODO(ricea): Implement these steps for cloning.
-            //
-            // vii. Let _value1_ and _value2_ be _value_.
-            // viii. If _canceled2_ is false and _cloneForBranch2_ is true, set
-            // value2 to ? StructuredDeserialize(? StructuredSerialize(value2),
-            // the current Realm Record).
-
-            if (!canceled1) {
-              ReadableStreamDefaultControllerEnqueue(branch1controller, value);
-            }
-
-            if (!canceled2) {
-              ReadableStreamDefaultControllerEnqueue(branch2controller, value);
-            }
-          });
-    }
-
-    function cancel1Algorithm(reason) {
-      canceled1 = true;
-      reason1 = reason;
-      if (canceled2) {
-        const cancelResult = ReadableStreamCancel(stream, [reason1, reason2]);
-        resolvePromise(cancelPromise, cancelResult);
-      }
-      return cancelPromise;
-    }
-
-    function cancel2Algorithm(reason) {
-      canceled2 = true;
-      reason2 = reason;
-      if (canceled1) {
-        const cancelResult = ReadableStreamCancel(stream, [reason1, reason2]);
-        resolvePromise(cancelPromise, cancelResult);
-      }
-      return cancelPromise;
-    }
-
-    const startAlgorithm = () => undefined;
-
-    const branch1Stream = CreateReadableStream(
-        startAlgorithm, pullAlgorithm, cancel1Algorithm);
-    const branch2Stream = CreateReadableStream(
-        startAlgorithm, pullAlgorithm, cancel2Algorithm);
-    const branch1controller = branch1Stream[_controller];
-    const branch2controller = branch2Stream[_controller];
-
-    thenPromise(reader[_closedPromise], undefined, r => {
-      if (closedOrErrored === true) {
-        return;
-      }
-
-      ReadableStreamDefaultControllerError(branch1controller, r);
-      ReadableStreamDefaultControllerError(branch2controller, r);
-      closedOrErrored = true;
-    });
-
-    return [branch1Stream, branch2Stream];
-  }
-
-  //
-  // Abstract Operations Used By Controllers
-  //
-
-  function ReadableStreamAddReadRequest(stream, forAuthorCode) {
-    const promise = createPromise();
-    stream[_reader][_readRequests].push({promise, forAuthorCode});
-    return promise;
-  }
-
-  function ReadableStreamCancel(stream, reason) {
-    stream[_readableStreamBits] |= DISTURBED;
-
-    const state = ReadableStreamGetState(stream);
-    if (state === STATE_CLOSED) {
-      return createResolvedPromise(undefined);
-    }
-    if (state === STATE_ERRORED) {
-      return createRejectedPromise(stream[_storedError]);
-    }
-
-    ReadableStreamClose(stream);
-
-    const sourceCancelPromise =
-          ReadableStreamDefaultControllerCancel(stream[_controller], reason);
-    return thenPromise(sourceCancelPromise, () => undefined);
-  }
-
-  function ReadableStreamClose(stream) {
-    ReadableStreamSetState(stream, STATE_CLOSED);
-
-    const reader = stream[_reader];
-    if (reader === undefined) {
-      return;
-    }
-
-    if (IsReadableStreamDefaultReader(reader) === true) {
-      reader[_readRequests].forEach(
-          request =>
-            resolvePromise(
-                request.promise,
-                ReadableStreamCreateReadResult(undefined, true,
-                                               request.forAuthorCode)));
-      reader[_readRequests] = new binding.SimpleQueue();
-    }
-
-    resolvePromise(reader[_closedPromise], undefined);
-  }
-
-  function ReadableStreamCreateReadResult(value, done, forAuthorCode) {
-    // assert(typeof done === 'boolean', 'Type(_done_) is Boolean.');
-    if (forAuthorCode) {
-      return {value, done};
-    }
-    const obj = ObjectCreate(null);
-    obj.value = value;
-    obj.done = done;
-    return obj;
-  }
-
-  function ReadableStreamError(stream, e) {
-    ReadableStreamSetState(stream, STATE_ERRORED);
-    stream[_storedError] = e;
-
-    const reader = stream[_reader];
-    if (reader === undefined) {
-      return;
-    }
-
-    if (IsReadableStreamDefaultReader(reader) === true) {
-      reader[_readRequests].forEach(request =>
-                                    rejectPromise(request.promise, e));
-      reader[_readRequests] = new binding.SimpleQueue();
-    }
-
-    rejectPromise(reader[_closedPromise], e);
-    markPromiseAsHandled(reader[_closedPromise]);
-  }
-
-  function ReadableStreamFulfillReadRequest(stream, chunk, done) {
-    const readRequest = stream[_reader][_readRequests].shift();
-    resolvePromise(readRequest.promise,
-                   ReadableStreamCreateReadResult(chunk, done,
-                                                  readRequest.forAuthorCode));
-  }
-
-  function ReadableStreamGetNumReadRequests(stream) {
-    const reader = stream[_reader];
-    const readRequests = reader[_readRequests];
-    return readRequests.length;
-  }
-
-  //
-  // Class ReadableStreamDefaultReader
-  //
-
-  class ReadableStreamDefaultReader {
-    constructor(stream) {
-      // |stream| here can be either an external ReadableStream (i.e.,
-      // IDL defined ReadableStream) or an internal ReadableStream (i.e.,
-      // the class defined in this file). In the former case, the
-      // internal stream is stored in [internalReadableStreamSymbol], so use it
-      // from now on.
-      if (stream[internalReadableStreamSymbol] !== undefined) {
-        stream = stream[internalReadableStreamSymbol];
-      }
-
-      if (IsReadableStream(stream) === false) {
-        throw new TypeError(errReaderConstructorBadArgument);
-      }
-      if (IsReadableStreamLocked(stream) === true) {
-        throw new TypeError(errReaderConstructorStreamAlreadyLocked);
-      }
-
-      ReadableStreamReaderGenericInitialize(this, stream);
-
-      this[_readRequests] = new binding.SimpleQueue();
-    }
-
-    get closed() {
-      if (IsReadableStreamDefaultReader(this) === false) {
-        return createRejectedPromise(
-            new TypeError(streamErrors.illegalInvocation));
-      }
-
-      return this[_closedPromise];
-    }
-
-    cancel(reason) {
-      if (IsReadableStreamDefaultReader(this) === false) {
-        return createRejectedPromise(
-            new TypeError(streamErrors.illegalInvocation));
-      }
-
-      if (this[_ownerReadableStream] === undefined) {
-        return createRejectedPromise(new TypeError(errCancelReleasedReader));
-      }
-
-      return ReadableStreamReaderGenericCancel(this, reason);
-    }
-
-    read() {
-      if (IsReadableStreamDefaultReader(this) === false) {
-        return createRejectedPromise(
-            new TypeError(streamErrors.illegalInvocation));
-      }
-
-      if (this[_ownerReadableStream] === undefined) {
-        return createRejectedPromise(new TypeError(errReadReleasedReader));
-      }
-
-      return ReadableStreamDefaultReaderRead(this, true);
-    }
-
-    releaseLock() {
-      if (IsReadableStreamDefaultReader(this) === false) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      if (this[_ownerReadableStream] === undefined) {
-        return;
-      }
-
-      if (this[_readRequests].length > 0) {
-        throw new TypeError(errReleaseReaderWithPendingRead);
-      }
-
-      ReadableStreamReaderGenericRelease(this);
-    }
-  }
-
-  //
-  //  Readable Stream Reader Abstract Operations
-  //
-
-  function IsReadableStreamDefaultReader(x) {
-    return hasOwnPropertyNoThrow(x, _readRequests);
-  }
-
-  function ReadableStreamReaderGenericCancel(reader, reason) {
-    return ReadableStreamCancel(reader[_ownerReadableStream], reason);
-  }
-
-  function ReadableStreamReaderGenericInitialize(reader, stream) {
-    reader[_ownerReadableStream] = stream;
-    stream[_reader] = reader;
-
-    switch (ReadableStreamGetState(stream)) {
-      case STATE_READABLE:
-        reader[_closedPromise] = createPromise();
-        break;
-      case STATE_CLOSED:
-        reader[_closedPromise] = createResolvedPromise(undefined);
-        break;
-      case STATE_ERRORED:
-        reader[_closedPromise] = createRejectedPromise(stream[_storedError]);
-        markPromiseAsHandled(reader[_closedPromise]);
-        break;
-    }
-  }
-
-  function ReadableStreamReaderGenericRelease(reader) {
-    if (ReadableStreamGetState(reader[_ownerReadableStream]) ===
-        STATE_READABLE) {
-      rejectPromise(
-          reader[_closedPromise],
-          new TypeError(errReleasedReaderClosedPromise));
-    } else {
-      reader[_closedPromise] =
-          createRejectedPromise(new TypeError(errReleasedReaderClosedPromise));
-    }
-    markPromiseAsHandled(reader[_closedPromise]);
-
-    reader[_ownerReadableStream][_reader] = undefined;
-    reader[_ownerReadableStream] = undefined;
-  }
-
-  function ReadableStreamDefaultReaderRead(reader, forAuthorCode = false) {
-    const stream = reader[_ownerReadableStream];
-    stream[_readableStreamBits] |= DISTURBED;
-
-    switch (ReadableStreamGetState(stream)) {
-      case STATE_CLOSED:
-        return createResolvedPromise(
-            ReadableStreamCreateReadResult(undefined, true, forAuthorCode));
-
-      case STATE_ERRORED:
-        return createRejectedPromise(stream[_storedError]);
-
-      default:
-        return ReadableStreamDefaultControllerPull(stream[_controller],
-                                                   forAuthorCode);
-    }
-  }
-
-  //
-  // Class ReadableStreamDefaultController
-  //
-
-  class ReadableStreamDefaultController {
-    constructor() {
-      throw new TypeError(streamErrors.illegalConstructor);
-    }
-
-    get desiredSize() {
-      if (IsReadableStreamDefaultController(this) === false) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      return ReadableStreamDefaultControllerGetDesiredSize(this);
-    }
-
-    close() {
-      if (IsReadableStreamDefaultController(this) === false) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      if (ReadableStreamDefaultControllerCanCloseOrEnqueue(this) === false) {
-        let errorDescription;
-        if (this[_readableStreamDefaultControllerBits] & CLOSE_REQUESTED) {
-          errorDescription = errCloseCloseRequestedStream;
-        } else {
-          const stream = this[_controlledReadableStream];
-          switch (ReadableStreamGetState(stream)) {
-            case STATE_ERRORED:
-              errorDescription = errCloseErroredStream;
-              break;
-
-            case STATE_CLOSED:
-              errorDescription = errCloseClosedStream;
-              break;
-          }
-        }
-        throw new TypeError(errorDescription);
-      }
-
-      return ReadableStreamDefaultControllerClose(this);
-    }
-
-    enqueue(chunk) {
-      if (IsReadableStreamDefaultController(this) === false) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(this)) {
-        const stream = this[_controlledReadableStream];
-        throw getReadableStreamEnqueueError(stream, this);
-      }
-
-      return ReadableStreamDefaultControllerEnqueue(this, chunk);
-    }
-
-    error(e) {
-      if (IsReadableStreamDefaultController(this) === false) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      return ReadableStreamDefaultControllerError(this, e);
-    }
-  }
-
-  const ReadableStreamDefaultController_prototype =
-        ReadableStreamDefaultController.prototype;
-
-  // [[CancelSteps]] in the standard.
-  function ReadableStreamDefaultControllerCancel(controller, reason) {
-    controller[_queue] = new binding.SimpleQueue();
-    return controller[_cancelAlgorithm](reason);
-  }
-
-  // [[PullSteps]] in the standard.
-  function ReadableStreamDefaultControllerPull(controller, forAuthorCode) {
-    const stream = controller[_controlledReadableStream];
-
-    if (controller[_queue].length > 0) {
-      const chunk = DequeueValue(controller);
-
-      if ((controller[_readableStreamDefaultControllerBits] &
-           CLOSE_REQUESTED) &&
-          controller[_queue].length === 0) {
-        ReadableStreamClose(stream);
-      } else {
-        ReadableStreamDefaultControllerCallPullIfNeeded(controller);
-      }
-
-      return createResolvedPromise(
-          ReadableStreamCreateReadResult(chunk, false, forAuthorCode));
-    }
-
-    const pendingPromise = ReadableStreamAddReadRequest(stream, forAuthorCode);
-    ReadableStreamDefaultControllerCallPullIfNeeded(controller);
-    return pendingPromise;
-  }
-
-  //
-  // Readable Stream Default Controller Abstract Operations
-  //
-
-  function IsReadableStreamDefaultController(x) {
-    return hasOwnPropertyNoThrow(x, _controlledReadableStream);
-  }
-
-  function ReadableStreamDefaultControllerCallPullIfNeeded(controller) {
-    const shouldPull =
-          ReadableStreamDefaultControllerShouldCallPull(controller);
-    if (shouldPull === false) {
-      return;
-    }
-
-    if (controller[_readableStreamDefaultControllerBits] & PULLING) {
-      controller[_readableStreamDefaultControllerBits] |= PULL_AGAIN;
-      return;
-    }
-
-    controller[_readableStreamDefaultControllerBits] |= PULLING;
-
-    thenPromise(
-        controller[_pullAlgorithm](),
-        () => {
-          controller[_readableStreamDefaultControllerBits] &= ~PULLING;
-
-          if (controller[_readableStreamDefaultControllerBits] & PULL_AGAIN) {
-            controller[_readableStreamDefaultControllerBits] &= ~PULL_AGAIN;
-            ReadableStreamDefaultControllerCallPullIfNeeded(controller);
-          }
-        },
-        e => {
-          ReadableStreamDefaultControllerError(controller, e);
-        });
-  }
-
-  function ReadableStreamDefaultControllerShouldCallPull(controller) {
-    if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)) {
-      return false;
-    }
-    if (!(controller[_readableStreamDefaultControllerBits] & STARTED)) {
-      return false;
-    }
-
-    const stream = controller[_controlledReadableStream];
-    if (IsReadableStreamLocked(stream) === true &&
-        ReadableStreamGetNumReadRequests(stream) > 0) {
-      return true;
-    }
-
-    const desiredSize =
-          ReadableStreamDefaultControllerGetDesiredSize(controller);
-    // assert(desiredSize !== null, '_desiredSize_ is not *null*.');
-    return desiredSize > 0;
-  }
-
-  function ReadableStreamDefaultControllerClose(controller) {
-    controller[_readableStreamDefaultControllerBits] |= CLOSE_REQUESTED;
-
-    if (controller[_queue].length === 0) {
-      ReadableStreamClose(controller[_controlledReadableStream]);
-    }
-  }
-
-  function ReadableStreamDefaultControllerEnqueue(controller, chunk) {
-    const stream = controller[_controlledReadableStream];
-
-    if (IsReadableStreamLocked(stream) === true &&
-        ReadableStreamGetNumReadRequests(stream) > 0) {
-      ReadableStreamFulfillReadRequest(stream, chunk, false);
-    } else {
-      let chunkSize;
-
-      // TODO(ricea): Would it be more efficient if we avoided the
-      // try ... catch when we're using the default strategy size algorithm?
-      try {
-        // Unlike other algorithms, strategySizeAlgorithm isn't indirected, so
-        // we need to be careful with the |this| value.
-        chunkSize = callFunction(controller[_strategySizeAlgorithm], undefined,
-                                 chunk);
-      } catch (chunkSizeE) {
-        ReadableStreamDefaultControllerError(controller, chunkSizeE);
-        throw chunkSizeE;
-      }
-
-      try {
-        EnqueueValueWithSize(controller, chunk, chunkSize);
-      } catch (enqueueE) {
-        ReadableStreamDefaultControllerError(controller, enqueueE);
-        throw enqueueE;
-      }
-    }
-
-    ReadableStreamDefaultControllerCallPullIfNeeded(controller);
-  }
-
-  function ReadableStreamDefaultControllerError(controller, e) {
-    const stream = controller[_controlledReadableStream];
-    if (ReadableStreamGetState(stream) !== STATE_READABLE) {
-      return;
-    }
-    controller[_queue] = new binding.SimpleQueue();
-    ReadableStreamError(stream, e);
-  }
-
-  function ReadableStreamDefaultControllerGetDesiredSize(controller) {
-    switch (ReadableStreamGetState(controller[_controlledReadableStream])) {
-      case STATE_ERRORED:
-        return null;
-
-      case STATE_CLOSED:
-        return 0;
-
-      default:
-        return controller[_strategyHWM] - controller[_queueTotalSize];
-    }
-  }
-
-  function ReadableStreamDefaultControllerHasBackpressure(controller) {
-    return !ReadableStreamDefaultControllerShouldCallPull(controller);
-  }
-
-  function ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) {
-    if (controller[_readableStreamDefaultControllerBits] & CLOSE_REQUESTED) {
-      return false;
-    }
-    const state = ReadableStreamGetState(controller[_controlledReadableStream]);
-    return state === STATE_READABLE;
-  }
-
-  function SetUpReadableStreamDefaultController(
-      stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm,
-      highWaterMark, sizeAlgorithm) {
-    controller[_controlledReadableStream] = stream;
-    controller[_queue] = new binding.SimpleQueue();
-    controller[_queueTotalSize] = 0;
-    controller[_strategySizeAlgorithm] = sizeAlgorithm;
-    controller[_strategyHWM] = highWaterMark;
-    controller[_pullAlgorithm] = pullAlgorithm;
-    controller[_cancelAlgorithm] = cancelAlgorithm;
-    stream[_controller] = controller;
-
-    thenPromise(createResolvedPromise(startAlgorithm()), () => {
-      controller[_readableStreamDefaultControllerBits] |= STARTED;
-      ReadableStreamDefaultControllerCallPullIfNeeded(controller);
-    }, r =>  ReadableStreamDefaultControllerError(controller, r));
-  }
-
-  function SetUpReadableStreamDefaultControllerFromUnderlyingSource(
-      stream, underlyingSource, highWaterMark, sizeAlgorithm) {
-    const controller = ObjectCreate(ReadableStreamDefaultController_prototype);
-    const startAlgorithm =
-          () => CallOrNoop1(underlyingSource, 'start', controller,
-                            'underlyingSource.start');
-    const pullAlgorithm = CreateAlgorithmFromUnderlyingMethodPassingController(
-        underlyingSource, 'pull', 0, controller, 'underlyingSource.pull');
-    const cancelAlgorithm = CreateAlgorithmFromUnderlyingMethod(
-        underlyingSource, 'cancel', 1, 'underlyingSource.cancel');
-    SetUpReadableStreamDefaultController(
-        stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm,
-        highWaterMark, sizeAlgorithm);
-  }
-
-  //
-  // Functions for transferable streams.
-  //
-
-  // The |port| which is passed to this function must be a MessagePort which is
-  // attached by a MessageChannel to the |port| that will be passed to
-  // ReadableStreamDeserialize.
-  function ReadableStreamSerialize(readable, port) {
-    // assert(IsReadableStream(readable),
-    //        `! IsReadableStream(_readable_) is true`);
-    if (IsReadableStreamLocked(readable)) {
-      throw new TypeError(streamErrors.cannotTransferLockedStream);
-    }
-
-    if (!binding.MessagePort_postMessage) {
-      throw new TypeError(streamErrors.cannotTransferContext);
-    }
-
-    const writable = CreateCrossRealmTransformWritable(port);
-    const promise =
-          ReadableStreamPipeTo(readable, writable, false, false, false);
-    markPromiseAsHandled(promise);
-  }
-
-  function ReadableStreamDeserialize(port) {
-    return CreateCrossRealmTransformReadable(port);
-  }
-
-  //
-  // Internal functions. Not part of the standard.
-  //
-
-  function ReadableStreamGetState(stream) {
-    return (stream[_readableStreamBits] & STATE_MASK) >> STATE_BITS_OFFSET;
-  }
-
-  function ReadableStreamSetState(stream, state) {
-    stream[_readableStreamBits] = (stream[_readableStreamBits] & ~STATE_MASK) |
-        (state << STATE_BITS_OFFSET);
-  }
-
-  //
-  // Functions exported for use by TransformStream. Not part of the standard.
-  //
-
-  function IsReadableStreamReadable(stream) {
-    return ReadableStreamGetState(stream) === STATE_READABLE;
-  }
-
-  function IsReadableStreamClosed(stream) {
-    return ReadableStreamGetState(stream) === STATE_CLOSED;
-  }
-
-  function IsReadableStreamErrored(stream) {
-    return ReadableStreamGetState(stream) === STATE_ERRORED;
-  }
-
-  // Used internally by enqueue() and also by TransformStream.
-  function getReadableStreamEnqueueError(stream, controller) {
-    if (controller[_readableStreamDefaultControllerBits] & CLOSE_REQUESTED) {
-      return new TypeError(errEnqueueCloseRequestedStream);
-    }
-
-    const state = ReadableStreamGetState(stream);
-    if (state === STATE_ERRORED) {
-      return new TypeError(errEnqueueErroredStream);
-    }
-    // assert(state === STATE_CLOSED, 'state is "closed"');
-    return new TypeError(errEnqueueClosedStream);
-  }
-
-  //
-  // Accessors used by TransformStream
-  //
-
-  function getReadableStreamController(stream) {
-    // assert(
-    //     IsReadableStream(stream), '! IsReadableStream(stream) is true.');
-    return stream[_controller];
-  }
-
-  function getReadableStreamStoredError(stream) {
-    // assert(
-    //     IsReadableStream(stream), '! IsReadableStream(stream) is true.');
-    return stream[_storedError];
-  }
-
-  // TODO(yhirano): Rename this to constructReadableStream.
-  function createReadableStream(underlyingSource, strategy) {
-    return new ReadableStream(underlyingSource, strategy);
-  }
-
-  // TODO(yhirano): Rename this to
-  // constructReadableStreamWithExternalController.
-  // TODO(ricea): Remove this once the C++ code switches to calling
-  // CreateReadableStream().
-  function createReadableStreamWithExternalController(
-      underlyingSource, strategy) {
-    return new ReadableStream(
-        underlyingSource, strategy, createWithExternalControllerSentinel);
-  }
-
-  Object.assign(binding, {
-    //
-    // ReadableStream exports to Blink C++
-    //
-    AcquireReadableStreamDefaultReader,
-    createReadableStream,
-    createReadableStreamWithExternalController,
-    IsReadableStream,
-    IsReadableStreamDisturbed,
-    IsReadableStreamLocked,
-    IsReadableStreamReadable,
-    IsReadableStreamClosed,
-    IsReadableStreamErrored,
-    IsReadableStreamDefaultReader,
-    ReadableStreamDefaultReaderRead,
-    ReadableStreamCancel,
-    ReadableStreamTee,
-    ReadableStreamPipeTo,
-    ReadableStreamSerialize,
-    ReadableStreamDeserialize,
-    internalReadableStreamSymbol,
-
-    //
-    // Controller exports to Blink C++
-    //
-    ReadableStreamDefaultControllerClose,
-    ReadableStreamDefaultControllerGetDesiredSize,
-    ReadableStreamDefaultControllerEnqueue,
-    ReadableStreamDefaultControllerError,
-
-    //
-    // Exports to TransformStream
-    //
-    CreateReadableStream,
-    ReadableStreamDefaultControllerCanCloseOrEnqueue,
-    ReadableStreamDefaultControllerHasBackpressure,
-
-    getReadableStreamEnqueueError,
-    getReadableStreamController,
-    getReadableStreamStoredError,
-  });
-});
diff --git a/third_party/blink/renderer/core/streams/SimpleQueue.js b/third_party/blink/renderer/core/streams/SimpleQueue.js
deleted file mode 100644
index b1db33d..0000000
--- a/third_party/blink/renderer/core/streams/SimpleQueue.js
+++ /dev/null
@@ -1,152 +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.
-
-// Queue implementation used by ReadableStream and WritableStream.
-
-(function(global, binding, v8) {
-  'use strict';
-
-  const _front = v8.createPrivateSymbol('front');
-  const _back = v8.createPrivateSymbol('back');
-  const _cursor = v8.createPrivateSymbol('cursor');
-  const _size = v8.createPrivateSymbol('size');
-  const _elements = v8.createPrivateSymbol('elements');
-  const _next = v8.createPrivateSymbol('next');
-
-  // Take copies of global objects to protect against them being replaced.
-  const RangeError = global.RangeError;
-
-  // shift() and peek() can only be called on a non-empty queue. This function
-  // throws an exception with the message mentioning |functionName| if |queue|
-  // is empty.
-  function requireNonEmptyQueue(queue, functionName) {
-    if (queue[_size] === 0) {
-      throw new RangeError(
-          `${functionName}() must not be called on an empty queue`);
-    }
-  }
-
-  // Simple queue structure. Avoids scalability issues with using
-  // InternalPackedArray directly by using multiple arrays in a linked list and
-  // keeping the array size bounded.
-  const QUEUE_MAX_ARRAY_SIZE = 16384;
-  class SimpleQueue {
-    constructor() {
-      // [_front] and [_back] are always defined.
-      this[_front] = {
-        [_elements]: new v8.InternalPackedArray(),
-        [_next]: undefined,
-      };
-      this[_back] = this[_front];
-      // The cursor is used to avoid calling InternalPackedArray.shift(). It
-      // contains the index of the front element of the array inside the
-      // frontmost node. It is always in the range [0, QUEUE_MAX_ARRAY_SIZE).
-      this[_cursor] = 0;
-      // When there is only one node, size === elements.length - cursor.
-      this[_size] = 0;
-    }
-
-    get length() {
-      return this[_size];
-    }
-
-    // For exception safety, this method is structured in order:
-    // 1. Read state
-    // 2. Calculate required state mutations
-    // 3. Perform state mutations
-    push(element) {
-      const oldBack = this[_back];
-      let newBack = oldBack;
-      // assert(oldBack[_next] === undefined);
-      if (oldBack[_elements].length === QUEUE_MAX_ARRAY_SIZE - 1) {
-        newBack = {
-          [_elements]: new v8.InternalPackedArray(),
-          [_next]: undefined,
-        };
-      }
-
-      // push() is the mutation most likely to throw an exception, so it
-      // goes first.
-      oldBack[_elements].push(element);
-      if (newBack !== oldBack) {
-        this[_back] = newBack;
-        oldBack[_next] = newBack;
-      }
-      ++this[_size];
-    }
-
-    // Like push(), shift() follows the read -> calculate -> mutate pattern for
-    // exception safety.
-    shift() {
-      requireNonEmptyQueue(this, 'shift');
-
-      const oldFront = this[_front];
-      let newFront = oldFront;
-      const oldCursor = this[_cursor];
-      let newCursor = oldCursor + 1;
-
-      const elements = oldFront[_elements];
-      const element = elements[oldCursor];
-
-      if (newCursor === QUEUE_MAX_ARRAY_SIZE) {
-        // assert(elements.length === QUEUE_MAX_ARRAY_SIZE);
-        // assert(oldFront[_next] !== undefined);
-        newFront = oldFront[_next];
-        newCursor = 0;
-      }
-
-      // No mutations before this point.
-      --this[_size];
-      this[_cursor] = newCursor;
-      if (oldFront !== newFront) {
-        this[_front] = newFront;
-      }
-
-      // Permit shifted element to be garbage collected.
-      elements[oldCursor] = undefined;
-
-      return element;
-    }
-
-    // The tricky thing about forEach() is that it can be called
-    // re-entrantly. The queue may be mutated inside the callback. It is easy to
-    // see that push() within the callback has no negative effects since the end
-    // of the queue is checked for on every iteration. If shift() is called
-    // repeatedly within the callback then the next iteration may return an
-    // element that has been removed. In this case the callback will be called
-    // with undefined values until we either "catch up" with elements that still
-    // exist or reach the back of the queue.
-    forEach(callback) {
-      let i = this[_cursor];
-      let node = this[_front];
-      let elements = node[_elements];
-      while (i !== elements.length || node[_next] !== undefined) {
-        if (i === elements.length) {
-          // assert(node[_next] !== undefined);
-          // assert(i === QUEUE_MAX_ARRAY_SIZE);
-          node = node[_next];
-          elements = node[_elements];
-          i = 0;
-          if (elements.length === 0) {
-            break;
-          }
-        }
-        callback(elements[i]);
-        ++i;
-      }
-    }
-
-    // Return the element that would be returned if shift() was called now,
-    // without modifying the queue.
-    peek() {
-      requireNonEmptyQueue(this, 'peek');
-
-      const front = this[_front];
-      const cursor = this[_cursor];
-      return front[_elements][cursor];
-    }
-  }
-
-  binding.SimpleQueue = SimpleQueue;
-});
diff --git a/third_party/blink/renderer/core/streams/TransformStream.js b/third_party/blink/renderer/core/streams/TransformStream.js
deleted file mode 100644
index 639be9b..0000000
--- a/third_party/blink/renderer/core/streams/TransformStream.js
+++ /dev/null
@@ -1,498 +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.
-
-// Implementation of TransformStream for Blink.  See
-// https://streams.spec.whatwg.org/#ts. The implementation closely follows the
-// standard, except where required for performance or integration with Blink.
-// In particular, classes, methods and abstract operations are implemented in
-// the same order as in the standard, to simplify side-by-side reading.
-
-(function(global, binding, v8) {
-  'use strict';
-
-  // Private symbols. These correspond to the internal slots in the standard.
-  // "[[X]]" in the standard is spelt _X in this implementation.
-
-  const _backpressure = v8.createPrivateSymbol('[[backpressure]]');
-  const _backpressureChangePromise =
-      v8.createPrivateSymbol('[[backpressureChangePromise]]');
-  const _readable = v8.createPrivateSymbol('[[readable]]');
-  const _transformStreamController =
-      v8.createPrivateSymbol('[[transformStreamController]]');
-  const _writable = v8.createPrivateSymbol('[[writable]]');
-  const _controlledTransformStream =
-      v8.createPrivateSymbol('[[controlledTransformStream]]');
-
-  // Unlike the version in the standard, the controller is passed to this.
-  const _flushAlgorithm = v8.createPrivateSymbol('[[flushAlgorithm]]');
-
-  // Unlike the version in the standard, the controller is passed in as the
-  // second argument.
-  const _transformAlgorithm = v8.createPrivateSymbol('[[transformAlgorithm]]');
-
-  // Javascript functions. It is important to use these copies, as the ones on
-  // the global object may have been overwritten. See "V8 Extras Design Doc",
-  // section "Security Considerations".
-  // https://docs.google.com/document/d/1AT5-T0aHGp7Lt29vPWFr2-qG8r3l9CByyvKwEuA8Ec0/edit#heading=h.9yixony1a18r
-  const ObjectCreate = global.Object.create;
-
-  const TypeError = global.TypeError;
-  const RangeError = global.RangeError;
-
-  const Promise = global.Promise;
-  const thenPromise = v8.uncurryThis(Promise.prototype.then);
-
-  // From CommonOperations.js
-  const {
-    createPromise,
-    createRejectedPromise,
-    createResolvedPromise,
-    hasOwnPropertyNoThrow,
-    resolvePromise,
-    CreateAlgorithmFromUnderlyingMethod,
-    CallOrNoop1,
-    MakeSizeAlgorithmFromSizeFunction,
-    PromiseCall2,
-    ValidateAndNormalizeHighWaterMark
-  } = binding.streamOperations;
-
-  // User-visible strings.
-  const streamErrors = binding.streamErrors;
-  const errStreamTerminated = 'The transform stream has been terminated';
-
-  let useCounted = false;
-
-  class TransformStream {
-    constructor(transformer = {},
-                writableStrategy = {}, readableStrategy = {}) {
-      if (!useCounted) {
-        binding.countUse('TransformStreamConstructor');
-        useCounted = true;
-      }
-
-      const writableSizeFunction = writableStrategy.size;
-      let writableHighWaterMark = writableStrategy.highWaterMark;
-
-      const readableSizeFunction = readableStrategy.size;
-      let readableHighWaterMark = readableStrategy.highWaterMark;
-
-      // readable and writableType are extension points for future byte streams.
-      const writableType = transformer.writableType;
-      if (writableType !== undefined) {
-        throw new RangeError(streamErrors.invalidType);
-      }
-
-      const writableSizeAlgorithm =
-          MakeSizeAlgorithmFromSizeFunction(writableSizeFunction);
-      if (writableHighWaterMark === undefined) {
-        writableHighWaterMark = 1;
-      }
-      writableHighWaterMark =
-          ValidateAndNormalizeHighWaterMark(writableHighWaterMark);
-
-      const readableType = transformer.readableType;
-      if (readableType !== undefined) {
-        throw new RangeError(streamErrors.invalidType);
-      }
-
-      const readableSizeAlgorithm =
-          MakeSizeAlgorithmFromSizeFunction(readableSizeFunction);
-      if (readableHighWaterMark === undefined) {
-        readableHighWaterMark = 0;
-      }
-      readableHighWaterMark =
-          ValidateAndNormalizeHighWaterMark(readableHighWaterMark);
-
-      const startPromise = createPromise();
-      InitializeTransformStream(
-          this, startPromise, writableHighWaterMark, writableSizeAlgorithm,
-          readableHighWaterMark, readableSizeAlgorithm);
-      SetUpTransformStreamDefaultControllerFromTransformer(this, transformer);
-      const startResult = CallOrNoop1(
-          transformer, 'start', this[_transformStreamController],
-          'transformer.start');
-      resolvePromise(startPromise, startResult);
-    }
-
-    get readable() {
-      if (!IsTransformStream(this)) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      return this[_readable];
-    }
-
-    get writable() {
-      if (!IsTransformStream(this)) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      return this[_writable];
-    }
-  }
-
-  const TransformStream_prototype = TransformStream.prototype;
-
-  // The controller is passed to |transformAlgorithm| and |flushAlgorithm|,
-  // unlike in the standard.
-  function CreateTransformStream(
-      startAlgorithm, transformAlgorithm, flushAlgorithm, writableHighWaterMark,
-      writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm) {
-    if (writableHighWaterMark === undefined) {
-      writableHighWaterMark = 1;
-    }
-    if (writableSizeAlgorithm === undefined) {
-      writableSizeAlgorithm = () => 1;
-    }
-    if (readableHighWaterMark === undefined) {
-      readableHighWaterMark = 0;
-    }
-    if (readableSizeAlgorithm === undefined) {
-      readableSizeAlgorithm = () => 1;
-    }
-    // assert(
-    //     typeof writableHighWaterMark === 'number' &&
-    //     writableHighWaterMark >= 0,
-    //     '! IsNonNegativeNumber(_writableHighWaterMark_) is *true*');
-    // assert(
-    //     typeof readableHighWaterMark === 'number' &&
-    //     readableHighWaterMark >= 0,
-    //     '! IsNonNegativeNumber(_readableHighWaterMark_) is true');
-    const stream = ObjectCreate(TransformStream_prototype);
-    const startPromise = createPromise();
-    InitializeTransformStream(
-        stream, startPromise, writableHighWaterMark, writableSizeAlgorithm,
-        readableHighWaterMark, readableSizeAlgorithm);
-    const controller = ObjectCreate(TransformStreamDefaultController_prototype);
-    SetUpTransformStreamDefaultController(
-        stream, controller, transformAlgorithm, flushAlgorithm);
-    const startResult = startAlgorithm();
-    resolvePromise(startPromise, startResult);
-    return stream;
-  }
-
-  function InitializeTransformStream(
-      stream, startPromise, writableHighWaterMark, writableSizeAlgorithm,
-      readableHighWaterMark, readableSizeAlgorithm) {
-    const startAlgorithm = () => startPromise;
-    const writeAlgorithm = chunk =>
-        TransformStreamDefaultSinkWriteAlgorithm(stream, chunk);
-    const abortAlgorithm = reason =>
-        TransformStreamDefaultSinkAbortAlgorithm(stream, reason);
-    const closeAlgorithm = () =>
-          TransformStreamDefaultSinkCloseAlgorithm(stream);
-    stream[_writable] = binding.CreateWritableStream(
-        startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm,
-        writableHighWaterMark, writableSizeAlgorithm);
-    const pullAlgorithm = () =>
-          TransformStreamDefaultSourcePullAlgorithm(stream);
-    const cancelAlgorithm = reason => {
-      TransformStreamErrorWritableAndUnblockWrite(stream, reason);
-      return createResolvedPromise(undefined);
-    };
-    stream[_readable] = binding.CreateReadableStream(
-        startAlgorithm, pullAlgorithm, cancelAlgorithm, readableHighWaterMark,
-        readableSizeAlgorithm);
-    stream[_backpressure] = undefined;
-    stream[_backpressureChangePromise] = undefined;
-    TransformStreamSetBackpressure(stream, true);
-    stream[_transformStreamController] = undefined;
-  }
-
-  function IsTransformStream(x) {
-    return hasOwnPropertyNoThrow(x, _transformStreamController);
-  }
-
-  function TransformStreamError(stream, e) {
-    const readable = stream[_readable];
-    // TODO(ricea): Remove this conditional once ReadableStream is updated.
-    if (binding.IsReadableStreamReadable(readable)) {
-      binding.ReadableStreamDefaultControllerError(
-          binding.getReadableStreamController(readable), e);
-    }
-
-    TransformStreamErrorWritableAndUnblockWrite(stream, e);
-  }
-
-  function TransformStreamErrorWritableAndUnblockWrite(stream, e) {
-    TransformStreamDefaultControllerClearAlgorithms(
-        stream[_transformStreamController]);
-    binding.WritableStreamDefaultControllerErrorIfNeeded(
-        binding.getWritableStreamController(stream[_writable]), e);
-
-    if (stream[_backpressure]) {
-      TransformStreamSetBackpressure(stream, false);
-    }
-  }
-
-  function TransformStreamSetBackpressure(stream, backpressure) {
-    // assert(
-    //     stream[_backpressure] !== backpressure,
-    //     'stream.[[backpressure]] is not backpressure');
-
-    if (stream[_backpressureChangePromise] !== undefined) {
-      resolvePromise(stream[_backpressureChangePromise], undefined);
-    }
-
-    stream[_backpressureChangePromise] = createPromise();
-    stream[_backpressure] = backpressure;
-  }
-
-  class TransformStreamDefaultController {
-    constructor() {
-      throw new TypeError(streamErrors.illegalConstructor);
-    }
-
-    get desiredSize() {
-      if (!IsTransformStreamDefaultController(this)) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      const readableController = binding.getReadableStreamController(
-          this[_controlledTransformStream][_readable]);
-      return binding.ReadableStreamDefaultControllerGetDesiredSize(
-          readableController);
-    }
-
-    enqueue(chunk) {
-      if (!IsTransformStreamDefaultController(this)) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      TransformStreamDefaultControllerEnqueue(this, chunk);
-    }
-
-    error(reason) {
-      if (!IsTransformStreamDefaultController(this)) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      TransformStreamDefaultControllerError(this, reason);
-    }
-
-    terminate() {
-      if (!IsTransformStreamDefaultController(this)) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-
-      TransformStreamDefaultControllerTerminate(this);
-    }
-  }
-
-  const TransformStreamDefaultController_prototype =
-      TransformStreamDefaultController.prototype;
-
-  function IsTransformStreamDefaultController(x) {
-    return hasOwnPropertyNoThrow(x, _controlledTransformStream);
-  }
-
-  function SetUpTransformStreamDefaultController(
-      stream, controller, transformAlgorithm, flushAlgorithm) {
-    // assert(
-    //     IsTransformStream(stream) === true,
-    //     '! IsTransformStream(_stream_) is *true*');
-    // assert(
-    //     stream[_transformStreamController] === undefined,
-    //     '_stream_.[[transformStreamController]] is *undefined*');
-    controller[_controlledTransformStream] = stream;
-    stream[_transformStreamController] = controller;
-    controller[_transformAlgorithm] = transformAlgorithm;
-    controller[_flushAlgorithm] = flushAlgorithm;
-  }
-
-  function SetUpTransformStreamDefaultControllerFromTransformer(
-      stream, transformer) {
-    // assert(transformer !== undefined, '_transformer_ is not *undefined*');
-    const controller = ObjectCreate(TransformStreamDefaultController_prototype);
-    let transformAlgorithm;
-    const transformMethod = transformer.transform;
-    if (transformMethod !== undefined) {
-      if (typeof transformMethod !== 'function') {
-        throw new TypeError('transformer.transform is not a function');
-      }
-      transformAlgorithm = chunk =>
-          PromiseCall2(transformMethod, transformer, chunk, controller);
-    } else {
-      transformAlgorithm = chunk => {
-        try {
-          TransformStreamDefaultControllerEnqueue(controller, chunk);
-          return createResolvedPromise();
-        } catch (resultValue) {
-          return createRejectedPromise(resultValue);
-        }
-      };
-    }
-    const flushAlgorithm = CreateAlgorithmFromUnderlyingMethod(
-        transformer, 'flush', 1, 'transformer.flush');
-    SetUpTransformStreamDefaultController(
-        stream, controller, transformAlgorithm, flushAlgorithm);
-  }
-
-  function TransformStreamDefaultControllerClearAlgorithms(controller) {
-    controller[_transformAlgorithm] = undefined;
-    controller[_flushAlgorithm] = undefined;
-  }
-
-  function TransformStreamDefaultControllerEnqueue(controller, chunk) {
-    const stream = controller[_controlledTransformStream];
-    const readableController =
-        binding.getReadableStreamController(stream[_readable]);
-
-    if (!binding.ReadableStreamDefaultControllerCanCloseOrEnqueue(
-            readableController)) {
-      throw binding.getReadableStreamEnqueueError(stream[_readable],
-                                                  readableController);
-    }
-
-    try {
-      binding.ReadableStreamDefaultControllerEnqueue(readableController, chunk);
-    } catch (e) {
-      TransformStreamErrorWritableAndUnblockWrite(stream, e);
-      throw binding.getReadableStreamStoredError(stream[_readable]);
-    }
-
-    const backpressure = binding.ReadableStreamDefaultControllerHasBackpressure(
-        readableController);
-    if (backpressure !== stream[_backpressure]) {
-      // assert(backpressure, 'backpressure is true');
-      TransformStreamSetBackpressure(stream, true);
-    }
-  }
-
-  function TransformStreamDefaultControllerError(controller, e) {
-    TransformStreamError(controller[_controlledTransformStream], e);
-  }
-
-  function TransformStreamDefaultControllerPerformTransform(controller, chunk) {
-    const transformPromise = controller[_transformAlgorithm](chunk, controller);
-    return thenPromise(transformPromise, undefined, r => {
-      TransformStreamError(controller[_controlledTransformStream], r);
-      throw r;
-    });
-  }
-
-  function TransformStreamDefaultControllerTerminate(controller) {
-    const stream = controller[_controlledTransformStream];
-    const readableController =
-        binding.getReadableStreamController(stream[_readable]);
-
-    if (binding.ReadableStreamDefaultControllerCanCloseOrEnqueue(
-            readableController)) {
-      binding.ReadableStreamDefaultControllerClose(readableController);
-    }
-
-    const error = new TypeError(errStreamTerminated);
-    TransformStreamErrorWritableAndUnblockWrite(stream, error);
-  }
-
-  function TransformStreamDefaultSinkWriteAlgorithm(stream, chunk) {
-    // assert(
-    //     binding.isWritableStreamWritable(stream[_writable]),
-    //     `stream.[[writable]][[state]] is "writable"`);
-
-    const controller = stream[_transformStreamController];
-
-    if (stream[_backpressure]) {
-      const backpressureChangePromise = stream[_backpressureChangePromise];
-      // assert(
-      //     backpressureChangePromise !== undefined,
-      //     `backpressureChangePromise is not undefined`);
-
-      return thenPromise(backpressureChangePromise, () => {
-        const writable = stream[_writable];
-        if (binding.isWritableStreamErroring(writable)) {
-          throw binding.getWritableStreamStoredError(writable);
-        }
-        // assert(binding.isWritableStreamWritable(writable),
-        //        `state is "writable"`);
-
-        return TransformStreamDefaultControllerPerformTransform(controller,
-                                                                chunk);
-      });
-    }
-
-    return TransformStreamDefaultControllerPerformTransform(controller, chunk);
-  }
-
-  function TransformStreamDefaultSinkAbortAlgorithm(stream, reason) {
-    TransformStreamError(stream, reason);
-    return createResolvedPromise();
-  }
-
-  function TransformStreamDefaultSinkCloseAlgorithm(stream) {
-    const readable = stream[_readable];
-    const controller = stream[_transformStreamController];
-    const flushPromise = controller[_flushAlgorithm](controller);
-    TransformStreamDefaultControllerClearAlgorithms(controller);
-
-    return thenPromise(
-        flushPromise,
-        () => {
-          if (binding.IsReadableStreamErrored(readable)) {
-            throw binding.getReadableStreamStoredError(readable);
-          }
-
-          const readableController =
-              binding.getReadableStreamController(readable);
-          if (binding.ReadableStreamDefaultControllerCanCloseOrEnqueue(
-                  readableController)) {
-            binding.ReadableStreamDefaultControllerClose(readableController);
-          }
-        },
-        r => {
-          TransformStreamError(stream, r);
-          throw binding.getReadableStreamStoredError(readable);
-        });
-  }
-
-  function TransformStreamDefaultSourcePullAlgorithm(stream) {
-    // assert(stream[_backpressure], 'stream.[[backpressure]] is true');
-    // assert(
-    //     stream[_backpressureChangePromise] !== undefined,
-    //     'stream.[[backpressureChangePromise]] is not undefined');
-
-    TransformStreamSetBackpressure(stream, false);
-    return stream[_backpressureChangePromise];
-  }
-
-  // A wrapper for CreateTransformStream() with only the arguments that
-  // blink::TransformStream needs. |transformAlgorithm| and |flushAlgorithm| are
-  // passed the controller, unlike in the standard.
-  function createTransformStreamSimple(transformAlgorithm, flushAlgorithm) {
-    return CreateTransformStream(() => createResolvedPromise(),
-                                 transformAlgorithm, flushAlgorithm);
-  }
-  function createTransformStream(
-      transformer, writableStrategy, readableStrategy) {
-    if (transformer === undefined) {
-      transformer = ObjectCreate(null);
-    }
-    if (writableStrategy === undefined) {
-      writableStrategy = ObjectCreate(null);
-    }
-    if (readableStrategy === undefined) {
-      readableStrategy = ObjectCreate(null);
-    }
-    return new TransformStream(transformer, writableStrategy, readableStrategy);
-  }
-
-  function getTransformStreamReadable(stream) {
-    return stream[_readable];
-  }
-
-  function getTransformStreamWritable(stream) {
-    return stream[_writable];
-  }
-
-  //
-  // Exports to Blink
-  //
-  Object.assign(binding, {
-    createTransformStreamSimple,
-    createTransformStream,
-    TransformStreamDefaultControllerEnqueue,
-    getTransformStreamReadable,
-    getTransformStreamWritable
-  });
-});
diff --git a/third_party/blink/renderer/core/streams/WritableStream.js b/third_party/blink/renderer/core/streams/WritableStream.js
deleted file mode 100644
index 58e2d6e..0000000
--- a/third_party/blink/renderer/core/streams/WritableStream.js
+++ /dev/null
@@ -1,1093 +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.
-
-// Implementation of WritableStream for Blink.  See
-// https://streams.spec.whatwg.org/#ws. The implementation closely follows the
-// standard, except where required for performance or integration with Blink.
-// In particular, classes, methods and abstract operations are implemented in
-// the same order as in the standard, to simplify side-by-side reading.
-
-(function(global, binding, v8) {
-  'use strict';
-
-  // Private symbols. These correspond to the internal slots in the standard.
-  // "[[X]]" in the standard is spelt _X in this implementation.
-
-  // TODO(ricea): Optimise [[closeRequest]] and [[inFlightCloseRequest]] into a
-  // single slot + a flag to say which one is set at the moment.
-  const _abortAlgorithm = v8.createPrivateSymbol('[[abortAlgorithm]]');
-  const _closeAlgorithm = v8.createPrivateSymbol('[[closeAlgorithm]]');
-  const _closeRequest = v8.createPrivateSymbol('[[closeRequest]]');
-  const _inFlightWriteRequest =
-        v8.createPrivateSymbol('[[inFlightWriteRequest]]');
-  const _inFlightCloseRequest =
-        v8.createPrivateSymbol('[[inFlightCloseRequest]]');
-  const _pendingAbortRequest =
-        v8.createPrivateSymbol('[[pendingAbortRequest]]');
-  // Flags and state are combined into a single integer field for efficiency.
-  const _stateAndFlags = v8.createPrivateSymbol('[[state]] and flags');
-  const _storedError = v8.createPrivateSymbol('[[storedError]]');
-  const _writableStreamController =
-        v8.createPrivateSymbol('[[writableStreamController]]');
-  const _writer = v8.createPrivateSymbol('[[writer]]');
-  const _writeRequests = v8.createPrivateSymbol('[[writeRequests]]');
-  const _closedPromise = v8.createPrivateSymbol('[[closedPromise]]');
-  const _ownerWritableStream =
-        v8.createPrivateSymbol('[[ownerWritableStream]]');
-  const _readyPromise = v8.createPrivateSymbol('[[readyPromise]]');
-  const _controlledWritableStream =
-        v8.createPrivateSymbol('[[controlledWritableStream]]');
-  const _started = v8.createPrivateSymbol('[[started]]');
-  const _strategyHWM = v8.createPrivateSymbol('[[strategyHWM]]');
-  const _strategySizeAlgorithm =
-        v8.createPrivateSymbol('[[strategySizeAlgorithm]]');
-  const _writeAlgorithm = v8.createPrivateSymbol('[[writeAlgorithm]]');
-  const internalWritableStreamSymbol = v8.createPrivateSymbol(
-      'internal WritableStream in exposed WritableStream interface');
-
-  // Numeric encodings of stream states. Stored in the _stateAndFlags slot.
-  const WRITABLE = 0;
-  const CLOSED = 1;
-  const ERRORING = 2;
-  const ERRORED = 3;
-
-  // Mask to extract or assign states to _stateAndFlags.
-  const STATE_MASK = 0xF;
-
-  // Also stored in _stateAndFlags.
-  const BACKPRESSURE_FLAG = 0x10;
-
-  // Javascript functions. It is important to use these copies, as the ones on
-  // the global object may have been overwritten. See "V8 Extras Design Doc",
-  // section "Security Considerations".
-  // https://docs.google.com/document/d/1AT5-T0aHGp7Lt29vPWFr2-qG8r3l9CByyvKwEuA8Ec0/edit#heading=h.9yixony1a18r
-  const ObjectCreate = global.Object.create;
-
-  const Function_call = v8.uncurryThis(global.Function.prototype.call);
-
-  const TypeError = global.TypeError;
-  const RangeError = global.RangeError;
-
-  const Boolean = global.Boolean;
-
-  const Promise = global.Promise;
-  const thenPromise = v8.uncurryThis(Promise.prototype.then);
-
-  // From CommonOperations.js
-  const {
-    _queue,
-    _queueTotalSize,
-    createPromise,
-    createRejectedPromise,
-    createResolvedPromise,
-    hasOwnPropertyNoThrow,
-    rejectPromise,
-    resolvePromise,
-    markPromiseAsHandled,
-    promiseState,
-    CreateAlgorithmFromUnderlyingMethod,
-    CreateAlgorithmFromUnderlyingMethodPassingController,
-    DequeueValue,
-    EnqueueValueWithSize,
-    MakeSizeAlgorithmFromSizeFunction,
-    PeekQueueValue,
-    ResetQueue,
-    ValidateAndNormalizeHighWaterMark,
-    CreateCrossRealmTransformReadable,
-    CreateCrossRealmTransformWritable,
-    CallOrNoop1,
-  } = binding.streamOperations;
-
-  // User-visible strings.
-  const streamErrors = binding.streamErrors;
-  const errWriterLockReleasedPrefix =
-        'This writable stream writer has been released and cannot be ';
-  const errCloseCloseRequestedStream = 'Cannot close a writable stream that ' +
-        'has already been requested to be closed';
-  const templateErrorCannotActionOnStateStream = (action, state) =>
-        `Cannot ${action} a ${state} writable stream`;
-  const errReleasedWriterClosedPromise = 'This writable stream writer has ' +
-        'been released and cannot be used to monitor the stream\'s state';
-
-  // These verbs are used after errWriterLockReleasedPrefix
-  const verbUsedToGetTheDesiredSize = 'used to get the desiredSize';
-  const verbAborted = 'aborted';
-  const verbClosed = 'closed';
-  const verbWrittenTo = 'written to';
-
-  // Utility functions (not from the standard).
-  function createWriterLockReleasedError(verb) {
-    return new TypeError(errWriterLockReleasedPrefix + verb);
-  }
-
-  const stateNames = {
-    [CLOSED]: 'closed',
-    [ERRORED]: 'errored'
-  };
-  function createCannotActionOnStateStreamError(action, state) {
-    // assert(stateNames[state] !== undefined,
-    //        `name for state ${state} exists in stateNames`);
-    return new TypeError(
-        templateErrorCannotActionOnStateStream(action, stateNames[state]));
-  }
-
-  function rejectPromises(queue, e) {
-    queue.forEach(promise => rejectPromise(promise, e));
-  }
-
-  class WritableStream {
-    constructor(underlyingSink = {}, strategy = {}) {
-      InitializeWritableStream(this);
-      const size = strategy.size;
-      let highWaterMark = strategy.highWaterMark;
-      const type = underlyingSink.type;
-      if (type !== undefined) {
-        throw new RangeError(streamErrors.invalidType);
-      }
-      const sizeAlgorithm = MakeSizeAlgorithmFromSizeFunction(size);
-      if (highWaterMark === undefined) {
-        highWaterMark = 1;
-      }
-      highWaterMark = ValidateAndNormalizeHighWaterMark(highWaterMark);
-      SetUpWritableStreamDefaultControllerFromUnderlyingSink(
-          this, underlyingSink, highWaterMark, sizeAlgorithm);
-    }
-  }
-
-  const WritableStream_prototype = WritableStream.prototype;
-
-  function createWritableStream(underlyingSink, strategy) {
-    return new WritableStream(underlyingSink, strategy);
-  }
-
-  // General Writable Stream Abstract Operations
-
-  function AcquireWritableStreamDefaultWriter(stream) {
-    return new WritableStreamDefaultWriter(stream);
-  }
-
-  function CreateWritableStream(
-      startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm,
-      highWaterMark, sizeAlgorithm) {
-    if (highWaterMark === undefined) {
-      highWaterMark = 1;
-    }
-    if (sizeAlgorithm === undefined) {
-      sizeAlgorithm = () => 1;
-    }
-    // assert(IsNonNegativeNumber(highWaterMark),
-    // '! IsNonNegativeNumber(_highWaterMark_) is *true*.')
-    const stream = ObjectCreate(WritableStream_prototype);
-    InitializeWritableStream(stream);
-    const controller = ObjectCreate(WritableStreamDefaultController_prototype);
-    SetUpWritableStreamDefaultController(
-        stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm,
-        abortAlgorithm, highWaterMark, sizeAlgorithm);
-    return stream;
-  }
-
-  function InitializeWritableStream(stream) {
-    stream[_stateAndFlags] = WRITABLE;
-    stream[_storedError] = undefined;
-    stream[_writer] = undefined;
-    stream[_writableStreamController] = undefined;
-    stream[_inFlightWriteRequest] = undefined;
-    stream[_closeRequest] = undefined;
-    stream[_inFlightCloseRequest] = undefined;
-    stream[_pendingAbortRequest] = undefined;
-    stream[_writeRequests] = new binding.SimpleQueue();
-  }
-
-  function IsWritableStream(x) {
-    return hasOwnPropertyNoThrow(x, _writableStreamController);
-  }
-
-  function IsWritableStreamLocked(stream) {
-    // assert(IsWritableStream(stream),
-    //        '! IsWritableStream(stream) is true.');
-    return stream[_writer] !== undefined;
-  }
-
-  function WritableStreamAbort(stream, reason) {
-    const state = stream[_stateAndFlags] & STATE_MASK;
-    if (state === CLOSED || state === ERRORED) {
-      return createResolvedPromise(undefined);
-    }
-    if (stream[_pendingAbortRequest] !== undefined) {
-      return stream[_pendingAbortRequest].promise;
-    }
-
-    // assert(state === WRITABLE || state === ERRORING,
-    //        '_state_ is `"writable"` or `"erroring"`');
-
-    const wasAlreadyErroring = state === ERRORING;
-    if (wasAlreadyErroring) {
-      reason = undefined;
-    }
-
-    const promise = createPromise();
-    stream[_pendingAbortRequest] = {promise, reason, wasAlreadyErroring};
-
-    if (!wasAlreadyErroring) {
-      WritableStreamStartErroring(stream, reason);
-    }
-    return promise;
-  }
-
-  // Writable Stream Abstract Operations Used by Controllers
-
-  function WritableStreamAddWriteRequest(stream) {
-    // assert(IsWritableStreamLocked(stream),
-    //        '! IsWritableStreamLocked(writer) is true.');
-    // assert((stream[_stateAndFlags] & STATE_MASK) === WRITABLE,
-    //        'stream.[[state]] is "writable".');
-    const promise = createPromise();
-    stream[_writeRequests].push(promise);
-    return promise;
-  }
-
-  function WritableStreamDealWithRejection(stream, error) {
-    const state = stream[_stateAndFlags] & STATE_MASK;
-    if (state === WRITABLE) {
-      WritableStreamStartErroring(stream, error);
-      return;
-    }
-
-    // assert(state === ERRORING, '_state_ is `"erroring"`');
-    WritableStreamFinishErroring(stream);
-  }
-
-  function WritableStreamStartErroring(stream, reason) {
-    // assert(stream[_storedError] === undefined,
-    //        '_stream_.[[storedError]] is *undefined*');
-    // assert((stream[_stateAndFlags] & STATE_MASK) === WRITABLE,
-    //        '_stream_.[[state]] is `"writable"`');
-
-    const controller = stream[_writableStreamController];
-    // assert(controller !== undefined, '_controller_ is not *undefined*');
-
-    stream[_stateAndFlags] = (stream[_stateAndFlags] & ~STATE_MASK) | ERRORING;
-    stream[_storedError] = reason;
-
-    const writer = stream[_writer];
-    if (writer !== undefined) {
-      WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason);
-    }
-
-    if (!WritableStreamHasOperationMarkedInFlight(stream) &&
-        controller[_started]) {
-      WritableStreamFinishErroring(stream);
-    }
-  }
-
-  function WritableStreamFinishErroring(stream) {
-    // assert((stream[_stateAndFlags] & STATE_MASK) === ERRORING,
-    //        '_stream_.[[state]] is `"erroring"`');
-    // assert(!WritableStreamHasOperationMarkedInFlight(stream),
-    //        '! WritableStreamHasOperationMarkedInFlight(_stream_) is ' +
-    //        '*false*');
-
-    stream[_stateAndFlags] = (stream[_stateAndFlags] & ~STATE_MASK) | ERRORED;
-
-    WritableStreamDefaultControllerErrorSteps(
-        stream[_writableStreamController]);
-
-    const storedError = stream[_storedError];
-    rejectPromises(stream[_writeRequests], storedError);
-    stream[_writeRequests] = new binding.SimpleQueue();
-
-    if (stream[_pendingAbortRequest] === undefined) {
-      WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
-      return;
-    }
-
-    const abortRequest = stream[_pendingAbortRequest];
-    stream[_pendingAbortRequest] = undefined;
-
-    if (abortRequest.wasAlreadyErroring === true) {
-      rejectPromise(abortRequest.promise, storedError);
-      WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
-      return;
-    }
-
-    const promise = WritableStreamDefaultControllerAbortSteps(
-        stream[_writableStreamController], abortRequest.reason);
-
-    thenPromise(
-        promise,
-        () => {
-          resolvePromise(abortRequest.promise, undefined);
-          WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
-        },
-        reason => {
-          rejectPromise(abortRequest.promise, reason);
-          WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
-        });
-  }
-
-  function WritableStreamFinishInFlightWrite(stream) {
-    // assert(stream[_inFlightWriteRequest] !== undefined,
-    //        '_stream_.[[inFlightWriteRequest]] is not *undefined*.');
-    resolvePromise(stream[_inFlightWriteRequest], undefined);
-    stream[_inFlightWriteRequest] = undefined;
-  }
-
-  function WritableStreamFinishInFlightWriteWithError(stream, error) {
-    // assert(stream[_inFlightWriteRequest] !== undefined,
-    //        '_stream_.[[inFlightWriteRequest]] is not *undefined*.');
-    rejectPromise(stream[_inFlightWriteRequest], error);
-    stream[_inFlightWriteRequest] = undefined;
-
-    // const state = stream[_stateAndFlags] & STATE_MASK;
-    // assert(state === WRITABLE || state === ERRORING,
-    //        '_stream_.[[state]] is `"writable"` or `"erroring"`');
-
-    WritableStreamDealWithRejection(stream, error);
-  }
-
-  function WritableStreamFinishInFlightClose(stream) {
-    // assert(stream[_inFlightCloseRequest] !== undefined,
-    //        '_stream_.[[inFlightCloseRequest]] is not *undefined*.');
-    resolvePromise(stream[_inFlightCloseRequest], undefined);
-    stream[_inFlightCloseRequest] = undefined;
-
-    const state = stream[_stateAndFlags] & STATE_MASK;
-    // assert(state === WRITABLE || state === ERRORING,
-    //        '_stream_.[[state]] is `"writable"` or `"erroring"`');
-
-    if (state === ERRORING) {
-      stream[_storedError] = undefined;
-      if (stream[_pendingAbortRequest] !== undefined) {
-        resolvePromise(stream[_pendingAbortRequest].promise, undefined);
-        stream[_pendingAbortRequest] = undefined;
-      }
-    }
-
-    stream[_stateAndFlags] = (stream[_stateAndFlags] & ~STATE_MASK) | CLOSED;
-    const writer = stream[_writer];
-    if (writer !== undefined) {
-      resolvePromise(writer[_closedPromise], undefined);
-    }
-
-    // assert(stream[_pendingAbortRequest] === undefined,
-    //        '_stream_.[[pendingAbortRequest]] is *undefined*');
-    // assert(stream[_storedError] === undefined,
-    //        '_stream_.[[storedError]] is *undefined*');
-  }
-
-  function WritableStreamFinishInFlightCloseWithError(stream, error) {
-    // assert(stream[_inFlightCloseRequest] !== undefined,
-    //        '_stream_.[[inFlightCloseRequest]] is not *undefined*.');
-    rejectPromise(stream[_inFlightCloseRequest], error);
-    stream[_inFlightCloseRequest] = undefined;
-
-    // const state = stream[_stateAndFlags] & STATE_MASK;
-    // assert(state === WRITABLE || state === ERRORING,
-    //        '_stream_.[[state]] is `"writable"` or `"erroring"`');
-
-    if (stream[_pendingAbortRequest] !== undefined) {
-      rejectPromise(stream[_pendingAbortRequest].promise, error);
-      stream[_pendingAbortRequest] = undefined;
-    }
-
-    WritableStreamDealWithRejection(stream, error);
-  }
-
-  function WritableStreamCloseQueuedOrInFlight(stream) {
-    return stream[_closeRequest] !== undefined ||
-        stream[_inFlightCloseRequest] !== undefined;
-  }
-
-  function WritableStreamHasOperationMarkedInFlight(stream) {
-    return stream[_inFlightWriteRequest] !== undefined ||
-        stream[_inFlightCloseRequest] !== undefined;
-  }
-
-  function WritableStreamMarkCloseRequestInFlight(stream) {
-    // assert(stream[_inFlightCloseRequest] === undefined,
-    //        '_stream_.[[inFlightCloseRequest]] is *undefined*.');
-    // assert(stream[_closeRequest] !== undefined,
-    //        '_stream_.[[closeRequest]] is not *undefined*.');
-    stream[_inFlightCloseRequest] = stream[_closeRequest];
-    stream[_closeRequest] = undefined;
-  }
-
-  function WritableStreamMarkFirstWriteRequestInFlight(stream) {
-    // assert(stream[_inFlightWriteRequest] === undefined,
-    //        '_stream_.[[inFlightWriteRequest]] is *undefined*.');
-    // assert(stream[_writeRequests].length !== 0,
-    //        '_stream_.[[writeRequests]] is not empty.');
-    const writeRequest = stream[_writeRequests].shift();
-    stream[_inFlightWriteRequest] = writeRequest;
-  }
-
-  function WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) {
-    // assert((stream[_stateAndFlags] & STATE_MASK) === ERRORED,
-    //        '_stream_.[[state]] is `"errored"`');
-
-    if (stream[_closeRequest] !== undefined) {
-      // assert(stream[_inFlightCloseRequest] === undefined,
-      //        '_stream_.[[inFlightCloseRequest]] is *undefined*');
-      rejectPromise(stream[_closeRequest], stream[_storedError]);
-      stream[_closeRequest] = undefined;
-    }
-
-    const writer = stream[_writer];
-    if (writer !== undefined) {
-      rejectPromise(writer[_closedPromise], stream[_storedError]);
-      markPromiseAsHandled(writer[_closedPromise]);
-    }
-  }
-
-  function WritableStreamUpdateBackpressure(stream, backpressure) {
-    // assert((stream[_stateAndFlags] & STATE_MASK) === WRITABLE,
-    //        'stream.[[state]] is "writable".');
-    // assert(!WritableStreamCloseQueuedOrInFlight(stream),
-    //        'WritableStreamCloseQueuedOrInFlight(_stream_) is *false*.');
-    const writer = stream[_writer];
-    if (writer !== undefined &&
-        backpressure !== Boolean(stream[_stateAndFlags] & BACKPRESSURE_FLAG)) {
-      if (backpressure) {
-        writer[_readyPromise] = createPromise();
-      } else {
-        // assert(!backpressure, '_backpressure_ is *false*.');
-        resolvePromise(writer[_readyPromise], undefined);
-      }
-    }
-    if (backpressure) {
-      stream[_stateAndFlags] |= BACKPRESSURE_FLAG;
-    } else {
-      stream[_stateAndFlags] &= ~BACKPRESSURE_FLAG;
-    }
-  }
-
-  //
-  // Functions for transferable streams.
-  //
-
-  // The |port| which is passed to this function must be a MessagePort which is
-  // attached by a MessageChannel to the |port| that will be passed to
-  // WritableStreamDeserialize.
-  function WritableStreamSerialize(writable, port) {
-    // assert(IsWritableStream(writable),
-    //        `! IsWritableStream(_writable_) is true`);
-    if (IsWritableStreamLocked(writable)) {
-      throw new TypeError(streamErrors.cannotTransferLockedStream);
-    }
-
-    if (!binding.MessagePort_postMessage) {
-      throw new TypeError(streamErrors.cannotTransferContext);
-    }
-
-    const readable = CreateCrossRealmTransformReadable(port);
-    const promise =
-          binding.ReadableStreamPipeTo(readable, writable, false, false, false);
-    markPromiseAsHandled(promise);
-  }
-
-  function WritableStreamDeserialize(port) {
-    return CreateCrossRealmTransformWritable(port);
-  }
-
-  // Functions to expose internals for ReadableStream.pipeTo. These are not
-  // part of the standard.
-  function isWritableStreamErrored(stream) {
-    // assert(
-    //     IsWritableStream(stream), '! IsWritableStream(stream) is true.');
-    return (stream[_stateAndFlags] & STATE_MASK) === ERRORED;
-  }
-
-  function isWritableStreamClosingOrClosed(stream) {
-    // assert(
-    //     IsWritableStream(stream), '! IsWritableStream(stream) is true.');
-    return WritableStreamCloseQueuedOrInFlight(stream) ||
-        (stream[_stateAndFlags] & STATE_MASK) === CLOSED;
-  }
-
-  function getWritableStreamStoredError(stream) {
-    // assert(
-    //     IsWritableStream(stream), '! IsWritableStream(stream) is true.');
-    return stream[_storedError];
-  }
-
-  // Expose internals for TransformStream
-  function isWritableStreamWritable(stream) {
-    // assert(
-    //     IsWritableStream(stream), '! IsWritableStream(stream) is true.');
-    return  (stream[_stateAndFlags] & STATE_MASK) === WRITABLE;
-  }
-
-  function isWritableStreamErroring(stream) {
-    // assert(
-    //     IsWritableStream(stream), '! IsWritableStream(stream) is true.');
-    return  (stream[_stateAndFlags] & STATE_MASK) === ERRORING;
-  }
-
-  function getWritableStreamController(stream) {
-    // assert(
-    //     IsWritableStream(stream), '! IsWritableStream(stream) is true.');
-    return stream[_writableStreamController];
-  }
-
-  class WritableStreamDefaultWriter {
-    constructor(stream) {
-      // |stream| here can be either an external WritableStream (i.e.,
-      // IDL defined WritableStream) or an internal WritableStream (i.e.,
-      // the class defined in this file). In the former case, the
-      // internal stream is stored in [internalWritableStreamSymbol], so use it
-      // from now on.
-      if (stream[internalWritableStreamSymbol] !== undefined) {
-        stream = stream[internalWritableStreamSymbol];
-      }
-      if (!IsWritableStream(stream)) {
-        throw new TypeError(streamErrors.illegalConstructor);
-      }
-      if (IsWritableStreamLocked(stream)) {
-        throw new TypeError(streamErrors.illegalConstructor);
-      }
-      this[_ownerWritableStream] = stream;
-      stream[_writer] = this;
-      const state = stream[_stateAndFlags] & STATE_MASK;
-      switch (state) {
-        case WRITABLE: {
-          if (!WritableStreamCloseQueuedOrInFlight(stream) &&
-              stream[_stateAndFlags] & BACKPRESSURE_FLAG) {
-            this[_readyPromise] = createPromise();
-          } else {
-            this[_readyPromise] = createResolvedPromise(undefined);
-          }
-          this[_closedPromise] = createPromise();
-          break;
-        }
-
-        case ERRORING: {
-          this[_readyPromise] = createRejectedPromise(stream[_storedError]);
-          markPromiseAsHandled(this[_readyPromise]);
-          this[_closedPromise] = createPromise();
-          break;
-        }
-
-        case CLOSED: {
-          this[_readyPromise] = createResolvedPromise(undefined);
-          this[_closedPromise] = createResolvedPromise(undefined);
-          break;
-        }
-
-        default: {
-          // assert(state === ERRORED, '_state_ is `"errored"`.');
-          const storedError = stream[_storedError];
-          this[_readyPromise] = createRejectedPromise(storedError);
-          markPromiseAsHandled(this[_readyPromise]);
-          this[_closedPromise] = createRejectedPromise(storedError);
-          markPromiseAsHandled(this[_closedPromise]);
-          break;
-        }
-      }
-    }
-
-    get closed() {
-      if (!IsWritableStreamDefaultWriter(this)) {
-        return createRejectedPromise(
-            new TypeError(streamErrors.illegalInvocation));
-      }
-      return this[_closedPromise];
-    }
-
-    get desiredSize() {
-      if (!IsWritableStreamDefaultWriter(this)) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-      if (this[_ownerWritableStream] === undefined) {
-        throw createWriterLockReleasedError(verbUsedToGetTheDesiredSize);
-      }
-      return WritableStreamDefaultWriterGetDesiredSize(this);
-    }
-
-    get ready() {
-      if (!IsWritableStreamDefaultWriter(this)) {
-        return createRejectedPromise(
-            new TypeError(streamErrors.illegalInvocation));
-      }
-      return this[_readyPromise];
-    }
-
-    abort(reason) {
-      if (!IsWritableStreamDefaultWriter(this)) {
-        return createRejectedPromise(
-            new TypeError(streamErrors.illegalInvocation));
-      }
-      if (this[_ownerWritableStream] === undefined) {
-        return createRejectedPromise(
-            createWriterLockReleasedError(verbAborted));
-      }
-      return WritableStreamDefaultWriterAbort(this, reason);
-    }
-
-    close() {
-      if (!IsWritableStreamDefaultWriter(this)) {
-        return createRejectedPromise(
-            new TypeError(streamErrors.illegalInvocation));
-      }
-      const stream = this[_ownerWritableStream];
-      if (stream === undefined) {
-        return createRejectedPromise(createWriterLockReleasedError(verbClosed));
-      }
-      if (WritableStreamCloseQueuedOrInFlight(stream)) {
-        return createRejectedPromise(
-            new TypeError(errCloseCloseRequestedStream));
-      }
-      return WritableStreamDefaultWriterClose(this);
-    }
-
-    releaseLock() {
-      if (!IsWritableStreamDefaultWriter(this)) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-      const stream = this[_ownerWritableStream];
-      if (stream === undefined) {
-        return;
-      }
-      // assert(stream[_writer] !== undefined,
-      //        'stream.[[writer]] is not undefined.');
-      WritableStreamDefaultWriterRelease(this);
-    }
-
-    write(chunk) {
-      if (!IsWritableStreamDefaultWriter(this)) {
-        return createRejectedPromise(
-            new TypeError(streamErrors.illegalInvocation));
-      }
-      if (this[_ownerWritableStream] === undefined) {
-        return createRejectedPromise(
-            createWriterLockReleasedError(verbWrittenTo));
-      }
-      return WritableStreamDefaultWriterWrite(this, chunk);
-    }
-  }
-
-  // Writable Stream Writer Abstract Operations
-
-  function IsWritableStreamDefaultWriter(x) {
-    return hasOwnPropertyNoThrow(x, _ownerWritableStream);
-  }
-
-  function WritableStreamDefaultWriterAbort(writer, reason) {
-    const stream = writer[_ownerWritableStream];
-    // assert(stream !== undefined,
-    //        'stream is not undefined.');
-    return WritableStreamAbort(stream, reason);
-  }
-
-  function WritableStreamDefaultWriterClose(writer) {
-    const stream = writer[_ownerWritableStream];
-    // assert(stream !== undefined, 'stream is not undefined.');
-    const state = stream[_stateAndFlags] & STATE_MASK;
-    if (state === CLOSED || state === ERRORED) {
-      return createRejectedPromise(
-          createCannotActionOnStateStreamError('close', state));
-    }
-
-    // assert(state === WRITABLE || state === ERRORING,
-    //        '_state_ is `"writable"` or `"erroring"`.');
-    // assert(!WritableStreamCloseQueuedOrInFlight(stream),
-    //        '! WritableStreamCloseQueuedOrInFlight(_stream_) is *false*.');
-    const promise = createPromise();
-    stream[_closeRequest] = promise;
-
-    if ((stream[_stateAndFlags] & BACKPRESSURE_FLAG) && state === WRITABLE) {
-      resolvePromise(writer[_readyPromise], undefined);
-    }
-    WritableStreamDefaultControllerClose(stream[_writableStreamController]);
-    return promise;
-  }
-
-  function WritableStreamDefaultWriterCloseWithErrorPropagation(writer) {
-    const stream = writer[_ownerWritableStream];
-    // assert(stream !== undefined, 'stream is not undefined.');
-    const state = stream[_stateAndFlags] & STATE_MASK;
-    if (WritableStreamCloseQueuedOrInFlight(stream) || state === CLOSED) {
-      return createResolvedPromise(undefined);
-    }
-    if (state === ERRORED) {
-      return createRejectedPromise(stream[_storedError]);
-    }
-
-    // assert(state === WRITABLE || state === ERRORING,
-    //        '_state_ is `"writable"` or `"erroring"`.');
-
-    return WritableStreamDefaultWriterClose(writer);
-  }
-
-  function WritableStreamDefaultWriterEnsureClosedPromiseRejected(
-      writer, error) {
-    if (promiseState(writer[_closedPromise]) === v8.kPROMISE_PENDING) {
-      rejectPromise(writer[_closedPromise], error);
-    } else {
-      writer[_closedPromise] = createRejectedPromise(error);
-    }
-    markPromiseAsHandled(writer[_closedPromise]);
-  }
-
-
-  function WritableStreamDefaultWriterEnsureReadyPromiseRejected(
-      writer, error) {
-    if (promiseState(writer[_readyPromise]) === v8.kPROMISE_PENDING) {
-      rejectPromise(writer[_readyPromise], error);
-    } else {
-      writer[_readyPromise] = createRejectedPromise(error);
-    }
-    markPromiseAsHandled(writer[_readyPromise]);
-  }
-
-  function WritableStreamDefaultWriterGetDesiredSize(writer) {
-    const stream = writer[_ownerWritableStream];
-    const state = stream[_stateAndFlags] & STATE_MASK;
-    if (state === ERRORED || state === ERRORING) {
-      return null;
-    }
-    if (state === CLOSED) {
-      return 0;
-    }
-    return WritableStreamDefaultControllerGetDesiredSize(
-        stream[_writableStreamController]);
-  }
-
-  function WritableStreamDefaultWriterRelease(writer) {
-    const stream = writer[_ownerWritableStream];
-    // assert(stream !== undefined,
-    //        'stream is not undefined.');
-    // assert(stream[_writer] === writer,
-    //        'stream.[[writer]] is writer.');
-    const releasedError = new TypeError(errReleasedWriterClosedPromise);
-    WritableStreamDefaultWriterEnsureReadyPromiseRejected(
-        writer, releasedError);
-    WritableStreamDefaultWriterEnsureClosedPromiseRejected(
-        writer, releasedError);
-    stream[_writer] = undefined;
-    writer[_ownerWritableStream] = undefined;
-  }
-
-  function WritableStreamDefaultWriterWrite(writer, chunk) {
-    const stream = writer[_ownerWritableStream];
-    // assert(stream !== undefined, 'stream is not undefined.');
-    const controller = stream[_writableStreamController];
-    const chunkSize =
-          WritableStreamDefaultControllerGetChunkSize(controller, chunk);
-    if (stream !== writer[_ownerWritableStream]) {
-      return createRejectedPromise(
-          createWriterLockReleasedError(verbWrittenTo));
-    }
-    const state = stream[_stateAndFlags] & STATE_MASK;
-    if (state === ERRORED) {
-      return createRejectedPromise(stream[_storedError]);
-    }
-    if (WritableStreamCloseQueuedOrInFlight(stream)) {
-      return createRejectedPromise(new TypeError(
-          templateErrorCannotActionOnStateStream('write to', 'closing')));
-    }
-    if (state === CLOSED) {
-      return createRejectedPromise(
-          createCannotActionOnStateStreamError('write to', CLOSED));
-    }
-    if (state === ERRORING) {
-      return createRejectedPromise(stream[_storedError]);
-    }
-    // assert(state === WRITABLE, '_state_ is `"writable"`');
-    const promise = WritableStreamAddWriteRequest(stream);
-    WritableStreamDefaultControllerWrite(controller, chunk, chunkSize);
-    return promise;
-  }
-
-  // Functions to expose internals for ReadableStream.pipeTo. These do not
-  // appear in the standard.
-  function getWritableStreamDefaultWriterClosedPromise(writer) {
-    // assert(
-    //     IsWritableStreamDefaultWriter(writer),
-    //     'writer is a WritableStreamDefaultWriter.');
-    return writer[_closedPromise];
-  }
-
-  function getWritableStreamDefaultWriterReadyPromise(writer) {
-    // assert(
-    //     IsWritableStreamDefaultWriter(writer),
-    //     'writer is a WritableStreamDefaultWriter.');
-    return writer[_readyPromise];
-  }
-
-  class WritableStreamDefaultController {
-    constructor() {
-      throw new TypeError(streamErrors.illegalConstructor);
-    }
-
-    error(e) {
-      if (!IsWritableStreamDefaultController(this)) {
-        throw new TypeError(streamErrors.illegalInvocation);
-      }
-      const state =
-            this[_controlledWritableStream][_stateAndFlags] & STATE_MASK;
-      if (state !== WRITABLE) {
-        return;
-      }
-      WritableStreamDefaultControllerError(this, e);
-    }
-  }
-
-  const WritableStreamDefaultController_prototype =
-        WritableStreamDefaultController.prototype;
-
-  // Writable Stream Default Controller Internal Methods
-
-  // TODO(ricea): Virtual dispatch via V8 Private Symbols seems to be difficult
-  // or impossible, so use static dispatch for now. This will have to be fixed
-  // when adding a byte controller.
-  function WritableStreamDefaultControllerAbortSteps(controller, reason) {
-    const result = controller[_abortAlgorithm](reason);
-    WritableStreamDefaultControllerClearAlgorithms(controller);
-    return result;
-  }
-
-  function WritableStreamDefaultControllerErrorSteps(controller) {
-    ResetQueue(controller);
-  }
-
-  // Writable Stream Default Controller Abstract Operations
-
-  function IsWritableStreamDefaultController(x) {
-    return hasOwnPropertyNoThrow(x, _controlledWritableStream);
-  }
-
-  function SetUpWritableStreamDefaultController(
-      stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm,
-      abortAlgorithm, highWaterMark, sizeAlgorithm) {
-    // assert(IsWritableStream(stream), '! IsWritableStream(_stream_) is
-    // *true*.');
-    // assert(stream[_writableStreamController] === undefined,
-    //        '_stream_.[[writableStreamController]] is *undefined*.');
-    controller[_controlledWritableStream] = stream;
-    stream[_writableStreamController] = controller;
-    // These are just initialised to avoid triggering the assert() in
-    // ResetQueue. They are overwritten by ResetQueue().
-    controller[_queue] = undefined;
-    controller[_queueTotalSize] = undefined;
-    ResetQueue(controller);
-    controller[_started] = false;
-    controller[_strategySizeAlgorithm] = sizeAlgorithm;
-    controller[_strategyHWM] = highWaterMark;
-    controller[_writeAlgorithm] = writeAlgorithm;
-    controller[_closeAlgorithm] = closeAlgorithm;
-    controller[_abortAlgorithm] = abortAlgorithm;
-    const backpressure =
-          WritableStreamDefaultControllerGetBackpressure(controller);
-    WritableStreamUpdateBackpressure(stream, backpressure);
-    const startResult = startAlgorithm();
-    const startPromise = createResolvedPromise(startResult);
-    thenPromise(
-        startPromise,
-        () => {
-          // const state = stream[_stateAndFlags] & STATE_MASK;
-          // assert(state === WRITABLE || state === ERRORING,
-          //        '_stream_.[[state]] is `"writable"` or `"erroring"`');
-          controller[_started] = true;
-          WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
-        },
-        r => {
-          // const state = stream[_stateAndFlags] & STATE_MASK;
-          // assert(state === WRITABLE || state === ERRORING,
-          //        '_stream_.[[state]] is `"writable"` or `"erroring"`');
-          controller[_started] = true;
-          WritableStreamDealWithRejection(stream, r);
-        });
-  }
-
-  function SetUpWritableStreamDefaultControllerFromUnderlyingSink(
-      stream, underlyingSink, highWaterMark, sizeAlgorithm) {
-    // assert(underlyingSink !== undefined, '_underlyingSink_ is not ' +
-    // '*undefined*.');
-    const controller = ObjectCreate(WritableStreamDefaultController_prototype);
-    const startAlgorithm =
-          () => CallOrNoop1(underlyingSink, 'start', controller,
-                            'underlyingSink.start');
-    const writeAlgorithm = CreateAlgorithmFromUnderlyingMethodPassingController(
-        underlyingSink, 'write', 1, controller, 'underlyingSink.write');
-    const closeAlgorithm = CreateAlgorithmFromUnderlyingMethod(
-        underlyingSink, 'close', 0, 'underlyingSink.close');
-    const abortAlgorithm = CreateAlgorithmFromUnderlyingMethod(
-        underlyingSink, 'abort', 1, 'underlyingSink.abort');
-    SetUpWritableStreamDefaultController(stream, controller, startAlgorithm,
-        writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark,
-        sizeAlgorithm);
-  }
-
-  function WritableStreamDefaultControllerClearAlgorithms(controller) {
-    controller[_writeAlgorithm] = undefined;
-    controller[_closeAlgorithm] = undefined;
-    controller[_abortAlgorithm] = undefined;
-  }
-
-  function WritableStreamDefaultControllerClose(controller) {
-    EnqueueValueWithSize(controller, 'close', 0);
-    WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
-  }
-
-  function WritableStreamDefaultControllerGetChunkSize(controller, chunk) {
-    try {
-      // Unlike other algorithms, strategySizeAlgorithm isn't indirected, so we
-      // need to be careful with the |this| value.
-      return Function_call(controller[_strategySizeAlgorithm], undefined,
-                           chunk);
-    } catch (e) {
-      WritableStreamDefaultControllerErrorIfNeeded(controller, e);
-      return 1;
-    }
-  }
-
-  function WritableStreamDefaultControllerGetDesiredSize(controller) {
-    return controller[_strategyHWM] - controller[_queueTotalSize];
-  }
-
-  function WritableStreamDefaultControllerWrite(controller, chunk, chunkSize) {
-    const writeRecord = {chunk};
-    try {
-      EnqueueValueWithSize(controller, writeRecord, chunkSize);
-    } catch (e) {
-      WritableStreamDefaultControllerErrorIfNeeded(controller, e);
-      return;
-    }
-    const stream = controller[_controlledWritableStream];
-    if (!WritableStreamCloseQueuedOrInFlight(stream) &&
-        (stream[_stateAndFlags] & STATE_MASK) === WRITABLE) {
-      const backpressure =
-            WritableStreamDefaultControllerGetBackpressure(controller);
-      WritableStreamUpdateBackpressure(stream, backpressure);
-    }
-    WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
-  }
-
-  function WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) {
-    const stream = controller[_controlledWritableStream];
-    if (!controller[_started]) {
-      return;
-    }
-    if (stream[_inFlightWriteRequest] !== undefined) {
-      return;
-    }
-    const state = stream[_stateAndFlags] & STATE_MASK;
-    if (state === CLOSED || state === ERRORED) {
-      return;
-    }
-    if (state === ERRORING) {
-      WritableStreamFinishErroring(stream);
-      return;
-    }
-    if (controller[_queue].length === 0) {
-      return;
-    }
-    const writeRecord = PeekQueueValue(controller);
-    if (writeRecord === 'close') {
-      WritableStreamDefaultControllerProcessClose(controller);
-    } else {
-      WritableStreamDefaultControllerProcessWrite(
-          controller, writeRecord.chunk);
-    }
-  }
-
-  function WritableStreamDefaultControllerErrorIfNeeded(controller, error) {
-    const state =
-          controller[_controlledWritableStream][_stateAndFlags] & STATE_MASK;
-    if (state === WRITABLE) {
-      WritableStreamDefaultControllerError(controller, error);
-    }
-  }
-
-  function WritableStreamDefaultControllerProcessClose(controller) {
-    const stream = controller[_controlledWritableStream];
-    WritableStreamMarkCloseRequestInFlight(stream);
-    DequeueValue(controller);
-    // assert(controller[_queue].length === 0,
-    //        'controller.[[queue]] is empty.');
-    const sinkClosePromise = controller[_closeAlgorithm]();
-    WritableStreamDefaultControllerClearAlgorithms(controller);
-    thenPromise(
-        sinkClosePromise, () => WritableStreamFinishInFlightClose(stream),
-        reason => WritableStreamFinishInFlightCloseWithError(stream, reason));
-  }
-
-  function WritableStreamDefaultControllerProcessWrite(controller, chunk) {
-    const stream = controller[_controlledWritableStream];
-    WritableStreamMarkFirstWriteRequestInFlight(stream);
-    const sinkWritePromise = controller[_writeAlgorithm](chunk);
-    thenPromise(
-        sinkWritePromise,
-        () => {
-          WritableStreamFinishInFlightWrite(stream);
-          const state = stream[_stateAndFlags] & STATE_MASK;
-          // assert(state === WRITABLE || state === ERRORING,
-          //        '_state_ is `"writable"` or `"erroring"`');
-          DequeueValue(controller);
-          if (!WritableStreamCloseQueuedOrInFlight(stream) &&
-              state === WRITABLE) {
-            const backpressure =
-                  WritableStreamDefaultControllerGetBackpressure(controller);
-            WritableStreamUpdateBackpressure(stream, backpressure);
-          }
-          WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
-        },
-        reason => {
-          const state = stream[_stateAndFlags] & STATE_MASK;
-          if (state === WRITABLE) {
-            WritableStreamDefaultControllerClearAlgorithms(controller);
-          }
-          WritableStreamFinishInFlightWriteWithError(stream, reason);
-        });
-  }
-
-  function WritableStreamDefaultControllerGetBackpressure(controller) {
-    const desiredSize =
-          WritableStreamDefaultControllerGetDesiredSize(controller);
-    return desiredSize <= 0;
-  }
-
-  function WritableStreamDefaultControllerError(controller, error) {
-    const stream = controller[_controlledWritableStream];
-    // assert((stream[_stateAndFlags] & STATE_MASK) === WRITABLE,
-    //        '_stream_.[[state]] is `"writable"`.');
-    WritableStreamDefaultControllerClearAlgorithms(controller);
-    WritableStreamStartErroring(stream, error);
-  }
-
-  Object.assign(binding, {
-    // Exports for ReadableStream
-    AcquireWritableStreamDefaultWriter,
-    IsWritableStream,
-    isWritableStreamClosingOrClosed,
-    isWritableStreamErrored,
-    isWritableStreamWritable,
-    IsWritableStreamLocked,
-    WritableStreamAbort,
-    WritableStreamCloseQueuedOrInFlight,
-    WritableStreamDefaultWriterCloseWithErrorPropagation,
-    getWritableStreamDefaultWriterClosedPromise,
-    WritableStreamDefaultWriterGetDesiredSize,
-    getWritableStreamDefaultWriterReadyPromise,
-    WritableStreamDefaultWriterRelease,
-    WritableStreamDefaultWriterWrite,
-    getWritableStreamStoredError,
-
-    // Exports for blink
-    createWritableStream,
-    internalWritableStreamSymbol,
-    WritableStreamSerialize,
-    WritableStreamDeserialize,
-
-    // Additional exports for TransformStream
-    CreateWritableStream,
-    WritableStream,
-    WritableStreamDefaultControllerErrorIfNeeded,
-    isWritableStreamErroring,
-    getWritableStreamController,
-
-    // Exports for CreateCrossRealmTransformWritable in CommonOperations.js
-    WritableStreamDefaultControllerClose,
-  });
-});
diff --git a/third_party/blink/renderer/core/streams/byte_length_queuing_strategy.idl b/third_party/blink/renderer/core/streams/byte_length_queuing_strategy.idl
index af68396e..193a180 100644
--- a/third_party/blink/renderer/core/streams/byte_length_queuing_strategy.idl
+++ b/third_party/blink/renderer/core/streams/byte_length_queuing_strategy.idl
@@ -6,7 +6,6 @@
 
 [
     Exposed=(Window,Worker,Worklet),
-    RuntimeEnabled=StreamsNative,
     ConstructorCallWith=ScriptState,
     Constructor([PermissiveDictionaryConversion] QueuingStrategyInit init)
 ] interface ByteLengthQueuingStrategy {
diff --git a/third_party/blink/renderer/core/streams/count_queuing_strategy.idl b/third_party/blink/renderer/core/streams/count_queuing_strategy.idl
index 02cfe7a..bf838cd2 100644
--- a/third_party/blink/renderer/core/streams/count_queuing_strategy.idl
+++ b/third_party/blink/renderer/core/streams/count_queuing_strategy.idl
@@ -6,7 +6,6 @@
 
 [
     Exposed=(Window,Worker,Worklet),
-    RuntimeEnabled=StreamsNative,
     ConstructorCallWith=ScriptState,
     Constructor([PermissiveDictionaryConversion] QueuingStrategyInit init)
 ] interface CountQueuingStrategy {
diff --git a/third_party/blink/renderer/core/streams/readable_stream.cc b/third_party/blink/renderer/core/streams/readable_stream.cc
index cefb778f..3f6b4552 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream.cc
@@ -5,9 +5,7 @@
 #include "third_party/blink/renderer/core/streams/readable_stream.h"
 
 #include "third_party/blink/renderer/core/streams/readable_stream_native.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_wrapper.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -34,26 +32,15 @@
                                        ScriptValue underlying_source,
                                        ScriptValue strategy,
                                        ExceptionState& exception_state) {
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    return ReadableStreamNative::Create(script_state, underlying_source,
-                                        strategy, exception_state);
-  }
-
-  return ReadableStreamWrapper::Create(script_state, underlying_source,
-                                       strategy, exception_state);
+  return ReadableStreamNative::Create(script_state, underlying_source, strategy,
+                                      exception_state);
 }
 
 ReadableStream* ReadableStream::CreateWithCountQueueingStrategy(
     ScriptState* script_state,
     UnderlyingSourceBase* underlying_source,
     size_t high_water_mark) {
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    return ReadableStreamNative::CreateWithCountQueueingStrategy(
-        script_state, underlying_source, high_water_mark);
-  }
-
-  // TODO(ricea): Select implementation based on StreamsNative feature here.
-  return ReadableStreamWrapper::CreateWithCountQueueingStrategy(
+  return ReadableStreamNative::CreateWithCountQueueingStrategy(
       script_state, underlying_source, high_water_mark);
 }
 
@@ -61,13 +48,7 @@
 ReadableStream* ReadableStream::Deserialize(ScriptState* script_state,
                                             MessagePort* port,
                                             ExceptionState& exception_state) {
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    return ReadableStreamNative::Deserialize(script_state, port,
-                                             exception_state);
-  }
-
-  return ReadableStreamWrapper::Deserialize(script_state, port,
-                                            exception_state);
+  return ReadableStreamNative::Deserialize(script_state, port, exception_state);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream.idl b/third_party/blink/renderer/core/streams/readable_stream.idl
index 847d6fa8..4f8b6d86 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream.idl
@@ -5,8 +5,7 @@
 // https://streams.spec.whatwg.org/#rs-class
 [
     Exposed=(Window,Worker,Worklet),
-    // TODO(yhirano): Remove CustomConstructor. See https://crbug.com/906476.
-    CustomConstructor(optional any underlyingSource, optional any strategy),
+    Constructor(optional any underlyingSource, optional any strategy),
     RaisesException=Constructor,
     ConstructorCallWith=ScriptState
 ] interface ReadableStream {
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc b/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc
index c803bc8..d1b9b523 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.cc
@@ -7,7 +7,6 @@
 #include "base/optional.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_default_controller.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
 #include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -16,110 +15,12 @@
 
 namespace {
 
-class ReadableStreamDefaultControllerWrapper final
-    : public ReadableStreamDefaultControllerInterface {
- public:
-  explicit ReadableStreamDefaultControllerWrapper(ScriptState* script_state,
-                                                  ScriptValue controller)
-      : ReadableStreamDefaultControllerInterface(script_state),
-        js_controller_(script_state->GetIsolate(), controller.V8Value()) {
-    js_controller_.SetPhantom();
-  }
-
-  // Users of the ReadableStreamDefaultControllerWrapper can call this to note
-  // that the stream has been canceled and thus they don't anticipate using the
-  // ReadableStreamDefaultControllerWrapper anymore.
-  // (close/desiredSize/enqueue/error will become no-ops afterward.)
-  void NoteHasBeenCanceled() override { js_controller_.Clear(); }
-
-  void Close() override {
-    ScriptState* script_state = script_state_;
-    // This will assert that the context is valid; do not call this method when
-    // the context is invalidated.
-    ScriptState::Scope scope(script_state);
-    v8::Isolate* isolate = script_state->GetIsolate();
-
-    v8::Local<v8::Value> controller = js_controller_.NewLocal(isolate);
-    if (controller.IsEmpty())
-      return;
-
-    v8::Local<v8::Value> args[] = {controller};
-    v8::MaybeLocal<v8::Value> result = V8ScriptRunner::CallExtra(
-        script_state, "ReadableStreamDefaultControllerClose", args);
-    js_controller_.Clear();
-    result.ToLocalChecked();
-  }
-
-  double DesiredSize() const override {
-    ScriptState* script_state = script_state_;
-    // This will assert that the context is valid; do not call this method when
-    // the context is invalidated.
-    ScriptState::Scope scope(script_state);
-    v8::Isolate* isolate = script_state->GetIsolate();
-
-    v8::Local<v8::Value> controller = js_controller_.NewLocal(isolate);
-    if (controller.IsEmpty())
-      return 0;
-
-    v8::Local<v8::Value> args[] = {controller};
-    v8::MaybeLocal<v8::Value> result = V8ScriptRunner::CallExtra(
-        script_state, "ReadableStreamDefaultControllerGetDesiredSize", args);
-
-    return result.ToLocalChecked().As<v8::Number>()->Value();
-  }
-
-  void Enqueue(v8::Local<v8::Value> js_chunk) const override {
-    ScriptState* script_state = script_state_;
-    // This will assert that the context is valid; do not call this method when
-    // the context is invalidated.
-    ScriptState::Scope scope(script_state);
-    v8::Isolate* isolate = script_state->GetIsolate();
-
-    v8::Local<v8::Value> controller = js_controller_.NewLocal(isolate);
-    if (controller.IsEmpty())
-      return;
-
-    v8::Local<v8::Value> args[] = {controller, js_chunk};
-    v8::MaybeLocal<v8::Value> result = V8ScriptRunner::CallExtra(
-        script_state, "ReadableStreamDefaultControllerEnqueue", args);
-    result.ToLocalChecked();
-  }
-
-  void Error(v8::Local<v8::Value> js_error) override {
-    ScriptState* script_state = script_state_;
-    // This will assert that the context is valid; do not call this method when
-    // the context is invalidated.
-    ScriptState::Scope scope(script_state);
-    v8::Isolate* isolate = script_state->GetIsolate();
-
-    v8::Local<v8::Value> controller = js_controller_.NewLocal(isolate);
-    if (controller.IsEmpty())
-      return;
-
-    v8::Local<v8::Value> args[] = {controller, js_error};
-    v8::MaybeLocal<v8::Value> result = V8ScriptRunner::CallExtra(
-        script_state, "ReadableStreamDefaultControllerError", args);
-    js_controller_.Clear();
-    result.ToLocalChecked();
-  }
-
-  void Trace(blink::Visitor* visitor) override {
-    visitor->Trace(script_state_);
-    ReadableStreamDefaultControllerInterface::Trace(visitor);
-  }
-
- private:
-  ScopedPersistent<v8::Value> js_controller_;
-};
-
 class ReadableStreamDefaultControllerNative final
     : public ReadableStreamDefaultControllerInterface {
  public:
   explicit ReadableStreamDefaultControllerNative(ScriptState* script_state,
                                                  ScriptValue controller)
       : ReadableStreamDefaultControllerInterface(script_state) {
-    DCHECK(RuntimeEnabledFeatures::StreamsNativeEnabled());
-
     v8::Local<v8::Object> controller_object =
         controller.V8Value().As<v8::Object>();
     controller_ = V8ReadableStreamDefaultController::ToImpl(controller_object);
@@ -189,12 +90,7 @@
 ReadableStreamDefaultControllerInterface*
 ReadableStreamDefaultControllerInterface::Create(ScriptState* script_state,
                                                  ScriptValue controller) {
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    return MakeGarbageCollected<ReadableStreamDefaultControllerNative>(
-        script_state, controller);
-  }
-
-  return MakeGarbageCollected<ReadableStreamDefaultControllerWrapper>(
+  return MakeGarbageCollected<ReadableStreamDefaultControllerNative>(
       script_state, controller);
 }
 
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl b/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
index 1a1fee3..63deec74 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_reader.idl
@@ -7,7 +7,6 @@
 // https://streams.spec.whatwg.org/#default-reader-class-definition
 [
     Exposed=(Window,Worker,Worklet),
-    RuntimeEnabled=StreamsNative,
     RaisesException=Constructor,
     ConstructorCallWith=ScriptState,
     Constructor(ReadableStream stream)
diff --git a/third_party/blink/renderer/core/streams/readable_stream_native.cc b/third_party/blink/renderer/core/streams/readable_stream_native.cc
index ff0a4deaf..2830a4b 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_native.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_native.cc
@@ -1241,8 +1241,6 @@
   PipeOptions pipe_options;
   UnpackPipeOptions(script_state, options, &pipe_options, exception_state);
 
-  DCHECK(RuntimeEnabledFeatures::StreamsNativeEnabled());
-
   // This cast is safe because the following code will only be run when the
   // native version of WritableStream is in use.
   WritableStreamNative* writable_native =
@@ -1285,8 +1283,6 @@
   PipeOptions pipe_options;
   UnpackPipeOptions(script_state, options, &pipe_options, exception_state);
 
-  DCHECK(RuntimeEnabledFeatures::StreamsNativeEnabled());
-
   // This cast is safe because the following code will only be run when the
   // native version of WritableStream is in use.
   WritableStreamNative* destination_native =
diff --git a/third_party/blink/renderer/core/streams/readable_stream_operations.cc b/third_party/blink/renderer/core/streams/readable_stream_operations.cc
deleted file mode 100644
index 7f58fdff..0000000
--- a/third_party/blink/renderer/core/streams/readable_stream_operations.cc
+++ /dev/null
@@ -1,392 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/streams/readable_stream_operations.h"
-
-#include <utility>
-
-#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_message_port.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
-#include "third_party/blink/renderer/core/messaging/message_port.h"
-#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-
-namespace blink {
-
-namespace {
-
-base::Optional<bool> BooleanOperationWithRethrow(
-    ScriptState* script_state,
-    ScriptValue value,
-    const char* operation,
-    ExceptionState& exception_state) {
-  DCHECK(!value.IsEmpty());
-
-  if (!value.IsObject())
-    return false;
-
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> args[] = {value.V8Value()};
-  v8::Local<v8::Value> local_value;
-
-  if (!V8ScriptRunner::CallExtra(script_state, operation, args)
-           .ToLocal(&local_value)) {
-    DCHECK(block.HasCaught() ||
-           script_state->GetIsolate()->IsExecutionTerminating());
-    exception_state.RethrowV8Exception(block.Exception());
-    return base::nullopt;
-  }
-
-  DCHECK(!block.HasCaught());
-  return local_value->BooleanValue(script_state->GetIsolate());
-}
-
-// Performs |operation| on |value|, catching any exceptions. This is for use in
-// DCHECK(). It is unsafe for general use because it ignores errors. Returns
-// |fallback_value|, which must be chosen so that the DCHECK() passed if an
-// exception was thrown, so that the behaviour matches a release build.
-bool BooleanOperationForDCheck(ScriptState* script_state,
-                               ScriptValue value,
-                               const char* operation,
-                               bool fallback_value) {
-  v8::Local<v8::Value> args[] = {value.V8Value()};
-  v8::Local<v8::Value> result_value;
-  v8::TryCatch block(script_state->GetIsolate());
-  if (V8ScriptRunner::CallExtra(script_state, operation, args)
-          .ToLocal(&result_value)) {
-    DCHECK(!block.HasCaught());
-    return result_value->BooleanValue(script_state->GetIsolate());
-  }
-  DCHECK(block.HasCaught() ||
-         script_state->GetIsolate()->IsExecutionTerminating());
-  return fallback_value;
-}
-
-// Performs IsReadableStreamDefaultReader(value), catching exceptions. Should
-// only be used in DCHECK(). Returns true on exception.
-bool IsDefaultReaderForDCheck(ScriptState* script_state, ScriptValue value) {
-  return BooleanOperationForDCheck(script_state, value,
-                                   "IsReadableStreamDefaultReader", true);
-}
-
-}  // namespace
-
-ScriptValue ReadableStreamOperations::CreateReadableStream(
-    ScriptState* script_state,
-    UnderlyingSourceBase* underlying_source,
-    ScriptValue strategy) {
-  ScriptState::Scope scope(script_state);
-
-  v8::Local<v8::Value> js_underlying_source =
-      ToV8(underlying_source, script_state);
-  v8::Local<v8::Value> js_strategy = strategy.V8Value();
-  v8::Local<v8::Value> args[] = {js_underlying_source, js_strategy};
-  return ScriptValue(
-      script_state->GetIsolate(),
-      V8ScriptRunner::CallExtra(
-          script_state, "createReadableStreamWithExternalController", args));
-}
-
-ScriptValue ReadableStreamOperations::CreateReadableStream(
-    ScriptState* script_state,
-    ScriptValue underlying_source,
-    ScriptValue strategy,
-    ExceptionState& exception_state) {
-  ScriptState::Scope scope(script_state);
-
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> args[] = {underlying_source.V8Value(),
-                                 strategy.V8Value()};
-  v8::Local<v8::Value> result;
-
-  if (!V8ScriptRunner::CallExtra(script_state, "createReadableStream", args)
-           .ToLocal(&result)) {
-    DCHECK(block.HasCaught() ||
-           script_state->GetIsolate()->IsExecutionTerminating());
-    exception_state.RethrowV8Exception(block.Exception());
-    return ScriptValue();
-  }
-  return ScriptValue(script_state->GetIsolate(), result);
-}
-
-ScriptValue ReadableStreamOperations::CreateCountQueuingStrategy(
-    ScriptState* script_state,
-    size_t high_water_mark) {
-  ScriptState::Scope scope(script_state);
-
-  v8::Local<v8::Value> args[] = {
-      v8::Number::New(script_state->GetIsolate(), high_water_mark)};
-  return ScriptValue(
-      script_state->GetIsolate(),
-      V8ScriptRunner::CallExtra(script_state,
-                                "createBuiltInCountQueuingStrategy", args));
-}
-
-ScriptValue ReadableStreamOperations::GetReader(
-    ScriptState* script_state,
-    ScriptValue stream,
-    ExceptionState& exception_state) {
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> args[] = {stream.V8Value()};
-  ScriptValue result(
-      script_state->GetIsolate(),
-      V8ScriptRunner::CallExtra(script_state,
-                                "AcquireReadableStreamDefaultReader", args));
-  if (block.HasCaught()) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return ScriptValue();
-  }
-  DCHECK(!result.IsEmpty() ||
-         script_state->GetIsolate()->IsExecutionTerminating());
-  return result;
-}
-
-base::Optional<bool> ReadableStreamOperations::IsReadableStream(
-    ScriptState* script_state,
-    ScriptValue value,
-    ExceptionState& exception_state) {
-  return BooleanOperationWithRethrow(script_state, value, "IsReadableStream",
-                                     exception_state);
-}
-
-bool ReadableStreamOperations::IsReadableStreamForDCheck(
-    ScriptState* script_state,
-    ScriptValue value) {
-  return BooleanOperationForDCheck(script_state, value, "IsReadableStream",
-                                   true);
-}
-
-base::Optional<bool> ReadableStreamOperations::IsDisturbed(
-    ScriptState* script_state,
-    ScriptValue stream,
-    ExceptionState& exception_state) {
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-  return BooleanOperationWithRethrow(
-      script_state, stream, "IsReadableStreamDisturbed", exception_state);
-}
-
-bool ReadableStreamOperations::IsDisturbedForDCheck(ScriptState* script_state,
-                                                    ScriptValue stream) {
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-  return BooleanOperationForDCheck(script_state, stream,
-                                   "IsReadableStreamDisturbed", false);
-}
-
-base::Optional<bool> ReadableStreamOperations::IsLocked(
-    ScriptState* script_state,
-    ScriptValue stream,
-    ExceptionState& exception_state) {
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-  return BooleanOperationWithRethrow(script_state, stream,
-                                     "IsReadableStreamLocked", exception_state);
-}
-
-bool ReadableStreamOperations::IsLockedForDCheck(ScriptState* script_state,
-                                                 ScriptValue stream) {
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-  return BooleanOperationForDCheck(script_state, stream,
-                                   "IsReadableStreamLocked", false);
-}
-
-base::Optional<bool> ReadableStreamOperations::IsReadable(
-    ScriptState* script_state,
-    ScriptValue stream,
-    ExceptionState& exception_state) {
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-  return BooleanOperationWithRethrow(
-      script_state, stream, "IsReadableStreamReadable", exception_state);
-}
-
-base::Optional<bool> ReadableStreamOperations::IsClosed(
-    ScriptState* script_state,
-    ScriptValue stream,
-    ExceptionState& exception_state) {
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-  return BooleanOperationWithRethrow(script_state, stream,
-                                     "IsReadableStreamClosed", exception_state);
-}
-
-base::Optional<bool> ReadableStreamOperations::IsErrored(
-    ScriptState* script_state,
-    ScriptValue stream,
-    ExceptionState& exception_state) {
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-  return BooleanOperationWithRethrow(
-      script_state, stream, "IsReadableStreamErrored", exception_state);
-}
-
-base::Optional<bool> ReadableStreamOperations::IsReadableStreamDefaultReader(
-    ScriptState* script_state,
-    ScriptValue value,
-    ExceptionState& exception_state) {
-  return BooleanOperationWithRethrow(
-      script_state, value, "IsReadableStreamDefaultReader", exception_state);
-}
-
-ScriptPromise ReadableStreamOperations::DefaultReaderRead(
-    ScriptState* script_state,
-    ScriptValue reader) {
-  DCHECK(IsDefaultReaderForDCheck(script_state, reader));
-
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> args[] = {reader.V8Value()};
-  v8::MaybeLocal<v8::Value> maybe_result = V8ScriptRunner::CallExtra(
-      script_state, "ReadableStreamDefaultReaderRead", args);
-  if (maybe_result.IsEmpty()) {
-    DCHECK(block.HasCaught() ||
-           script_state->GetIsolate()->IsExecutionTerminating());
-    return ScriptPromise::Reject(script_state, block.Exception());
-  }
-  return ScriptPromise::Cast(script_state, maybe_result.ToLocalChecked());
-}
-
-ScriptValue ReadableStreamOperations::Tee(ScriptState* script_state,
-                                          ScriptValue stream,
-                                          ExceptionState& exception_state) {
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-  DCHECK(!IsLockedForDCheck(script_state, stream));
-
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> args[] = {stream.V8Value()};
-  v8::Local<v8::Value> result;
-  if (!V8ScriptRunner::CallExtra(script_state, "ReadableStreamTee", args)
-           .ToLocal(&result)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return ScriptValue();
-  }
-  return ScriptValue(script_state->GetIsolate(), result);
-}
-
-void ReadableStreamOperations::Serialize(ScriptState* script_state,
-                                         ScriptValue stream,
-                                         MessagePort* port,
-                                         ExceptionState& exception_state) {
-  DCHECK(port);
-  DCHECK(IsReadableStreamForDCheck(script_state, stream));
-  DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> port_v8_value = ToV8(port, script_state);
-  DCHECK(!port_v8_value.IsEmpty());
-  v8::Local<v8::Value> args[] = {stream.V8Value(), port_v8_value};
-  ScriptValue result(
-      script_state->GetIsolate(),
-      V8ScriptRunner::CallExtra(script_state, "ReadableStreamSerialize", args));
-  if (block.HasCaught()) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-  return;
-}
-
-ScriptValue ReadableStreamOperations::Deserialize(
-    ScriptState* script_state,
-    MessagePort* port,
-    ExceptionState& exception_state) {
-  DCHECK(port);
-  DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
-  auto* isolate = script_state->GetIsolate();
-  v8::TryCatch block(isolate);
-  v8::Local<v8::Value> port_v8 = ToV8(port, script_state);
-  DCHECK(!port_v8.IsEmpty());
-  v8::Local<v8::Value> args[] = {port_v8};
-  ScriptValue result(script_state->GetIsolate(),
-                     V8ScriptRunner::CallExtra(
-                         script_state, "ReadableStreamDeserialize", args));
-  if (block.HasCaught()) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return ScriptValue();
-  }
-  if (result.IsEmpty()) {
-    DCHECK(isolate->IsExecutionTerminating());
-    return ScriptValue();
-  }
-  DCHECK(IsReadableStreamForDCheck(script_state, result));
-  return result;
-}
-
-ScriptPromise ReadableStreamOperations::Cancel(
-    ScriptState* script_state,
-    ScriptValue stream,
-    ScriptValue reason,
-    ExceptionState& exception_state) {
-  v8::Local<v8::Value> args[] = {stream.V8Value(), reason.V8Value()};
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> result;
-
-  if (!V8ScriptRunner::CallExtra(script_state, "ReadableStreamCancel", args)
-           .ToLocal(&result)) {
-    DCHECK(block.HasCaught() ||
-           script_state->GetIsolate()->IsExecutionTerminating());
-    exception_state.RethrowV8Exception(block.Exception());
-    return ScriptPromise();
-  }
-  return ScriptPromise(script_state, result);
-}
-
-ScriptPromise ReadableStreamOperations::PipeTo(
-    ScriptState* script_state,
-    ScriptValue stream,
-    ScriptValue destination,
-    ScriptValue options,
-    ExceptionState& exception_state) {
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> result;
-  v8::Isolate* isolate = script_state->GetIsolate();
-  v8::Local<v8::Boolean> prevent_close;
-  v8::Local<v8::Boolean> prevent_abort;
-  v8::Local<v8::Boolean> prevent_cancel;
-
-  if (options.IsUndefined()) {
-    // All values default to false.
-    prevent_close = v8::Boolean::New(isolate, false);
-    prevent_abort = v8::Boolean::New(isolate, false);
-    prevent_cancel = v8::Boolean::New(isolate, false);
-  } else {
-    v8::Local<v8::Context> context = script_state->GetContext();
-    v8::Local<v8::Object> v8_options;
-    if (!options.V8Value()->ToObject(context).ToLocal(&v8_options)) {
-      exception_state.RethrowV8Exception(block.Exception());
-      return ScriptPromise();
-    }
-    v8::Local<v8::Value> prevent_close_v, prevent_abort_v, prevent_cancel_v;
-    if (!v8_options->Get(context, V8String(isolate, "preventClose"))
-             .ToLocal(&prevent_close_v)) {
-      exception_state.RethrowV8Exception(block.Exception());
-      return ScriptPromise();
-    }
-    if (!v8_options->Get(context, V8String(isolate, "preventAbort"))
-             .ToLocal(&prevent_abort_v)) {
-      exception_state.RethrowV8Exception(block.Exception());
-      return ScriptPromise();
-    }
-    if (!v8_options->Get(context, V8String(isolate, "preventCancel"))
-             .ToLocal(&prevent_cancel_v)) {
-      exception_state.RethrowV8Exception(block.Exception());
-      return ScriptPromise();
-    }
-    prevent_close = prevent_close_v->ToBoolean(isolate);
-    prevent_abort = prevent_abort_v->ToBoolean(isolate);
-    prevent_cancel = prevent_cancel_v->ToBoolean(isolate);
-  }
-
-  v8::Local<v8::Value> args[] = {stream.V8Value(), destination.V8Value(),
-                                 prevent_close, prevent_abort, prevent_cancel};
-  if (!V8ScriptRunner::CallExtra(script_state, "ReadableStreamPipeTo", args)
-           .ToLocal(&result)) {
-    DCHECK(block.HasCaught() ||
-           script_state->GetIsolate()->IsExecutionTerminating());
-    exception_state.RethrowV8Exception(block.Exception());
-    return ScriptPromise();
-  }
-
-  return ScriptPromise(script_state, result);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_operations.h b/third_party/blink/renderer/core/streams/readable_stream_operations.h
deleted file mode 100644
index 92ed0ec6..0000000
--- a/third_party/blink/renderer/core/streams/readable_stream_operations.h
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_OPERATIONS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_OPERATIONS_H_
-
-#include "base/optional.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/core/core_export.h"
-
-namespace blink {
-
-class UnderlyingSourceBase;
-class ExceptionState;
-class MessagePort;
-class ScriptState;
-
-// This class has various methods for ReadableStream[Reader] implemented with
-// V8 Extras.
-//
-//     DEPRECATED: None of these functions work correctly with the new C++
-//     implementation of ReadableStream. Use the ReadableStream API directly
-//     instead.
-//
-// All methods should be called in an appropriate V8 context. All ScriptValue
-// arguments must not be empty.
-//
-// Boolean methods return an optional bool, where an empty value indicates that
-// Javascript failed to return a value (ie. an exception occurred). Exceptions
-// are not caught, so that they can be handled by user Javascript. This implicit
-// exception passing is error-prone and bad.
-//
-// In methods which take an ExceptionState& parameter, exception passing is
-// explicit. Callers must check exception_state.HadException() on
-// return. Although these methods return base::nullopt if and only if an
-// exception was thrown, outside of unit tests exception_state should always be
-// used to determine failure.
-//
-// TODO(ricea): Add ExceptionState arguments to the rest of the non-Promise
-// methods to make exception passing explicit. https://crbug.com/853189.
-class CORE_EXPORT ReadableStreamOperations {
-  STATIC_ONLY(ReadableStreamOperations);
-
- public:
-  // createReadableStreamWithExternalController
-  // Instantiates ReadableStream defined in the script and returns it.
-  // If the caller supplies an invalid strategy (e.g. one that returns
-  // negative sizes, or doesn't have appropriate properties), or an exception
-  // occurs for another reason, this will return an empty value.
-  static ScriptValue CreateReadableStream(ScriptState*,
-                                          UnderlyingSourceBase*,
-                                          ScriptValue strategy);
-
-  // createReadableStream
-  // Instantiates ReadableStream defined in the script and returns it.
-  static ScriptValue CreateReadableStream(ScriptState*,
-                                          ScriptValue underlying_source,
-                                          ScriptValue strategy,
-                                          ExceptionState& exception_state);
-
-  // createBuiltInCountQueuingStrategy
-  // If the constructor throws, this will return an empty value.
-  static ScriptValue CreateCountQueuingStrategy(ScriptState*,
-                                                size_t high_water_mark);
-
-  // AcquireReadableStreamDefaultReader
-  // This function assumes |IsReadableStream(stream)|.
-  static ScriptValue GetReader(ScriptState*,
-                               ScriptValue stream,
-                               ExceptionState&);
-
-  // IsReadableStream, exception-catching version. Exceptions will be passed to
-  // |exception_state|.
-  static base::Optional<bool> IsReadableStream(ScriptState*,
-                                               ScriptValue,
-                                               ExceptionState& exception_state);
-
-  // Performs IsReadableStream.
-  // Catches exceptions, and returns false if there are any. Should only be used
-  // in a DCHECK statement that passes when the return value is true.
-  static bool IsReadableStreamForDCheck(ScriptState*, ScriptValue);
-
-  // IsReadableStreamDisturbed.
-  // This function assumes |IsReadableStream(stream)|.
-  static base::Optional<bool> IsDisturbed(ScriptState*,
-                                          ScriptValue stream,
-                                          ExceptionState& exception_state);
-
-  // Performs IsReadableStreamDisturbed.
-  // Catches exceptions, and returns false if there are any. Should only be used
-  // in a DCHECK statement that passes when the return value is false.
-  static bool IsDisturbedForDCheck(ScriptState*, ScriptValue stream);
-
-  // IsReadableStreamLocked.
-  // This function assumes |IsReadableStream(stream)|.
-  static base::Optional<bool> IsLocked(ScriptState*,
-                                       ScriptValue stream,
-                                       ExceptionState&);
-
-  // Performs IsReadableStreamLocked.
-  // Catches exceptions, and returns false if there are any. Should only be used
-  // in a DCHECK statement that passes when the return value is false.
-  static bool IsLockedForDCheck(ScriptState*, ScriptValue stream);
-
-  // IsReadableStreamReadable.
-  // This function assumes |IsReadableStream(stream)|.
-  static base::Optional<bool> IsReadable(ScriptState*,
-                                         ScriptValue stream,
-                                         ExceptionState& exception_state);
-
-  // IsReadableStreamClosed.
-  // This function assumes |IsReadableStream(stream)|.
-  static base::Optional<bool> IsClosed(ScriptState*,
-                                       ScriptValue stream,
-                                       ExceptionState& exception_state);
-
-  // IsReadableStreamErrored.
-  // This function assumes |IsReadableStream(stream)|.
-  static base::Optional<bool> IsErrored(ScriptState*,
-                                        ScriptValue stream,
-                                        ExceptionState& exception_state);
-
-  // IsReadableStreamDefaultReader.
-  static base::Optional<bool> IsReadableStreamDefaultReader(
-      ScriptState*,
-      ScriptValue,
-      ExceptionState& exception_state);
-
-  // ReadableStreamDefaultReaderRead
-  // This function assumes |IsReadableStreamDefaultReader(reader)|.
-  // If an exception occurs, returns a rejected promise.
-  static ScriptPromise DefaultReaderRead(ScriptState*, ScriptValue reader);
-
-  // ReadableStreamTee
-  // This function assumes |IsReadableStream(stream)| and |!IsLocked(stream)|
-  static ScriptValue Tee(ScriptState*, ScriptValue stream, ExceptionState&);
-
-  // ReadableStreamSerialize. The MessagePort passed in must be one half of a
-  // MessageChannel. The other half can later be passed to Deserialize to
-  // produce an equivalent ReadableStream in a different context.
-  static void Serialize(ScriptState*,
-                        ScriptValue stream,
-                        MessagePort* port,
-                        ExceptionState&);
-
-  // ReadableStreamDeserialize returns a new ReadableStream in the current
-  // context given a MessagePort which is bound to one which was previously
-  // passed to Serialize().
-  static ScriptValue Deserialize(ScriptState*, MessagePort*, ExceptionState&);
-
-  // ReadableStreamCancel
-  // This function assumes |IsReadableStream(stream)|
-  static ScriptPromise Cancel(ScriptState*,
-                              ScriptValue stream,
-                              ScriptValue reason,
-                              ExceptionState& exception_state);
-
-  // ReadableStreamPipeTo
-  // This function assumes |IsReadableStream(stream)|, |!IsLocked(stream)|,
-  // |IsWritableStream(destination)| and |!IsLocked(destination)|.
-  static ScriptPromise PipeTo(ScriptState*,
-                              ScriptValue stream,
-                              ScriptValue destination,
-                              ScriptValue options,
-                              ExceptionState& exception_state);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_OPERATIONS_H_
diff --git a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc b/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
deleted file mode 100644
index c2a350ee..0000000
--- a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
+++ /dev/null
@@ -1,627 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/streams/readable_stream_operations.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_extras_test_utils.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_iterator_result_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/messaging/message_channel.h"
-#include "third_party/blink/renderer/core/streams/readable_stream.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_interface.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_wrapper.h"
-#include "third_party/blink/renderer/core/streams/test_underlying_source.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
-#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
-#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-namespace {
-
-class ReadableStreamOperationsTestNotReached : public ScriptFunction {
- public:
-  static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) {
-    ReadableStreamOperationsTestNotReached* self =
-        MakeGarbageCollected<ReadableStreamOperationsTestNotReached>(
-            script_state);
-    return self->BindToV8Function();
-  }
-
-  explicit ReadableStreamOperationsTestNotReached(ScriptState* script_state)
-      : ScriptFunction(script_state) {}
-
- private:
-  ScriptValue Call(ScriptValue) override;
-};
-
-ScriptValue ReadableStreamOperationsTestNotReached::Call(ScriptValue) {
-  EXPECT_TRUE(false) << "'Unreachable' code was reached";
-  return ScriptValue();
-}
-
-class Iteration final : public GarbageCollected<Iteration> {
- public:
-  Iteration() : is_set_(false), is_done_(false), is_valid_(true) {}
-
-  void Set(ScriptState* script_state, ScriptValue v) {
-    DCHECK(!v.IsEmpty());
-    is_set_ = true;
-    v8::TryCatch block(script_state->GetIsolate());
-    v8::Local<v8::Value> value;
-    v8::Local<v8::Value> item = v.V8Value();
-    if (!item->IsObject() ||
-        !V8UnpackIteratorResult(script_state, item.As<v8::Object>(), &is_done_)
-             .ToLocal(&value)) {
-      is_valid_ = false;
-      return;
-    }
-    value_ = ToCoreString(
-        value->ToString(script_state->GetContext()).ToLocalChecked());
-  }
-
-  bool IsSet() const { return is_set_; }
-  bool IsDone() const { return is_done_; }
-  bool IsValid() const { return is_valid_; }
-  const String& Value() const { return value_; }
-
-  void Trace(blink::Visitor* visitor) {}
-
- private:
-  bool is_set_;
-  bool is_done_;
-  bool is_valid_;
-  String value_;
-};
-
-class ReaderFunction : public ScriptFunction {
- public:
-  static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
-                                                Iteration* iteration) {
-    ReaderFunction* self =
-        MakeGarbageCollected<ReaderFunction>(script_state, iteration);
-    return self->BindToV8Function();
-  }
-
-  ReaderFunction(ScriptState* script_state, Iteration* iteration)
-      : ScriptFunction(script_state), iteration_(iteration) {}
-
-  void Trace(blink::Visitor* visitor) override {
-    visitor->Trace(iteration_);
-    ScriptFunction::Trace(visitor);
-  }
-
- private:
-  ScriptValue Call(ScriptValue value) override {
-    iteration_->Set(GetScriptState(), value);
-    return value;
-  }
-
-  Member<Iteration> iteration_;
-};
-
-// Returns the internal V8 Extras implementation of a ReadableStream object.
-// Requires StreamsNative feature to be off.
-ScriptValue CheckedGetInternalStream(ScriptState* script_state,
-                                     ReadableStream* readable_stream) {
-  CHECK(!RuntimeEnabledFeatures::StreamsNativeEnabled());
-  ReadableStreamWrapper* readable_stream_wrapper =
-      static_cast<ReadableStreamWrapper*>(readable_stream);
-  return readable_stream_wrapper->GetInternalStream(script_state);
-}
-
-ScriptValue CheckedGetInternalStream(ScriptState* script_state,
-                                     ScriptValue stream) {
-  ReadableStream* readable_stream =
-      V8ReadableStream::ToImpl(stream.V8Value().As<v8::Object>());
-  return CheckedGetInternalStream(script_state, readable_stream);
-}
-
-TEST(ReadableStreamOperationsTest, IsReadableStream) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-  EXPECT_FALSE(
-      ReadableStreamOperations::IsReadableStream(
-          scope.GetScriptState(),
-          ScriptValue(scope.GetIsolate(), v8::Undefined(scope.GetIsolate())),
-          ASSERT_NO_EXCEPTION)
-          .value_or(true));
-  EXPECT_FALSE(ReadableStreamOperations::IsReadableStream(
-                   scope.GetScriptState(),
-                   ScriptValue::CreateNull(scope.GetIsolate()),
-                   ASSERT_NO_EXCEPTION)
-                   .value_or(true));
-  EXPECT_FALSE(
-      ReadableStreamOperations::IsReadableStream(
-          scope.GetScriptState(),
-          ScriptValue(scope.GetIsolate(), v8::Object::New(scope.GetIsolate())),
-          ASSERT_NO_EXCEPTION)
-          .value_or(true));
-  ScriptValue stream = EvalWithPrintingError(&scope, "new ReadableStream()");
-  EXPECT_FALSE(stream.IsEmpty());
-  EXPECT_FALSE(ReadableStreamOperations::IsReadableStream(
-                   scope.GetScriptState(), stream, ASSERT_NO_EXCEPTION)
-                   .value_or(false));
-  ASSERT_TRUE(V8ReadableStream::HasInstance(stream.V8Value().As<v8::Object>(),
-                                            scope.GetIsolate()));
-
-  ScriptValue internal_stream =
-      CheckedGetInternalStream(scope.GetScriptState(), stream);
-  ASSERT_FALSE(internal_stream.IsEmpty());
-  EXPECT_TRUE(ReadableStreamOperations::IsReadableStream(
-                  scope.GetScriptState(), internal_stream, ASSERT_NO_EXCEPTION)
-                  .value_or(false));
-}
-
-TEST(ReadableStreamOperationsTest, IsReadableStreamDefaultReaderInvalid) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-  EXPECT_FALSE(
-      ReadableStreamOperations::IsReadableStreamDefaultReader(
-          scope.GetScriptState(),
-          ScriptValue(scope.GetIsolate(), v8::Undefined(scope.GetIsolate())),
-          ASSERT_NO_EXCEPTION)
-          .value_or(true));
-  EXPECT_FALSE(ReadableStreamOperations::IsReadableStreamDefaultReader(
-                   scope.GetScriptState(),
-                   ScriptValue::CreateNull(scope.GetIsolate()),
-                   ASSERT_NO_EXCEPTION)
-                   .value_or(true));
-  EXPECT_FALSE(
-      ReadableStreamOperations::IsReadableStreamDefaultReader(
-          scope.GetScriptState(),
-          ScriptValue(scope.GetIsolate(), v8::Object::New(scope.GetIsolate())),
-          ASSERT_NO_EXCEPTION)
-          .value_or(true));
-  ScriptValue stream = EvalWithPrintingError(&scope, "new ReadableStream()");
-  ASSERT_FALSE(stream.IsEmpty());
-
-  EXPECT_FALSE(ReadableStreamOperations::IsReadableStreamDefaultReader(
-                   scope.GetScriptState(), stream, ASSERT_NO_EXCEPTION)
-                   .value_or(true));
-}
-
-TEST(ReadableStreamOperationsTest, GetReader) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-  auto* stream =
-      ReadableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  ASSERT_TRUE(stream);
-
-  ScriptValue internal_stream =
-      CheckedGetInternalStream(scope.GetScriptState(), stream);
-  ASSERT_FALSE(internal_stream.IsEmpty());
-
-  EXPECT_EQ(ReadableStreamOperations::IsLocked(
-                scope.GetScriptState(), internal_stream, ASSERT_NO_EXCEPTION),
-            base::make_optional(false));
-  ScriptValue reader;
-  reader = ReadableStreamOperations::GetReader(
-      scope.GetScriptState(), internal_stream, ASSERT_NO_EXCEPTION);
-  ASSERT_FALSE(reader.IsEmpty());
-  EXPECT_EQ(ReadableStreamOperations::IsLocked(
-                scope.GetScriptState(), internal_stream, ASSERT_NO_EXCEPTION),
-            base::make_optional(true));
-
-  EXPECT_EQ(ReadableStreamOperations::IsReadableStream(
-                scope.GetScriptState(), reader, ASSERT_NO_EXCEPTION),
-            base::make_optional(false));
-  EXPECT_EQ(ReadableStreamOperations::IsReadableStreamDefaultReader(
-                scope.GetScriptState(), reader, ASSERT_NO_EXCEPTION),
-            base::make_optional(true));
-
-  // Already locked!
-  DummyExceptionStateForTesting exception_state;
-  reader = ReadableStreamOperations::GetReader(
-      scope.GetScriptState(), internal_stream, exception_state);
-  EXPECT_TRUE(exception_state.HadException());
-  EXPECT_TRUE(reader.IsEmpty());
-}
-
-TEST(ReadableStreamOperationsTest, IsDisturbed) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-  auto* stream =
-      ReadableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  ASSERT_TRUE(stream);
-
-  ScriptValue internal_stream =
-      CheckedGetInternalStream(scope.GetScriptState(), stream);
-  EXPECT_EQ(ReadableStreamOperations::IsDisturbed(
-                scope.GetScriptState(), internal_stream, ASSERT_NO_EXCEPTION),
-            base::make_optional(false));
-
-  stream->cancel(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-
-  EXPECT_EQ(ReadableStreamOperations::IsDisturbed(
-                scope.GetScriptState(), internal_stream, ASSERT_NO_EXCEPTION),
-            base::make_optional(true));
-}
-
-TEST(ReadableStreamOperationsTest, Read) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-  ScriptValue reader =
-      EvalWithPrintingError(&scope,
-                            "var controller;"
-                            "function start(c) { controller = c; }"
-                            "new ReadableStream({start}).getReader()");
-  EXPECT_FALSE(reader.IsEmpty());
-  ASSERT_TRUE(ReadableStreamOperations::IsReadableStreamDefaultReader(
-                  scope.GetScriptState(), reader, ASSERT_NO_EXCEPTION)
-                  .value_or(false));
-
-  Iteration* it1 = MakeGarbageCollected<Iteration>();
-  Iteration* it2 = MakeGarbageCollected<Iteration>();
-  ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader)
-      .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it1),
-            ReadableStreamOperationsTestNotReached::CreateFunction(
-                scope.GetScriptState()));
-  ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader)
-      .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it2),
-            ReadableStreamOperationsTestNotReached::CreateFunction(
-                scope.GetScriptState()));
-
-  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
-  EXPECT_FALSE(it1->IsSet());
-  EXPECT_FALSE(it2->IsSet());
-
-  ASSERT_FALSE(
-      EvalWithPrintingError(&scope, "controller.enqueue('hello')").IsEmpty());
-  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
-  EXPECT_TRUE(it1->IsSet());
-  EXPECT_TRUE(it1->IsValid());
-  EXPECT_FALSE(it1->IsDone());
-  EXPECT_EQ("hello", it1->Value());
-  EXPECT_FALSE(it2->IsSet());
-
-  ASSERT_FALSE(EvalWithPrintingError(&scope, "controller.close()").IsEmpty());
-  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
-  EXPECT_TRUE(it1->IsSet());
-  EXPECT_TRUE(it1->IsValid());
-  EXPECT_FALSE(it1->IsDone());
-  EXPECT_EQ("hello", it1->Value());
-  EXPECT_TRUE(it2->IsSet());
-  EXPECT_TRUE(it2->IsValid());
-  EXPECT_TRUE(it2->IsDone());
-}
-
-TEST(ReadableStreamOperationsTest,
-     CreateReadableStreamWithCustomUnderlyingSourceAndStrategy) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-  auto* underlying_source =
-      MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
-
-  ScriptValue strategy = ReadableStreamOperations::CreateCountQueuingStrategy(
-      scope.GetScriptState(), 10);
-  ASSERT_FALSE(strategy.IsEmpty());
-
-  ScriptValue stream = ReadableStreamOperations::CreateReadableStream(
-      scope.GetScriptState(), underlying_source, strategy);
-  ASSERT_FALSE(stream.IsEmpty());
-
-  EXPECT_EQ(10, underlying_source->DesiredSize());
-
-  underlying_source->Enqueue(ScriptValue::From(scope.GetScriptState(), "a"));
-  EXPECT_EQ(9, underlying_source->DesiredSize());
-
-  underlying_source->Enqueue(ScriptValue::From(scope.GetScriptState(), "b"));
-  EXPECT_EQ(8, underlying_source->DesiredSize());
-
-  ScriptValue reader;
-  reader = ReadableStreamOperations::GetReader(scope.GetScriptState(), stream,
-                                               ASSERT_NO_EXCEPTION);
-  ASSERT_FALSE(reader.IsEmpty());
-
-  Iteration* it1 = MakeGarbageCollected<Iteration>();
-  Iteration* it2 = MakeGarbageCollected<Iteration>();
-  Iteration* it3 = MakeGarbageCollected<Iteration>();
-  ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader)
-      .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it1),
-            ReadableStreamOperationsTestNotReached::CreateFunction(
-                scope.GetScriptState()));
-  ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader)
-      .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it2),
-            ReadableStreamOperationsTestNotReached::CreateFunction(
-                scope.GetScriptState()));
-  ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader)
-      .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it3),
-            ReadableStreamOperationsTestNotReached::CreateFunction(
-                scope.GetScriptState()));
-
-  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
-
-  EXPECT_EQ(10, underlying_source->DesiredSize());
-
-  EXPECT_TRUE(it1->IsSet());
-  EXPECT_TRUE(it1->IsValid());
-  EXPECT_FALSE(it1->IsDone());
-  EXPECT_EQ("a", it1->Value());
-
-  EXPECT_TRUE(it2->IsSet());
-  EXPECT_TRUE(it2->IsValid());
-  EXPECT_FALSE(it2->IsDone());
-  EXPECT_EQ("b", it2->Value());
-
-  EXPECT_FALSE(it3->IsSet());
-
-  underlying_source->Close();
-  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
-
-  EXPECT_TRUE(it3->IsSet());
-  EXPECT_TRUE(it3->IsValid());
-  EXPECT_TRUE(it3->IsDone());
-}
-
-TEST(ReadableStreamOperationsTest, IsReadable) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-
-  auto* readable =
-      ReadableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  ASSERT_TRUE(readable);
-
-  auto* closing_source =
-      MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
-  auto* closed = ReadableStream::CreateWithCountQueueingStrategy(
-      scope.GetScriptState(), closing_source, 0);
-  ASSERT_TRUE(closed);
-  closing_source->Close();
-
-  auto* erroring_source =
-      MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
-  auto* errored = ReadableStream::CreateWithCountQueueingStrategy(
-      scope.GetScriptState(), erroring_source, 0);
-  ASSERT_TRUE(errored);
-  erroring_source->Error(
-      ScriptValue(scope.GetIsolate(), v8::Undefined(scope.GetIsolate())));
-
-  EXPECT_EQ(ReadableStreamOperations::IsReadable(
-                scope.GetScriptState(),
-                CheckedGetInternalStream(scope.GetScriptState(), readable),
-                ASSERT_NO_EXCEPTION),
-            base::make_optional(true));
-  EXPECT_EQ(ReadableStreamOperations::IsReadable(
-                scope.GetScriptState(),
-                CheckedGetInternalStream(scope.GetScriptState(), closed),
-                ASSERT_NO_EXCEPTION),
-            base::make_optional(false));
-  EXPECT_EQ(ReadableStreamOperations::IsReadable(
-                scope.GetScriptState(),
-                CheckedGetInternalStream(scope.GetScriptState(), errored),
-                ASSERT_NO_EXCEPTION),
-            base::make_optional(false));
-}
-
-TEST(ReadableStreamOperationsTest, IsClosed) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-
-  ReadableStream* readable =
-      ReadableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  ASSERT_TRUE(readable);
-
-  auto* closing_source =
-      MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
-  auto* closed = ReadableStream::CreateWithCountQueueingStrategy(
-      scope.GetScriptState(), closing_source, 0);
-  ASSERT_TRUE(closed);
-  closing_source->Close();
-
-  auto* erroring_source =
-      MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
-  auto* errored = ReadableStream::CreateWithCountQueueingStrategy(
-      scope.GetScriptState(), erroring_source, 0);
-  ASSERT_TRUE(errored);
-  erroring_source->Error(
-      ScriptValue(scope.GetIsolate(), v8::Undefined(scope.GetIsolate())));
-
-  EXPECT_EQ(ReadableStreamOperations::IsClosed(
-                scope.GetScriptState(),
-                CheckedGetInternalStream(scope.GetScriptState(), readable),
-                ASSERT_NO_EXCEPTION),
-            base::make_optional(false));
-  EXPECT_EQ(ReadableStreamOperations::IsClosed(
-                scope.GetScriptState(),
-                CheckedGetInternalStream(scope.GetScriptState(), closed),
-                ASSERT_NO_EXCEPTION),
-            base::make_optional(true));
-  EXPECT_EQ(ReadableStreamOperations::IsClosed(
-                scope.GetScriptState(),
-                CheckedGetInternalStream(scope.GetScriptState(), errored),
-                ASSERT_NO_EXCEPTION),
-            base::make_optional(false));
-}
-
-TEST(ReadableStreamOperationsTest, IsErrored) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-
-  auto* readable =
-      ReadableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  ASSERT_TRUE(readable);
-
-  auto* closing_source =
-      MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
-  ReadableStream* closed = ReadableStream::CreateWithCountQueueingStrategy(
-      scope.GetScriptState(), closing_source, 0);
-  ASSERT_TRUE(closed);
-  closing_source->Close();
-
-  auto* erroring_source =
-      MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
-  auto* errored = ReadableStream::CreateWithCountQueueingStrategy(
-      scope.GetScriptState(), erroring_source, 0);
-  ASSERT_TRUE(errored);
-  erroring_source->Error(
-      ScriptValue(scope.GetIsolate(), v8::Undefined(scope.GetIsolate())));
-
-  EXPECT_EQ(ReadableStreamOperations::IsErrored(
-                scope.GetScriptState(),
-                CheckedGetInternalStream(scope.GetScriptState(), readable),
-                ASSERT_NO_EXCEPTION),
-            base::make_optional(false));
-  EXPECT_EQ(ReadableStreamOperations::IsErrored(
-                scope.GetScriptState(),
-                CheckedGetInternalStream(scope.GetScriptState(), closed),
-                ASSERT_NO_EXCEPTION),
-            base::make_optional(false));
-  EXPECT_EQ(ReadableStreamOperations::IsErrored(
-                scope.GetScriptState(),
-                CheckedGetInternalStream(scope.GetScriptState(), errored),
-                ASSERT_NO_EXCEPTION),
-            base::make_optional(true));
-}
-
-TEST(ReadableStreamOperationsTest, Tee) {
-  ScopedStreamsNativeForTest enabled(false);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-  v8::Local<v8::Context> context = scope.GetScriptState()->GetContext();
-  NonThrowableExceptionState exception_state;
-  auto* source =
-      MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
-  auto* stream = ReadableStream::CreateWithCountQueueingStrategy(
-      scope.GetScriptState(), source, 0);
-  ASSERT_TRUE(stream);
-
-  ScriptValue result = ReadableStreamOperations::Tee(
-      scope.GetScriptState(),
-      CheckedGetInternalStream(scope.GetScriptState(), stream),
-      exception_state);
-  ASSERT_FALSE(result.IsEmpty());
-  ASSERT_TRUE(result.IsObject());
-
-  v8::Local<v8::Value> v8_branch1, v8_branch2;
-  ASSERT_TRUE(
-      result.V8Value().As<v8::Object>()->Get(context, 0).ToLocal(&v8_branch1));
-  ASSERT_TRUE(
-      result.V8Value().As<v8::Object>()->Get(context, 1).ToLocal(&v8_branch2));
-
-  ScriptValue new1(scope.GetIsolate(), v8_branch1);
-  ScriptValue new2(scope.GetIsolate(), v8_branch2);
-
-  ASSERT_TRUE(ReadableStreamOperations::IsReadableStream(
-                  scope.GetScriptState(), new1, ASSERT_NO_EXCEPTION)
-                  .value_or(true));
-  ASSERT_TRUE(ReadableStreamOperations::IsReadableStream(
-                  scope.GetScriptState(), new2, ASSERT_NO_EXCEPTION)
-                  .value_or(true));
-
-  ScriptValue reader1 = ReadableStreamOperations::GetReader(
-      scope.GetScriptState(), new1, exception_state);
-  ScriptValue reader2 = ReadableStreamOperations::GetReader(
-      scope.GetScriptState(), new2, exception_state);
-
-  ASSERT_FALSE(reader1.IsEmpty());
-  ASSERT_FALSE(reader2.IsEmpty());
-
-  Iteration* it1 = MakeGarbageCollected<Iteration>();
-  Iteration* it2 = MakeGarbageCollected<Iteration>();
-  ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader1)
-      .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it1),
-            ReadableStreamOperationsTestNotReached::CreateFunction(
-                scope.GetScriptState()));
-  ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader2)
-      .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it2),
-            ReadableStreamOperationsTestNotReached::CreateFunction(
-                scope.GetScriptState()));
-
-  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
-  EXPECT_FALSE(it1->IsSet());
-  EXPECT_FALSE(it2->IsSet());
-
-  source->Enqueue(
-      ScriptValue(scope.GetIsolate(), V8String(scope.GetIsolate(), "hello")));
-  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
-
-  EXPECT_TRUE(it1->IsSet());
-  EXPECT_TRUE(it1->IsValid());
-  EXPECT_FALSE(it1->IsDone());
-  EXPECT_EQ("hello", it1->Value());
-  EXPECT_TRUE(it2->IsSet());
-  EXPECT_TRUE(it2->IsValid());
-  EXPECT_FALSE(it2->IsDone());
-  EXPECT_EQ("hello", it2->Value());
-}
-
-TEST(ReadableStreamOperationsTest, Serialize) {
-  ScopedStreamsNativeForTest streams_native_enabled(false);
-  ScopedTransferableStreamsForTest transferable_streams_enabled(true);
-
-  V8TestingScope scope;
-  TryCatchScope try_catch_scope(scope.GetIsolate());
-  auto* source =
-      MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
-  auto* stream = ReadableStream::CreateWithCountQueueingStrategy(
-      scope.GetScriptState(), source, 0);
-  ASSERT_TRUE(stream);
-
-  source->Enqueue(
-      ScriptValue(scope.GetIsolate(), V8String(scope.GetIsolate(), "hello")));
-  ScriptValue internal_stream =
-      CheckedGetInternalStream(scope.GetScriptState(), stream);
-  auto* channel =
-      MakeGarbageCollected<MessageChannel>(scope.GetExecutionContext());
-  ReadableStreamOperations::Serialize(scope.GetScriptState(), internal_stream,
-                                      channel->port1(), ASSERT_NO_EXCEPTION);
-  EXPECT_TRUE(ReadableStreamOperations::IsLocked(
-      scope.GetScriptState(), internal_stream, ASSERT_NO_EXCEPTION));
-  ScriptValue transferred = ReadableStreamOperations::Deserialize(
-      scope.GetScriptState(), channel->port2(), ASSERT_NO_EXCEPTION);
-  ASSERT_FALSE(transferred.IsEmpty());
-  ScriptValue reader = ReadableStreamOperations::GetReader(
-      scope.GetScriptState(), transferred, ASSERT_NO_EXCEPTION);
-  ASSERT_FALSE(reader.IsEmpty());
-  Iteration* it = MakeGarbageCollected<Iteration>();
-  ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader)
-      .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it),
-            ReadableStreamOperationsTestNotReached::CreateFunction(
-                scope.GetScriptState()));
-  // Let the message pass through the MessagePort.
-  test::RunPendingTasks();
-  // Let the Read promise resolve.
-  v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
-
-  EXPECT_TRUE(it->IsSet());
-  EXPECT_TRUE(it->IsValid());
-  EXPECT_FALSE(it->IsDone());
-  EXPECT_EQ("hello", it->Value());
-}
-
-}  // namespace
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_reader.cc b/third_party/blink/renderer/core/streams/readable_stream_reader.cc
index 44b969d7..efc14b7 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_reader.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_reader.cc
@@ -19,7 +19,6 @@
     ScriptState* script_state,
     ReadableStream* stream,
     ExceptionState& exception_state) {
-  DCHECK(RuntimeEnabledFeatures::StreamsNativeEnabled());
   auto* stream_native = static_cast<ReadableStreamNative*>(stream);
   auto* reader = MakeGarbageCollected<ReadableStreamReader>(
       script_state, stream_native, exception_state);
diff --git a/third_party/blink/renderer/core/streams/readable_stream_test.cc b/third_party/blink/renderer/core/streams/readable_stream_test.cc
index 522f6f5..84c0d97 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_test.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_test.cc
@@ -29,9 +29,9 @@
 namespace {
 
 // Web platform tests test ReadableStream more thoroughly from scripts.
-class ReadableStreamTest : public testing::TestWithParam<bool> {
+class ReadableStreamTest : public testing::Test {
  public:
-  ReadableStreamTest() : feature_(GetParam()) {}
+  ReadableStreamTest() {}
 
   base::Optional<String> ReadAll(V8TestingScope& scope,
                                  ReadableStream* stream) {
@@ -40,7 +40,6 @@
     v8::Local<v8::Context> context = script_state->GetContext();
     v8::Local<v8::Value> v8_stream = ToV8(stream, context->Global(), isolate);
     v8::Local<v8::Object> global = context->Global();
-
     bool set_result = false;
     if (!global->Set(context, V8String(isolate, "stream"), v8_stream)
              .To(&set_result)) {
@@ -92,12 +91,9 @@
     NOTREACHED();
     return base::nullopt;
   }
-
- private:
-  ScopedStreamsNativeForTest feature_;
 };
 
-TEST_P(ReadableStreamTest, CreateWithoutArguments) {
+TEST_F(ReadableStreamTest, CreateWithoutArguments) {
   V8TestingScope scope;
 
   ReadableStream* stream =
@@ -106,7 +102,7 @@
   ASSERT_FALSE(scope.GetExceptionState().HadException());
 }
 
-TEST_P(ReadableStreamTest, CreateWithUnderlyingSourceOnly) {
+TEST_F(ReadableStreamTest, CreateWithUnderlyingSourceOnly) {
   V8TestingScope scope;
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
@@ -125,7 +121,7 @@
   EXPECT_TRUE(underlying_source->IsStartCalled());
 }
 
-TEST_P(ReadableStreamTest, CreateWithFullArguments) {
+TEST_F(ReadableStreamTest, CreateWithFullArguments) {
   V8TestingScope scope;
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
@@ -143,7 +139,7 @@
   EXPECT_TRUE(underlying_source->IsStartCalled());
 }
 
-TEST_P(ReadableStreamTest, CreateWithPathologicalStrategy) {
+TEST_F(ReadableStreamTest, CreateWithPathologicalStrategy) {
   V8TestingScope scope;
   auto* underlying_source =
       MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState());
@@ -164,7 +160,7 @@
 }
 
 // Testing getReader, locked, IsLocked and IsDisturbed.
-TEST_P(ReadableStreamTest, GetReader) {
+TEST_F(ReadableStreamTest, GetReader) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   v8::Isolate* isolate = scope.GetIsolate();
@@ -216,7 +212,7 @@
             base::make_optional(true));
 }
 
-TEST_P(ReadableStreamTest, Cancel) {
+TEST_F(ReadableStreamTest, Cancel) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   v8::Isolate* isolate = scope.GetIsolate();
@@ -241,7 +237,7 @@
   EXPECT_FALSE(underlying_source->IsCancelledWithNull());
 }
 
-TEST_P(ReadableStreamTest, CancelWithNull) {
+TEST_F(ReadableStreamTest, CancelWithNull) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   v8::Isolate* isolate = scope.GetIsolate();
@@ -269,7 +265,7 @@
 
 // TODO(yhirano): Write tests for pipeThrough and pipeTo.
 
-TEST_P(ReadableStreamTest, Tee) {
+TEST_F(ReadableStreamTest, Tee) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   v8::Isolate* isolate = scope.GetIsolate();
@@ -320,7 +316,7 @@
   EXPECT_EQ(*result2, "hello, bye");
 }
 
-TEST_P(ReadableStreamTest, Close) {
+TEST_F(ReadableStreamTest, Close) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   ExceptionState& exception_state = scope.GetExceptionState();
@@ -349,7 +345,7 @@
             base::make_optional(false));
 }
 
-TEST_P(ReadableStreamTest, Error) {
+TEST_F(ReadableStreamTest, Error) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   v8::Isolate* isolate = scope.GetIsolate();
@@ -379,7 +375,7 @@
             base::make_optional(true));
 }
 
-TEST_P(ReadableStreamTest, LockAndDisturb) {
+TEST_F(ReadableStreamTest, LockAndDisturb) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   ExceptionState& exception_state = scope.GetExceptionState();
@@ -405,7 +401,7 @@
             base::make_optional(true));
 }
 
-TEST_P(ReadableStreamTest, Serialize) {
+TEST_F(ReadableStreamTest, Serialize) {
   ScopedTransferableStreamsForTest enabled(true);
 
   V8TestingScope scope;
@@ -436,7 +432,7 @@
             base::make_optional<String>("hello, bye"));
 }
 
-TEST_P(ReadableStreamTest, GetReadHandle) {
+TEST_F(ReadableStreamTest, GetReadHandle) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   auto* isolate = scope.GetIsolate();
@@ -516,8 +512,6 @@
   EXPECT_TRUE(done);
 }
 
-INSTANTIATE_TEST_SUITE_P(, ReadableStreamTest, ::testing::Values(false, true));
-
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_wrapper.cc b/third_party/blink/renderer/core/streams/readable_stream_wrapper.cc
deleted file mode 100644
index 61c222c..0000000
--- a/third_party/blink/renderer/core/streams/readable_stream_wrapper.cc
+++ /dev/null
@@ -1,439 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/streams/readable_stream_wrapper.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
-#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_operations.h"
-#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-
-namespace blink {
-
-class ReadableStreamWrapper::ReadHandleImpl final
-    : public ReadableStream::ReadHandle {
- public:
-  ReadHandleImpl(v8::Isolate* isolate, v8::Local<v8::Value> reader)
-      : reader_(isolate, reader) {}
-
-  ~ReadHandleImpl() override = default;
-
-  ScriptPromise Read(ScriptState* script_state) override {
-    return ReadableStreamOperations::DefaultReaderRead(
-        script_state,
-        ScriptValue(script_state->GetIsolate(),
-                    reader_.NewLocal(script_state->GetIsolate())));
-  }
-
-  void Trace(Visitor* visitor) override {
-    visitor->Trace(reader_);
-    ReadHandle::Trace(visitor);
-  }
-
- private:
-  TraceWrapperV8Reference<v8::Value> reader_;
-};
-
-void ReadableStreamWrapper::Init(ScriptState* script_state,
-                                 ScriptValue underlying_source,
-                                 ScriptValue strategy,
-                                 ExceptionState& exception_state) {
-  ScriptValue value = ReadableStreamOperations::CreateReadableStream(
-      script_state, underlying_source, strategy, exception_state);
-  if (exception_state.HadException())
-    return;
-
-  DCHECK(value.IsObject());
-  InitWithInternalStream(script_state, value.V8Value().As<v8::Object>(),
-                         exception_state);
-}
-
-void ReadableStreamWrapper::InitWithInternalStream(
-    ScriptState* script_state,
-    v8::Local<v8::Object> object,
-    ExceptionState& exception_state) {
-  DCHECK(ReadableStreamOperations::IsReadableStreamForDCheck(
-      script_state, ScriptValue(script_state->GetIsolate(), object)));
-  object_.Set(script_state->GetIsolate(), object);
-
-  v8::Isolate* isolate = script_state->GetIsolate();
-  v8::TryCatch block(isolate);
-  v8::Local<v8::Value> wrapper = ToV8(this, script_state);
-  if (wrapper.IsEmpty()) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-
-  v8::Local<v8::Context> context = script_state->GetContext();
-  v8::Local<v8::Object> bindings =
-      context->GetExtrasBindingObject().As<v8::Object>();
-  v8::Local<v8::Value> symbol_value;
-  if (!bindings->Get(context, V8String(isolate, "internalReadableStreamSymbol"))
-           .ToLocal(&symbol_value)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-
-  if (wrapper.As<v8::Object>()
-          ->Set(context, symbol_value.As<v8::Symbol>(), object)
-          .IsNothing()) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-}
-
-ReadableStreamWrapper* ReadableStreamWrapper::Create(
-    ScriptState* script_state,
-    ScriptValue underlying_source,
-    ScriptValue strategy,
-    ExceptionState& exception_state) {
-  auto* stream = MakeGarbageCollected<ReadableStreamWrapper>();
-  stream->Init(script_state, underlying_source, strategy, exception_state);
-  if (exception_state.HadException())
-    return nullptr;
-  return stream;
-}
-
-ReadableStreamWrapper* ReadableStreamWrapper::CreateFromInternalStream(
-    ScriptState* script_state,
-    ScriptValue object,
-    ExceptionState& exception_state) {
-  DCHECK(object.IsObject());
-  return CreateFromInternalStream(
-      script_state, object.V8Value().As<v8::Object>(), exception_state);
-}
-
-ReadableStreamWrapper* ReadableStreamWrapper::CreateFromInternalStream(
-    ScriptState* script_state,
-    v8::Local<v8::Object> object,
-    ExceptionState& exception_state) {
-  auto* stream = MakeGarbageCollected<ReadableStreamWrapper>();
-  stream->InitWithInternalStream(script_state, object, exception_state);
-  if (exception_state.HadException())
-    return nullptr;
-  return stream;
-}
-
-ReadableStreamWrapper* ReadableStreamWrapper::CreateWithCountQueueingStrategy(
-    ScriptState* script_state,
-    UnderlyingSourceBase* underlying_source,
-    size_t high_water_mark) {
-  v8::TryCatch block(script_state->GetIsolate());
-  ScriptValue strategy =
-      ReadableStreamOperations::CreateCountQueuingStrategy(script_state, 0);
-  if (strategy.IsEmpty())
-    return nullptr;
-
-  ScriptValue value = ReadableStreamOperations::CreateReadableStream(
-      script_state, underlying_source, strategy);
-  if (value.IsEmpty())
-    return nullptr;
-
-  ExceptionState exception_state(script_state->GetIsolate(),
-                                 ExceptionState::kConstructionContext,
-                                 "ReadableStream");
-  DCHECK(value.V8Value()->IsObject());
-  auto* stream = CreateFromInternalStream(script_state, value, exception_state);
-  if (exception_state.HadException())
-    exception_state.ClearException();
-  return stream;
-}
-
-void ReadableStreamWrapper::Trace(Visitor* visitor) {
-  visitor->Trace(object_);
-  ReadableStream::Trace(visitor);
-}
-
-ScriptPromise ReadableStreamWrapper::cancel(ScriptState* script_state,
-                                            ExceptionState& exception_state) {
-  return cancel(script_state,
-                ScriptValue(script_state->GetIsolate(),
-                            v8::Undefined(script_state->GetIsolate())),
-                exception_state);
-}
-
-bool ReadableStreamWrapper::locked(ScriptState* script_state,
-                                   ExceptionState& exception_state) const {
-  auto result = IsLocked(script_state, exception_state);
-
-  return !result || *result;
-}
-
-ScriptPromise ReadableStreamWrapper::cancel(ScriptState* script_state,
-                                            ScriptValue reason,
-                                            ExceptionState& exception_state) {
-  if (locked(script_state, exception_state) &&
-      !exception_state.HadException()) {
-    exception_state.ThrowTypeError("Cannot cancel a locked stream");
-  }
-
-  if (exception_state.HadException())
-    return ScriptPromise();
-
-  return ReadableStreamOperations::Cancel(
-      script_state, GetInternalStream(script_state), reason, exception_state);
-}
-
-ScriptValue ReadableStreamWrapper::getReader(ScriptState* script_state,
-                                             ExceptionState& exception_state) {
-  return ReadableStreamOperations::GetReader(
-      script_state, GetInternalStream(script_state), exception_state);
-}
-
-ScriptValue ReadableStreamWrapper::getReader(ScriptState* script_state,
-                                             ScriptValue options,
-                                             ExceptionState& exception_state) {
-  GetReaderValidateOptions(script_state, options, exception_state);
-  if (exception_state.HadException()) {
-    return ScriptValue();
-  }
-  return ReadableStreamOperations::GetReader(
-      script_state, GetInternalStream(script_state), exception_state);
-}
-
-ScriptValue ReadableStreamWrapper::pipeThrough(
-    ScriptState* script_state,
-    ScriptValue transform_stream,
-    ExceptionState& exception_state) {
-  return pipeThrough(script_state, transform_stream,
-                     ScriptValue(script_state->GetIsolate(),
-                                 v8::Undefined(script_state->GetIsolate())),
-                     exception_state);
-}
-
-// https://streams.spec.whatwg.org/#rs-pipe-through
-ScriptValue ReadableStreamWrapper::pipeThrough(
-    ScriptState* script_state,
-    ScriptValue transform_stream,
-    ScriptValue options,
-    ExceptionState& exception_state) {
-  ScriptValue readable;
-  WritableStream* writable = nullptr;
-  PipeThroughExtractReadableWritable(script_state, this, transform_stream,
-                                     &readable, &writable, exception_state);
-  if (exception_state.HadException()) {
-    return ScriptValue();
-  }
-
-  DCHECK(!RuntimeEnabledFeatures::StreamsNativeEnabled());
-
-  // This cast is safe because the following code will only be run when the
-  // native version of WritableStream is not in use.
-  WritableStreamWrapper* writable_wrapper =
-      static_cast<WritableStreamWrapper*>(writable);
-
-  // 8. Let _promise_ be ! ReadableStreamPipeTo(*this*, _writable_,
-  //    _preventClose_, _preventAbort_, _preventCancel_,
-  //   _signal_).
-
-  ScriptPromise promise = ReadableStreamOperations::PipeTo(
-      script_state, GetInternalStream(script_state),
-      writable_wrapper->GetInternalStream(script_state), options,
-      exception_state);
-  if (exception_state.HadException()) {
-    return ScriptValue();
-  }
-
-  // 9. Set _promise_.[[PromiseIsHandled]] to *true*.
-  promise.MarkAsHandled();
-
-  // 10. Return _readable_.
-  return readable;
-}
-
-ScriptPromise ReadableStreamWrapper::pipeTo(ScriptState* script_state,
-                                            ScriptValue destination,
-                                            ExceptionState& exception_state) {
-  return pipeTo(script_state, destination,
-                ScriptValue(script_state->GetIsolate(),
-                            v8::Undefined(script_state->GetIsolate())),
-                exception_state);
-}
-
-ScriptPromise ReadableStreamWrapper::pipeTo(ScriptState* script_state,
-                                            ScriptValue destination_value,
-                                            ScriptValue options,
-                                            ExceptionState& exception_state) {
-  WritableStream* destination = PipeToCheckSourceAndDestination(
-      script_state, this, destination_value, exception_state);
-  if (exception_state.HadException()) {
-    return ScriptPromise();
-  }
-  DCHECK(destination);
-
-  DCHECK(!RuntimeEnabledFeatures::StreamsNativeEnabled());
-
-  // This cast is safe because the following code will only be run when the
-  // native version of WritableStream is not in use.
-  WritableStreamWrapper* destination_wrapper =
-      static_cast<WritableStreamWrapper*>(destination);
-
-  return ReadableStreamOperations::PipeTo(
-      script_state, GetInternalStream(script_state),
-      destination_wrapper->GetInternalStream(script_state), options,
-      exception_state);
-}
-
-ScriptValue ReadableStreamWrapper::tee(ScriptState* script_state,
-                                       ExceptionState& exception_state) {
-  return CallTeeAndReturnBranchArray(script_state, this, exception_state);
-}
-
-void ReadableStreamWrapper::Tee(ScriptState* script_state,
-                                ReadableStream** branch1,
-                                ReadableStream** branch2,
-                                ExceptionState& exception_state) {
-  v8::Local<v8::Context> context = script_state->GetContext();
-
-  if (locked(script_state, exception_state) &&
-      !exception_state.HadException()) {
-    exception_state.ThrowTypeError("The stream is already locked.");
-  }
-
-  if (exception_state.HadException())
-    return;
-
-  ScriptValue tee_result = ReadableStreamOperations::Tee(
-      script_state, GetInternalStream(script_state), exception_state);
-  if (tee_result.IsEmpty())
-    return;
-
-  DCHECK(!exception_state.HadException());
-  DCHECK(tee_result.V8Value()->IsArray());
-
-  v8::Local<v8::Array> branches = tee_result.V8Value().As<v8::Array>();
-  v8::Local<v8::Value> v8_branch1, v8_branch2;
-  v8::TryCatch block(script_state->GetIsolate());
-
-  if (!branches->Get(context, 0).ToLocal(&v8_branch1)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-  if (!branches->Get(context, 1).ToLocal(&v8_branch2)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-
-  DCHECK(v8_branch1->IsObject());
-  DCHECK(v8_branch2->IsObject());
-
-  ReadableStreamWrapper* temp_branch1 =
-      MakeGarbageCollected<ReadableStreamWrapper>();
-  ReadableStreamWrapper* temp_branch2 =
-      MakeGarbageCollected<ReadableStreamWrapper>();
-
-  temp_branch1->InitWithInternalStream(
-      script_state, v8_branch1.As<v8::Object>(), exception_state);
-  if (exception_state.HadException())
-    return;
-
-  temp_branch2->InitWithInternalStream(
-      script_state, v8_branch2.As<v8::Object>(), exception_state);
-  if (exception_state.HadException())
-    return;
-
-  *branch1 = temp_branch1;
-  *branch2 = temp_branch2;
-}
-
-ReadableStream::ReadHandle* ReadableStreamWrapper::GetReadHandle(
-    ScriptState* script_state,
-    ExceptionState& exception_state) {
-  ScriptValue reader = ReadableStreamOperations::GetReader(
-      script_state, GetInternalStream(script_state), exception_state);
-  if (exception_state.HadException()) {
-    return nullptr;
-  }
-  return MakeGarbageCollected<ReadHandleImpl>(script_state->GetIsolate(),
-                                              reader.V8Value());
-}
-
-base::Optional<bool> ReadableStreamWrapper::IsLocked(
-    ScriptState* script_state,
-    ExceptionState& exception_state) const {
-  return ReadableStreamOperations::IsLocked(
-      script_state, GetInternalStream(script_state), exception_state);
-}
-
-base::Optional<bool> ReadableStreamWrapper::IsDisturbed(
-    ScriptState* script_state,
-    ExceptionState& exception_state) const {
-  return ReadableStreamOperations::IsDisturbed(
-      script_state, GetInternalStream(script_state), exception_state);
-}
-
-base::Optional<bool> ReadableStreamWrapper::IsReadable(
-    ScriptState* script_state,
-    ExceptionState& exception_state) const {
-  return ReadableStreamOperations::IsReadable(
-      script_state, GetInternalStream(script_state), exception_state);
-}
-
-base::Optional<bool> ReadableStreamWrapper::IsClosed(
-    ScriptState* script_state,
-    ExceptionState& exception_state) const {
-  return ReadableStreamOperations::IsClosed(
-      script_state, GetInternalStream(script_state), exception_state);
-}
-
-base::Optional<bool> ReadableStreamWrapper::IsErrored(
-    ScriptState* script_state,
-    ExceptionState& exception_state) const {
-  return ReadableStreamOperations::IsErrored(
-      script_state, GetInternalStream(script_state), exception_state);
-}
-
-void ReadableStreamWrapper::LockAndDisturb(ScriptState* script_state,
-                                           ExceptionState& exception_state) {
-  ScriptState::Scope scope(script_state);
-
-  const base::Optional<bool> is_locked =
-      IsLocked(script_state, exception_state);
-  if (!is_locked || is_locked.value())
-    return;
-
-  ScriptValue reader = getReader(script_state, exception_state);
-  if (reader.IsEmpty())
-    return;
-
-  ScriptPromise promise =
-      ReadableStreamOperations::DefaultReaderRead(script_state, reader);
-  promise.MarkAsHandled();
-}
-
-void ReadableStreamWrapper::Serialize(ScriptState* script_state,
-                                      MessagePort* port,
-                                      ExceptionState& exception_state) {
-  ReadableStreamOperations::Serialize(
-      script_state, GetInternalStream(script_state), port, exception_state);
-}
-
-// static
-ReadableStreamWrapper* ReadableStreamWrapper::Deserialize(
-    ScriptState* script_state,
-    MessagePort* port,
-    ExceptionState& exception_state) {
-  // We need to execute V8 Extras JavaScript to create the new ReadableStream.
-  // We will not run author code.
-  v8::Isolate::AllowJavascriptExecutionScope allow_js(
-      script_state->GetIsolate());
-  ScriptValue internal_stream = ReadableStreamOperations::Deserialize(
-      script_state, port, exception_state);
-  if (exception_state.HadException())
-    return nullptr;
-  return CreateFromInternalStream(script_state, internal_stream,
-                                  exception_state);
-}
-
-ScriptValue ReadableStreamWrapper::GetInternalStream(
-    ScriptState* script_state) const {
-  return ScriptValue(script_state->GetIsolate(),
-                     object_.NewLocal(script_state->GetIsolate()));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/readable_stream_wrapper.h b/third_party/blink/renderer/core/streams/readable_stream_wrapper.h
deleted file mode 100644
index de06dee..0000000
--- a/third_party/blink/renderer/core/streams/readable_stream_wrapper.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_WRAPPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_WRAPPER_H_
-
-#include "base/optional.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/core/streams/readable_stream.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-// This is an implementation of the corresponding IDL interface.
-class CORE_EXPORT ReadableStreamWrapper : public ReadableStream {
- public:
-  // Call one of Init functions before using the instance.
-  ReadableStreamWrapper() = default;
-  ~ReadableStreamWrapper() override = default;
-
-  // If an error happens, |exception_state.HadException()| will be true, and
-  // |this| will not be usable after that.
-  void Init(ScriptState*,
-            ScriptValue underlying_source,
-            ScriptValue strategy,
-            ExceptionState& exception_state);
-  void InitWithInternalStream(ScriptState*,
-                              v8::Local<v8::Object> object,
-                              ExceptionState& exception_state);
-
-  // Create* functions call Init* internally and returns null when an error
-  // happens.
-  static ReadableStreamWrapper* Create(ScriptState*,
-                                       ScriptValue underlying_source,
-                                       ScriptValue strategy,
-                                       ExceptionState&);
-  static ReadableStreamWrapper* CreateFromInternalStream(
-      ScriptState*,
-      v8::Local<v8::Object> object,
-      ExceptionState&);
-  static ReadableStreamWrapper* CreateFromInternalStream(ScriptState*,
-                                                         ScriptValue object,
-                                                         ExceptionState&);
-  // This function doesn't take ExceptionState because the caller cannot have
-  // one. Returns null when an error happens.
-  static ReadableStreamWrapper* CreateWithCountQueueingStrategy(
-      ScriptState*,
-      UnderlyingSourceBase* underlying_source,
-      size_t high_water_mark);
-
-  void Trace(Visitor* visitor) override;
-
-  // IDL defined functions
-  bool locked(ScriptState*, ExceptionState&) const override;
-  ScriptPromise cancel(ScriptState*, ExceptionState&) override;
-  ScriptPromise cancel(ScriptState*,
-                       ScriptValue reason,
-                       ExceptionState&) override;
-  ScriptValue getReader(ScriptState*, ExceptionState&) override;
-  ScriptValue getReader(ScriptState*,
-                        ScriptValue options,
-                        ExceptionState&) override;
-  ScriptValue pipeThrough(ScriptState*,
-                          ScriptValue transform_stream,
-                          ExceptionState&) override;
-  ScriptValue pipeThrough(ScriptState*,
-                          ScriptValue transform_stream,
-                          ScriptValue options,
-                          ExceptionState&) override;
-  ScriptPromise pipeTo(ScriptState*,
-                       ScriptValue destination,
-                       ExceptionState&) override;
-  ScriptPromise pipeTo(ScriptState*,
-                       ScriptValue destination,
-                       ScriptValue options,
-                       ExceptionState&) override;
-  ScriptValue tee(ScriptState*, ExceptionState&) override;
-
-  void Tee(ScriptState*,
-           ReadableStream** branch1,
-           ReadableStream** branch2,
-           ExceptionState&) override;
-
-  ReadHandle* GetReadHandle(ScriptState*, ExceptionState&) override;
-
-  base::Optional<bool> IsLocked(ScriptState*, ExceptionState&) const override;
-  base::Optional<bool> IsDisturbed(ScriptState*,
-                                   ExceptionState&) const override;
-  base::Optional<bool> IsReadable(ScriptState*, ExceptionState&) const override;
-  base::Optional<bool> IsClosed(ScriptState*, ExceptionState&) const override;
-  base::Optional<bool> IsErrored(ScriptState*, ExceptionState&) const override;
-
-  // Makes this stream locked and disturbed.
-  void LockAndDisturb(ScriptState*, ExceptionState&) override;
-
-  // Serialize this stream to |port|. The stream will be locked by this
-  // operation.
-  void Serialize(ScriptState*, MessagePort* port, ExceptionState&) override;
-
-  // Given a |port| which is entangled with a MessagePort that was previously
-  // passed to Serialize(), returns a new ReadableStreamWrapper which behaves
-  // like it was the original.
-  static ReadableStreamWrapper* Deserialize(ScriptState*,
-                                            MessagePort* port,
-                                            ExceptionState&);
-
-  ScriptValue GetInternalStream(ScriptState* script_state) const;
-
-  // In some cases we are known to fail to trace the stream correctly. In such
-  // cases |object_| will be silently gone. This function is for detecting the
-  // issue. Use this function at places where an actual crash happens. Do not
-  // use this function to write "just in case" code.
-  bool IsBroken() const override { return object_.IsEmpty(); }
-
- private:
-  class ReadHandleImpl;
-
-  TraceWrapperV8Reference<v8::Object> object_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_READABLE_STREAM_WRAPPER_H_
diff --git a/third_party/blink/renderer/core/streams/transform_stream.cc b/third_party/blink/renderer/core/streams/transform_stream.cc
index 193df1c..be44552 100644
--- a/third_party/blink/renderer/core/streams/transform_stream.cc
+++ b/third_party/blink/renderer/core/streams/transform_stream.cc
@@ -8,12 +8,10 @@
 #include "third_party/blink/renderer/core/streams/readable_stream.h"
 #include "third_party/blink/renderer/core/streams/transform_stream_native.h"
 #include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
-#include "third_party/blink/renderer/core/streams/transform_stream_wrapper.h"
-#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -59,15 +57,9 @@
                                          ExceptionState& exception_state) {
   auto* ts = MakeGarbageCollected<TransformStream>();
 
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    TransformStreamNative::InitFromJS(
-        script_state, transformer, writable_strategy, readable_strategy,
-        &ts->readable_, &ts->writable_, exception_state);
-  } else {
-    TransformStreamWrapper::InitFromJS(
-        script_state, transformer, writable_strategy, readable_strategy,
-        &ts->readable_, &ts->writable_, exception_state);
-  }
+  TransformStreamNative::InitFromJS(
+      script_state, transformer, writable_strategy, readable_strategy,
+      &ts->readable_, &ts->writable_, exception_state);
 
   if (exception_state.HadException()) {
     return nullptr;
@@ -79,13 +71,8 @@
 void TransformStream::Init(TransformStreamTransformer* transformer,
                            ScriptState* script_state,
                            ExceptionState& exception_state) {
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    TransformStreamNative::Init(script_state, transformer, &readable_,
-                                &writable_, exception_state);
-  } else {
-    TransformStreamWrapper::Init(script_state, transformer, &readable_,
-                                 &writable_, exception_state);
-  }
+  TransformStreamNative::Init(script_state, transformer, &readable_, &writable_,
+                              exception_state);
 
   if (exception_state.HadException()) {
     return;
diff --git a/third_party/blink/renderer/core/streams/transform_stream.h b/third_party/blink/renderer/core/streams/transform_stream.h
index b46bde0d..11d9514 100644
--- a/third_party/blink/renderer/core/streams/transform_stream.h
+++ b/third_party/blink/renderer/core/streams/transform_stream.h
@@ -9,7 +9,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
diff --git a/third_party/blink/renderer/core/streams/transform_stream_default_controller_wrapper.cc b/third_party/blink/renderer/core/streams/transform_stream_default_controller_wrapper.cc
deleted file mode 100644
index c421610..0000000
--- a/third_party/blink/renderer/core/streams/transform_stream_default_controller_wrapper.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_wrapper.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-
-namespace blink {
-
-TransformStreamDefaultControllerWrapper::
-    TransformStreamDefaultControllerWrapper(ScriptState* script_state,
-                                            v8::Local<v8::Value> controller)
-    : script_state_(script_state), controller_(controller) {
-  DCHECK(controller->IsObject());
-}
-
-void TransformStreamDefaultControllerWrapper::Enqueue(
-    v8::Local<v8::Value> chunk,
-    ExceptionState& exception_state) {
-  DCHECK(controller_->IsObject());
-  v8::Local<v8::Value> args[] = {controller_, chunk};
-  v8::TryCatch block(script_state_->GetIsolate());
-  V8ScriptRunner::CallExtra(script_state_,
-                            "TransformStreamDefaultControllerEnqueue", args);
-  if (block.HasCaught()) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/transform_stream_default_controller_wrapper.h b/third_party/blink/renderer/core/streams/transform_stream_default_controller_wrapper.h
deleted file mode 100644
index 7c60936..0000000
--- a/third_party/blink/renderer/core/streams/transform_stream_default_controller_wrapper.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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_CORE_STREAMS_TRANSFORM_STREAM_DEFAULT_CONTROLLER_WRAPPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_TRANSFORM_STREAM_DEFAULT_CONTROLLER_WRAPPER_H_
-
-#include "base/macros.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_interface.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-// Implementation of TransformStreamDefaultControllerInterface for the V8 Extras
-// implementation of Streams.
-class CORE_EXPORT TransformStreamDefaultControllerWrapper final
-    : public TransformStreamDefaultControllerInterface {
-  STACK_ALLOCATED();
-
- public:
-  TransformStreamDefaultControllerWrapper(ScriptState*,
-                                          v8::Local<v8::Value> controller);
-
-  void Enqueue(v8::Local<v8::Value> chunk, ExceptionState&) override;
-
- private:
-  Member<ScriptState> script_state_;
-  v8::Local<v8::Value> controller_;
-
-  DISALLOW_COPY_AND_ASSIGN(TransformStreamDefaultControllerWrapper);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_TRANSFORM_STREAM_DEFAULT_CONTROLLER_WRAPPER_H_
diff --git a/third_party/blink/renderer/core/streams/transform_stream_test.cc b/third_party/blink/renderer/core/streams/transform_stream_test.cc
index 5c735c28..173e331 100644
--- a/third_party/blink/renderer/core/streams/transform_stream_test.cc
+++ b/third_party/blink/renderer/core/streams/transform_stream_test.cc
@@ -23,7 +23,6 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/to_v8.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "v8/include/v8.h"
 
@@ -33,9 +32,9 @@
 using ::testing::_;
 using ::testing::Mock;
 
-class TransformStreamTest : public ::testing::TestWithParam<bool> {
+class TransformStreamTest : public ::testing::Test {
  public:
-  TransformStreamTest() : feature_(GetParam()) {}
+  TransformStreamTest() {}
 
   TransformStream* Stream() const { return stream_; }
 
@@ -67,7 +66,6 @@
 
  private:
   Persistent<TransformStream> stream_;
-  ScopedStreamsNativeForTest feature_;
 };
 
 class IdentityTransformer final : public TransformStreamTransformer {
@@ -120,14 +118,14 @@
 };
 
 // If this doesn't work then nothing else will.
-TEST_P(TransformStreamTest, Construct) {
+TEST_F(TransformStreamTest, Construct) {
   V8TestingScope scope;
   Init(MakeGarbageCollected<IdentityTransformer>(scope.GetScriptState()),
        scope.GetScriptState(), ASSERT_NO_EXCEPTION);
   EXPECT_TRUE(Stream());
 }
 
-TEST_P(TransformStreamTest, Accessors) {
+TEST_F(TransformStreamTest, Accessors) {
   V8TestingScope scope;
   Init(MakeGarbageCollected<IdentityTransformer>(scope.GetScriptState()),
        scope.GetScriptState(), ASSERT_NO_EXCEPTION);
@@ -137,7 +135,7 @@
   EXPECT_TRUE(writable);
 }
 
-TEST_P(TransformStreamTest, TransformIsCalled) {
+TEST_F(TransformStreamTest, TransformIsCalled) {
   V8TestingScope scope;
   auto* mock = MakeGarbageCollected<MockTransformStreamTransformer>(
       scope.GetScriptState());
@@ -158,7 +156,7 @@
   Mock::AllowLeak(mock);
 }
 
-TEST_P(TransformStreamTest, FlushIsCalled) {
+TEST_F(TransformStreamTest, FlushIsCalled) {
   V8TestingScope scope;
   auto* mock = MakeGarbageCollected<MockTransformStreamTransformer>(
       scope.GetScriptState());
@@ -217,7 +215,7 @@
   return Has("name", "TypeError") && Has("message", message);
 }
 
-TEST_P(TransformStreamTest, EnqueueFromTransform) {
+TEST_F(TransformStreamTest, EnqueueFromTransform) {
   V8TestingScope scope;
   auto* script_state = scope.GetScriptState();
   Init(MakeGarbageCollected<IdentityTransformer>(scope.GetScriptState()),
@@ -238,7 +236,7 @@
   EXPECT_TRUE(IsIteratorForStringMatching(script_state, tester.Value(), "a"));
 }
 
-TEST_P(TransformStreamTest, EnqueueFromFlush) {
+TEST_F(TransformStreamTest, EnqueueFromFlush) {
   class EnqueueFromFlushTransformer : public TransformStreamTransformer {
    public:
     explicit EnqueueFromFlushTransformer(ScriptState* script_state)
@@ -280,7 +278,7 @@
   EXPECT_TRUE(IsIteratorForStringMatching(script_state, tester.Value(), "a"));
 }
 
-TEST_P(TransformStreamTest, ThrowFromTransform) {
+TEST_F(TransformStreamTest, ThrowFromTransform) {
   static constexpr char kMessage[] = "errorInTransform";
   class ThrowFromTransformTransformer : public TransformStreamTransformer {
    public:
@@ -331,7 +329,7 @@
   EXPECT_TRUE(IsTypeError(script_state, write_tester.Value(), kMessage));
 }
 
-TEST_P(TransformStreamTest, ThrowFromFlush) {
+TEST_F(TransformStreamTest, ThrowFromFlush) {
   static constexpr char kMessage[] = "errorInFlush";
   class ThrowFromFlushTransformer : public TransformStreamTransformer {
    public:
@@ -380,7 +378,7 @@
   EXPECT_TRUE(IsTypeError(script_state, write_tester.Value(), kMessage));
 }
 
-TEST_P(TransformStreamTest, CreateFromReadableWritablePair) {
+TEST_F(TransformStreamTest, CreateFromReadableWritablePair) {
   V8TestingScope scope;
   ReadableStream* readable =
       ReadableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
@@ -391,7 +389,5 @@
   EXPECT_EQ(writable, transform.Writable());
 }
 
-INSTANTIATE_TEST_SUITE_P(, TransformStreamTest, ::testing::Values(false, true));
-
 }  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/transform_stream_wrapper.cc b/third_party/blink/renderer/core/streams/transform_stream_wrapper.cc
deleted file mode 100644
index 5069438..0000000
--- a/third_party/blink/renderer/core/streams/transform_stream_wrapper.cc
+++ /dev/null
@@ -1,222 +0,0 @@
-// 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/core/streams/transform_stream_wrapper.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
-#include "third_party/blink/renderer/core/streams/readable_stream.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_wrapper.h"
-#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_interface.h"
-#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_wrapper.h"
-#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
-#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
-
-namespace blink {
-
-// Base class for FlushAlgorithm and TransformAlgorithm. Contains common
-// construction code and members.
-class TransformStreamWrapper::Algorithm : public ScriptFunction {
- public:
-  // This is templated just to avoid having two identical copies of the
-  // function.
-  template <typename T>
-  static v8::Local<v8::Function> Create(TransformStreamTransformer* transformer,
-                                        ScriptState* script_state,
-                                        ExceptionState& exception_state) {
-    auto* algorithm =
-        MakeGarbageCollected<T>(transformer, script_state, exception_state);
-    return algorithm->BindToV8Function();
-  }
-
-  Algorithm(TransformStreamTransformer* transformer,
-            ScriptState* script_state,
-            ExceptionState& exception_state)
-      : ScriptFunction(script_state),
-        transformer_(transformer),
-        interface_name_(exception_state.InterfaceName()),
-        property_name_(exception_state.PropertyName()) {}
-
-  void Trace(Visitor* visitor) override {
-    visitor->Trace(transformer_);
-    ScriptFunction::Trace(visitor);
-  }
-
- protected:
-  // AlgorithmScope holds the stack-allocated objects used by the CallRaw()
-  // methods for FlushAlgorithm and TransformAlgorithm.
-  class AlgorithmScope {
-    STACK_ALLOCATED();
-
-   public:
-    AlgorithmScope(Algorithm* owner,
-                   const v8::FunctionCallbackInfo<v8::Value>& info,
-                   v8::Local<v8::Value> controller)
-        : controller_(owner->GetScriptState(), controller),
-          exception_state_(owner->GetScriptState()->GetIsolate(),
-                           // Using the original context would result in every
-                           // exception claiming to have happened during
-                           // construction. Since that is not helpful, don't
-                           // annotate exceptions with where we think they came
-                           // from.
-                           ExceptionState::kUnknownContext,
-                           owner->interface_name_,
-                           owner->property_name_),
-          reject_promise_scope_(info, exception_state_) {}
-
-    TransformStreamDefaultControllerInterface* GetController() {
-      return &controller_;
-    }
-
-    ExceptionState* GetExceptionState() { return &exception_state_; }
-
-   private:
-    TransformStreamDefaultControllerWrapper controller_;
-    ExceptionState exception_state_;
-    ExceptionToRejectPromiseScope reject_promise_scope_;
-  };
-
-  Member<TransformStreamTransformer> transformer_;
-  const char* const interface_name_;
-  const char* const property_name_;
-};
-
-class TransformStreamWrapper::FlushAlgorithm
-    : public TransformStreamWrapper::Algorithm {
- protected:
-  using Algorithm::Algorithm;
-
- private:
-  void CallRaw(const v8::FunctionCallbackInfo<v8::Value>& info) override {
-    DCHECK_EQ(info.Length(), 1);
-    AlgorithmScope algorithm_scope(this, info, info[0]);
-    ExceptionState& exception_state = *algorithm_scope.GetExceptionState();
-
-    transformer_->Flush(algorithm_scope.GetController(), exception_state);
-    if (exception_state.HadException())
-      return;
-    V8SetReturnValue(info,
-                     ScriptPromise::CastUndefined(GetScriptState()).V8Value());
-  }
-};
-
-class TransformStreamWrapper::TransformAlgorithm
-    : public TransformStreamWrapper::Algorithm {
- protected:
-  using Algorithm::Algorithm;
-
- private:
-  void CallRaw(const v8::FunctionCallbackInfo<v8::Value>& info) override {
-    DCHECK_EQ(info.Length(), 2);
-    AlgorithmScope algorithm_scope(this, info, info[1]);
-    ExceptionState& exception_state = *algorithm_scope.GetExceptionState();
-
-    transformer_->Transform(info[0], algorithm_scope.GetController(),
-                            exception_state);
-    if (exception_state.HadException())
-      return;
-    V8SetReturnValue(info,
-                     ScriptPromise::CastUndefined(GetScriptState()).V8Value());
-  }
-};
-
-// static
-void TransformStreamWrapper::InitFromJS(ScriptState* script_state,
-                                        ScriptValue transformer,
-                                        ScriptValue writable_strategy,
-                                        ScriptValue readable_strategy,
-                                        Member<ReadableStream>* readable,
-                                        Member<WritableStream>* writable,
-                                        ExceptionState& exception_state) {
-  DCHECK(!RuntimeEnabledFeatures::StreamsNativeEnabled());
-
-  v8::Local<v8::Value> args[] = {transformer.V8Value(),
-                                 writable_strategy.V8Value(),
-                                 readable_strategy.V8Value()};
-  v8::Local<v8::Value> stream;
-  {
-    v8::TryCatch block(script_state->GetIsolate());
-    if (!V8ScriptRunner::CallExtra(script_state, "createTransformStream", args)
-             .ToLocal(&stream)) {
-      DCHECK(block.HasCaught());
-      exception_state.RethrowV8Exception(block.Exception());
-      return;
-    }
-  }
-  DCHECK(stream->IsObject());
-  InitInternal(script_state, stream.As<v8::Object>(), readable, writable,
-               exception_state);
-}
-
-// static
-void TransformStreamWrapper::Init(ScriptState* script_state,
-                                  TransformStreamTransformer* transformer,
-                                  Member<ReadableStream>* readable,
-                                  Member<WritableStream>* writable,
-                                  ExceptionState& exception_state) {
-  auto transform_algorithm = Algorithm::Create<TransformAlgorithm>(
-      transformer, script_state, exception_state);
-  auto flush_algorithm = Algorithm::Create<FlushAlgorithm>(
-      transformer, script_state, exception_state);
-  v8::Local<v8::Value> args[] = {transform_algorithm, flush_algorithm};
-  v8::Local<v8::Value> stream;
-  {
-    v8::TryCatch block(script_state->GetIsolate());
-    if (!V8ScriptRunner::CallExtra(script_state, "createTransformStreamSimple",
-                                   args)
-             .ToLocal(&stream)) {
-      DCHECK(block.HasCaught());
-      exception_state.RethrowV8Exception(block.Exception());
-      return;
-    }
-  }
-  DCHECK(stream->IsObject());
-  InitInternal(script_state, stream.As<v8::Object>(), readable, writable,
-               exception_state);
-}
-
-// static
-void TransformStreamWrapper::InitInternal(ScriptState* script_state,
-                                          v8::Local<v8::Object> stream,
-                                          Member<ReadableStream>* readable_out,
-                                          Member<WritableStream>* writable_out,
-                                          ExceptionState& exception_state) {
-  v8::Local<v8::Value> readable, writable;
-  v8::Local<v8::Value> args[] = {stream};
-  v8::TryCatch block(script_state->GetIsolate());
-  if (!V8ScriptRunner::CallExtra(script_state, "getTransformStreamReadable",
-                                 args)
-           .ToLocal(&readable)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-  if (!V8ScriptRunner::CallExtra(script_state, "getTransformStreamWritable",
-                                 args)
-           .ToLocal(&writable)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-
-  DCHECK(readable->IsObject());
-  *readable_out = ReadableStreamWrapper::CreateFromInternalStream(
-      script_state, readable.As<v8::Object>(), exception_state);
-
-  if (!*readable_out)
-    return;
-
-  DCHECK(writable->IsObject());
-  *writable_out = WritableStreamWrapper::CreateFromInternalStream(
-      script_state, writable.As<v8::Object>(), exception_state);
-
-  return;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/transform_stream_wrapper.h b/third_party/blink/renderer/core/streams/transform_stream_wrapper.h
deleted file mode 100644
index f0668df..0000000
--- a/third_party/blink/renderer/core/streams/transform_stream_wrapper.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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_CORE_STREAMS_TRANSFORM_STREAM_WRAPPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_TRANSFORM_STREAM_WRAPPER_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class ExceptionState;
-class ReadableStream;
-class ScriptState;
-class TransformStreamTransformer;
-class WritableStream;
-
-// Helpers to create a TransformStream using V8 Extras. This is not a subclass
-// of TransformStream, because it is only needed during creation of the object.
-class TransformStreamWrapper {
-  STATIC_ONLY(TransformStreamWrapper);
-
- public:
-  // Creates a (readable, writable) pair from JS objects.
-  static void InitFromJS(ScriptState*,
-                         ScriptValue transformer,
-                         ScriptValue writable_strategy,
-                         ScriptValue readable_strategy,
-                         Member<ReadableStream>*,
-                         Member<WritableStream>*,
-                         ExceptionState&);
-
-  // Creates a (readable, writable) pair from a C++ object.
-  static void Init(ScriptState*,
-                   TransformStreamTransformer*,
-                   Member<ReadableStream>*,
-                   Member<WritableStream>*,
-                   ExceptionState&);
-
- private:
-  class Algorithm;
-  class FlushAlgorithm;
-  class TransformAlgorithm;
-
-  // Creates a (readable, writable) pair from an internal V8 Extras
-  // TransformStream object.
-  static void InitInternal(ScriptState*,
-                           v8::Local<v8::Object> stream,
-                           Member<ReadableStream>*,
-                           Member<WritableStream>*,
-                           ExceptionState&);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_TRANSFORM_STREAM_WRAPPER_H_
diff --git a/third_party/blink/renderer/core/streams/writable_stream.cc b/third_party/blink/renderer/core/streams/writable_stream.cc
index d08a22b..80c9a25 100644
--- a/third_party/blink/renderer/core/streams/writable_stream.cc
+++ b/third_party/blink/renderer/core/streams/writable_stream.cc
@@ -4,14 +4,11 @@
 
 #include "third_party/blink/renderer/core/streams/writable_stream.h"
 
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/core/streams/writable_stream_native.h"
-#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -38,16 +35,9 @@
                                        ScriptValue underlying_sink,
                                        ScriptValue strategy,
                                        ExceptionState& exception_state) {
-  WritableStream* stream = nullptr;
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    stream = MakeGarbageCollected<WritableStreamNative>(
-        script_state, underlying_sink, strategy, exception_state);
-  } else {
-    auto* stream_wrapper = MakeGarbageCollected<WritableStreamWrapper>();
-    stream = stream_wrapper;
-    stream_wrapper->Init(script_state, underlying_sink, strategy,
-                         exception_state);
-  }
+  WritableStream* stream = MakeGarbageCollected<WritableStreamNative>(
+      script_state, underlying_sink, strategy, exception_state);
+
   if (exception_state.HadException())
     return nullptr;
 
@@ -58,12 +48,7 @@
     ScriptState* script_state,
     UnderlyingSinkBase* underlying_sink,
     size_t high_water_mark) {
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    return WritableStreamNative::CreateWithCountQueueingStrategy(
-        script_state, underlying_sink, high_water_mark);
-  }
-
-  return WritableStreamWrapper::CreateWithCountQueueingStrategy(
+  return WritableStreamNative::CreateWithCountQueueingStrategy(
       script_state, underlying_sink, high_water_mark);
 }
 
@@ -71,12 +56,7 @@
 WritableStream* WritableStream::Deserialize(ScriptState* script_state,
                                             MessagePort* port,
                                             ExceptionState& exception_state) {
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    return WritableStreamNative::Deserialize(script_state, port,
-                                             exception_state);
-  }
-  return WritableStreamWrapper::Deserialize(script_state, port,
-                                            exception_state);
+  return WritableStreamNative::Deserialize(script_state, port, exception_state);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/writable_stream.h b/third_party/blink/renderer/core/streams/writable_stream.h
index cbc4f616..6934e623 100644
--- a/third_party/blink/renderer/core/streams/writable_stream.h
+++ b/third_party/blink/renderer/core/streams/writable_stream.h
@@ -5,16 +5,16 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_H_
 
+#include "base/optional.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "v8/include/v8.h"
 
 namespace blink {
 
+class ExceptionState;
 class MessagePort;
+class ScriptState;
 class UnderlyingSinkBase;
 
 // This is an implementation of the corresponding IDL interface.
diff --git a/third_party/blink/renderer/core/streams/writable_stream.idl b/third_party/blink/renderer/core/streams/writable_stream.idl
index 798ebcb..a1d17bb 100644
--- a/third_party/blink/renderer/core/streams/writable_stream.idl
+++ b/third_party/blink/renderer/core/streams/writable_stream.idl
@@ -5,8 +5,7 @@
 // https://streams.spec.whatwg.org/#ws-class
 [
     Exposed=(Window,Worker,Worklet),
-    // TODO(yhirano): Remove CustomConstructor. See https://crbug.com/906476.
-    CustomConstructor(optional any underlyingSink, optional any strategy),
+    Constructor(optional any underlyingSink, optional any strategy),
     MeasureAs=WritableStreamConstructor,
     RaisesException=Constructor,
     ConstructorCallWith=ScriptState
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.h b/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
index 887c41e2..583bb6f 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
@@ -87,7 +87,7 @@
                     double chunk_size);
 
   // https://streams.spec.whatwg.org/#writable-stream-default-controller-error
-  // TODO(yhirano): Make this private once we ship StreamsNative.
+  // TODO(ricea): Make this private.
   static void Error(ScriptState*,
                     WritableStreamDefaultController*,
                     v8::Local<v8::Value> error);
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller_interface.cc b/third_party/blink/renderer/core/streams/writable_stream_default_controller_interface.cc
index 3c08c02..641a4cd 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_controller_interface.cc
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller_interface.cc
@@ -6,47 +6,18 @@
 
 #include "base/optional.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream_default_controller.h"
 #include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
 
 namespace {
 
-class WritableStreamDefaultControllerWrapper final
-    : public WritableStreamDefaultControllerInterface {
- public:
-  explicit WritableStreamDefaultControllerWrapper(ScriptValue controller)
-      : controller_(controller.GetIsolate(), controller.V8Value()) {}
-
-  void Error(ScriptState* script_state,
-             v8::Local<v8::Value> js_error) override {
-    v8::Isolate* isolate = script_state->GetIsolate();
-
-    v8::Local<v8::Value> controller = controller_.NewLocal(isolate);
-    v8::Local<v8::Value> args[] = {controller, js_error};
-    v8::MaybeLocal<v8::Value> result = V8ScriptRunner::CallExtra(
-        script_state, "WritableStreamDefaultControllerError", args);
-    result.ToLocalChecked();
-  }
-
-  void Trace(blink::Visitor* visitor) override {
-    visitor->Trace(controller_);
-    WritableStreamDefaultControllerInterface::Trace(visitor);
-  }
-
- private:
-  TraceWrapperV8Reference<v8::Value> controller_;
-};
-
 class WritableStreamDefaultControllerNative final
     : public WritableStreamDefaultControllerInterface {
  public:
   explicit WritableStreamDefaultControllerNative(ScriptValue controller) {
-    DCHECK(RuntimeEnabledFeatures::StreamsNativeEnabled());
     DCHECK(controller.IsObject());
     controller_ = V8WritableStreamDefaultController::ToImpl(
         controller.V8Value().As<v8::Object>());
@@ -75,12 +46,7 @@
 
 WritableStreamDefaultControllerInterface*
 WritableStreamDefaultControllerInterface::Create(ScriptValue controller) {
-  if (RuntimeEnabledFeatures::StreamsNativeEnabled()) {
-    return MakeGarbageCollected<WritableStreamDefaultControllerNative>(
-        controller);
-  }
-
-  return MakeGarbageCollected<WritableStreamDefaultControllerWrapper>(
+  return MakeGarbageCollected<WritableStreamDefaultControllerNative>(
       controller);
 }
 
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc b/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc
index 176bf68..6b358091 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_writer.cc
@@ -66,7 +66,6 @@
     ScriptState* script_state,
     WritableStream* stream,
     ExceptionState& exception_state) {
-  DCHECK(RuntimeEnabledFeatures::StreamsNativeEnabled());
   auto* writer = MakeGarbageCollected<WritableStreamDefaultWriter>(
       script_state, static_cast<WritableStreamNative*>(stream),
       exception_state);
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl b/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
index 0bed52d6..68cf0dd 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_writer.idl
@@ -7,7 +7,6 @@
 // https://streams.spec.whatwg.org/#default-writer-class-definition
 [
     Exposed=(Window,Worker,Worklet),
-    RuntimeEnabled=StreamsNative,
     RaisesException=Constructor,
     ConstructorCallWith=ScriptState,
     Constructor(WritableStream stream)
diff --git a/third_party/blink/renderer/core/streams/writable_stream_test.cc b/third_party/blink/renderer/core/streams/writable_stream_test.cc
index 109a4de..ff643d0 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_test.cc
+++ b/third_party/blink/renderer/core/streams/writable_stream_test.cc
@@ -21,16 +21,7 @@
 
 namespace {
 
-// Web platform tests test WritableStream more thoroughly from scripts.
-class WritableStreamTest : public testing::TestWithParam<bool> {
- public:
-  WritableStreamTest() : feature_(GetParam()) {}
-
- private:
-  ScopedStreamsNativeForTest feature_;
-};
-
-TEST_P(WritableStreamTest, CreateWithoutArguments) {
+TEST(WritableStreamTest, CreateWithoutArguments) {
   V8TestingScope scope;
 
   WritableStream* stream =
@@ -40,7 +31,7 @@
 }
 
 // Testing getWriter, locked and IsLocked.
-TEST_P(WritableStreamTest, GetWriter) {
+TEST(WritableStreamTest, GetWriter) {
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
 
@@ -59,7 +50,7 @@
             base::make_optional(true));
 }
 
-TEST_P(WritableStreamTest, Serialize) {
+TEST(WritableStreamTest, Serialize) {
   ScopedTransferableStreamsForTest enable_transferable_streams(true);
 
   V8TestingScope scope;
@@ -111,8 +102,6 @@
   EXPECT_EQ(ToCoreString(result.As<v8::String>()), "a");
 }
 
-INSTANTIATE_TEST_SUITE_P(, WritableStreamTest, ::testing::Values(false, true));
-
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc b/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc
deleted file mode 100644
index d51ea53..0000000
--- a/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
-#include "third_party/blink/renderer/core/messaging/message_port.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_operations.h"
-#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-
-namespace blink {
-
-void WritableStreamWrapper::Init(ScriptState* script_state,
-                                 ScriptValue underlying_sink,
-                                 ScriptValue strategy,
-                                 ExceptionState& exception_state) {
-  v8::Local<v8::Object> internal_stream;
-  v8::TryCatch block(script_state->GetIsolate());
-
-  if (!CreateInternalStream(script_state, underlying_sink.V8Value(),
-                            strategy.V8Value())
-           .ToLocal(&internal_stream)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-
-  if (!InitInternal(script_state, internal_stream)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return;
-  }
-}
-
-WritableStreamWrapper* WritableStreamWrapper::CreateFromInternalStream(
-    ScriptState* script_state,
-    v8::Local<v8::Object> internal_stream,
-    ExceptionState& exception_state) {
-  v8::TryCatch block(script_state->GetIsolate());
-  auto* stream = MakeGarbageCollected<WritableStreamWrapper>();
-  if (!stream->InitInternal(script_state, internal_stream)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return nullptr;
-  }
-  return stream;
-}
-
-WritableStreamWrapper* WritableStreamWrapper::CreateWithCountQueueingStrategy(
-    ScriptState* script_state,
-    UnderlyingSinkBase* underlying_sink,
-    size_t high_water_mark) {
-  ScriptValue strategy = ReadableStreamOperations::CreateCountQueuingStrategy(
-      script_state, high_water_mark);
-  if (strategy.IsEmpty())
-    return nullptr;
-
-  auto underlying_sink_value = ScriptValue::From(script_state, underlying_sink);
-  auto* stream = MakeGarbageCollected<WritableStreamWrapper>();
-
-  ExceptionState exception_state(script_state->GetIsolate(),
-                                 ExceptionState::kConstructionContext,
-                                 "WritableStream");
-  stream->Init(script_state, underlying_sink_value, strategy, exception_state);
-  if (exception_state.HadException())
-    return nullptr;
-  return stream;
-}
-
-bool WritableStreamWrapper::InitInternal(
-    ScriptState* script_state,
-    v8::Local<v8::Object> internal_stream) {
-  v8::Isolate* isolate = script_state->GetIsolate();
-
-#if DCHECK_IS_ON()
-  v8::Local<v8::Value> args[] = {internal_stream};
-  v8::Local<v8::Value> result_value;
-
-  if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStream", args)
-           .ToLocal(&result_value)) {
-    DLOG(FATAL) << "Failing to call IsWritableStream for DCHECK.";
-    return false;
-  }
-  DCHECK(result_value->BooleanValue(isolate));
-#endif  // DCHECK_IS_ON()
-
-  internal_stream_.Set(isolate, internal_stream);
-
-  v8::Local<v8::Value> wrapper = ToV8(this, script_state);
-  if (wrapper.IsEmpty())
-    return false;
-
-  v8::Local<v8::Context> context = script_state->GetContext();
-  v8::Local<v8::Object> bindings =
-      context->GetExtrasBindingObject().As<v8::Object>();
-  v8::Local<v8::Value> symbol_value;
-  if (!bindings->Get(context, V8String(isolate, "internalWritableStreamSymbol"))
-           .ToLocal(&symbol_value)) {
-    return false;
-  }
-
-  if (wrapper.As<v8::Object>()
-          ->Set(context, symbol_value.As<v8::Symbol>(),
-                internal_stream_.NewLocal(isolate))
-          .IsNothing()) {
-    return false;
-  }
-
-  return true;
-}
-
-v8::MaybeLocal<v8::Object> WritableStreamWrapper::CreateInternalStream(
-    ScriptState* script_state,
-    v8::Local<v8::Value> underlying_sink,
-    v8::Local<v8::Value> strategy) {
-  v8::Local<v8::Value> args[] = {underlying_sink, strategy};
-  v8::Local<v8::Value> stream;
-
-  if (!V8ScriptRunner::CallExtra(script_state, "createWritableStream", args)
-           .ToLocal(&stream)) {
-    return v8::MaybeLocal<v8::Object>();
-  }
-
-  DCHECK(stream->IsObject());
-  return v8::MaybeLocal<v8::Object>(stream.As<v8::Object>());
-}
-
-void WritableStreamWrapper::Trace(Visitor* visitor) {
-  visitor->Trace(internal_stream_);
-  ScriptWrappable::Trace(visitor);
-}
-
-bool WritableStreamWrapper::locked(ScriptState* script_state,
-                                   ExceptionState& exception_state) const {
-  auto result = IsLocked(script_state, exception_state);
-
-  return !result || *result;
-}
-
-ScriptPromise WritableStreamWrapper::abort(ScriptState* script_state,
-                                           ExceptionState& exception_state) {
-  return abort(script_state,
-               ScriptValue(script_state->GetIsolate(),
-                           v8::Undefined(script_state->GetIsolate())),
-               exception_state);
-}
-
-ScriptPromise WritableStreamWrapper::abort(ScriptState* script_state,
-                                           ScriptValue reason,
-                                           ExceptionState& exception_state) {
-  if (locked(script_state, exception_state) &&
-      !exception_state.HadException()) {
-    exception_state.ThrowTypeError("Cannot abort a locked stream");
-    return ScriptPromise();
-  }
-
-  v8::Local<v8::Value> args[] = {
-      internal_stream_.NewLocal(script_state->GetIsolate()), reason.V8Value()};
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> result;
-
-  if (!V8ScriptRunner::CallExtra(script_state, "WritableStreamAbort", args)
-           .ToLocal(&result)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return ScriptPromise();
-  }
-  return ScriptPromise(script_state, result);
-}
-
-ScriptValue WritableStreamWrapper::getWriter(ScriptState* script_state,
-                                             ExceptionState& exception_state) {
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> args[] = {
-      internal_stream_.NewLocal(script_state->GetIsolate())};
-  v8::Local<v8::Value> result;
-
-  if (!V8ScriptRunner::CallExtra(script_state,
-                                 "AcquireWritableStreamDefaultWriter", args)
-           .ToLocal(&result)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return ScriptValue();
-  }
-  return ScriptValue(script_state->GetIsolate(), result);
-}
-
-base::Optional<bool> WritableStreamWrapper::IsLocked(
-    ScriptState* script_state,
-    ExceptionState& exception_state) const {
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> args[] = {
-      internal_stream_.NewLocal(script_state->GetIsolate())};
-  v8::Local<v8::Value> result_value;
-
-  if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStreamLocked", args)
-           .ToLocal(&result_value)) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return base::nullopt;
-  }
-  return result_value->BooleanValue(script_state->GetIsolate());
-}
-
-void WritableStreamWrapper::Serialize(ScriptState* script_state,
-                                      MessagePort* port,
-                                      ExceptionState& exception_state) {
-  DCHECK(port);
-  DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
-  v8::TryCatch block(script_state->GetIsolate());
-  v8::Local<v8::Value> port_v8_value = ToV8(port, script_state);
-  DCHECK(!port_v8_value.IsEmpty());
-  v8::Local<v8::Value> args[] = {GetInternalStream(script_state).V8Value(),
-                                 port_v8_value};
-  V8ScriptRunner::CallExtra(script_state, "WritableStreamSerialize", args);
-  if (block.HasCaught()) {
-    exception_state.RethrowV8Exception(block.Exception());
-  }
-}
-
-// static
-WritableStreamWrapper* WritableStreamWrapper::Deserialize(
-    ScriptState* script_state,
-    MessagePort* port,
-    ExceptionState& exception_state) {
-  // We need to execute V8 Extras JavaScript to create the new WritableStream.
-  // We will not run author code.
-  auto* isolate = script_state->GetIsolate();
-  v8::Isolate::AllowJavascriptExecutionScope allow_js(isolate);
-  DCHECK(port);
-  DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled());
-  v8::TryCatch block(isolate);
-  v8::Local<v8::Value> port_v8 = ToV8(port, script_state);
-  DCHECK(!port_v8.IsEmpty());
-  v8::Local<v8::Value> args[] = {port_v8};
-  ScriptValue internal_stream(
-      isolate, V8ScriptRunner::CallExtra(script_state,
-                                         "WritableStreamDeserialize", args));
-  if (block.HasCaught()) {
-    exception_state.RethrowV8Exception(block.Exception());
-    return nullptr;
-  }
-  DCHECK(!internal_stream.IsEmpty());
-  return CreateFromInternalStream(script_state, internal_stream,
-                                  exception_state);
-}
-
-ScriptValue WritableStreamWrapper::GetInternalStream(
-    ScriptState* script_state) const {
-  return ScriptValue(script_state->GetIsolate(),
-                     internal_stream_.NewLocal(script_state->GetIsolate()));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/streams/writable_stream_wrapper.h b/third_party/blink/renderer/core/streams/writable_stream_wrapper.h
deleted file mode 100644
index 658c6d1..0000000
--- a/third_party/blink/renderer/core/streams/writable_stream_wrapper.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_WRAPPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_WRAPPER_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/core/streams/writable_stream.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class MessagePort;
-class WritableStreamWrapper;
-
-// This is an implementation of the WritableStream interface that delegates to
-// the V8 Extras implementation.
-class CORE_EXPORT WritableStreamWrapper final : public WritableStream {
- public:
-  // Call one of Init functions before using the instance.
-  WritableStreamWrapper() = default;
-  ~WritableStreamWrapper() override = default;
-
-  // If an error happens, |exception_state.HadException()| will be true, and
-  // |this| will not be usable after that.
-  void Init(ScriptState*,
-            ScriptValue underlying_sink,
-            ScriptValue strategy,
-            ExceptionState& exception_state);
-
-  static WritableStreamWrapper* CreateFromInternalStream(
-      ScriptState* script_state,
-      ScriptValue internal_stream,
-      ExceptionState& exception_state) {
-    DCHECK(internal_stream.IsObject());
-    return CreateFromInternalStream(script_state,
-                                    internal_stream.V8Value().As<v8::Object>(),
-                                    exception_state);
-  }
-  static WritableStreamWrapper* CreateFromInternalStream(
-      ScriptState*,
-      v8::Local<v8::Object> internal_stream,
-      ExceptionState&);
-
-  static WritableStreamWrapper* CreateWithCountQueueingStrategy(
-      ScriptState*,
-      UnderlyingSinkBase*,
-      size_t high_water_mark);
-
-  void Trace(Visitor* visitor) override;
-
-  // IDL defined functions
-  bool locked(ScriptState*, ExceptionState&) const override;
-  ScriptPromise abort(ScriptState*, ExceptionState&) override;
-  ScriptPromise abort(ScriptState*,
-                      ScriptValue reason,
-                      ExceptionState&) override;
-  ScriptValue getWriter(ScriptState*, ExceptionState&) override;
-
-  base::Optional<bool> IsLocked(ScriptState*, ExceptionState&) const override;
-
-  // Serialize this stream to |port|. The stream will be locked by this
-  // operation.
-  void Serialize(ScriptState*, MessagePort* port, ExceptionState&) override;
-
-  // Given a |port| which is entangled with a MessagePort that was previously
-  // passed to Serialize(), returns a new WritableStreamWrapper which behaves
-  // like it was the original.
-  static WritableStreamWrapper* Deserialize(ScriptState*,
-                                            MessagePort* port,
-                                            ExceptionState&);
-
-  ScriptValue GetInternalStream(ScriptState*) const;
-
- private:
-  bool InitInternal(ScriptState*, v8::Local<v8::Object> internal_stream);
-
-  static v8::MaybeLocal<v8::Object> CreateInternalStream(
-      ScriptState* script_state,
-      v8::Local<v8::Value> underlying_sink,
-      v8::Local<v8::Value> strategy);
-
-  TraceWrapperV8Reference<v8::Object> internal_stream_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_WRAPPER_H_
diff --git a/third_party/blink/renderer/core/timing/layout_shift.idl b/third_party/blink/renderer/core/timing/layout_shift.idl
index 53b66c62..2170984 100644
--- a/third_party/blink/renderer/core/timing/layout_shift.idl
+++ b/third_party/blink/renderer/core/timing/layout_shift.idl
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // https://wicg.github.io/layout-instability/#sec-layout-shift
-[Exposed=Window, RuntimeEnabled=LayoutInstabilityAPI]
+[Exposed=Window]
 interface LayoutShift : PerformanceEntry {
     readonly attribute double value;
     readonly attribute boolean hadRecentInput;
diff --git a/third_party/blink/renderer/core/timing/performance_observer.cc b/third_party/blink/renderer/core/timing/performance_observer.cc
index 992b20f..3d0901d 100644
--- a/third_party/blink/renderer/core/timing/performance_observer.cc
+++ b/third_party/blink/renderer/core/timing/performance_observer.cc
@@ -66,8 +66,7 @@
       supportedEntryTypes.push_back(
           performance_entry_names::kLargestContentfulPaint);
     }
-    if (RuntimeEnabledFeatures::LayoutInstabilityAPIEnabled(execution_context))
-      supportedEntryTypes.push_back(performance_entry_names::kLayoutShift);
+    supportedEntryTypes.push_back(performance_entry_names::kLayoutShift);
     supportedEntryTypes.push_back(performance_entry_names::kLongtask);
   }
   supportedEntryTypes.push_back(performance_entry_names::kMark);
diff --git a/third_party/blink/renderer/core/timing/window_performance.cc b/third_party/blink/renderer/core/timing/window_performance.cc
index 5ae9d4a..fae639d 100644
--- a/third_party/blink/renderer/core/timing/window_performance.cc
+++ b/third_party/blink/renderer/core/timing/window_performance.cc
@@ -425,8 +425,6 @@
 void WindowPerformance::AddLayoutShiftValue(double value,
                                             bool input_detected,
                                             base::TimeTicks input_timestamp) {
-  DCHECK(RuntimeEnabledFeatures::LayoutInstabilityAPIEnabled(
-      GetExecutionContext()));
   auto* entry = MakeGarbageCollected<LayoutShift>(
       now(), value, input_detected,
       input_detected ? MonotonicTimeToDOMHighResTimeStamp(input_timestamp)
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc b/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc
index e301c43..e228072 100644
--- a/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc
+++ b/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc
@@ -27,7 +27,7 @@
 
 #include <memory>
 
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/modules/speech/speech_grammar_list.h"
 #include "third_party/blink/renderer/modules/speech/speech_recognition.h"
@@ -85,7 +85,7 @@
 mojo::Remote<mojom::blink::SpeechRecognizer>&
 SpeechRecognitionController::GetSpeechRecognizer() {
   if (!speech_recognizer_) {
-    GetSupplementable()->GetInterfaceProvider().GetInterface(
+    GetSupplementable()->GetBrowserInterfaceBroker().GetInterface(
         speech_recognizer_.BindNewPipeAndPassReceiver());
   }
   return speech_recognizer_;
diff --git a/third_party/blink/renderer/modules/webusb/usb_device.cc b/third_party/blink/renderer/modules/webusb/usb_device.cc
index 35f1512..5985cec3 100644
--- a/third_party/blink/renderer/modules/webusb/usb_device.cc
+++ b/third_party/blink/renderer/modules/webusb/usb_device.cc
@@ -349,16 +349,24 @@
     unsigned length) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
-  if (EnsureDeviceConfigured(resolver)) {
-    auto parameters = ConvertControlTransferParameters(setup, resolver);
-    if (parameters) {
-      device_requests_.insert(resolver);
-      device_->ControlTransferIn(
-          std::move(parameters), length, 0,
-          WTF::Bind(&USBDevice::AsyncControlTransferIn, WrapPersistent(this),
-                    WrapPersistent(resolver)));
-    }
+  if (!EnsureNoDeviceOrInterfaceChangeInProgress(resolver))
+    return promise;
+
+  if (!opened_) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError, kOpenRequired));
+    return promise;
   }
+
+  auto parameters = ConvertControlTransferParameters(setup, resolver);
+  if (!parameters)
+    return promise;
+
+  device_requests_.insert(resolver);
+  device_->ControlTransferIn(
+      std::move(parameters), length, 0,
+      WTF::Bind(&USBDevice::AsyncControlTransferIn, WrapPersistent(this),
+                WrapPersistent(resolver)));
   return promise;
 }
 
@@ -367,16 +375,24 @@
     const USBControlTransferParameters* setup) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
-  if (EnsureDeviceConfigured(resolver)) {
-    auto parameters = ConvertControlTransferParameters(setup, resolver);
-    if (parameters) {
-      device_requests_.insert(resolver);
-      device_->ControlTransferOut(
-          std::move(parameters), Vector<uint8_t>(), 0,
-          WTF::Bind(&USBDevice::AsyncControlTransferOut, WrapPersistent(this),
-                    0, WrapPersistent(resolver)));
-    }
+  if (!EnsureNoDeviceOrInterfaceChangeInProgress(resolver))
+    return promise;
+
+  if (!opened_) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError, kOpenRequired));
+    return promise;
   }
+
+  auto parameters = ConvertControlTransferParameters(setup, resolver);
+  if (!parameters)
+    return promise;
+
+  device_requests_.insert(resolver);
+  device_->ControlTransferOut(
+      std::move(parameters), Vector<uint8_t>(), 0,
+      WTF::Bind(&USBDevice::AsyncControlTransferOut, WrapPersistent(this), 0,
+                WrapPersistent(resolver)));
   return promise;
 }
 
@@ -386,9 +402,15 @@
     const ArrayBufferOrArrayBufferView& data) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
-  if (!EnsureDeviceConfigured(resolver))
+  if (!EnsureNoDeviceOrInterfaceChangeInProgress(resolver))
     return promise;
 
+  if (!opened_) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError, kOpenRequired));
+    return promise;
+  }
+
   auto parameters = ConvertControlTransferParameters(setup, resolver);
   if (!parameters)
     return promise;
@@ -589,62 +611,83 @@
   return false;
 }
 
-bool USBDevice::EnsureNoDeviceOrInterfaceChangeInProgress(
+bool USBDevice::EnsureNoDeviceChangeInProgress(
     ScriptPromiseResolver* resolver) const {
   if (!device_) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kNotFoundError, kDeviceDisconnected));
-  } else if (device_state_change_in_progress_) {
+    return false;
+  }
+
+  if (device_state_change_in_progress_) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kInvalidStateError, kDeviceStateChangeInProgress));
-  } else if (AnyInterfaceChangeInProgress()) {
+    return false;
+  }
+
+  return true;
+}
+
+bool USBDevice::EnsureNoDeviceOrInterfaceChangeInProgress(
+    ScriptPromiseResolver* resolver) const {
+  if (!EnsureNoDeviceChangeInProgress(resolver))
+    return false;
+
+  if (AnyInterfaceChangeInProgress()) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kInvalidStateError, kInterfaceStateChangeInProgress));
-  } else {
-    return true;
+    return false;
   }
-  return false;
+
+  return true;
 }
 
 bool USBDevice::EnsureDeviceConfigured(ScriptPromiseResolver* resolver) const {
-  if (!device_) {
-    resolver->Reject(MakeGarbageCollected<DOMException>(
-        DOMExceptionCode::kNotFoundError, kDeviceDisconnected));
-  } else if (device_state_change_in_progress_) {
-    resolver->Reject(MakeGarbageCollected<DOMException>(
-        DOMExceptionCode::kInvalidStateError, kDeviceStateChangeInProgress));
-  } else if (!opened_) {
+  if (!EnsureNoDeviceChangeInProgress(resolver))
+    return false;
+
+  if (!opened_) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kInvalidStateError, kOpenRequired));
-  } else if (configuration_index_ == kNotFound) {
+    return false;
+  }
+
+  if (configuration_index_ == kNotFound) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kInvalidStateError,
         "The device must have a configuration selected."));
-  } else {
-    return true;
+    return false;
   }
-  return false;
+
+  return true;
 }
 
 bool USBDevice::EnsureInterfaceClaimed(uint8_t interface_number,
                                        ScriptPromiseResolver* resolver) const {
   if (!EnsureDeviceConfigured(resolver))
     return false;
+
   wtf_size_t interface_index = FindInterfaceIndex(interface_number);
   if (interface_index == kNotFound) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kNotFoundError, kInterfaceNotFound));
-  } else if (interface_state_change_in_progress_[interface_index]) {
+    return false;
+  }
+
+  if (interface_state_change_in_progress_[interface_index]) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kInvalidStateError, kInterfaceStateChangeInProgress));
-  } else if (!claimed_interfaces_[interface_index]) {
+    return false;
+  }
+
+  if (!claimed_interfaces_[interface_index]) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kInvalidStateError,
         "The specified interface has not been claimed."));
-  } else {
-    return true;
+    return false;
   }
-  return false;
+
+  return true;
 }
 
 bool USBDevice::EnsureEndpointAvailable(bool in_transfer,
@@ -652,12 +695,14 @@
                                         ScriptPromiseResolver* resolver) const {
   if (!EnsureDeviceConfigured(resolver))
     return false;
+
   if (endpoint_number == 0 || endpoint_number >= kEndpointsBitsNumber) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kIndexSizeError,
         "The specified endpoint number is out of range."));
     return false;
   }
+
   auto& bit_vector = in_transfer ? in_endpoints_ : out_endpoints_;
   if (!bit_vector[endpoint_number - 1]) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -667,6 +712,7 @@
         "interface."));
     return false;
   }
+
   return true;
 }
 
diff --git a/third_party/blink/renderer/modules/webusb/usb_device.h b/third_party/blink/renderer/modules/webusb/usb_device.h
index d6319b5..774a66b 100644
--- a/third_party/blink/renderer/modules/webusb/usb_device.h
+++ b/third_party/blink/renderer/modules/webusb/usb_device.h
@@ -116,6 +116,7 @@
   wtf_size_t FindAlternateIndex(wtf_size_t interface_index,
                                 uint8_t alternate_setting) const;
   bool IsProtectedInterfaceClass(wtf_size_t interface_index) const;
+  bool EnsureNoDeviceChangeInProgress(ScriptPromiseResolver*) const;
   bool EnsureNoDeviceOrInterfaceChangeInProgress(ScriptPromiseResolver*) const;
   bool EnsureDeviceConfigured(ScriptPromiseResolver*) const;
   bool EnsureInterfaceClaimed(uint8_t interface_number,
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 70cfa715..c103b596 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -16,7 +16,10 @@
 import("//v8/gni/v8.gni")
 
 # Most targets in this file are private actions so use that as the default.
-visibility = [ ":*" ]
+visibility = [
+  ":*",
+  "//third_party/blink/renderer/platform/heap:test_support",
+]
 
 blink_platform_avx_files = [
   "audio/cpu/x86/vector_math_avx.cc",
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index 396a3b93..b643353 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -686,10 +686,6 @@
   RuntimeEnabledFeatures::SetCooperativeSchedulingEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableStreamsNative(bool enable) {
-  RuntimeEnabledFeatures::SetStreamsNativeEnabled(enable);
-}
-
 void WebRuntimeFeatures::EnableMouseSubframeNoImplicitCapture(bool enable) {
   RuntimeEnabledFeatures::SetMouseSubframeNoImplicitCaptureEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index 0bae6d34..c5dc5b5 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -143,6 +143,7 @@
     context_provider_->RemoveObserver(this);
 
   waiting_for_compositor_ack_ = false;
+  last_frame_id_.reset();
 
   resource_provider_->OnContextLost();
 
@@ -206,16 +207,10 @@
     return;
   }
 
-  scoped_refptr<media::VideoFrame> video_frame =
-      video_frame_provider_->GetCurrentFrame();
-
   // We do have a new frame that we could display.  See if we're supposed to
   // actually submit a frame or not, and try to submit one.
-  //
-  // Not submitting a frame when waiting for a previous ack saves memory by
-  // not building up unused remote side resources. See https://crbug.com/830828.
-  if (waiting_for_compositor_ack_ ||
-      !SubmitFrame(current_begin_frame_ack, std::move(video_frame))) {
+  auto video_frame = video_frame_provider_->GetCurrentFrame();
+  if (!SubmitFrame(current_begin_frame_ack, std::move(video_frame))) {
     compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack);
     return;
   }
@@ -391,6 +386,15 @@
   if (!compositor_frame_sink_ || !ShouldSubmit())
     return false;
 
+  // Not submitting a frame when waiting for a previous ack saves memory by
+  // not building up unused remote side resources. See https://crbug.com/830828.
+  //
+  // Similarly we don't submit the same frame multiple times.
+  if (waiting_for_compositor_ack_ || last_frame_id_ == video_frame->unique_id())
+    return false;
+
+  last_frame_id_ = video_frame->unique_id();
+
   gfx::Size frame_size(video_frame->natural_size());
   if (rotation_ == media::VIDEO_ROTATION_90 ||
       rotation_ == media::VIDEO_ROTATION_270) {
@@ -434,16 +438,21 @@
   DCHECK(!frame_size_.IsEmpty());
   TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitEmptyFrame");
 
-  if (!compositor_frame_sink_)
+  // If there's nothing to submit to or we've already submitted an empty frame,
+  // don't submit another one.
+  if (!compositor_frame_sink_ || !last_frame_id_.has_value())
     return;
 
+  last_frame_id_.reset();
   compositor_frame_sink_->SubmitCompositorFrame(
       child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
           .local_surface_id(),
       CreateCompositorFrame(viz::BeginFrameAck::CreateManualAckWithDamage(),
                             nullptr),
       nullptr, 0);
-  waiting_for_compositor_ack_ = true;
+
+  // We don't set |waiting_for_compositor_ack_| here since we want to allow a
+  // subsequent real frame to replace it at any time if needed.
 }
 
 void VideoFrameSubmitter::SubmitSingleFrame() {
@@ -461,10 +470,10 @@
   if (!video_frame)
     return;
 
-  SubmitFrame(viz::BeginFrameAck::CreateManualAckWithDamage(),
-              std::move(video_frame));
-
-  video_frame_provider_->PutCurrentFrame();
+  if (SubmitFrame(viz::BeginFrameAck::CreateManualAckWithDamage(),
+                  std::move(video_frame))) {
+    video_frame_provider_->PutCurrentFrame();
+  }
 }
 
 bool VideoFrameSubmitter::ShouldSubmit() const {
@@ -526,6 +535,8 @@
 }
 
 void VideoFrameSubmitter::GenerateNewSurfaceId() {
+  last_frame_id_.reset();
+
   // We need a new id in the event of context loss.
   child_local_surface_id_allocator_.GenerateId();
 
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
index 949a261..92fff22 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -175,6 +176,8 @@
 
   base::OneShotTimer empty_frame_timer_;
 
+  base::Optional<int> last_frame_id_;
+
   THREAD_CHECKER(thread_checker_);
 
   base::WeakPtrFactory<VideoFrameSubmitter> weak_ptr_factory_{this};
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
index 3e786d9f..4b0dce2 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
@@ -221,6 +221,12 @@
                                           std::move(context_provider));
   }
 
+  void AckSubmittedFrame() {
+    WTF::Vector<viz::ReturnedResource> resources;
+    EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
+    submitter_->DidReceiveCompositorFrameAck(resources);
+  }
+
  protected:
   base::test::TaskEnvironment task_environment_;
   std::unique_ptr<base::SimpleTestTickClock> now_src_;
@@ -289,12 +295,14 @@
       BEGINFRAME_FROM_HERE, now_src_.get());
   submitter_->OnBeginFrame(args, {});
   task_environment_.RunUntilIdle();
+  AckSubmittedFrame();
 
   // StopRendering submits one more frame.
   EXPECT_SUBMISSION(SubmissionType::kStateChange);
   EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
   submitter_->StopRendering();
   task_environment_.RunUntilIdle();
+  AckSubmittedFrame();
 
   // No frames should be produced after StopRendering().
   EXPECT_CALL(*sink_, DidNotProduceFrame(_));
@@ -366,6 +374,7 @@
   EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
   submitter_->SetIsSurfaceVisible(true);
   task_environment_.RunUntilIdle();
+  AckSubmittedFrame();
 
   EXPECT_TRUE(ShouldSubmit());
 
@@ -375,7 +384,14 @@
   task_environment_.RunUntilIdle();
 
   EXPECT_FALSE(ShouldSubmit());
-  EXPECT_GET_PUT_FRAME();
+
+  // We should only see a GetCurrentFrame() without a PutCurrentFrame() since
+  // we drop the submission because !ShouldSubmit().
+  EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
+      .WillOnce(Return(media::VideoFrame::CreateFrame(
+          media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
+          gfx::Size(8, 8), base::TimeDelta())));
+
   SubmitSingleFrame();
 }
 
@@ -391,6 +407,7 @@
   EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
   EXPECT_SUBMISSION(SubmissionType::kStateChange);
   submitter_->SetForceSubmit(true);
+  AckSubmittedFrame();
 
   EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
   submitter_->StartRendering();
@@ -401,12 +418,14 @@
   submitter_->SetIsSurfaceVisible(true);
   task_environment_.RunUntilIdle();
   EXPECT_TRUE(ShouldSubmit());
+  AckSubmittedFrame();
 
   EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
   EXPECT_SUBMISSION(SubmissionType::kStateChange);
   submitter_->SetIsSurfaceVisible(false);
   task_environment_.RunUntilIdle();
   EXPECT_TRUE(ShouldSubmit());
+  AckSubmittedFrame();
 
   EXPECT_SUBMISSION(SubmissionType::kManual);
   SubmitSingleFrame();
@@ -432,12 +451,7 @@
 
   submitter_->DidReceiveFrame();
   task_environment_.RunUntilIdle();
-
-  {
-    WTF::Vector<viz::ReturnedResource> resources;
-    EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
-    submitter_->DidReceiveCompositorFrameAck(resources);
-  }
+  AckSubmittedFrame();
 
   // Check to see if an update to rotation just before rendering is
   // communicated.
@@ -446,12 +460,7 @@
   EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
   submitter_->StartRendering();
   task_environment_.RunUntilIdle();
-
-  {
-    WTF::Vector<viz::ReturnedResource> resources;
-    EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
-    submitter_->DidReceiveCompositorFrameAck(resources);
-  }
+  AckSubmittedFrame();
 
   EXPECT_CALL(*video_frame_provider_, UpdateCurrentFrame(_, _))
       .WillOnce(Return(true));
@@ -470,12 +479,7 @@
       BEGINFRAME_FROM_HERE, now_src_.get());
   submitter_->OnBeginFrame(args, {});
   task_environment_.RunUntilIdle();
-
-  {
-    WTF::Vector<viz::ReturnedResource> resources;
-    EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
-    submitter_->DidReceiveCompositorFrameAck(resources);
-  }
+  AckSubmittedFrame();
 
   // Check to see if changing rotation while rendering is handled.
   submitter_->SetRotation(media::VideoRotation::VIDEO_ROTATION_270);
@@ -559,9 +563,7 @@
 }
 
 TEST_F(VideoFrameSubmitterTest, ReturnsResourceOnCompositorAck) {
-  WTF::Vector<viz::ReturnedResource> resources;
-  EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
-  submitter_->DidReceiveCompositorFrameAck(resources);
+  AckSubmittedFrame();
   task_environment_.RunUntilIdle();
 }
 
@@ -595,6 +597,28 @@
   task_environment_.RunUntilIdle();
 }
 
+// Similar to above but verifies the single-frame paint path.
+TEST_F(VideoFrameSubmitterTest, WaitingForAckPreventsSubmitSingleFrame) {
+  EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
+
+  submitter_->StartRendering();
+  task_environment_.RunUntilIdle();
+
+  EXPECT_SUBMISSION(SubmissionType::kManual);
+  submitter_->DidReceiveFrame();
+  task_environment_.RunUntilIdle();
+
+  // GetCurrentFrame() should be called, but PutCurrentFrame() should not, since
+  // the frame is dropped waiting for the ack.
+  EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
+      .WillOnce(Return(media::VideoFrame::CreateFrame(
+          media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
+          gfx::Size(8, 8), base::TimeDelta())));
+
+  submitter_->DidReceiveFrame();
+  task_environment_.RunUntilIdle();
+}
+
 // Test that after context is lost, the CompositorFrameSink is recreated but the
 // SurfaceEmbedder isn't.
 TEST_F(VideoFrameSubmitterTest, RecreateCompositorFrameSinkAfterContextLost) {
@@ -671,6 +695,7 @@
     EXPECT_EQ(viz::kInitialChildSequenceNumber,
               local_surface_id.child_sequence_number());
     EXPECT_EQ(gfx::Size(8, 8), frame_size());
+    AckSubmittedFrame();
   }
 
   EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
@@ -733,11 +758,7 @@
     EXPECT_EQ(sink_->last_submitted_compositor_frame().size_in_pixels(),
               rotated_size);
 
-    // submitter_->DidReceiveFrame();
-
-    WTF::Vector<viz::ReturnedResource> resources;
-    EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
-    submitter_->DidReceiveCompositorFrameAck(resources);
+    AckSubmittedFrame();
   }
 
   {
@@ -765,9 +786,7 @@
     EXPECT_EQ(sink_->last_submitted_compositor_frame().size_in_pixels(),
               natural_size);
 
-    WTF::Vector<viz::ReturnedResource> resources;
-    EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
-    submitter_->DidReceiveCompositorFrameAck(resources);
+    AckSubmittedFrame();
   }
 
   {
@@ -794,9 +813,7 @@
     EXPECT_EQ(sink_->last_submitted_compositor_frame().size_in_pixels(),
               rotated_size);
 
-    WTF::Vector<viz::ReturnedResource> resources;
-    EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_));
-    submitter_->DidReceiveCompositorFrameAck(resources);
+    AckSubmittedFrame();
   }
 }
 
@@ -845,4 +862,59 @@
             video_frame_provider_->preferred_interval);
 }
 
+TEST_F(VideoFrameSubmitterTest, NoDuplicateFramesOnBeginFrame) {
+  EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
+  submitter_->StartRendering();
+  task_environment_.RunUntilIdle();
+  EXPECT_TRUE(IsRendering());
+
+  auto vf = media::VideoFrame::CreateFrame(
+      media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
+      gfx::Size(8, 8), base::TimeDelta());
+
+  EXPECT_CALL(*video_frame_provider_, UpdateCurrentFrame(_, _))
+      .WillOnce(Return(true));
+  EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()).WillOnce(Return(vf));
+  EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
+  EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _));
+  EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _));
+  EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
+  EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
+  viz::BeginFrameArgs args = begin_frame_source_->CreateBeginFrameArgs(
+      BEGINFRAME_FROM_HERE, now_src_.get());
+  submitter_->OnBeginFrame(args, {});
+  task_environment_.RunUntilIdle();
+  AckSubmittedFrame();
+
+  // Trying to submit the same frame again does nothing... even if
+  // UpdateCurrentFrame() lies about there being a new frame.
+  EXPECT_CALL(*video_frame_provider_, UpdateCurrentFrame(_, _))
+      .WillOnce(Return(true));
+  EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()).WillOnce(Return(vf));
+  EXPECT_CALL(*sink_, DidNotProduceFrame(_));
+  submitter_->OnBeginFrame(args, {});
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(VideoFrameSubmitterTest, NoDuplicateFramesDidReceiveFrame) {
+  auto vf = media::VideoFrame::CreateFrame(
+      media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
+      gfx::Size(8, 8), base::TimeDelta());
+
+  EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()).WillOnce(Return(vf));
+  EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
+  EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _));
+  EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _));
+  EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
+  EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
+  submitter_->DidReceiveFrame();
+  task_environment_.RunUntilIdle();
+  AckSubmittedFrame();
+
+  // Trying to submit the same frame again does nothing...
+  EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()).WillOnce(Return(vf));
+  submitter_->DidReceiveFrame();
+  task_environment_.RunUntilIdle();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn
index d9637cde..01955c9 100644
--- a/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -100,6 +100,7 @@
   deps = [
     "//testing/gtest",
     "//third_party/blink/public/mojom:mojom_platform_blink_headers",
+    "//third_party/blink/renderer/platform:bindings_buildflags",
   ]
 }
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index ee35f70f..02a6cf3f 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -857,13 +857,6 @@
       status: "stable",
     },
     {
-      // Exposes layout shift scores to Javascript. See explainer:
-      // http://bit.ly/lsm-explainer.
-      name: "LayoutInstabilityAPI",
-      origin_trial_feature_name: "LayoutJankAPI",
-      status: "stable",
-    },
-    {
       name: "LayoutNG",
       implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFieldset", "LayoutNGFlexBox", "LayoutNGFragmentItem", "LayoutNGLineCache", "EditingNG", "BidiCaretAffinity", "LayoutNGTable"],
       status: "stable",
@@ -1580,10 +1573,6 @@
       status: "stable"
     },
     {
-      name: "StreamsNative",
-      status: "stable",
-    },
-    {
       name: "SurfaceEmbeddingFeatures",
       status: "stable",
     },
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 d917da2..d7a3b710 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
@@ -348,9 +348,6 @@
 Bug(none) paint/invalidation/compositing/subpixel-offset-scaled-transform-composited.html [ Failure ]
 
 Bug(none) paint/pagination/composited-paginated-outlined-box.html [ Failure ]
-
-crbug.com/882075 compositing/overflow/composited-sticky-element-with-non-integer-relative-position-to-container.html [ Failure ]
-
 Bug(none) paint/invalidation/clip/mask-clip-change-stacking-child.html [ Failure ]
 Bug(none) paint/invalidation/media-audio-no-spurious-repaints.html [ Failure ]
 Bug(none) paint/invalidation/subpixel-shadow-included-in-invalidation.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 669ab77d..13c9b0f0 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1868,10 +1868,6 @@
 ### virtual/layout_ng_experimental/css3/flexbox/
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/auto-height-column-with-border-and-padding.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/box-sizing-min-max-sizes.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-center-with-margins-and-wrap.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-center-with-margins.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-baseline.html [ Skip ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-column.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-end.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-vertical-writing-mode.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align.html [ Failure ]
@@ -1902,7 +1898,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/overflow-auto-resizes-correctly.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-height-replaced-element.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/position-absolute-child.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relayout-align-items.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relpos-with-percentage-top.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/style-change.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/true-centering.html [ Failure ]
@@ -1913,13 +1908,8 @@
 
 ### virtual/layout_ng_experimental/external/wpt/css/css-flexbox/
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/Flexible-order.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-items-001.htm [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-items-003.htm [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-items-004.htm [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-self-002.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-self-003.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-self-008.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-self-009.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-items-baseline-overflow-non-visible.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-001.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-003.html [ Failure ]
 crbug.com/807497 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-005.html [ Failure ]
@@ -1929,7 +1919,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-wrap-reverse.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-align-items-center.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-basis-010.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-direction-row-vertical.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-flow-003.html [ Failure ]
@@ -1938,7 +1927,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-flow-010.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-flow-011.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-flow-012.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-items-flexibility.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-004.xht [ Failure ]
 crbug.com/249112 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-005.xht [ Failure ]
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-006.xht [ Failure ]
@@ -1953,16 +1941,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox-flex-direction-column-reverse.htm [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox-flex-wrap-wrap-reverse.htm [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-items-baseline.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-items-center-2.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-items-center.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-items-flexend-2.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-items-flexend.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-self-auto.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-self-baseline.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-self-center.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-self-flexend.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-self-flexstart.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_align-self-stretch.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_direction-column-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-column-reverse-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-column-reverse-wrap.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/webusb-test.js b/third_party/blink/web_tests/external/wpt/resources/chromium/webusb-test.js
index c4d4e8f1..8bccfd1f 100644
--- a/third_party/blink/web_tests/external/wpt/resources/chromium/webusb-test.js
+++ b/third_party/blink/web_tests/external/wpt/resources/chromium/webusb-test.js
@@ -241,23 +241,39 @@
     return Promise.resolve({ success: true });
   }
 
-  controlTransferIn(params, length, timeout) {
+  async controlTransferIn(params, length, timeout) {
     assert_true(this.opened_);
-    assert_false(this.currentConfiguration_ == null, 'device configured');
-    return Promise.resolve({
+
+    if ((params.recipient == device.mojom.UsbControlTransferRecipient.INTERFACE ||
+         params.recipient == device.mojom.UsbControlTransferRecipient.ENDPOINT) &&
+        this.currentConfiguration_ == null) {
+      return {
+        status: device.mojom.UsbTransferStatus.PERMISSION_DENIED,
+      };
+    }
+
+    return {
       status: device.mojom.UsbTransferStatus.OK,
       data: [length >> 8, length & 0xff, params.request, params.value >> 8,
              params.value & 0xff, params.index >> 8, params.index & 0xff]
-    });
+    };
   }
 
-  controlTransferOut(params, data, timeout) {
+  async controlTransferOut(params, data, timeout) {
     assert_true(this.opened_);
-    assert_false(this.currentConfiguration_ == null, 'device configured');
-    return Promise.resolve({
+
+    if ((params.recipient == device.mojom.UsbControlTransferRecipient.INTERFACE ||
+         params.recipient == device.mojom.UsbControlTransferRecipient.ENDPOINT) &&
+        this.currentConfiguration_ == null) {
+      return {
+        status: device.mojom.UsbTransferStatus.PERMISSION_DENIED,
+      };
+    }
+
+    return {
       status: device.mojom.UsbTransferStatus.OK,
       bytesWritten: data.byteLength
-    });
+    };
   }
 
   genericTransferIn(endpointNumber, length, timeout) {
diff --git a/third_party/blink/web_tests/external/wpt/webusb/usbDevice.https.any.js b/third_party/blink/web_tests/external/wpt/webusb/usbDevice.https.any.js
index 03dbe8f..b416870 100644
--- a/third_party/blink/web_tests/external/wpt/webusb/usbDevice.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webusb/usbDevice.https.any.js
@@ -22,6 +22,19 @@
       'The device must have a configuration selected.');
 }
 
+function assertRejectsWithNotClaimedError(promise) {
+  return assertRejectsWithError(
+      promise, 'InvalidStateError',
+      'The specified interface has not been claimed.');
+}
+
+function assertRejectsWithEndpointNotFoundError(promise) {
+  return assertRejectsWithError(
+      promise, 'NotFoundError',
+      'The specified endpoint is not part of a claimed and selected ' +
+      'alternate interface.');
+}
+
 function assertRejectsWithDeviceStateChangeInProgressError(promise) {
   return assertRejectsWithError(
     promise, 'InvalidStateError',
@@ -236,20 +249,6 @@
         assertRejectsWithNotConfiguredError(device.claimInterface(0)),
         assertRejectsWithNotConfiguredError(device.releaseInterface(0)),
         assertRejectsWithNotConfiguredError(device.selectAlternateInterface(0, 1)),
-        assertRejectsWithNotConfiguredError(device.controlTransferIn({
-            requestType: 'vendor',
-            recipient: 'device',
-            request: 0x42,
-            value: 0x1234,
-            index: 0x5678
-        }, 7)),
-        assertRejectsWithNotConfiguredError(device.controlTransferOut({
-            requestType: 'vendor',
-            recipient: 'device',
-            request: 0x42,
-            value: 0x1234,
-            index: 0x5678
-        }, new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]))),
         assertRejectsWithNotConfiguredError(device.clearHalt('in', 1)),
         assertRejectsWithNotConfiguredError(device.transferIn(1, 8)),
         assertRejectsWithNotConfiguredError(
@@ -484,6 +483,79 @@
   await device.close();
 }, 'can issue all types of IN control transfers');
 
+usb_test(async () => {
+  let { device } = await getFakeDevice();
+  let usbRequestTypes = ['standard', 'class', 'vendor'];
+  let usbRecipients = ['device', 'other'];
+  await device.open();
+  await Promise.all(usbRequestTypes.flatMap(requestType => {
+    return usbRecipients.map(async recipient => {
+      let result = await device.controlTransferIn({
+        requestType: requestType,
+        recipient: recipient,
+        request: 0x42,
+        value: 0x1234,
+        index: 0x5678
+      }, 7);
+      assert_true(result instanceof USBInTransferResult);
+      assert_equals(result.status, 'ok');
+      assert_equals(result.data.byteLength, 7);
+      assert_equals(result.data.getUint16(0), 0x07);
+      assert_equals(result.data.getUint8(2), 0x42);
+      assert_equals(result.data.getUint16(3), 0x1234);
+      assert_equals(result.data.getUint16(5), 0x5678);
+    });
+  }));
+  await device.close();
+}, 'device-scope IN control transfers don\'t require configuration');
+
+usb_test(async () => {
+  let { device } = await getFakeDevice();
+  let usbRequestTypes = ['standard', 'class', 'vendor'];
+  let usbRecipients = ['interface', 'endpoint'];
+  await device.open();
+  await Promise.all(usbRequestTypes.flatMap(requestType => {
+    return usbRecipients.map(recipient => {
+      let index = recipient === 'interface' ? 0x5600 : 0x5681;
+      return assertRejectsWithNotConfiguredError(device.controlTransferIn({
+        requestType: requestType,
+        recipient: recipient,
+        request: 0x42,
+        value: 0x1234,
+        index: index
+      }, 7));
+    });
+  }));
+  await device.close();
+}, 'interface-scope IN control transfers require configuration');
+
+usb_test(async () => {
+  let { device } = await getFakeDevice();
+  let usbRequestTypes = ['standard', 'class', 'vendor'];
+  let usbRecipients = ['interface', 'endpoint'];
+  await device.open();
+  await device.selectConfiguration(1);
+  await Promise.all(usbRequestTypes.flatMap(requestType => {
+    return [
+      assertRejectsWithNotClaimedError(device.controlTransferIn({
+        requestType: requestType,
+        recipient: 'interface',
+        request: 0x42,
+        value: 0x1234,
+        index: 0x5600
+      }, 7)),
+      assertRejectsWithNotFoundError(device.controlTransferIn({
+        requestType: requestType,
+        recipient: 'endpoint',
+        request: 0x42,
+        value: 0x1234,
+        index: 0x5681
+      }, 7))
+    ];
+  }));
+  await device.close();
+}, 'interface-scope IN control transfers require claiming the interface');
+
 usb_test(() => {
   return getFakeDevice().then(({ device, fakeDevice }) => {
     return device.open()
@@ -533,6 +605,93 @@
   await device.close();
 }, 'can issue all types of OUT control transfers');
 
+usb_test(async () => {
+  let { device } = await getFakeDevice();
+  let usbRequestTypes = ['standard', 'class', 'vendor'];
+  let usbRecipients = ['device', 'other'];
+  let dataArray = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
+  let dataTypes = [dataArray, dataArray.buffer];
+  await device.open();
+  await Promise.all(usbRequestTypes.flatMap(requestType => {
+    return usbRecipients.flatMap(recipient => {
+      let transferParams = {
+        requestType: requestType,
+        recipient: recipient,
+        request: 0x42,
+        value: 0x1234,
+        index: 0x5678
+      };
+      return dataTypes.map(async data => {
+        let result = await device.controlTransferOut(transferParams, data);
+        assert_true(result instanceof USBOutTransferResult);
+        assert_equals(result.status, 'ok');
+        assert_equals(result.bytesWritten, 8);
+      }).push((async () => {
+        let result = await device.controlTransferOut(transferParams);
+        assert_true(result instanceof USBOutTransferResult);
+        assert_equals(result.status, 'ok');
+      })());
+    });
+  }));
+  await device.close();
+}, 'device-scope OUT control transfers don\'t require configuration');
+
+usb_test(async () => {
+  let { device } = await getFakeDevice();
+  let usbRequestTypes = ['standard', 'class', 'vendor'];
+  let usbRecipients = ['interface', 'endpoint'];
+  let dataArray = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
+  let dataTypes = [dataArray, dataArray.buffer];
+  await device.open();
+  await Promise.all(usbRequestTypes.flatMap(requestType => {
+    return usbRecipients.flatMap(recipient => {
+      let index = recipient === 'interface' ? 0x5600 : 0x5681;
+      let transferParams = {
+        requestType: requestType,
+        recipient: recipient,
+        request: 0x42,
+        value: 0x1234,
+        index: index
+      };
+      return dataTypes.map(data => {
+        return assertRejectsWithNotConfiguredError(
+            device.controlTransferOut(transferParams, data));
+      }).push(assertRejectsWithNotConfiguredError(
+          device.controlTransferOut(transferParams)));
+    });
+  }));
+  await device.close();
+}, 'interface-scope OUT control transfers require configuration');
+
+usb_test(async () => {
+  let { device } = await getFakeDevice();
+  let usbRequestTypes = ['standard', 'class', 'vendor'];
+  let usbRecipients = ['interface', 'endpoint'];
+  let dataArray = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
+  let dataTypes = [dataArray, dataArray.buffer];
+  await device.open();
+  await device.selectConfiguration(1);
+  await Promise.all(usbRequestTypes.flatMap(requestType => {
+    return usbRecipients.flatMap(recipient => {
+      let index = recipient === 'interface' ? 0x5600 : 0x5681;
+      let assertion = recipient === 'interface'
+          ? assertRejectsWithNotClaimedError
+          : assertRejectsWithEndpointNotFoundError;
+      let transferParams = {
+        requestType: requestType,
+        recipient: recipient,
+        request: 0x42,
+        value: 0x1234,
+        index: index
+      };
+      return dataTypes.map(data => {
+        return assertion(device.controlTransferOut(transferParams, data));
+      }).push(assertion(device.controlTransferOut(transferParams)));
+    });
+  }));
+  await device.close();
+}, 'interface-scope OUT control transfers an interface claim');
+
 usb_test(() => {
   return getFakeDevice().then(({ device, fakeDevice }) => {
     return device.open()
@@ -738,23 +897,17 @@
     let data = new DataView(new ArrayBuffer(1024));
     for (let i = 0; i < 1024; ++i)
       data.setUint8(i, i & 0xff);
-    const notFoundMessage = 'The specified endpoint is not part of a claimed ' +
-                            'and selected alternate interface.';
     const rangeError = 'The specified endpoint number is out of range.';
     return device.open()
       .then(() => device.selectConfiguration(1))
       .then(() => device.claimInterface(0))
       .then(() => Promise.all([
-          assertRejectsWithError(device.transferIn(2, 8),
-                                 'NotFoundError', notFoundMessage), // Unclaimed
-          assertRejectsWithError(device.transferIn(3, 8), 'NotFoundError',
-                                 notFoundMessage), // Non-existent
+          assertRejectsWithEndpointNotFoundError(device.transferIn(2, 8)), // Unclaimed
+          assertRejectsWithEndpointNotFoundError(device.transferIn(3, 8)), // Non-existent
           assertRejectsWithError(
               device.transferIn(16, 8), 'IndexSizeError', rangeError),
-          assertRejectsWithError(device.transferOut(2, data),
-                                 'NotFoundError', notFoundMessage), // Unclaimed
-          assertRejectsWithError(device.transferOut(3, data), 'NotFoundError',
-                                 notFoundMessage), // Non-existent
+          assertRejectsWithEndpointNotFoundError(device.transferOut(2, data)), // Unclaimed
+          assertRejectsWithEndpointNotFoundError(device.transferOut(3, data)), // Non-existent
           assertRejectsWithError(
               device.transferOut(16, data), 'IndexSizeError', rangeError),
       ]));
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..642885369
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM.html
new file mode 100644
index 0000000..ea38387
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script>
+testRunner.waitUntilDone();
+</script>
+<script src="../../../forms/resources/picker-common.js"></script>
+<input type="time" id="time" value="00:23">
+<script>
+openPicker(document.getElementById('time'), () => testRunner.notifyDone(), () => testRunner.notifyDone());
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..6e7f5e4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM.html
new file mode 100644
index 0000000..a57c3cb
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script>
+testRunner.waitUntilDone();
+</script>
+<script src="../../../forms/resources/picker-common.js"></script>
+<input type="time" id="time" value="12:48">
+<script>
+openPicker(document.getElementById('time'), () => testRunner.notifyDone(), () => testRunner.notifyDone());
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..bdc61b8
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour.html
new file mode 100644
index 0000000..3675062
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script>
+testRunner.waitUntilDone();
+if (window.internals)
+    internals.settings.setLangAttributeAwareFormControlUIEnabled(true);
+</script>
+<script src="../../../forms/resources/picker-common.js"></script>
+<input type="time" id="time" value="14:15" lang="ru">
+<script>
+openPicker(document.getElementById('time'), () => testRunner.notifyDone(), () => testRunner.notifyDone());
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..2579f791
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko.html
new file mode 100644
index 0000000..b8a7fd9
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script>
+testRunner.waitUntilDone();
+if (window.internals)
+    internals.settings.setLangAttributeAwareFormControlUIEnabled(true);
+</script>
+<script src="../../../forms/resources/picker-common.js"></script>
+<input type="time" id="time" value="14:15" lang="ko">
+<script>
+openPicker(document.getElementById('time'), () => testRunner.notifyDone(), () => testRunner.notifyDone());
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..e5bb4c4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm.html
new file mode 100644
index 0000000..00377a58
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script>
+testRunner.waitUntilDone();
+</script>
+<script src="../../../forms/resources/picker-common.js"></script>
+<input type="time" id="time" value="18:17:28" step="1">
+<script>
+openPicker(document.getElementById('time'), () => testRunner.notifyDone(), () => testRunner.notifyDone());
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-select-value-12-AM.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-select-value-12-AM.html
new file mode 100644
index 0000000..f90a72f
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-select-value-12-AM.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../../resources/testharness.js"></script>
+<script src="../../../../resources/testharnessreport.js"></script>
+<script src="../../../forms/resources/common.js"></script>
+<script src="../../../forms/resources/picker-common.js"></script>
+<script src="../../../forms/calendar-picker/resources/calendar-picker-common.js"></script>
+</head>
+<body>
+<input type="time" id="time" value="22:15" step="1">
+<script>
+
+let t = async_test('Test select 12AM value in time popup');
+
+function selectValue() {
+  let timeElement = document.getElementById("time");
+  timeElement.addEventListener("change", t.step_func_done(() => {
+    assert_equals(timeElement.value, "00:17:00");
+  }));
+  clickTimeCellAt(0, 2);
+  clickTimeCellAt(1, 2);
+  clickTimeCellAt(3, 1);
+  clickSubmitTimeButton();
+}
+
+t.step(() => {
+  openPicker(document.getElementById('time'), t.step_func(selectValue),  t.step_func_done(() => {
+    assert_false(internals.runtimeFlags.formControlsRefreshEnabled, "Popup did not open.");
+  }));
+});
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-select-value-12-PM.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-select-value-12-PM.html
new file mode 100644
index 0000000..628d713
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-select-value-12-PM.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../../resources/testharness.js"></script>
+<script src="../../../../resources/testharnessreport.js"></script>
+<script src="../../../forms/resources/common.js"></script>
+<script src="../../../forms/resources/picker-common.js"></script>
+<script src="../../../forms/calendar-picker/resources/calendar-picker-common.js"></script>
+</head>
+<body>
+<input type="time" id="time" value="23:15" step="1">
+<script>
+
+let t = async_test('Test select 12PM value in time popup');
+
+function selectValue() {
+  let timeElement = document.getElementById("time");
+  timeElement.addEventListener("change", t.step_func_done(() => {
+    assert_equals(timeElement.value, "12:17:04");
+  }));
+  clickTimeCellAt(0, 1);
+  clickTimeCellAt(1, 2);
+  clickTimeCellAt(2, 4);
+  clickSubmitTimeButton();
+}
+
+t.step(() => {
+  openPicker(document.getElementById('time'), t.step_func(selectValue),  t.step_func_done(() => {
+    assert_false(internals.runtimeFlags.formControlsRefreshEnabled, "Popup did not open.");
+  }));
+});
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-select-value-PM-to-AM.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-select-value-PM-to-AM.html
new file mode 100644
index 0000000..03fd768
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/time-picker/time-picker-select-value-PM-to-AM.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../../resources/testharness.js"></script>
+<script src="../../../../resources/testharnessreport.js"></script>
+<script src="../../../forms/resources/common.js"></script>
+<script src="../../../forms/resources/picker-common.js"></script>
+<script src="../../../forms/calendar-picker/resources/calendar-picker-common.js"></script>
+</head>
+<body>
+<input type="time" id="time" value="14:15" step="1">
+<script>
+
+let t = async_test('Test select AM value in time popup');
+
+function selectValue() {
+  let timeElement = document.getElementById("time");
+  timeElement.addEventListener("change", t.step_func_done(() => {
+    assert_equals(timeElement.value, "06:16:00");
+  }));
+  clickTimeCellAt(0, 4);
+  clickTimeCellAt(1, 1);
+  clickTimeCellAt(3, 1);
+  clickSubmitTimeButton();
+}
+
+t.step(() => {
+  openPicker(document.getElementById('time'), t.step_func(selectValue),  t.step_func_done(() => {
+    assert_false(internals.runtimeFlags.formControlsRefreshEnabled, "Popup did not open.");
+  }));
+});
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/speech/scripted/mock-speechrecognizer.js b/third_party/blink/web_tests/fast/speech/scripted/mock-speechrecognizer.js
index 666e8e8..8c34b19e 100644
--- a/third_party/blink/web_tests/fast/speech/scripted/mock-speechrecognizer.js
+++ b/third_party/blink/web_tests/fast/speech/scripted/mock-speechrecognizer.js
@@ -16,7 +16,7 @@
     this.task_queue_ = [];
 
     this.binding_ = new mojo.Binding(blink.mojom.SpeechRecognizer, this);
-    this.interceptor_ = new MojoInterfaceInterceptor(blink.mojom.SpeechRecognizer.name);
+    this.interceptor_ = new MojoInterfaceInterceptor(blink.mojom.SpeechRecognizer.name, "context", true);
     this.interceptor_.oninterfacerequest = e => {
       this.binding_.bind(e.handle);
       this.binding_.setConnectionErrorHandler(() => {
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
index 5d12857a..c19f445 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/multicol/composited-opacity-2nd-and-3rd-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/multicol/composited-with-child-layer-in-next-column-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/multicol/composited-with-child-layer-in-next-column-expected.png
index a08106f..e529c295 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/multicol/composited-with-child-layer-in-next-column-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/multicol/composited-with-child-layer-in-next-column-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/overflow/float-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/overflow/float-overflow-expected.txt
index 05e6d5d8..54f5b0c 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/overflow/float-overflow-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/overflow/float-overflow-expected.txt
@@ -47,22 +47,22 @@
           "reason": "geometry"
         },
         {
-          "object": "LayoutDeprecatedFlexibleBox DIV class='outer box'",
+          "object": "LayoutFlexibleBox DIV class='outer box'",
           "rect": [61, 249, 62, 22],
           "reason": "geometry"
         },
         {
-          "object": "LayoutDeprecatedFlexibleBox DIV class='outer box'",
+          "object": "LayoutFlexibleBox DIV class='outer box'",
           "rect": [61, 243, 62, 22],
           "reason": "geometry"
         },
         {
-          "object": "LayoutDeprecatedFlexibleBox DIV class='outer box'",
+          "object": "LayoutFlexibleBox DIV class='outer box'",
           "rect": [61, 210, 62, 22],
           "reason": "geometry"
         },
         {
-          "object": "LayoutDeprecatedFlexibleBox DIV class='outer box'",
+          "object": "LayoutFlexibleBox DIV class='outer box'",
           "rect": [61, 204, 62, 22],
           "reason": "geometry"
         },
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/overflow/float-overflow-right-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/overflow/float-overflow-right-expected.txt
index 237a747b..f6fe399 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/overflow/float-overflow-right-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/overflow/float-overflow-right-expected.txt
@@ -47,22 +47,22 @@
           "reason": "geometry"
         },
         {
-          "object": "LayoutDeprecatedFlexibleBox DIV class='outer box'",
+          "object": "LayoutFlexibleBox DIV class='outer box'",
           "rect": [677, 249, 62, 22],
           "reason": "geometry"
         },
         {
-          "object": "LayoutDeprecatedFlexibleBox DIV class='outer box'",
+          "object": "LayoutFlexibleBox DIV class='outer box'",
           "rect": [677, 243, 62, 22],
           "reason": "geometry"
         },
         {
-          "object": "LayoutDeprecatedFlexibleBox DIV class='outer box'",
+          "object": "LayoutFlexibleBox DIV class='outer box'",
           "rect": [677, 210, 62, 22],
           "reason": "geometry"
         },
         {
-          "object": "LayoutDeprecatedFlexibleBox DIV class='outer box'",
+          "object": "LayoutFlexibleBox DIV class='outer box'",
           "rect": [677, 204, 62, 22],
           "reason": "geometry"
         },
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 6c6af40..36b3f60b 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
@@ -7,39 +7,14 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "EllipsisBox",
+          "object": "LayoutDeprecatedFlexibleBox DIV id='container' class='folded'",
           "rect": [8, 8, 285, 24],
-          "reason": "disappeared"
+          "reason": "chunk disappeared"
         },
         {
-          "object": "LayoutDeprecatedFlexibleBox DIV id='container'",
-          "rect": [8, 8, 285, 2],
-          "reason": "incremental"
-        },
-        {
-          "object": "InlineTextBox '___these_two_lines_should_be_identical___'",
+          "object": "LayoutFlexibleBox DIV id='container'",
           "rect": [8, 10, 284, 43],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '___these_two_lines_should_be_identical___'",
-          "rect": [8, 10, 284, 43],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox '___these_two_lines_should_be_identical___'",
-          "rect": [8, 10, 284, 43],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutDeprecatedFlexibleBox DIV id='container'",
-          "rect": [8, 32, 284, 21],
-          "reason": "incremental"
-        },
-        {
-          "object": "LayoutDeprecatedFlexibleBox DIV id='container'",
-          "rect": [292, 10, 1, 22],
-          "reason": "incremental"
+          "reason": "chunk appeared"
         }
       ]
     }
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..a82c1b9
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..0693100
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..8032b6c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..3d0ab1e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..4ec9496
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..74a68d7b3
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..e17aa47
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..6bd9481
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
index f589e13..26d0ee45 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..5f1c7c53f
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
index 14bb827..8fd360d8 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..c9d1cdcc
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..bdcb422
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..700f9e1a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..a22ca14
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..2b680b0
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..41a8cb3
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..140a596
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..eb003ed
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..905ce85
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
index 9efa2b1..c715380f 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..47d77cd
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
index b920ab77..7c695cab 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..bb5cc44
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..9758875
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..79c5b68
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..13f5ecd
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
index 8f762ea6..99816c30 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..2a48053d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
index e952b3a..004d040 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..9b0ac7a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..9758875
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..79c5b68
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..13f5ecd
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
index 8f762ea6..99816c30 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..2a48053d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
index e952b3a..004d040 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..9b0ac7a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..68ae5d2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..ea9d1c4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..339ca1a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
index 220ec0e..0463dc58 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..1197cb4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
index f1829177..b2dde208 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..bd556f0
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..626732d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..7a5d30c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..a911f7f
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..6872c70
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..f1df2ec1
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..68ae5d2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..ea9d1c4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..339ca1a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
index 220ec0e..0463dc58 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..1197cb4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
index f1829177..b2dde208 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..bd556f0
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/win7/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..4e21479
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..c351dcc
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
new file mode 100644
index 0000000..d1344e1
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-AM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
new file mode 100644
index 0000000..0a4dc3d
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-12-PM-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
new file mode 100644
index 0000000..db48182e
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-24-hour-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
index 837f0d8..eaf74d1 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
new file mode 100644
index 0000000..afeec17b
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-ko-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
index a8120af..826729f 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-milliseconds-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
new file mode 100644
index 0000000..5813df14
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/time-picker/time-picker-appearance-seconds-pm-expected.png
Binary files differ
diff --git a/third_party/wayland-protocols/BUILD.gn b/third_party/wayland-protocols/BUILD.gn
index 8a204e5..6d9a2d6f3 100644
--- a/third_party/wayland-protocols/BUILD.gn
+++ b/third_party/wayland-protocols/BUILD.gn
@@ -4,6 +4,12 @@
 
 import("//third_party/wayland/wayland_protocol.gni")
 
+wayland_protocol("gtk_primary_selection_protocol") {
+  sources = [
+    "unstable/gtk-primary-selection/gtk-primary-selection.xml",
+  ]
+}
+
 wayland_protocol("xdg_shell_protocol") {
   sources = [
     "src/unstable/xdg-shell/xdg-shell-unstable-v5.xml",
diff --git a/third_party/wayland-protocols/unstable/gtk-primary-selection/README b/third_party/wayland-protocols/unstable/gtk-primary-selection/README
new file mode 100644
index 0000000..9f02e5f
--- /dev/null
+++ b/third_party/wayland-protocols/unstable/gtk-primary-selection/README
@@ -0,0 +1,4 @@
+GTK primary selection protocol
+
+Maintainers:
+Alexander Dunaev <adunaev@igalia.com>
diff --git a/third_party/wayland-protocols/unstable/gtk-primary-selection/gtk-primary-selection.xml b/third_party/wayland-protocols/unstable/gtk-primary-selection/gtk-primary-selection.xml
new file mode 100644
index 0000000..02cab94f
--- /dev/null
+++ b/third_party/wayland-protocols/unstable/gtk-primary-selection/gtk-primary-selection.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="gtk_primary_selection">
+  <copyright>
+    Copyright © 2015, 2016 Red Hat
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <description summary="Primary selection protocol">
+    This protocol provides the ability to have a primary selection device to
+    match that of the X server. This primary selection is a shortcut to the
+    common clipboard selection, where text just needs to be selected in order
+    to allow copying it elsewhere. The de facto way to perform this action
+    is the middle mouse button, although it is not limited to this one.
+
+    Clients wishing to honor primary selection should create a primary
+    selection source and set it as the selection through
+    wp_primary_selection_device.set_selection whenever the text selection
+    changes. In order to minimize calls in pointer-driven text selection,
+    it should happen only once after the operation finished. Similarly,
+    a NULL source should be set when text is unselected.
+
+    wp_primary_selection_offer objects are first announced through the
+    wp_primary_selection_device.data_offer event. Immediately after this event,
+    the primary data offer will emit wp_primary_selection_offer.offer events
+    to let know of the mime types being offered.
+
+    When the primary selection changes, the client with the keyboard focus
+    will receive wp_primary_selection_device.selection events. Only the client
+    with the keyboard focus will receive such events with a non-NULL
+    wp_primary_selection_offer. Across keyboard focus changes, previously
+    focused clients will receive wp_primary_selection_device.events with a
+    NULL wp_primary_selection_offer.
+
+    In order to request the primary selection data, the client must pass
+    a recent serial pertaining to the press event that is triggering the
+    operation, if the compositor deems the serial valid and recent, the
+    wp_primary_selection_source.send event will happen in the other end
+    to let the transfer begin. The client owning the primary selection
+    should write the requested data, and close the file descriptor
+    immediately.
+
+    If the primary selection owner client disappeared during the transfer,
+    the client reading the data will receive a
+    wp_primary_selection_device.selection event with a NULL
+    wp_primary_selection_offer, the client should take this as a hint
+    to finish the reads related to the no longer existing offer.
+
+    The primary selection owner should be checking for errors during
+    writes, merely cancelling the ongoing transfer if any happened.
+  </description>
+
+  <interface name="gtk_primary_selection_device_manager" version="1">
+    <description summary="X primary selection emulation">
+      The primary selection device manager is a singleton global object that
+      provides access to the primary selection. It allows to create
+      wp_primary_selection_source objects, as well as retrieving the per-seat
+      wp_primary_selection_device objects.
+    </description>
+
+    <request name="create_source">
+      <description summary="create a new primary selection source">
+	Create a new primary selection source.
+      </description>
+      <arg name="id" type="new_id" interface="gtk_primary_selection_source"/>
+    </request>
+
+    <request name="get_device">
+      <description summary="create a new primary selection device">
+        Create a new data device for a given seat.
+      </description>
+      <arg name="id" type="new_id" interface="gtk_primary_selection_device"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the primary selection device manager">
+	Destroy the primary selection device manager.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="gtk_primary_selection_device" version="1">
+    <request name="set_selection">
+      <description summary="set the primary selection">
+	Replaces the current selection. The previous owner of the primary selection
+	will receive a wp_primary_selection_source.cancelled event.
+
+	To unset the selection, set the source to NULL.
+      </description>
+      <arg name="source" type="object" interface="gtk_primary_selection_source" allow-null="true"/>
+      <arg name="serial" type="uint" summary="serial of the event that triggered this request"/>
+    </request>
+
+    <event name="data_offer">
+      <description summary="introduce a new wp_primary_selection_offer">
+	Introduces a new wp_primary_selection_offer object that may be used
+	to receive the current primary selection. Immediately following this
+	event, the new wp_primary_selection_offer object will send
+	wp_primary_selection_offer.offer events to describe the offered mime
+	types.
+      </description>
+      <arg name="offer" type="new_id" interface="gtk_primary_selection_offer"/>
+    </event>
+
+    <event name="selection">
+      <description summary="advertise a new primary selection">
+	The wp_primary_selection_device.selection event is sent to notify the
+	client of a new primary selection. This event is sent after the
+	wp_primary_selection.data_offer event introducing this object, and after
+	the offer has announced its mimetypes through
+	wp_primary_selection_offer.offer.
+
+	The data_offer is valid until a new offer or NULL is received
+	or until the client loses keyboard focus. The client must destroy the
+	previous selection data_offer, if any, upon receiving this event.
+      </description>
+      <arg name="id" type="object" interface="gtk_primary_selection_offer" allow-null="true"/>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the primary selection device">
+	Destroy the primary selection device.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="gtk_primary_selection_offer" version="1">
+    <description summary="offer to transfer primary selection contents">
+      A wp_primary_selection_offer represents an offer to transfer the contents
+      of the primary selection clipboard to the client. Similar to
+      wl_data_offer, the offer also describes the mime types that the source
+      will transferthat the
+      data can be converted to and provides the mechanisms for transferring the
+      data directly to the client.
+    </description>
+
+    <request name="receive">
+      <description summary="request that the data is transferred">
+	To transfer the contents of the primary selection clipboard, the client
+	issues this request and indicates the mime type that it wants to
+	receive. The transfer happens through the passed file descriptor
+	(typically created with the pipe system call). The source client writes
+	the data in the mime type representation requested and then closes the
+	file descriptor.
+
+	The receiving client reads from the read end of the pipe until EOF and
+	closes its end, at which point the transfer is complete.
+      </description>
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the primary selection offer">
+	Destroy the primary selection offer.
+      </description>
+    </request>
+
+    <event name="offer">
+      <description summary="advertise offered mime type">
+	Sent immediately after creating announcing the wp_primary_selection_offer
+	through wp_primary_selection_device.data_offer. One event is sent per
+	offered mime type.
+      </description>
+      <arg name="mime_type" type="string"/>
+    </event>
+  </interface>
+
+  <interface name="gtk_primary_selection_source" version="1">
+    <description summary="offer to replace the contents of the primary selection">
+      The source side of a wp_primary_selection_offer, it provides a way to
+      describe the offered data and respond to requests to transfer the
+      requested contents of the primary selection clipboard.
+    </description>
+
+    <request name="offer">
+      <description summary="add an offered mime type">
+	This request adds a mime type to the set of mime types advertised to
+	targets. Can be called several times to offer multiple types.
+      </description>
+      <arg name="mime_type" type="string"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the primary selection source">
+	Destroy the primary selection source.
+      </description>
+    </request>
+
+    <event name="send">
+      <description summary="send the primary selection contents">
+	Request for the current primary selection contents from the client.
+	Send the specified mime type over the passed file descriptor, then
+	close it.
+      </description>
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </event>
+
+    <event name="cancelled">
+      <description summary="request for primary selection contents was canceled">
+	This primary selection source is no longer valid. The client should
+	clean up and destroy this primary selection source.
+      </description>
+    </event>
+  </interface>
+</protocol>
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
index 7aacf65..fa2ad5c 100644
--- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
+++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
@@ -57,6 +57,8 @@
       import {Renderer, createWebGLContext} from '../js/cottontail/src/core/renderer.js';
       import {Gltf2Node} from '../js/cottontail/src/nodes/gltf2.js';
       import {QueryArgs} from '../js/cottontail/src/util/query-args.js';
+      import {Node} from '../js/cottontail/src/core/node.js';
+      import {RayNode} from '../js/cottontail/src/nodes/ray-node.js';
       import {FallbackHelper} from '../js/cottontail/src/util/fallback-helper.js';
 
       // If requested, initialize the WebXR polyfill
@@ -64,9 +66,14 @@
         var polyfill = new WebXRPolyfill();
       }
 
+      // Debug constants.
+      const visualiseOrigin = false;
+      const visualiseFloorSpace = false;
+
       // XR globals.
       let xrButton = null;
       let xrRefSpace = null;
+      let xrFloorSpace = null;
 
       // WebGL scene globals.
       let gl = null;
@@ -78,6 +85,33 @@
       solarSystem.scale = [0.1, 0.1, 0.1];
       scene.addNode(solarSystem);
 
+      // Visualise the origin.
+      if(visualiseOrigin) {
+        let xRay = new RayNode({direction : [5, 0, 0], baseColor : [1, 0, 0, 1]});
+        let yRay = new RayNode({direction : [0, 5, 0], baseColor : [0, 1, 0, 1]});
+        let zRay = new RayNode({direction : [0, 0, 5], baseColor : [0, 0, 1, 1]});
+
+        scene.addNode(xRay);
+        scene.addNode(yRay);
+        scene.addNode(zRay);
+      }
+
+      // Visualise the floor space.
+      let floorSpaceNode = new Node();
+      floorSpaceNode.visible = false;
+
+      if(visualiseFloorSpace) {
+        let xRay = new RayNode({direction : [5, 0, 0], baseColor : [1, 0, 0, 1]});
+        let yRay = new RayNode({direction : [0, 5, 0], baseColor : [0, 1, 0, 1]});
+        let zRay = new RayNode({direction : [0, 0, 5], baseColor : [0, 0, 1, 1]});
+
+        floorSpaceNode.addNode(xRay);
+        floorSpaceNode.addNode(yRay);
+        floorSpaceNode.addNode(zRay);
+      }
+
+      scene.addNode(floorSpaceNode);
+
       // No skybox is added to this scene, and we're not clearing the background to
       // black because we want the real world to show through.
       scene.clear = false;
@@ -100,7 +134,10 @@
 
         // Test the new XRSessionInit dictionary by asking for a nonexistent
         // optional feature. This should be silently ignored.
-        let options = {optionalFeatures: ['unicorns-and-rainbows']};
+        let options = {
+          requiredFeatures: ['local-floor'],
+          optionalFeatures: ['unicorns-and-rainbows'],
+        };
 
         // Even though this is a non-immersive session, the fact that it's
         // using environment integration means it must be requested in a user
@@ -130,8 +167,12 @@
         session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
 
         session.requestReferenceSpace('local').then((refSpace) => {
-          xrRefSpace = refSpace;
-          session.requestAnimationFrame(onXRFrame);
+          session.requestReferenceSpace('local-floor').then((floorSpace) => {
+            xrRefSpace = refSpace;
+            xrFloorSpace = floorSpace;
+
+            session.requestAnimationFrame(onXRFrame);
+          });
         });
       }
 
@@ -148,6 +189,15 @@
         let session = frame.session;
         let pose = frame.getViewerPose(xrRefSpace);
 
+        let floorSpacePose = xrFloorSpace ? frame.getPose(xrFloorSpace, xrRefSpace) : null;
+
+        if(floorSpacePose && visualiseFloorSpace) {
+          floorSpaceNode.matrix = floorSpacePose.transform.matrix;
+          floorSpaceNode.visible = true;
+        } else {
+          floorSpaceNode.visible = false;
+        }
+
         scene.startFrame();
 
         session.requestAnimationFrame(onXRFrame);
diff --git a/ui/base/clipboard/clipboard_constants.cc b/ui/base/clipboard/clipboard_constants.cc
index 649a78c1..f4e9a0e 100644
--- a/ui/base/clipboard/clipboard_constants.cc
+++ b/ui/base/clipboard/clipboard_constants.cc
@@ -7,6 +7,7 @@
 namespace ui {
 
 const char kMimeTypeText[] = "text/plain";
+const char kMimeTypeTextUtf8[] = "text/plain;charset=utf-8";
 const char kMimeTypeURIList[] = "text/uri-list";
 const char kMimeTypeMozillaURL[] = "text/x-moz-url";
 const char kMimeTypeDownloadURL[] = "downloadurl";
diff --git a/ui/base/clipboard/clipboard_constants.h b/ui/base/clipboard/clipboard_constants.h
index 9f114db2..cbee2e1a4b 100644
--- a/ui/base/clipboard/clipboard_constants.h
+++ b/ui/base/clipboard/clipboard_constants.h
@@ -27,6 +27,7 @@
 
 // MIME type constants.
 COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeText[];
+COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeTextUtf8[];
 COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeURIList[];
 COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeDownloadURL[];
 COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) extern const char kMimeTypeMozillaURL[];
diff --git a/ui/file_manager/file_manager/background/js/file_operation_handler.js b/ui/file_manager/file_manager/background/js/file_operation_handler.js
index 36bc838..fdd6b261 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_handler.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_handler.js
@@ -63,6 +63,9 @@
         item.id = event.taskId;
         item.type = FileOperationHandler.getType_(event.status.operationType);
         item.message = FileOperationHandler.getMessage_(event);
+        item.itemCount = event.status.numRemainingItems;
+        item.sourceMessage = event.status.processingEntryName;
+        item.destinationMessage = event.status.targetDirEntryName;
         item.progressMax = event.status.totalBytes;
         item.progressValue = event.status.processedBytes;
         item.cancelCallback = this.fileOperationManager_.requestTaskCancel.bind(
diff --git a/ui/file_manager/file_manager/background/js/file_operation_util.js b/ui/file_manager/file_manager/background/js/file_operation_util.js
index e064cf4..51f7fe9 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_util.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_util.js
@@ -645,7 +645,8 @@
       numRemainingItems: this.numRemainingItems,
       totalBytes: this.totalBytes,
       processedBytes: this.processedBytes,
-      processingEntryName: processingEntry ? processingEntry.name : ''
+      processingEntryName: processingEntry ? processingEntry.name : '',
+      targetDirEntryName: this.targetDirEntry.name
     };
   }
 
diff --git a/ui/file_manager/file_manager/common/js/file_type.js b/ui/file_manager/file_manager/common/js/file_type.js
index 131576e..ccc8ae5 100644
--- a/ui/file_manager/file_manager/common/js/file_type.js
+++ b/ui/file_manager/file_manager/common/js/file_type.js
@@ -494,6 +494,17 @@
  */
 FileType.getType = (entry, opt_mimeType) => {
   if (entry.isDirectory) {
+    // For removable partitions, use the file system type.
+    if (/** @type {VolumeEntry}*/ (entry).volumeInfo &&
+        /** @type {VolumeEntry}*/ (entry).volumeInfo.diskFileSystemType) {
+      return {
+        name: '',
+        type: 'partition',
+        subtype:
+            /** @type {VolumeEntry}*/ (entry).volumeInfo.diskFileSystemType,
+        icon: '',
+      };
+    }
     return FileType.DIRECTORY;
   }
 
diff --git a/ui/file_manager/file_manager/common/js/progress_center_common.js b/ui/file_manager/file_manager/common/js/progress_center_common.js
index 8cdc995..01aff58 100644
--- a/ui/file_manager/file_manager/common/js/progress_center_common.js
+++ b/ui/file_manager/file_manager/common/js/progress_center_common.js
@@ -88,13 +88,6 @@
     this.destinationMessage = '';
 
     /**
-     * Optional sub message for the progress item.
-     * TODO(crbug.com/947388) get rid of the subMessage field.
-     * @type {string}
-     */
-    this.subMessage = '';
-
-    /**
      * Number of items being processed.
      * @type {number}
      */
@@ -189,19 +182,12 @@
 
   /**
    * Clones the item.
-   * @return {ProgressCenterItem} New item having the same properties with this.
+   * TODO(adanilo) This is used by ProgressCenterItemGroup only, remove when
+   * VS feedback panels are turned on permanently.
+   * @return {!ProgressCenterItem} New item having the same properties as this.
    */
   clone() {
-    const newItem = new ProgressCenterItem();
-    newItem.id = this.id;
-    newItem.state = this.state;
-    newItem.message = this.message;
-    newItem.progressMax = this.progressMax;
-    newItem.progressValue = this.progressValue;
-    newItem.type = this.type;
-    newItem.single = this.single;
-    newItem.quiet = this.quiet;
-    newItem.cancelCallback = this.cancelCallback;
-    return newItem;
+    const clonedItem = Object.assign(new ProgressCenterItem(), this);
+    return /** @type {!ProgressCenterItem} */ (clonedItem);
   }
 }
diff --git a/ui/file_manager/file_manager/foreground/js/file_list_model.js b/ui/file_manager/file_manager/foreground/js/file_list_model.js
index aff8f98..f53a216 100644
--- a/ui/file_manager/file_manager/foreground/js/file_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/file_list_model.js
@@ -76,6 +76,11 @@
    * @return {string} Localized string representation of file type.
    */
   static getFileTypeString(fileType) {
+    // Partitions on removable volumes are treated separately, they don't
+    // have translatable names.
+    if (fileType.type === 'partition') {
+      return fileType.subtype;
+    }
     if (fileType.subtype) {
       return strf(fileType.name, fileType.subtype);
     } else {
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
index d8562cc..bb3da3e 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -547,8 +547,6 @@
                 const destinationName = util.getEntryLabel(
                     destinationLocationInfo, destinationEntry);
                 item.destinationMessage = destinationName;
-                item.subMessage =
-                    strf('TO_FOLDER_NAME', item.destinationMessage);
                 this.progressCenter_.updateItem(item);
 
                 // Start the pasting operation.
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index a624ccd..6f43340a 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -961,12 +961,6 @@
             .contentMimeType;
     div.textContent =
         FileListModel.getFileTypeString(FileType.getType(entry, mimeType));
-
-    // For removable partitions, display file system type.
-    if (!mimeType && entry.volumeInfo && entry.volumeInfo.diskFileSystemType) {
-      div.textContent = entry.volumeInfo.diskFileSystemType;
-    }
-
     return div;
   }
 
diff --git a/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js b/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js
index 687b5bd3..f6e0fabe 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js
@@ -420,8 +420,10 @@
             this.generateSourceString_(item, panelItem.userData);
         panelItem.setAttribute('primary-text', primaryText);
         panelItem.setAttribute('data-progress-id', item.id);
-        if (item.subMessage) {
-          panelItem.setAttribute('secondary-text', item.subMessage);
+        if (item.destinationMessage) {
+          panelItem.setAttribute(
+              'secondary-text',
+              strf('TO_FOLDER_NAME', item.destinationMessage));
         }
         // On progress panels, make the cancel button aria-lable more useful.
         const cancelLabel = strf('CANCEL_ACTIVITY_LABEL', primaryText);
diff --git a/ui/file_manager/integration_tests/file_manager/file_display.js b/ui/file_manager/integration_tests/file_manager/file_display.js
index 5670a65f..283121d 100644
--- a/ui/file_manager/integration_tests/file_manager/file_display.js
+++ b/ui/file_manager/integration_tests/file_manager/file_display.js
@@ -233,8 +233,63 @@
 };
 
 /**
- * Tests partitions display in the file table when root removable entry
- * is selected. Checks file system type is displayed.
+ * Tests that the file system type is properly displayed in the type
+ * column. Checks that the entries can be properly sorted by type.
+ * crbug.com/973743
+ */
+testcase.fileDisplayUsbPartitionSort = async () => {
+  const removableGroup = '#directory-tree [root-type-icon="removable"]';
+
+  // Open Files app on local downloads.
+  const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
+
+  // Mount removable device with partitions.
+  await sendTestMessage({name: 'mountUsbWithMultiplePartitionTypes'});
+
+  // Wait and select the removable group by clicking the label.
+  await remoteCall.waitAndClickElement(appId, removableGroup);
+
+  // Wait for partitions to appear in the file table list.
+  let expectedRows = [
+    ['partition-3', '--', 'vfat'],
+    ['partition-2', '--', 'ext4'],
+    ['partition-1', '--', 'ntfs'],
+  ];
+  const options = {orderCheck: true, ignoreLastModifiedTime: true};
+  await remoteCall.waitForFiles(appId, expectedRows, options);
+
+  // Sort by type in ascending order.
+  await remoteCall.callRemoteTestUtil(
+      'fakeMouseClick', appId, ['.table-header-cell:nth-of-type(4)']);
+  await remoteCall.waitForElement(appId, '.table-header-sort-image-asc');
+
+  // Check that partitions are sorted in ascending order based on the partition
+  // type.
+  expectedRows = [
+    ['partition-2', '--', 'ext4'],
+    ['partition-1', '--', 'ntfs'],
+    ['partition-3', '--', 'vfat'],
+  ];
+  await remoteCall.waitForFiles(appId, expectedRows, options);
+
+  // Sort by type in descending order.
+  await remoteCall.callRemoteTestUtil(
+      'fakeMouseClick', appId, ['.table-header-cell:nth-of-type(4)']);
+  await remoteCall.waitForElement(appId, '.table-header-sort-image-desc');
+
+  // Check that partitions are sorted in descending order based on the partition
+  // type.
+  expectedRows = [
+    ['partition-3', '--', 'vfat'],
+    ['partition-1', '--', 'ntfs'],
+    ['partition-2', '--', 'ext4'],
+  ];
+  await remoteCall.waitForFiles(appId, expectedRows, options);
+};
+
+/**
+ * Tests display of partitions in file list after mounting a removable USB
+ * volume.
  */
 testcase.fileDisplayPartitionFileTable = async () => {
   const removableGroup = '#directory-tree [root-type-icon="removable"]';
@@ -259,7 +314,7 @@
 
   const partitionTwo = await remoteCall.waitForElement(
       appId, '#file-list [file-name="partition-2"] .type');
-  chrome.test.assertEq('ext4', partitionOne.text);
+  chrome.test.assertEq('ext4', partitionTwo.text);
 };
 
 /**
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index babf798..24a14654 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -31,6 +31,20 @@
     "gpu/wayland_surface_factory.cc",
     "gpu/wayland_surface_factory.h",
     "gpu/wayland_surface_gpu.h",
+    "host/gtk_primary_selection_device.cc",
+    "host/gtk_primary_selection_device.h",
+    "host/gtk_primary_selection_device_manager.cc",
+    "host/gtk_primary_selection_device_manager.h",
+    "host/gtk_primary_selection_offer.cc",
+    "host/gtk_primary_selection_offer.h",
+    "host/gtk_primary_selection_source.cc",
+    "host/gtk_primary_selection_source.h",
+    "host/internal/wayland_data_device_base.cc",
+    "host/internal/wayland_data_device_base.h",
+    "host/internal/wayland_data_offer_base.cc",
+    "host/internal/wayland_data_offer_base.h",
+    "host/internal/wayland_data_source_base.cc",
+    "host/internal/wayland_data_source_base.h",
     "host/wayland_buffer_manager_connector.cc",
     "host/wayland_buffer_manager_connector.h",
     "host/wayland_buffer_manager_host.cc",
@@ -109,6 +123,7 @@
     "//mojo/public/cpp/system",
     "//skia",
     "//third_party/wayland:wayland_client",
+    "//third_party/wayland-protocols:gtk_primary_selection_protocol",
     "//third_party/wayland-protocols:linux_dmabuf_protocol",
     "//third_party/wayland-protocols:presentation_time_protocol",
     "//third_party/wayland-protocols:text_input_protocol",
diff --git a/ui/ozone/platform/wayland/DEPS b/ui/ozone/platform/wayland/DEPS
index dfc8f06..32f3223e 100644
--- a/ui/ozone/platform/wayland/DEPS
+++ b/ui/ozone/platform/wayland/DEPS
@@ -3,6 +3,7 @@
   "+ui/base/hit_test.h", # UI hit test doesn't bring in all of ui/base.
   "+ui/base/ui_base_features.h",
   "+mojo/public",
+  "+ui/base/clipboard/clipboard_constants.h",
   "+ui/base/dragdrop/drag_drop_types.h",
   "+ui/base/dragdrop/os_exchange_data.h",
   "+ui/base/dragdrop/os_exchange_data_provider_aura.h",
diff --git a/ui/ozone/platform/wayland/common/wayland_object.cc b/ui/ozone/platform/wayland/common/wayland_object.cc
index afb78c83..859b8d8 100644
--- a/ui/ozone/platform/wayland/common/wayland_object.cc
+++ b/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
 
+#include <gtk-primary-selection-client-protocol.h>
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include <presentation-time-client-protocol.h>
 #include <text-input-unstable-v1-client-protocol.h>
@@ -53,6 +54,28 @@
 
 }  // namespace
 
+const wl_interface*
+    ObjectTraits<gtk_primary_selection_device_manager>::interface =
+        &gtk_primary_selection_device_manager_interface;
+void (*ObjectTraits<gtk_primary_selection_device_manager>::deleter)(
+    gtk_primary_selection_device_manager*) =
+    &gtk_primary_selection_device_manager_destroy;
+
+const wl_interface* ObjectTraits<gtk_primary_selection_device>::interface =
+    &gtk_primary_selection_device_interface;
+void (*ObjectTraits<gtk_primary_selection_device>::deleter)(
+    gtk_primary_selection_device*) = &gtk_primary_selection_device_destroy;
+
+const wl_interface* ObjectTraits<gtk_primary_selection_offer>::interface =
+    &gtk_primary_selection_offer_interface;
+void (*ObjectTraits<gtk_primary_selection_offer>::deleter)(
+    gtk_primary_selection_offer*) = &gtk_primary_selection_offer_destroy;
+
+const wl_interface* ObjectTraits<gtk_primary_selection_source>::interface =
+    &gtk_primary_selection_source_interface;
+void (*ObjectTraits<gtk_primary_selection_source>::deleter)(
+    gtk_primary_selection_source*) = &gtk_primary_selection_source_destroy;
+
 const wl_interface* ObjectTraits<wl_buffer>::interface = &wl_buffer_interface;
 void (*ObjectTraits<wl_buffer>::deleter)(wl_buffer*) = &wl_buffer_destroy;
 
diff --git a/ui/ozone/platform/wayland/common/wayland_object.h b/ui/ozone/platform/wayland/common/wayland_object.h
index 367e1c58..bac3dbe6 100644
--- a/ui/ozone/platform/wayland/common/wayland_object.h
+++ b/ui/ozone/platform/wayland/common/wayland_object.h
@@ -8,6 +8,10 @@
 #include <wayland-client-core.h>
 #include <memory>
 
+struct gtk_primary_selection_device;
+struct gtk_primary_selection_device_manager;
+struct gtk_primary_selection_offer;
+struct gtk_primary_selection_source;
 struct wl_buffer;
 struct wl_callback;
 struct wl_compositor;
@@ -47,6 +51,30 @@
 struct ObjectTraits;
 
 template <>
+struct ObjectTraits<gtk_primary_selection_device_manager> {
+  static const wl_interface* interface;
+  static void (*deleter)(gtk_primary_selection_device_manager*);
+};
+
+template <>
+struct ObjectTraits<gtk_primary_selection_device> {
+  static const wl_interface* interface;
+  static void (*deleter)(gtk_primary_selection_device*);
+};
+
+template <>
+struct ObjectTraits<gtk_primary_selection_offer> {
+  static const wl_interface* interface;
+  static void (*deleter)(gtk_primary_selection_offer*);
+};
+
+template <>
+struct ObjectTraits<gtk_primary_selection_source> {
+  static const wl_interface* interface;
+  static void (*deleter)(gtk_primary_selection_source*);
+};
+
+template <>
 struct ObjectTraits<wl_buffer> {
   static const wl_interface* interface;
   static void (*deleter)(wl_buffer*);
diff --git a/ui/ozone/platform/wayland/common/wayland_util.cc b/ui/ozone/platform/wayland/common/wayland_util.cc
index 309ab08..1bc9349 100644
--- a/ui/ozone/platform/wayland/common/wayland_util.cc
+++ b/ui/ozone/platform/wayland/common/wayland_util.cc
@@ -131,4 +131,12 @@
   return true;
 }
 
+void ReadDataFromFD(base::ScopedFD fd, std::string* contents) {
+  DCHECK(contents);
+  char buffer[1 << 10];  // 1 kB in bytes.
+  ssize_t length;
+  while ((length = read(fd.get(), buffer, sizeof(buffer))) > 0)
+    contents->append(buffer, length);
+}
+
 }  // namespace wl
diff --git a/ui/ozone/platform/wayland/common/wayland_util.h b/ui/ozone/platform/wayland/common/wayland_util.h
index 739229f..dd7ec71 100644
--- a/ui/ozone/platform/wayland/common/wayland_util.h
+++ b/ui/ozone/platform/wayland/common/wayland_util.h
@@ -5,9 +5,12 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
 #define UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
 
+#include <string>
+
 #include <wayland-client.h>
 
 #include "base/callback.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
 
@@ -39,6 +42,9 @@
 // currently mmap'ed in memory address space.
 bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer);
 
+// Helper function to read data from a file.
+void ReadDataFromFD(base::ScopedFD fd, std::string* contents);
+
 }  // namespace wl
 
 #endif  // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc b/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
new file mode 100644
index 0000000..70be8577
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
@@ -0,0 +1,64 @@
+// 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/ozone/platform/wayland/host/gtk_primary_selection_device.h"
+
+#include <gtk-primary-selection-client-protocol.h>
+
+#include "ui/ozone/platform/wayland/host/gtk_primary_selection_offer.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+
+namespace ui {
+
+// static
+GtkPrimarySelectionDevice::GtkPrimarySelectionDevice(
+    WaylandConnection* connection,
+    gtk_primary_selection_device* data_device)
+    : internal::WaylandDataDeviceBase(connection), data_device_(data_device) {
+  static const struct gtk_primary_selection_device_listener kListener = {
+      GtkPrimarySelectionDevice::OnDataOffer,
+      GtkPrimarySelectionDevice::OnSelection};
+  gtk_primary_selection_device_add_listener(data_device_.get(), &kListener,
+                                            this);
+}
+
+GtkPrimarySelectionDevice::~GtkPrimarySelectionDevice() = default;
+
+// static
+void GtkPrimarySelectionDevice::OnDataOffer(
+    void* data,
+    gtk_primary_selection_device* data_device,
+    gtk_primary_selection_offer* offer) {
+  auto* self = static_cast<GtkPrimarySelectionDevice*>(data);
+  DCHECK(self);
+
+  self->connection()->clipboard()->UpdateSequenceNumber(
+      ClipboardBuffer::kCopyPaste);
+
+  self->set_data_offer(std::make_unique<GtkPrimarySelectionOffer>(offer));
+}
+
+// static
+void GtkPrimarySelectionDevice::OnSelection(
+    void* data,
+    gtk_primary_selection_device* data_device,
+    gtk_primary_selection_offer* offer) {
+  auto* self = static_cast<GtkPrimarySelectionDevice*>(data);
+  DCHECK(self);
+
+  // 'offer' will be null to indicate that the selection is no longer valid,
+  // i.e. there is no longer clipboard data available to paste.
+  if (!offer) {
+    self->ResetDataOffer();
+
+    // Clear Clipboard cache.
+    self->connection()->clipboard()->SetData(std::string(), std::string());
+    return;
+  }
+
+  DCHECK(self->data_offer());
+  self->data_offer()->EnsureTextMimeTypeIfNeeded();
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h b/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h
new file mode 100644
index 0000000..173faae
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h
@@ -0,0 +1,51 @@
+// 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_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_DEVICE_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_DEVICE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/internal/wayland_data_device_base.h"
+
+struct gtk_primary_selection_device;
+
+namespace ui {
+
+class WaylandConnection;
+
+// This class provides access to primary selection clipboard available on GTK.
+class GtkPrimarySelectionDevice : public internal::WaylandDataDeviceBase {
+ public:
+  GtkPrimarySelectionDevice(WaylandConnection* connection,
+                            gtk_primary_selection_device* data_device);
+  ~GtkPrimarySelectionDevice() override;
+
+  gtk_primary_selection_device* data_device() const {
+    return data_device_.get();
+  }
+
+ private:
+  // gtk_primary_selection_device_listener callbacks
+  static void OnDataOffer(void* data,
+                          gtk_primary_selection_device* data_device,
+                          gtk_primary_selection_offer* offer);
+  static void OnSelection(void* data,
+                          gtk_primary_selection_device* data_device,
+                          gtk_primary_selection_offer* offer);
+
+  // The Wayland object wrapped by this instance.
+  wl::Object<gtk_primary_selection_device> data_device_;
+
+  DISALLOW_COPY_AND_ASSIGN(GtkPrimarySelectionDevice);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_DEVICE_H_
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
new file mode 100644
index 0000000..90a8225b
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.cc
@@ -0,0 +1,38 @@
+// 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/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
+
+#include <gtk-primary-selection-client-protocol.h>
+
+#include "ui/ozone/platform/wayland/host/gtk_primary_selection_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+
+namespace ui {
+
+GtkPrimarySelectionDeviceManager::GtkPrimarySelectionDeviceManager(
+    gtk_primary_selection_device_manager* manager,
+    WaylandConnection* connection)
+    : gtk_primary_selection_device_manager_(manager), connection_(connection) {
+  DCHECK(connection_);
+  DCHECK(gtk_primary_selection_device_manager_);
+}
+
+GtkPrimarySelectionDeviceManager::~GtkPrimarySelectionDeviceManager() = default;
+
+gtk_primary_selection_device* GtkPrimarySelectionDeviceManager::GetDevice() {
+  DCHECK(connection_->seat());
+  return gtk_primary_selection_device_manager_get_device(
+      gtk_primary_selection_device_manager_.get(), connection_->seat());
+}
+
+std::unique_ptr<GtkPrimarySelectionSource>
+GtkPrimarySelectionDeviceManager::CreateSource() {
+  gtk_primary_selection_source* data_source =
+      gtk_primary_selection_device_manager_create_source(
+          gtk_primary_selection_device_manager_.get());
+  return std::make_unique<GtkPrimarySelectionSource>(data_source, connection_);
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h
new file mode 100644
index 0000000..ea05aa38
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.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 UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_DEVICE_MANAGER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_DEVICE_MANAGER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+struct gtk_primary_selection_device_manager;
+struct gtk_primary_selection_device;
+
+namespace ui {
+
+class GtkPrimarySelectionSource;
+class WaylandConnection;
+
+class GtkPrimarySelectionDeviceManager {
+ public:
+  GtkPrimarySelectionDeviceManager(
+      gtk_primary_selection_device_manager* manager,
+      WaylandConnection* connection);
+  ~GtkPrimarySelectionDeviceManager();
+
+  gtk_primary_selection_device* GetDevice();
+  std::unique_ptr<GtkPrimarySelectionSource> CreateSource();
+
+ private:
+  wl::Object<gtk_primary_selection_device_manager>
+      gtk_primary_selection_device_manager_;
+
+  WaylandConnection* connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(GtkPrimarySelectionDeviceManager);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_DEVICE_MANAGER_H_
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_offer.cc b/ui/ozone/platform/wayland/host/gtk_primary_selection_offer.cc
new file mode 100644
index 0000000..3ab1ad7
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_offer.cc
@@ -0,0 +1,59 @@
+// 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/ozone/platform/wayland/host/gtk_primary_selection_offer.h"
+
+#include <gtk-primary-selection-client-protocol.h>
+
+#include <fcntl.h>
+#include <algorithm>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+
+namespace ui {
+
+GtkPrimarySelectionOffer::GtkPrimarySelectionOffer(
+    gtk_primary_selection_offer* data_offer)
+    : data_offer_(data_offer) {
+  static const struct gtk_primary_selection_offer_listener kListener = {
+      GtkPrimarySelectionOffer::OnOffer};
+  gtk_primary_selection_offer_add_listener(data_offer, &kListener, this);
+}
+
+GtkPrimarySelectionOffer::~GtkPrimarySelectionOffer() {
+  data_offer_.reset();
+}
+
+base::ScopedFD GtkPrimarySelectionOffer::Receive(const std::string& mime_type) {
+  if (!base::Contains(mime_types(), mime_type))
+    return base::ScopedFD();
+
+  base::ScopedFD read_fd;
+  base::ScopedFD write_fd;
+  PCHECK(base::CreatePipe(&read_fd, &write_fd));
+
+  // If we needed to forcibly write "text/plain" as an available
+  // mimetype, then it is safer to "read" the clipboard data with
+  // a mimetype mime_type known to be available.
+  std::string effective_mime_type = mime_type;
+  if (mime_type == kMimeTypeText && text_plain_mime_type_inserted())
+    effective_mime_type = kMimeTypeTextUtf8;
+
+  gtk_primary_selection_offer_receive(
+      data_offer_.get(), effective_mime_type.data(), write_fd.get());
+  return read_fd;
+}
+
+// static
+void GtkPrimarySelectionOffer::OnOffer(void* data,
+                                       gtk_primary_selection_offer* data_offer,
+                                       const char* mime_type) {
+  auto* self = static_cast<GtkPrimarySelectionOffer*>(data);
+  self->AddMimeType(mime_type);
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_offer.h b/ui/ozone/platform/wayland/host/gtk_primary_selection_offer.h
new file mode 100644
index 0000000..23f6e11
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_offer.h
@@ -0,0 +1,49 @@
+// 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_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_OFFER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_OFFER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/internal/wayland_data_offer_base.h"
+
+struct gtk_primary_selection_offer;
+
+namespace ui {
+
+// This class represents a piece of data offered for transfer by another
+// client, the source client (see GtkPrimarySelectionSource for more).
+// It is used by the primary selection mechanism.
+//
+// The offer describes MIME types that the data can be converted to and provides
+// the mechanism for transferring the data directly from the source client.
+class GtkPrimarySelectionOffer : public internal::WaylandDataOfferBase {
+ public:
+  // Takes ownership of data_offer.
+  explicit GtkPrimarySelectionOffer(gtk_primary_selection_offer* data_offer);
+  ~GtkPrimarySelectionOffer() override;
+
+  // internal::WaylandDataOfferBase overrides:
+  base::ScopedFD Receive(const std::string& mime_type) override;
+
+ private:
+  // gtk_primary_selection_offer_listener callbacks.
+  static void OnOffer(void* data,
+                      gtk_primary_selection_offer* data_offer,
+                      const char* mime_type);
+
+  // The Wayland object wrapped by this instance.
+  wl::Object<gtk_primary_selection_offer> data_offer_;
+
+  DISALLOW_COPY_AND_ASSIGN(GtkPrimarySelectionOffer);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_OFFER_H_
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_source.cc b/ui/ozone/platform/wayland/host/gtk_primary_selection_source.cc
new file mode 100644
index 0000000..3cef463
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_source.cc
@@ -0,0 +1,76 @@
+// 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/ozone/platform/wayland/host/gtk_primary_selection_source.h"
+
+#include <gtk-primary-selection-client-protocol.h>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+
+namespace ui {
+
+GtkPrimarySelectionSource::GtkPrimarySelectionSource(
+    gtk_primary_selection_source* data_source,
+    WaylandConnection* connection)
+    : data_source_(data_source), connection_(connection) {
+  DCHECK(connection_);
+  DCHECK(data_source_);
+
+  static const struct gtk_primary_selection_source_listener
+      kDataSourceListener = {GtkPrimarySelectionSource::OnSend,
+                             GtkPrimarySelectionSource::OnCancelled};
+  gtk_primary_selection_source_add_listener(data_source_.get(),
+                                            &kDataSourceListener, this);
+}
+
+GtkPrimarySelectionSource::~GtkPrimarySelectionSource() = default;
+
+// static
+void GtkPrimarySelectionSource::OnSend(void* data,
+                                       gtk_primary_selection_source* source,
+                                       const char* mime_type,
+                                       int32_t fd) {
+  GtkPrimarySelectionSource* self =
+      static_cast<GtkPrimarySelectionSource*>(data);
+  std::string contents;
+  base::Optional<std::vector<uint8_t>> mime_data;
+  self->GetClipboardData(mime_type, &mime_data);
+  if (!mime_data.has_value() && strcmp(mime_type, kMimeTypeTextUtf8) == 0)
+    self->GetClipboardData(kMimeTypeText, &mime_data);
+  contents.assign(mime_data->begin(), mime_data->end());
+  bool result =
+      base::WriteFileDescriptor(fd, contents.data(), contents.length());
+  DCHECK(result);
+  close(fd);
+}
+
+// static
+void GtkPrimarySelectionSource::OnCancelled(
+    void* data,
+    gtk_primary_selection_source* source) {
+  GtkPrimarySelectionSource* self =
+      static_cast<GtkPrimarySelectionSource*>(data);
+  self->connection_->clipboard()->DataSourceCancelled(
+      ClipboardBuffer::kSelection);
+}
+
+void GtkPrimarySelectionSource::WriteToClipboard(
+    const PlatformClipboard::DataMap& data_map) {
+  for (const auto& data : data_map) {
+    gtk_primary_selection_source_offer(data_source_.get(), data.first.c_str());
+    if (strcmp(data.first.c_str(), kMimeTypeText) == 0)
+      gtk_primary_selection_source_offer(data_source_.get(), kMimeTypeTextUtf8);
+  }
+
+  gtk_primary_selection_device_set_selection(
+      connection_->primary_selection_device(), data_source_.get(),
+      connection_->serial());
+
+  connection_->ScheduleFlush();
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/gtk_primary_selection_source.h b/ui/ozone/platform/wayland/host/gtk_primary_selection_source.h
new file mode 100644
index 0000000..02326c9
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/gtk_primary_selection_source.h
@@ -0,0 +1,46 @@
+// 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_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_SOURCE_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_SOURCE_H_
+
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/internal/wayland_data_source_base.h"
+#include "ui/ozone/public/platform_clipboard.h"
+
+struct gtk_primary_selection_source;
+
+namespace ui {
+
+class WaylandConnection;
+
+class GtkPrimarySelectionSource : public internal::WaylandDataSourceBase {
+ public:
+  // Takes ownership of data_source.
+  GtkPrimarySelectionSource(gtk_primary_selection_source* data_source,
+                            WaylandConnection* connection);
+  ~GtkPrimarySelectionSource() override;
+
+  void WriteToClipboard(const PlatformClipboard::DataMap& data_map) override;
+
+ private:
+  // gtk_primary_selection_source_listener callbacks
+  static void OnSend(void* data,
+                     gtk_primary_selection_source* source,
+                     const char* mime_type,
+                     int32_t fd);
+  static void OnCancelled(void* data, gtk_primary_selection_source* source);
+
+  // The gtk_primary_selection_source wrapped by this instance.
+  wl::Object<gtk_primary_selection_source> data_source_;
+
+  WaylandConnection* connection_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(GtkPrimarySelectionSource);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_SOURCE_H_
diff --git a/ui/ozone/platform/wayland/host/internal/wayland_data_device_base.cc b/ui/ozone/platform/wayland/host/internal/wayland_data_device_base.cc
new file mode 100644
index 0000000..bfaa6d7
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/internal/wayland_data_device_base.cc
@@ -0,0 +1,97 @@
+// 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/ozone/platform/wayland/host/internal/wayland_data_device_base.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+
+namespace ui {
+namespace internal {
+
+WaylandDataDeviceBase::WaylandDataDeviceBase(WaylandConnection* connection)
+    : connection_(connection) {}
+
+WaylandDataDeviceBase::~WaylandDataDeviceBase() = default;
+
+const std::vector<std::string>& WaylandDataDeviceBase::GetAvailableMimeTypes()
+    const {
+  if (!data_offer_) {
+    static std::vector<std::string> dummy;
+    return dummy;
+  }
+
+  return data_offer_->mime_types();
+}
+
+bool WaylandDataDeviceBase::RequestSelectionData(const std::string& mime_type) {
+  if (!data_offer_)
+    return false;
+
+  base::ScopedFD fd = data_offer_->Receive(mime_type);
+  if (!fd.is_valid()) {
+    LOG(ERROR) << "Failed to open file descriptor.";
+    return false;
+  }
+
+  // Ensure there is not pending operation to be performed by the compositor,
+  // otherwise read(..) can block awaiting data to be sent to pipe.
+  RegisterDeferredReadClosure(
+      base::BindOnce(&GtkPrimarySelectionDevice::ReadClipboardDataFromFD,
+                     base::Unretained(this), std::move(fd), mime_type));
+  RegisterDeferredReadCallback();
+  return true;
+}
+
+void WaylandDataDeviceBase::ResetDataOffer() {
+  data_offer_.reset();
+}
+
+void WaylandDataDeviceBase::ReadClipboardDataFromFD(
+    base::ScopedFD fd,
+    const std::string& mime_type) {
+  std::string contents;
+  wl::ReadDataFromFD(std::move(fd), &contents);
+  connection_->clipboard()->SetData(contents, mime_type);
+}
+
+void WaylandDataDeviceBase::RegisterDeferredReadCallback() {
+  DCHECK(!deferred_read_callback_);
+
+  deferred_read_callback_.reset(wl_display_sync(connection_->display()));
+
+  static const wl_callback_listener kListener = {
+      GtkPrimarySelectionDevice::DeferredReadCallback};
+
+  wl_callback_add_listener(deferred_read_callback_.get(), &kListener, this);
+
+  connection_->ScheduleFlush();
+}
+
+void WaylandDataDeviceBase::RegisterDeferredReadClosure(
+    base::OnceClosure closure) {
+  deferred_read_closure_ = std::move(closure);
+}
+
+// static
+void WaylandDataDeviceBase::DeferredReadCallback(void* data,
+                                                 struct wl_callback* cb,
+                                                 uint32_t time) {
+  auto* data_device = static_cast<WaylandDataDeviceBase*>(data);
+  DCHECK(data_device);
+  data_device->DeferredReadCallbackInternal(cb, time);
+}
+
+void WaylandDataDeviceBase::DeferredReadCallbackInternal(struct wl_callback* cb,
+                                                         uint32_t time) {
+  DCHECK(!deferred_read_closure_.is_null());
+  std::move(deferred_read_closure_).Run();
+  deferred_read_callback_.reset();
+}
+
+}  // namespace internal
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/internal/wayland_data_device_base.h b/ui/ozone/platform/wayland/host/internal/wayland_data_device_base.h
new file mode 100644
index 0000000..824bfc8
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/internal/wayland_data_device_base.h
@@ -0,0 +1,82 @@
+// 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_OZONE_PLATFORM_WAYLAND_HOST_INTERNAL_WAYLAND_DATA_DEVICE_BASE_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_INTERNAL_WAYLAND_DATA_DEVICE_BASE_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+namespace ui {
+
+class WaylandConnection;
+
+namespace internal {
+
+class WaylandDataOfferBase;
+
+// Implements high level (protocol-agnostic) interface to a Wayland data device.
+class WaylandDataDeviceBase {
+ public:
+  explicit WaylandDataDeviceBase(WaylandConnection* connection);
+  virtual ~WaylandDataDeviceBase();
+
+  // Returns MIME types given by the current data offer.
+  const std::vector<std::string>& GetAvailableMimeTypes() const;
+  // Extracts data of the specified MIME type from the data offer.
+  bool RequestSelectionData(const std::string& mime_type);
+
+ protected:
+  WaylandConnection* connection() const { return connection_; }
+  WaylandDataOfferBase* data_offer() { return data_offer_.get(); }
+  void set_data_offer(std::unique_ptr<WaylandDataOfferBase> data_offer) {
+    data_offer_ = std::move(data_offer);
+  }
+
+  // Resets the data offer.
+  void ResetDataOffer();
+  // Reads data of the requested MIME type from the data offer and gives it to
+  // the clipboard linked to the Wayland connection.
+  void ReadClipboardDataFromFD(base::ScopedFD fd, const std::string& mime_type);
+
+  // Registers DeferredReadCallback as display sync callback listener, to
+  // ensure there is no pending operation to be performed by the compositor,
+  // otherwise read(..) could block awaiting data to be sent to pipe. It is
+  // reset once it's called.
+  void RegisterDeferredReadCallback();
+
+  void RegisterDeferredReadClosure(base::OnceClosure closure);
+
+ private:
+  // wl_callback_listener callback
+  static void DeferredReadCallback(void* data,
+                                   struct wl_callback* cb,
+                                   uint32_t time);
+
+  void DeferredReadCallbackInternal(struct wl_callback* cb,
+                                    uint32_t time);
+
+  // Used to call out to WaylandConnection once clipboard data
+  // has been successfully read.
+  WaylandConnection* const connection_ = nullptr;
+
+  // Offer that holds the most-recent clipboard selection, or null if no
+  // clipboard data is available.
+  std::unique_ptr<WaylandDataOfferBase> data_offer_;
+
+  // Before blocking on read(), make sure server has written data on the pipe.
+  base::OnceClosure deferred_read_closure_;
+  wl::Object<wl_callback> deferred_read_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandDataDeviceBase);
+};
+
+}  // namespace internal
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_INTERNAL_WAYLAND_DATA_DEVICE_BASE_H_
diff --git a/ui/ozone/platform/wayland/host/internal/wayland_data_offer_base.cc b/ui/ozone/platform/wayland/host/internal/wayland_data_offer_base.cc
new file mode 100644
index 0000000..d2068d7d
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/internal/wayland_data_offer_base.cc
@@ -0,0 +1,44 @@
+// 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/ozone/platform/wayland/host/internal/wayland_data_offer_base.h"
+
+#include "base/stl_util.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+
+namespace ui {
+namespace internal {
+
+namespace {
+
+const char kString[] = "STRING";
+const char kText[] = "TEXT";
+const char kUtf8String[] = "UTF8_STRING";
+
+}  // namespace
+
+WaylandDataOfferBase::WaylandDataOfferBase() = default;
+WaylandDataOfferBase::~WaylandDataOfferBase() = default;
+
+void WaylandDataOfferBase::EnsureTextMimeTypeIfNeeded() {
+  if (base::Contains(mime_types_, kMimeTypeText))
+    return;
+
+  if (std::any_of(mime_types_.begin(), mime_types_.end(),
+                  [](const std::string& mime_type) {
+                    return mime_type == kString || mime_type == kText ||
+                           mime_type == kMimeTypeTextUtf8 ||
+                           mime_type == kUtf8String;
+                  })) {
+    mime_types_.push_back(kMimeTypeText);
+    text_plain_mime_type_inserted_ = true;
+  }
+}
+
+void WaylandDataOfferBase::AddMimeType(const char* mime_type) {
+  mime_types_.push_back(mime_type);
+}
+
+}  // namespace internal
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/internal/wayland_data_offer_base.h b/ui/ozone/platform/wayland/host/internal/wayland_data_offer_base.h
new file mode 100644
index 0000000..b1e6102
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/internal/wayland_data_offer_base.h
@@ -0,0 +1,57 @@
+// 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_OZONE_PLATFORM_WAYLAND_HOST_INTERNAL_WAYLAND_DATA_OFFER_BASE_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_INTERNAL_WAYLAND_DATA_OFFER_BASE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+
+namespace ui {
+namespace internal {
+
+// Implements common part of WaylandDataOffer and GtkPrimarySelectionOffer
+// (which is handling of the clipboard data).
+class WaylandDataOfferBase {
+ public:
+  WaylandDataOfferBase();
+  virtual ~WaylandDataOfferBase();
+
+  const std::vector<std::string>& mime_types() const { return mime_types_; }
+  bool text_plain_mime_type_inserted() const {
+    return text_plain_mime_type_inserted_;
+  }
+
+  // Some X11 applications on Gnome/Wayland (running through XWayland)
+  // do not send the "text/plain" MIME type that Chrome relies on, but
+  // instead they send types like "text/plain;charset=utf-8".
+  // When it happens, this method forcibly injects "text/plain" into the
+  // list of provided MIME types so that Chrome clipboard's machinery
+  // works fine.
+  void EnsureTextMimeTypeIfNeeded();
+
+  // Inserts the specified MIME type into the internal list.
+  void AddMimeType(const char* mime_type);
+
+  // Creates a pipe (read & write FDs), passes the write end of the pipe
+  // to the compositor and returns the read end.
+  virtual base::ScopedFD Receive(const std::string& mime_type) = 0;
+
+ private:
+  // MIME types provided in this offer.
+  std::vector<std::string> mime_types_;
+
+  // Whether "text/plain" had been inserted forcibly.
+  bool text_plain_mime_type_inserted_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandDataOfferBase);
+};
+
+}  // namespace internal
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_INTERNAL_WAYLAND_DATA_OFFER_BASE_H_
diff --git a/ui/ozone/platform/wayland/host/internal/wayland_data_source_base.cc b/ui/ozone/platform/wayland/host/internal/wayland_data_source_base.cc
new file mode 100644
index 0000000..a101fdb
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/internal/wayland_data_source_base.cc
@@ -0,0 +1,23 @@
+// 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/ozone/platform/wayland/host/internal/wayland_data_source_base.h"
+
+namespace ui {
+namespace internal {
+
+WaylandDataSourceBase::WaylandDataSourceBase() = default;
+WaylandDataSourceBase::~WaylandDataSourceBase() = default;
+
+void WaylandDataSourceBase::GetClipboardData(
+    const std::string& mime_type,
+    base::Optional<std::vector<uint8_t>>* data) const {
+  auto it = data_map_.find(mime_type);
+  if (it == data_map_.end())
+    return;
+  data->emplace(it->second);
+}
+
+}  // namespace internal
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/internal/wayland_data_source_base.h b/ui/ozone/platform/wayland/host/internal/wayland_data_source_base.h
new file mode 100644
index 0000000..e630f4c
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/internal/wayland_data_source_base.h
@@ -0,0 +1,40 @@
+// 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_OZONE_PLATFORM_WAYLAND_HOST_INTERNAL_WAYLAND_DATA_SOURCE_BASE_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_INTERNAL_WAYLAND_DATA_SOURCE_BASE_H_
+
+#include "base/macros.h"
+#include "ui/ozone/public/platform_clipboard.h"
+
+namespace ui {
+namespace internal {
+
+// Implements high level (protocol-agnostic) interface to a Wayland data source.
+class WaylandDataSourceBase {
+ public:
+  WaylandDataSourceBase();
+  virtual ~WaylandDataSourceBase();
+
+  void set_data_map(const PlatformClipboard::DataMap& data_map) {
+    data_map_ = data_map;
+  }
+
+  // Writes data to the system clipboard using the protocol-defined data source.
+  virtual void WriteToClipboard(const PlatformClipboard::DataMap& data_map) = 0;
+
+ protected:
+  void GetClipboardData(const std::string& mime_type,
+                        base::Optional<std::vector<uint8_t>>* data) const;
+
+ private:
+  PlatformClipboard::DataMap data_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandDataSourceBase);
+};
+
+}  // namespace internal
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_INTERNAL_WAYLAND_DATA_SOURCE_BASE_H_
diff --git a/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/ui/ozone/platform/wayland/host/wayland_clipboard.cc
index d56445d0..1b07e98 100644
--- a/ui/ozone/platform/wayland/host/wayland_clipboard.cc
+++ b/ui/ozone/platform/wayland/host/wayland_clipboard.cc
@@ -3,6 +3,11 @@
 // found in the LICENSE file.
 
 #include "ui/ozone/platform/wayland/host/wayland_clipboard.h"
+
+#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
+#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
+#include "ui/ozone/platform/wayland/host/gtk_primary_selection_source.h"
+#include "ui/ozone/platform/wayland/host/internal/wayland_data_source_base.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_device.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
 
@@ -10,8 +15,13 @@
 
 WaylandClipboard::WaylandClipboard(
     WaylandDataDeviceManager* data_device_manager,
-    WaylandDataDevice* data_device)
-    : data_device_manager_(data_device_manager), data_device_(data_device) {
+    WaylandDataDevice* data_device,
+    GtkPrimarySelectionDeviceManager* primary_selection_device_manager,
+    GtkPrimarySelectionDevice* primary_selection_device)
+    : data_device_manager_(data_device_manager),
+      data_device_(data_device),
+      primary_selection_device_manager_(primary_selection_device_manager),
+      primary_selection_device_(primary_selection_device) {
   DCHECK(data_device_manager_);
   DCHECK(data_device_);
 }
@@ -22,17 +32,25 @@
     ClipboardBuffer buffer,
     const PlatformClipboard::DataMap& data_map,
     PlatformClipboard::OfferDataClosure callback) {
-  // TODO(https://crbug.com/921950): Implement primary selection.
-  if (buffer != ClipboardBuffer::kCopyPaste) {
-    std::move(callback).Run();
-    return;
+  internal::WaylandDataSourceBase* data_source = nullptr;
+  if (buffer == ClipboardBuffer::kCopyPaste) {
+    if (!clipboard_data_source_)
+      clipboard_data_source_ = data_device_manager_->CreateSource();
+    data_source = clipboard_data_source_.get();
+  } else {
+    if (!primary_selection_device_manager_) {
+      std::move(callback).Run();
+      return;
+    }
+    if (!primary_data_source_)
+      primary_data_source_ = primary_selection_device_manager_->CreateSource();
+    data_source = primary_data_source_.get();
   }
 
-  if (!clipboard_data_source_) {
-    clipboard_data_source_ = data_device_manager_->CreateSource();
-    clipboard_data_source_->WriteToClipboard(data_map);
-  }
-  clipboard_data_source_->UpdateDataMap(data_map);
+  DCHECK(data_source);
+  data_source->WriteToClipboard(data_map);
+  data_source->set_data_map(data_map);
+
   std::move(callback).Run();
 }
 
@@ -41,26 +59,23 @@
     const std::string& mime_type,
     PlatformClipboard::DataMap* data_map,
     PlatformClipboard::RequestDataClosure callback) {
-  // TODO(https://crbug.com/921950): Implement primary selection.
-  if (buffer != ClipboardBuffer::kCopyPaste) {
-    std::move(callback).Run({});
-    return;
-  }
-
   read_clipboard_closure_ = std::move(callback);
-
   DCHECK(data_map);
   data_map_ = data_map;
-  if (!data_device_->RequestSelectionData(mime_type))
-    SetData({}, mime_type);
+  if (buffer == ClipboardBuffer::kCopyPaste) {
+    if (!data_device_->RequestSelectionData(mime_type))
+      SetData({}, mime_type);
+  } else {
+    if (!primary_selection_device_->RequestSelectionData(mime_type))
+      SetData({}, mime_type);
+  }
 }
 
 bool WaylandClipboard::IsSelectionOwner(ClipboardBuffer buffer) {
-  // TODO(https://crbug.com/921950): Implement primary selection.
-  if (buffer != ClipboardBuffer::kCopyPaste)
-    return false;
-
-  return !!clipboard_data_source_;
+  if (buffer == ClipboardBuffer::kCopyPaste)
+    return !!clipboard_data_source_;
+  else
+    return !!primary_data_source_;
 }
 
 void WaylandClipboard::SetSequenceNumberUpdateCb(
@@ -73,19 +88,24 @@
 void WaylandClipboard::GetAvailableMimeTypes(
     ClipboardBuffer buffer,
     PlatformClipboard::GetMimeTypesClosure callback) {
-  // TODO(https://crbug.com/921950): Implement primary selection.
-  if (buffer != ClipboardBuffer::kCopyPaste) {
-    std::move(callback).Run({});
-    return;
+  if (buffer == ClipboardBuffer::kCopyPaste) {
+    std::move(callback).Run(data_device_->GetAvailableMimeTypes());
+  } else {
+    DCHECK(primary_selection_device_);
+    std::move(callback).Run(primary_selection_device_->GetAvailableMimeTypes());
   }
-
-  std::move(callback).Run(data_device_->GetAvailableMimeTypes());
 }
 
-void WaylandClipboard::DataSourceCancelled() {
-  DCHECK(clipboard_data_source_);
-  SetData({}, {});
-  clipboard_data_source_.reset();
+void WaylandClipboard::DataSourceCancelled(ClipboardBuffer buffer) {
+  if (buffer == ClipboardBuffer::kCopyPaste) {
+    DCHECK(clipboard_data_source_);
+    SetData({}, {});
+    clipboard_data_source_.reset();
+  } else {
+    DCHECK(primary_data_source_);
+    SetData({}, {});
+    primary_data_source_.reset();
+  }
 }
 
 void WaylandClipboard::SetData(const std::string& contents,
@@ -105,10 +125,6 @@
 }
 
 void WaylandClipboard::UpdateSequenceNumber(ClipboardBuffer buffer) {
-  // TODO(https://crbug.com/921950): Implement primary selection.
-  if (buffer != ClipboardBuffer::kCopyPaste)
-    return;
-
   if (!update_sequence_cb_.is_null())
     update_sequence_cb_.Run(buffer);
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_clipboard.h b/ui/ozone/platform/wayland/host/wayland_clipboard.h
index c808bba..e720bdd2 100644
--- a/ui/ozone/platform/wayland/host/wayland_clipboard.h
+++ b/ui/ozone/platform/wayland/host/wayland_clipboard.h
@@ -6,11 +6,15 @@
 #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_
 
 #include "base/callback.h"
+#include "base/macros.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_source.h"
 #include "ui/ozone/public/platform_clipboard.h"
 
 namespace ui {
 
+class GtkPrimarySelectionDevice;
+class GtkPrimarySelectionDeviceManager;
+class GtkPrimarySelectionSource;
 class WaylandDataDevice;
 class WaylandDataDeviceManager;
 
@@ -20,8 +24,11 @@
 // manager.
 class WaylandClipboard : public PlatformClipboard {
  public:
-  WaylandClipboard(WaylandDataDeviceManager* data_device_manager,
-                   WaylandDataDevice* data_device);
+  WaylandClipboard(
+      WaylandDataDeviceManager* data_device_manager,
+      WaylandDataDevice* data_device,
+      GtkPrimarySelectionDeviceManager* primary_selection_device_manager,
+      GtkPrimarySelectionDevice* primary_selection_device);
   ~WaylandClipboard() override;
 
   // PlatformClipboard.
@@ -41,7 +48,7 @@
   void SetSequenceNumberUpdateCb(
       PlatformClipboard::SequenceNumberUpdateCb cb) override;
 
-  void DataSourceCancelled();
+  void DataSourceCancelled(ClipboardBuffer buffer);
   void SetData(const std::string& contents, const std::string& mime_type);
   void UpdateSequenceNumber(ClipboardBuffer buffer);
 
@@ -58,10 +65,13 @@
   PlatformClipboard::RequestDataClosure read_clipboard_closure_;
 
   std::unique_ptr<WaylandDataSource> clipboard_data_source_;
+  std::unique_ptr<GtkPrimarySelectionSource> primary_data_source_;
 
-  // These two instances are owned by the connection.
-  WaylandDataDeviceManager* const data_device_manager_ = nullptr;
-  WaylandDataDevice* const data_device_ = nullptr;
+  // These four instances are owned by the connection.
+  WaylandDataDeviceManager* const data_device_manager_;
+  WaylandDataDevice* const data_device_;
+  GtkPrimarySelectionDeviceManager* const primary_selection_device_manager_;
+  GtkPrimarySelectionDevice* const primary_selection_device_;
 
   DISALLOW_COPY_AND_ASSIGN(WaylandClipboard);
 };
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
index 9d92366f7..232f853 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -34,6 +34,7 @@
 
 namespace {
 constexpr uint32_t kMaxCompositorVersion = 4;
+constexpr uint32_t kMaxGtkPrimarySelectionDeviceManagerVersion = 1;
 constexpr uint32_t kMaxLinuxDmabufVersion = 3;
 constexpr uint32_t kMaxSeatVersion = 4;
 constexpr uint32_t kMaxShmVersion = 1;
@@ -234,8 +235,15 @@
   DCHECK(!data_device_);
   wl_data_device* data_device = data_device_manager_->GetDevice();
   data_device_ = std::make_unique<WaylandDataDevice>(this, data_device);
-  clipboard_ = std::make_unique<WaylandClipboard>(data_device_manager_.get(),
-                                                  data_device_.get());
+
+  if (primary_selection_device_manager_) {
+    primary_selection_device_ = std::make_unique<GtkPrimarySelectionDevice>(
+        this, primary_selection_device_manager_->GetDevice());
+  }
+
+  clipboard_ = std::make_unique<WaylandClipboard>(
+      data_device_manager_.get(), data_device_.get(),
+      primary_selection_device_manager_.get(), primary_selection_device_.get());
 }
 
 bool WaylandConnection::BeginWatchingFd(
@@ -352,6 +360,14 @@
         std::make_unique<WaylandDataDeviceManager>(
             data_device_manager.release(), connection);
     connection->EnsureDataDevice();
+  } else if (!connection->primary_selection_device_manager_ &&
+             strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
+    wl::Object<gtk_primary_selection_device_manager> manager =
+        wl::Bind<gtk_primary_selection_device_manager>(
+            registry, name, kMaxGtkPrimarySelectionDeviceManagerVersion);
+    connection->primary_selection_device_manager_ =
+        std::make_unique<GtkPrimarySelectionDeviceManager>(manager.release(),
+                                                           connection);
   } else if (!connection->zwp_dmabuf_ &&
              (strcmp(interface, "zwp_linux_dmabuf_v1") == 0)) {
     wl::Object<zwp_linux_dmabuf_v1> zwp_linux_dmabuf =
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h
index fb843b5..e26d191f 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -16,6 +16,8 @@
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
+#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
 #include "ui/ozone/platform/wayland/host/wayland_clipboard.h"
 #include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_device.h"
@@ -54,6 +56,9 @@
   zxdg_shell_v6* shell_v6() const { return shell_v6_.get(); }
   wl_seat* seat() const { return seat_.get(); }
   wl_data_device* data_device() const { return data_device_->data_device(); }
+  gtk_primary_selection_device* primary_selection_device() const {
+    return primary_selection_device_->data_device();
+  }
   wp_presentation* presentation() const { return presentation_.get(); }
   zwp_text_input_manager_v1* text_input_manager_v1() const {
     return text_input_manager_v1_.get();
@@ -188,6 +193,10 @@
   std::unique_ptr<WaylandShm> shm_;
   std::unique_ptr<WaylandBufferManagerHost> buffer_manager_host_;
 
+  std::unique_ptr<GtkPrimarySelectionDeviceManager>
+      primary_selection_device_manager_;
+  std::unique_ptr<GtkPrimarySelectionDevice> primary_selection_device_;
+
   // Manages Wayland windows.
   WaylandWindowManager wayland_window_manager_;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device.cc b/ui/ozone/platform/wayland/host/wayland_data_device.cc
index 81a2a73..5c56235 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/dragdrop/os_exchange_data_provider_aura.h"
@@ -23,9 +24,6 @@
 
 namespace {
 
-constexpr char kMimeTypeText[] = "text/plain";
-constexpr char kMimeTypeTextUTF8[] = "text/plain;charset=utf-8";
-
 int GetOperation(uint32_t source_actions, uint32_t dnd_action) {
   uint32_t action = dnd_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE
                         ? dnd_action
@@ -56,7 +54,7 @@
                          const std::string& mime_type,
                          OSExchangeData* os_exchange_data) {
   DCHECK(os_exchange_data);
-  if ((mime_type == kMimeTypeText || mime_type == kMimeTypeTextUTF8)) {
+  if ((mime_type == kMimeTypeText || mime_type == kMimeTypeTextUtf8)) {
     DCHECK(!os_exchange_data->HasString());
     AddStringToOSExchangeData(data, os_exchange_data);
     return;
@@ -70,7 +68,7 @@
 // static
 WaylandDataDevice::WaylandDataDevice(WaylandConnection* connection,
                                      wl_data_device* data_device)
-    : data_device_(data_device), connection_(connection) {
+    : internal::WaylandDataDeviceBase(connection), data_device_(data_device) {
   static const struct wl_data_device_listener kDataDeviceListener = {
       WaylandDataDevice::OnDataOffer, WaylandDataDevice::OnEnter,
       WaylandDataDevice::OnLeave,     WaylandDataDevice::OnMotion,
@@ -80,25 +78,6 @@
 
 WaylandDataDevice::~WaylandDataDevice() = default;
 
-bool WaylandDataDevice::RequestSelectionData(const std::string& mime_type) {
-  if (!selection_offer_)
-    return false;
-
-  base::ScopedFD fd = selection_offer_->Receive(mime_type);
-  if (!fd.is_valid()) {
-    LOG(ERROR) << "Failed to open file descriptor.";
-    return false;
-  }
-
-  // Ensure there is not pending operation to be performed by the compositor,
-  // otherwise read(..) can block awaiting data to be sent to pipe.
-  deferred_read_closure_ =
-      base::BindOnce(&WaylandDataDevice::ReadClipboardDataFromFD,
-                     base::Unretained(this), std::move(fd), mime_type);
-  RegisterDeferredReadCallback();
-  return true;
-}
-
 void WaylandDataDevice::RequestDragData(
     const std::string& mime_type,
     base::OnceCallback<void(const std::string&)> callback) {
@@ -110,9 +89,9 @@
 
   // Ensure there is not pending operation to be performed by the compositor,
   // otherwise read(..) can block awaiting data to be sent to pipe.
-  deferred_read_closure_ = base::BindOnce(
+  RegisterDeferredReadClosure(base::BindOnce(
       &WaylandDataDevice::ReadDragDataFromFD, base::Unretained(this),
-      std::move(fd), std::move(callback));
+      std::move(fd), std::move(callback)));
   RegisterDeferredReadCallback();
 }
 
@@ -121,7 +100,7 @@
   DCHECK(buffer);
   DCHECK(source_data_);
 
-  if (mime_type != kMimeTypeText && mime_type != kMimeTypeTextUTF8)
+  if (mime_type != kMimeTypeText && mime_type != kMimeTypeTextUtf8)
     return;
 
   const OSExchangeData::FilenameToURLPolicy policy =
@@ -148,7 +127,7 @@
   DCHECK(data_source);
 
   WaylandWindow* window =
-      connection_->wayland_window_manager()->GetCurrentFocusedWindow();
+      connection()->wayland_window_manager()->GetCurrentFocusedWindow();
   if (!window) {
     LOG(ERROR) << "Failed to get focused window.";
     return;
@@ -156,47 +135,24 @@
   const SkBitmap* icon = PrepareDragIcon(data);
   source_data_ = std::make_unique<ui::OSExchangeData>(data.provider().Clone());
   wl_data_device_start_drag(data_device_.get(), data_source, window->surface(),
-                            icon_surface_.get(), connection_->serial());
+                            icon_surface_.get(), connection()->serial());
   if (icon)
     DrawDragIcon(icon);
-  connection_->ScheduleFlush();
+  connection()->ScheduleFlush();
 }
 
 void WaylandDataDevice::ResetSourceData() {
   source_data_.reset();
 }
 
-std::vector<std::string> WaylandDataDevice::GetAvailableMimeTypes() {
-  if (selection_offer_)
-    return selection_offer_->GetAvailableMimeTypes();
-
-  return std::vector<std::string>();
-}
-
-void WaylandDataDevice::ReadClipboardDataFromFD(base::ScopedFD fd,
-                                                const std::string& mime_type) {
-  std::string contents;
-  ReadDataFromFD(std::move(fd), &contents);
-  connection_->clipboard()->SetData(contents, mime_type);
-}
-
 void WaylandDataDevice::ReadDragDataFromFD(
     base::ScopedFD fd,
     base::OnceCallback<void(const std::string&)> callback) {
   std::string contents;
-  ReadDataFromFD(std::move(fd), &contents);
+  wl::ReadDataFromFD(std::move(fd), &contents);
   std::move(callback).Run(contents);
 }
 
-void WaylandDataDevice::ReadDataFromFD(base::ScopedFD fd,
-                                       std::string* contents) {
-  DCHECK(contents);
-  char buffer[1 << 10];  // 1 kB in bytes.
-  ssize_t length;
-  while ((length = read(fd.get(), buffer, sizeof(buffer))) > 0)
-    contents->append(buffer, length);
-}
-
 void WaylandDataDevice::HandleDeferredLeaveIfNeeded() {
   if (!is_leaving_)
     return;
@@ -210,7 +166,7 @@
                                     wl_data_offer* offer) {
   auto* self = static_cast<WaylandDataDevice*>(data);
 
-  self->connection_->clipboard()->UpdateSequenceNumber(
+  self->connection()->clipboard()->UpdateSequenceNumber(
       ClipboardBuffer::kCopyPaste);
 
   DCHECK(!self->new_offer_);
@@ -241,7 +197,7 @@
   // all mime types offered because current implementation doesn't decide
   // action based on mime type.
   self->unprocessed_mime_types_.clear();
-  for (auto mime : self->drag_offer_->GetAvailableMimeTypes()) {
+  for (auto mime : self->drag_offer_->mime_types()) {
     self->unprocessed_mime_types_.push_back(mime);
     self->drag_offer_->Accept(serial, mime);
   }
@@ -336,45 +292,24 @@
   // 'offer' will be null to indicate that the selection is no longer valid,
   // i.e. there is no longer clipboard data available to paste.
   if (!offer) {
-    self->selection_offer_.reset();
+    self->ResetDataOffer();
 
     // Clear Clipboard cache.
-    self->connection_->clipboard()->SetData(std::string(), std::string());
+    self->connection()->clipboard()->SetData({}, {});
     return;
   }
 
   DCHECK(self->new_offer_);
-  self->selection_offer_ = std::move(self->new_offer_);
+  self->set_data_offer(std::move(self->new_offer_));
 
-  self->selection_offer_->EnsureTextMimeTypeIfNeeded();
-}
-
-void WaylandDataDevice::RegisterDeferredReadCallback() {
-  static const wl_callback_listener kDeferredReadListener = {
-      WaylandDataDevice::DeferredReadCallback};
-
-  DCHECK(!deferred_read_callback_);
-  deferred_read_callback_.reset(wl_display_sync(connection_->display()));
-  wl_callback_add_listener(deferred_read_callback_.get(),
-                           &kDeferredReadListener, this);
-  connection_->ScheduleFlush();
-}
-
-void WaylandDataDevice::DeferredReadCallback(void* data,
-                                             struct wl_callback* cb,
-                                             uint32_t time) {
-  auto* data_device = static_cast<WaylandDataDevice*>(data);
-  DCHECK(data_device);
-  DCHECK(!data_device->deferred_read_closure_.is_null());
-  std::move(data_device->deferred_read_closure_).Run();
-  data_device->deferred_read_callback_.reset();
+  self->data_offer()->EnsureTextMimeTypeIfNeeded();
 }
 
 const SkBitmap* WaylandDataDevice::PrepareDragIcon(const OSExchangeData& data) {
   const SkBitmap* icon_bitmap = data.provider().GetDragImage().bitmap();
   if (!icon_bitmap || icon_bitmap->empty())
     return nullptr;
-  icon_surface_.reset(wl_compositor_create_surface(connection_->compositor()));
+  icon_surface_.reset(wl_compositor_create_surface(connection()->compositor()));
   DCHECK(icon_surface_);
   return icon_bitmap;
 }
@@ -385,7 +320,7 @@
   gfx::Size size(icon_bitmap->width(), icon_bitmap->height());
 
   if (!shm_buffer_ || shm_buffer_->size() != size) {
-    shm_buffer_ = std::make_unique<WaylandShmBuffer>(connection_->shm(), size);
+    shm_buffer_ = std::make_unique<WaylandShmBuffer>(connection()->shm(), size);
     if (!shm_buffer_->IsValid()) {
       LOG(ERROR) << "Failed to create drag icon buffer.";
       return;
@@ -436,7 +371,7 @@
 std::string WaylandDataDevice::SelectNextMimeType() {
   while (!unprocessed_mime_types_.empty()) {
     std::string& mime_type = unprocessed_mime_types_.front();
-    if ((mime_type == kMimeTypeText || mime_type == kMimeTypeTextUTF8) &&
+    if ((mime_type == kMimeTypeText || mime_type == kMimeTypeTextUtf8) &&
         !received_data_->HasString()) {
       return mime_type;
     }
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device.h b/ui/ozone/platform/wayland/host/wayland_data_device.h
index c69be56..e22edd8 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_device.h
@@ -17,6 +17,7 @@
 #include "base/macros.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/internal/wayland_data_device_base.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_offer.h"
 #include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
 
@@ -31,12 +32,10 @@
 
 // This class provides access to inter-client data transfer mechanisms
 // such as copy-and-paste and drag-and-drop mechanisms.
-class WaylandDataDevice {
+class WaylandDataDevice : public internal::WaylandDataDeviceBase {
  public:
   WaylandDataDevice(WaylandConnection* connection, wl_data_device* data_device);
-  ~WaylandDataDevice();
-
-  bool RequestSelectionData(const std::string& mime_type);
+  ~WaylandDataDevice() override;
 
   // Requests the data to the platform when Chromium gets drag-and-drop started
   // by others. Once reading the data from platform is done, |callback| should
@@ -53,22 +52,15 @@
   // Resets |source_data_| when the dragging is finished.
   void ResetSourceData();
 
-  std::vector<std::string> GetAvailableMimeTypes();
-
   wl_data_device* data_device() const { return data_device_.get(); }
 
   bool IsDragEntered() { return drag_offer_ != nullptr; }
 
  private:
-  void ReadClipboardDataFromFD(base::ScopedFD fd, const std::string& mime_type);
-
   void ReadDragDataFromFD(
       base::ScopedFD fd,
       base::OnceCallback<void(const std::string&)> callback);
 
-  // Helper function to read data from fd.
-  void ReadDataFromFD(base::ScopedFD fd, std::string* contents);
-
   // If source_data_ is not set, data is being dragged from an external
   // application (non-chromium).
   bool IsDraggingExternalData() const { return !source_data_; }
@@ -108,15 +100,6 @@
                           wl_data_device* data_device,
                           wl_data_offer* id);
 
-  // Registers DeferredReadCallback as display sync callback listener, to
-  // ensure there is no pending operation to be performed by the compositor,
-  // otherwise read(..) could block awaiting data to be sent to pipe. It is
-  // reset once it's called.
-  void RegisterDeferredReadCallback();
-  static void DeferredReadCallback(void* data,
-                                   struct wl_callback* cb,
-                                   uint32_t time);
-
   // Returns the drag icon bitmap and creates and wayland surface to draw it
   // on, if a valid drag image is present in |data|; otherwise returns null.
   const SkBitmap* PrepareDragIcon(const OSExchangeData& data);
@@ -141,10 +124,6 @@
   // The wl_data_device wrapped by this WaylandDataDevice.
   wl::Object<wl_data_device> data_device_;
 
-  // Used to call out to WaylandConnection once clipboard data
-  // has been successfully read.
-  WaylandConnection* connection_ = nullptr;
-
   // There are two separate data offers at a time, the drag offer and the
   // selection offer, each with independent lifetimes. When we receive a new
   // offer, it is not immediately possible to know whether the new offer is the
@@ -152,20 +131,12 @@
   // of new data offers temporarily until its identity becomes known.
   std::unique_ptr<WaylandDataOffer> new_offer_;
 
-  // Offer that holds the most-recent clipboard selection, or null if no
-  // clipboard data is available.
-  std::unique_ptr<WaylandDataOffer> selection_offer_;
-
   // Offer to receive data from another process via drag-and-drop, or null if no
   // drag-and-drop from another process is in progress.
   std::unique_ptr<WaylandDataOffer> drag_offer_;
 
   WaylandWindow* window_ = nullptr;
 
-  // Make sure server has written data on the pipe, before block on read().
-  base::OnceClosure deferred_read_closure_;
-  wl::Object<wl_callback> deferred_read_callback_;
-
   bool is_handling_dropped_data_ = false;
   bool is_leaving_ = false;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_data_offer.cc b/ui/ozone/platform/wayland/host/wayland_data_offer.cc
index 73d4dbc1..4a186a7 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_offer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_offer.cc
@@ -10,19 +10,10 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
+#include "ui/base/clipboard/clipboard_constants.h"
 
 namespace ui {
 
-namespace {
-
-const char kString[] = "STRING";
-const char kText[] = "TEXT";
-const char kTextPlain[] = "text/plain";
-const char kTextPlainUtf8[] = "text/plain;charset=utf-8";
-const char kUtf8String[] = "UTF8_STRING";
-
-}  // namespace
-
 WaylandDataOffer::WaylandDataOffer(wl_data_offer* data_offer)
     : data_offer_(data_offer),
       source_actions_(WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE),
@@ -54,23 +45,8 @@
   wl_data_offer_accept(data_offer_.get(), serial, nullptr);
 }
 
-void WaylandDataOffer::EnsureTextMimeTypeIfNeeded() {
-  if (base::Contains(mime_types_, kTextPlain))
-    return;
-
-  if (std::any_of(mime_types_.begin(), mime_types_.end(),
-                  [](const std::string& mime_type) {
-                    return mime_type == kString || mime_type == kText ||
-                           mime_type == kTextPlainUtf8 ||
-                           mime_type == kUtf8String;
-                  })) {
-    mime_types_.push_back(kTextPlain);
-    text_plain_mime_type_inserted_ = true;
-  }
-}
-
 base::ScopedFD WaylandDataOffer::Receive(const std::string& mime_type) {
-  if (!base::Contains(mime_types_, mime_type))
+  if (!base::Contains(mime_types(), mime_type))
     return base::ScopedFD();
 
   base::ScopedFD read_fd;
@@ -81,9 +57,8 @@
   // mimetype, then it is safer to "read" the clipboard data with
   // a mimetype mime_type known to be available.
   std::string effective_mime_type = mime_type;
-  if (mime_type == kTextPlain && text_plain_mime_type_inserted_) {
-    effective_mime_type = kTextPlainUtf8;
-  }
+  if (mime_type == kMimeTypeText && text_plain_mime_type_inserted())
+    effective_mime_type = kMimeTypeTextUtf8;
 
   wl_data_offer_receive(data_offer_.get(), effective_mime_type.data(),
                         write_fd.get());
@@ -109,7 +84,7 @@
                                wl_data_offer* data_offer,
                                const char* mime_type) {
   auto* self = static_cast<WaylandDataOffer*>(data);
-  self->mime_types_.push_back(mime_type);
+  self->AddMimeType(mime_type);
 }
 
 void WaylandDataOffer::OnSourceAction(void* data,
diff --git a/ui/ozone/platform/wayland/host/wayland_data_offer.h b/ui/ozone/platform/wayland/host/wayland_data_offer.h
index ec7abc9..24cba88 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_offer.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_offer.h
@@ -13,6 +13,7 @@
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/internal/wayland_data_offer_base.h"
 
 namespace ui {
 
@@ -23,31 +24,19 @@
 // The offer describes the different mime types that the data can be
 // converted to and provides the mechanism for transferring the data
 // directly from the source client.
-class WaylandDataOffer {
+class WaylandDataOffer : public internal::WaylandDataOfferBase {
  public:
   // Takes ownership of data_offer.
   explicit WaylandDataOffer(wl_data_offer* data_offer);
-  ~WaylandDataOffer();
+  ~WaylandDataOffer() override;
 
-  const std::vector<std::string>& GetAvailableMimeTypes() const {
-    return mime_types_;
-  }
-
-  // Some X11 applications on Gnome/Wayland (running through XWayland)
-  // do not send the "text/plain" mime type that Chrome relies on, but
-  // instead they send mime types like "text/plain;charset=utf-8".
-  // When it happens, this method forcibly injects "text/plain" to the
-  // list of provided mime types so that Chrome clipboard's machinery
-  // works fine.
-  void EnsureTextMimeTypeIfNeeded();
   void SetAction(uint32_t dnd_actions, uint32_t preferred_action);
   void Accept(uint32_t serial, const std::string& mime_type);
   void Reject(uint32_t serial);
 
-  // Creates a pipe (read & write FDs), passing the write-end of to pipe
-  // to the compositor (via wl_data_offer_receive) and returning the
-  // read-end to the pipe.
-  base::ScopedFD Receive(const std::string& mime_type);
+  // internal::WaylandDataOfferBase overrides:
+  base::ScopedFD Receive(const std::string& mime_type) override;
+
   void FinishOffer();
   uint32_t source_actions() const;
   uint32_t dnd_action() const;
@@ -65,14 +54,11 @@
   static void OnAction(void* data, wl_data_offer* offer, uint32_t dnd_action);
 
   wl::Object<wl_data_offer> data_offer_;
-  std::vector<std::string> mime_types_;
   // Actions offered by the data source
   uint32_t source_actions_;
   // Action selected by the compositor
   uint32_t dnd_action_;
 
-  bool text_plain_mime_type_inserted_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(WaylandDataOffer);
 };
 
diff --git a/ui/ozone/platform/wayland/host/wayland_data_source.cc b/ui/ozone/platform/wayland/host/wayland_data_source.cc
index 1f41fd6..4dcbeb9 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_source.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_source.cc
@@ -5,15 +5,13 @@
 #include "ui/ozone/platform/wayland/host/wayland_data_source.h"
 
 #include "base/files/file_util.h"
+#include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace ui {
 
-constexpr char kTextMimeType[] = "text/plain";
-constexpr char kTextMimeTypeUtf8[] = "text/plain;charset=utf-8";
-
 WaylandDataSource::WaylandDataSource(wl_data_source* data_source,
                                      WaylandConnection* connection)
     : data_source_(data_source), connection_(connection) {
@@ -30,8 +28,8 @@
     const PlatformClipboard::DataMap& data_map) {
   for (const auto& data : data_map) {
     wl_data_source_offer(data_source_.get(), data.first.c_str());
-    if (strcmp(data.first.c_str(), kTextMimeType) == 0)
-      wl_data_source_offer(data_source_.get(), kTextMimeTypeUtf8);
+    if (strcmp(data.first.c_str(), kMimeTypeText) == 0)
+      wl_data_source_offer(data_source_.get(), kMimeTypeTextUtf8);
   }
   wl_data_device_set_selection(connection_->data_device(), data_source_.get(),
                                connection_->serial());
@@ -39,16 +37,11 @@
   connection_->ScheduleFlush();
 }
 
-void WaylandDataSource::UpdateDataMap(
-    const PlatformClipboard::DataMap& data_map) {
-  data_map_ = data_map;
-}
-
 void WaylandDataSource::Offer(const ui::OSExchangeData& data) {
   // TODO(jkim): Handle mime types based on data.
   std::vector<std::string> mime_types;
-  mime_types.push_back(kTextMimeType);
-  mime_types.push_back(kTextMimeTypeUtf8);
+  mime_types.push_back(kMimeTypeText);
+  mime_types.push_back(kMimeTypeTextUtf8);
 
   source_window_ =
       connection_->wayland_window_manager()->GetCurrentFocusedWindow();
@@ -94,8 +87,8 @@
   } else {
     base::Optional<std::vector<uint8_t>> mime_data;
     self->GetClipboardData(mime_type, &mime_data);
-    if (!mime_data.has_value() && strcmp(mime_type, kTextMimeTypeUtf8) == 0)
-      self->GetClipboardData(kTextMimeType, &mime_data);
+    if (!mime_data.has_value() && strcmp(mime_type, kMimeTypeTextUtf8) == 0)
+      self->GetClipboardData(kMimeTypeText, &mime_data);
     contents.assign(mime_data->begin(), mime_data->end());
   }
   bool result =
@@ -113,7 +106,8 @@
     self->connection_->FinishDragSession(self->dnd_action_,
                                          self->source_window_);
   } else {
-    self->connection_->clipboard()->DataSourceCancelled();
+    self->connection_->clipboard()->DataSourceCancelled(
+        ClipboardBuffer::kCopyPaste);
   }
 }
 
@@ -133,17 +127,6 @@
   self->dnd_action_ = dnd_action;
 }
 
-void WaylandDataSource::GetClipboardData(
-    const std::string& mime_type,
-    base::Optional<std::vector<uint8_t>>* data) {
-  auto it = data_map_.find(mime_type);
-  if (it != data_map_.end()) {
-    data->emplace(it->second);
-    // TODO: return here?
-    return;
-  }
-}
-
 void WaylandDataSource::GetDragData(const std::string& mime_type,
                                     std::string* contents) {
   auto it = drag_data_map_.find(mime_type);
diff --git a/ui/ozone/platform/wayland/host/wayland_data_source.h b/ui/ozone/platform/wayland/host/wayland_data_source.h
index 5cddfb7..7ee699b 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_source.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_source.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/internal/wayland_data_source_base.h"
 #include "ui/ozone/public/platform_clipboard.h"
 
 namespace ui {
@@ -28,22 +29,21 @@
 // transfer and provides a way to describe the offered data
 // (wl_data_source_offer) // and a way to respond to requests to
 // transfer the data (OnSend listener).
-class WaylandDataSource {
+class WaylandDataSource : public internal::WaylandDataSourceBase {
  public:
   using DragDataMap = std::map<std::string, std::string>;
 
   // Takes ownership of data_source.
   explicit WaylandDataSource(wl_data_source* data_source,
                              WaylandConnection* connection);
-  ~WaylandDataSource();
+  ~WaylandDataSource() override;
 
   void set_connection(WaylandConnection* connection) {
     DCHECK(connection);
     connection_ = connection;
   }
 
-  void WriteToClipboard(const PlatformClipboard::DataMap& data_map);
-  void UpdateDataMap(const PlatformClipboard::DataMap& data_map);
+  void WriteToClipboard(const PlatformClipboard::DataMap& data_map) override;
   void Offer(const ui::OSExchangeData& data);
   void SetAction(int operation);
   void SetDragData(const DragDataMap& data_map);
@@ -63,15 +63,12 @@
   static void OnDnDFinished(void* data, wl_data_source* source);
   static void OnAction(void* data, wl_data_source* source, uint32_t dnd_action);
 
-  void GetClipboardData(const std::string& mime_type,
-                        base::Optional<std::vector<uint8_t>>* data);
   void GetDragData(const std::string& mime_type, std::string* contents);
 
   wl::Object<wl_data_source> data_source_;
   WaylandConnection* connection_ = nullptr;
   WaylandWindow* source_window_ = nullptr;
 
-  PlatformClipboard::DataMap data_map_;
   DragDataMap drag_data_map_;
   // Action selected by the compositor
   uint32_t dnd_action_;
diff --git a/ui/ozone/platform/x11/x11_clipboard_ozone.cc b/ui/ozone/platform/x11/x11_clipboard_ozone.cc
index 9724513..0f8b04c4 100644
--- a/ui/ozone/platform/x11/x11_clipboard_ozone.cc
+++ b/ui/ozone/platform/x11/x11_clipboard_ozone.cc
@@ -21,7 +21,6 @@
 
 const char kChromeSelection[] = "CHROME_SELECTION";
 const char kClipboard[] = "CLIPBOARD";
-const char kMimeTypeUtf8[] = "text/plain;charset=utf-8";
 const char kString[] = "STRING";
 const char kTargets[] = "TARGETS";
 const char kTimestamp[] = "TIMESTAMP";
@@ -31,7 +30,7 @@
 void ExpandTypes(std::vector<std::string>* list) {
   bool has_mime_type_text = Contains(*list, ui::kMimeTypeText);
   bool has_string = Contains(*list, kString);
-  bool has_mime_type_utf8 = Contains(*list, kMimeTypeUtf8);
+  bool has_mime_type_utf8 = Contains(*list, kMimeTypeTextUtf8);
   bool has_utf8_string = Contains(*list, kUtf8String);
   if (has_mime_type_text && !has_string)
     list->push_back(kString);
@@ -40,7 +39,7 @@
   if (has_mime_type_utf8 && !has_utf8_string)
     list->push_back(kUtf8String);
   if (has_utf8_string && !has_mime_type_utf8)
-    list->push_back(kMimeTypeUtf8);
+    list->push_back(kMimeTypeTextUtf8);
 }
 
 XID FindXEventTarget(const XEvent& xev) {
@@ -188,7 +187,7 @@
     std::string key = target_name;
     // Allow conversions for text/plain[;charset=utf-8] <=> [UTF8_]STRING.
     if (key == kUtf8String && !Contains(offer_data_map, kUtf8String)) {
-      key = kMimeTypeUtf8;
+      key = kMimeTypeTextUtf8;
     } else if (key == kString && !Contains(offer_data_map, kString)) {
       key = kMimeTypeText;
     }
@@ -355,7 +354,7 @@
   if (!Contains(selection_state.mime_types, target)) {
     if (target == kMimeTypeText) {
       target = kString;
-    } else if (target == kMimeTypeUtf8) {
+    } else if (target == kMimeTypeTextUtf8) {
       target = kUtf8String;
     }
   }
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index 424575a..c9217806 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -634,32 +634,6 @@
   native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
 }
 
-void DesktopWindowTreeHostPlatform::DispatchEvent(ui::Event* event) {
-#if defined(USE_OZONE)
-  // Make sure the |event| is marked as a non-client if it's a non-client
-  // mouse down event. This is needed to make sure the WindowEventDispatcher
-  // does not set a |mouse_pressed_handler_| for such events, because they are
-  // not always followed with non-client mouse up events in case of
-  // Ozone/Wayland or Ozone/X11.
-  //
-  // Also see the comment in WindowEventDispatcher::PreDispatchMouseEvent..
-  aura::Window* content_window = desktop_native_widget_aura_->content_window();
-  if (content_window && content_window->delegate()) {
-    if (event->IsMouseEvent()) {
-      ui::MouseEvent* mouse_event = event->AsMouseEvent();
-      int flags = mouse_event->flags();
-      int hit_test_code = content_window->delegate()->GetNonClientComponent(
-          mouse_event->location());
-      if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
-        flags |= ui::EF_IS_NON_CLIENT;
-      mouse_event->set_flags(flags);
-    }
-  }
-#endif
-
-  WindowTreeHostPlatform::DispatchEvent(event);
-}
-
 void DesktopWindowTreeHostPlatform::OnClosed() {
   SetPlatformWindow(nullptr);
   desktop_native_widget_aura_->OnHostClosed();
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
index 65f4ed9e..2d1d013 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -96,7 +96,6 @@
   void HideImpl() override;
 
   // PlatformWindowDelegateBase:
-  void DispatchEvent(ui::Event* event) override;
   void OnClosed() override;
   void OnWindowStateChanged(ui::PlatformWindowState new_state) override;
   void OnCloseRequest() override;